341

I had a heated discussion today about our MVC application. We have a website written in MVC (ASP.NET), and it usually follows the pattern of do something in the view -> hit the controller -> controller builds a model (calls a Manager that gets the data, builds the model in the controller method itself) -> model goes to view -> rinse & repeat.

He said that our code was too tightly coupled. For example, if we wanted a desktop application as well, we would not be able to use our existing code.

The solution and best practice he said is to build an API, and then build your website on top of your API, and then building a desktop application, mobile app, etc. is very simple.

This seems like a bad idea to me for various reasons.

Anyway I can't seem to find anything by googling that might discuss this practice. Does anyone have any information about pros, cons, why you should, why you shouldn't or further reading?

Some reasons I think it's a bad idea:

  • It's way too abstract to run your backend off an API. You're trying to make it too flexible which will make it an unmanagable mess.

  • All the stuff built into MVC seems useless, like roles and authentication. For example, [Authorize] attributes and security; you will have to roll your own.

  • All your API calls will require security information attached, and you will have to develop a token system and whatnot.

  • You will have to write complete API calls for every single function your program will ever do. Pretty much every method you want to implement will need to be ran off an API. A Get/Update/Delete for every user, plus a variant for each other operation eg update user name, add user to a group, etc. etc. and each one would be a distinct API call.

  • You lose all kinds of tools like interfaces and abstract classes when it comes to APIs. Stuff like WCF has very tenuous support for interfaces.

  • You have a method that creates a user, or performs some task. If you want to create 50 users, you can just call it 50 times. When you decide to do this method as an API your local webserver can named-pipes connect to it and no problem - your desktop client can hit it too, but suddenly your bulk user creation will involve hammering the API over the Internet 50 times which isn't good. So you have to create a bulk method, but really you're just creating it for desktop clients. This way, you end up having to a) modify your API based on what's integrating with it, and you can't just directly integrate with it, b) do a lot more work to create an extra function.

  • YAGNI. Unless you're specifically planning to write two identically functioning applications, one web and one Windows application for example, it is a huge amount of extra development work.

  • Debugging is much harder when you can't step through end-to-end.

  • Lots of independent operations that will require lots of back and forth, for example some code might get the current user, check the user is in the administrator role, get the company the user belongs to, get a list of other members, send them all an email. That would require a lot of API calls, or writing a bespoke method the specific task you want, where that bespoke method's only benefit would be speed yet the downside would be it would be inflexible.

  • Probably some more reasons these are just off the top of my head.

It just seems to me like unless you really need two identical applications, then it's really not worth it. I've never seen an ASP.NET application built like this either, you'd have to write two separate applications (the API and your code) and version control them both as well (if your user page gets a new field, you'd have to update the API and your consuming code simultaneously to ensure no ill-effects or put lots of extra work into keeping it robust).


Edit: Some great responses, really starting to get a good idea of what this all means now. So to expand on my question, how would you structure an MVC app to follow this API structure?

For example, you have a website that displays info about a user. Under MVC, you have:

View - (CS)HTML page that displays a UserViewModel Controller - Calls GetUser() and creates a UserViewModel that it passes to the view Manager class (sort of your API) that has a GetUser method.

The controller does GetUser() but you want a desktop app too. This means your GetUser needs to be exposed via some kind of API. You might want a TCP connection, either WCF, or perhaps Remoting. You also want a mobile app which will be RESTful since persistent connections are flaky.

So would you then write an API for each one, a WCF web service that has a method GetUser() and the code just does return new UserManager().GetUser() ? And an mvc 4 web api method that does the same thing? While continuing to call GetUser directly in your MVC controller method?

Or would you choose the solution that would work for all three (web api REST service) and build everything on that, so all three apps make API calls (the mvc ones, to the local machine).

And is this just a theoretical perfect scenario? I can see large overheads in developing this way, especially if you have to develop in a way that will let you do operations in a RESTful manner. I think some of this has been covered in the replies.


Edit 2: After reading more stuff, I've put a comment below that I think might explain it. The question is a bit of a trick question I think. Should you write your back-end as an API had me confused thinking there should be a single webservice that everything (mvc app, desktop app, mobile app) calls to do stuff.

The conclusion I have come to is that what you should really do is make sure your business logic layer is correctly decoupled. Looking at my code, I do this already - the controller will call GetUser() on a manager, then create a view model from it to render with a View. So really, the business logic layer is an API. If you want to call it from a desktop app though, you'll need to write something like a WCF service to facilitate calling it. Even just having a WCF method called GetUser() that contains the code return MyBusinessLayer.GetUser() would be sufficient. So the API is the business logic, and WCF / web api etc. are just titbits of code to let external applications in to call it.

So there is some overhead, in that you have to wrap your business logic layer in different APIs depending on what you need, and you will have to write an API method for each operation you want your other apps to do, plus you will need to sort out a way to do authentication, but for the most part it's the same. Stick your business logic in a separate project (class library), and you will probably have no issue!

Hopefully this interpretation is correct. Thanks for all the discussion/comments it has generated.

26
  • 28
    Could you please expose the reasons why you think it would be a bad idea ? Nowadays I must admit I see no reason NOT to do it. It makes, among other advantages, porting your application to different platforms much easier and allows a great flexibility on front-end without even touching your back-end code...
    – Laurent S.
    Commented Jun 25, 2015 at 12:14
  • 13
    @SLC: When you say API, do you mean a web service API like a SOAP or REST interface? Because you should make the back-end an API, but you shouldn't make it a web service.
    – JacquesB
    Commented Jun 25, 2015 at 15:34
  • 7
    @IanNewson "a mobile app, for example, they tend to have less features." I have never heard a convincing reason why mobile apps should be second class citizens... (yet everybody seems to do it this way)
    – Michael
    Commented Jun 25, 2015 at 16:31
  • 3
    @IanNewson maybe it's just me then... but I always find myself hamstrung by not being able to do some thing or other on mobile to the point where I do very little on mobile
    – Michael
    Commented Jun 25, 2015 at 17:06
  • 13
    You say YAGNI applies, but my experience has been apps either get a UI rewrite every couple years, or everyone complains that they do need one. Sure would be nice if we didn't lose our busniess logic because a new front end technology has arrived.
    – corsiKa
    Commented Jun 25, 2015 at 19:03

14 Answers 14

298

Yes you should.

It not only makes your back end re-usable but allows for more security and better design. If you write your backend as part of a single system, you're making a monolithic design that's never easy to extend, replace or enhance.

One area where this is popular at the moment is in Microservices. Where the backend is split into many little (or even large) services that each provide an API that the client system consumes. If you imagine using many 3rd party sources of data in your application you realise you might be doing this already.

One other benefit is that the construction and maintenance of each service can be handed off to a different team, they can add features to it that do not affect any other team producing product. Only when they are done and release their service do you them start to add features to your product to consume them. This can make development much smoother (though potentially slower overall, you would tend to get better quality and understandable)


Edit: OK I see your problem. You think of the API as a remote library. It's not. Think of the service as more of a data providing service. You call the service to get data and then perform operations on that data locally. To determine if a user is logged on you would call "GetUser" and then look at the 'logged on' value, for example. (YMMV with that example, of course).

Your example for bulk user creation is just making excuses - there is no difference here, whatever you could have done in a monolithic system can still be done in a service architecture (e.g. you would have passed an array of users to bulk-create, or a single one to create. You can still do exactly the same with services).

MVC is already based around the concept of isolated services, only the MVC frameworks bundle them into a single project. That doesn't mean you lose anything except the bundled helpers that your framework is giving you. Use a different framework and you'll have to use different helpers. Or, in this case, rolling your own (or adding them directly using a library).

Debugging is easy too - you can thoroughly test the API in isolation so you don't need to debug into it (and you can debug end-to-end, Visual Studio can attach to several processes simultaneously).

Things like extra work implementing security is a good thing. Currently, if you bundle all the code into your website, if a hacker gains access to it, they also gain access to everything, DB included. If you split it into an API the hacker can do very little with your code unless they also hack the API layer too - which will be incredibly difficult for them (ever wondered how attackers gain vast lists of all website's users or cc details? It's because they hacked the OS or the web server and it had a direct connection to the DB where they could run "select * from users" with ease).

I'll say that I have seen many web sites (and client-server applications) written like this. When I worked in the financial services industry, nobody would ever write a website all-in-one, partly as it's too much of a security risk, and partly because much development is pretty GUIs over stable (i.e. legacy) back-end data processing systems. It's easy to expose the DP system as a website using a service style architecture.

2nd Edit: Some links on the subject (for the OP):

Note that when talking about these in context of a website, the web server should be considered the presentation layer, because it is the client that calls the other tiers, and also because it constructs the UI views that are sent to the browser for rendering. It's a big subject, and there are many ways to design your application - data-centric or domain-centric (I typically consider domain centric to be 'purer', but YMMV), but it all comes down to sticking a logic tier in between your client and your DB. It's a little like MVC if you consider the middle, API, tier to be equivalent to your Model, only the model is not a simple wrapper for the DB, it's richer and can do much more (e.g. aggregate data from 2 data sources, post-process the data to fit the API, cache the data, etc.):

15
  • 2
    Is that a yes from an architecture astronaut perspective? I can understand your 2nd and 3rd paragraphs from a service point of view, but we're talking about GetUser, CreateUser, IsUserLoggedIn and hundreds of tiny functions that were previously single lines of code being converted into API calls.
    – NibblyPig
    Commented Jun 25, 2015 at 13:19
  • 13
    Imagine you're writing it as a website - all those tiny functions cannot be as interactive as you imagine, so you'll have to get the data and cache it locally while you construct your page (or pass them as potentially stale data to the client, as appropriate to the system). For a lot of this, you have to change your design from "react on demand" to "anticipate up front" but most of your system will be making API calls. Design your API to be less granular and more data-centric, so IsUserLoggedOn doesn't have to be an API call, you only need a "GetUserDetails" once that you then inspect locally.
    – gbjbaanb
    Commented Jun 25, 2015 at 13:25
  • 5
    We used this method at my last place of employment and it worked wonderfully. Our main product was a web app, but we were able to create a desktop app and even Excel sheets that could access the same web services as our web app did for all of it's data, and additionally expose the services to our clients so they could program against them.
    – Kik
    Commented Jun 25, 2015 at 21:06
  • 2
    Here's another benefit: you can expose the backend API to your website customers. At our company, we did this, and some big software company customers (after trying out the backend on our host) paid to have the backend wrapped up as a self-hosted product all by itself. Depending on the product, some customers are less interested in the frontend veneer and much more interested in what your product actually does - the backend. That's another product to sell.
    – Reid
    Commented Jun 25, 2015 at 22:28
  • 2
    This also makes it easier to use the same logic from a webservice. One of those things that our teams always think we'll never have to do... It makes unit testing easier, as well.
    – ps2goat
    Commented Jun 26, 2015 at 21:13
97

You cannot possibly avoid building an API. Even if you build "just a Website", it will still need to get its data from your backend somehow. However you decide to do this, that is your de facto API.

Knowing this, the real question isn't whether to build an API, but how to build it. You can do it on-the-fly as an ad hoc thing -and indeed, many Websites are built exactly this way- or you can design it carefully to be usable in other contexts. Put into this context, it becomes pretty clear that your colleague is right: you should do the API first, and then build your site on top of it.

Nevertheless, this brings with it some concerns, as you point out. To address them:

It's way too abstract to run your backend off an API. You're trying to make it too flexible which will make it an unmanageable mess.

That depends on how you do it. As George Pólya points out in his excellent text How to Solve It, oftentimes "the more general problem may be easier to solve". This is called the Inventor's Paradox. In the case of programming, it often works by means of separation of concerns: your backend no longer has to be concerned with the format of the data that it puts in and takes out, and so its code can be much simpler. Your data parsers and renderers no longer have to be concerned with what happens to the data they create, so they, too, can be simpler. It all works by breaking the code down into more manageable chunks.

All the stuff built into MVC seems useless, like roles and authentication. For example, [Authorize] attributes and security; you will have to roll your own.

I confess that I find it extremely difficult to sympathize with people who refuse to learn their tools. Just because you do not understand their use does not mean that they are useless, and it certainly doesn't mean you should roll your own. Quite the contrary; you shouldn't go rolling your own tools until you understand the alternatives, so that you can be sure to address the same problems that they do (even if only in your own ways).

Consider Linus Torvalds, who is most famous for writing Linux, but who also wrote git: now one of the most popular version-control systems in the world. One of the driving factors in his design was a deep opposition to Subversion (another extremely popular VCS, and arguably the most popular at the time git was written); he resolved to take everything that Subversion could, and to whatever extent it was possible, solve those problems differently. To do this, he had to become an expert on Subversion in his own right, precisely so that he could understand the same problem domains and take a different approach.

Or, in the process of learning your tools, you may find yourself finding that they're useful as-is, and don't need to be replaced.

All your API calls will require security information attached, and you will have to develop a token system and whatnot.

Yes. This is how it should be.

You will have to write complete API calls for every single function your program will ever do. Pretty much every method you want to implement will need to be ran off an API. A Get/Update/Delete for every user, plus a variant for each other operation eg update user name, add user to a group, etc. etc. and each one would be a distinct API call.

Not necessarily. This is where architectures like REST come into play. You identify the resources your application works with, and the operations that make sense to apply to those resources, and then you implement these without worrying so much about the others.

You lose all kinds of tools like interfaces and abstract classes when it comes to APIs. Stuff like WCF has very tenuous support for interfaces.

On the contrary, interfaces become much more important when you're using an API, not less. They come out in the representations you render them into. Most people nowadays specify a JSON-based format for this, but you can use any format you wish, as long as you specify it well. You render the output of your calls to this format on the backend, and parse it out into whatever you wish (likely the same kind of object) on the frontend. The overhead is small, and the gains in flexibility are huge.

You have a method that creates a user, or performs some task. If you want to create 50 users, you can just call it 50 times. When you decide to do this method as an API your local webserver can named-pipes connect to it and no problem - your desktop client can hit it too, but suddenly your bulk user creation will involve hammering the API over the Internet 50 times which isn't good. So you have to create a bulk method, but really you're just creating it for desktop clients. This way, you end up having to a) modify your API based on what's integrating with it, and you can't just directly integrate with it, b) do a lot more work to create an extra function.

Creating a bulk version of an existing method is hardly something I would call "a lot more work". If you're not worried about things like atomicity, the bulk method can wind up being not much more than a very thin frontend for the original.

YAGNI. Unless you're specifically planning to write two identically functioning applications, one web and one Windows application for example, it is a huge amount of extra development work.

No, YANI (You Already Need It). I outlined that as above. The only question is how much design work to put into it.

Debugging is much harder when you can't step through end-to-end.

Why wouldn't you be able to step through end-to-end?

But more to the point, being able to examine the data going back and forth in an easily-recognized format that cuts out all the display cruft actually tends to make debugging easier, not harder.

Lots of independent operations that will require lots of back and forth, for example some code might get the current user, check the user is in the administrator role, get the company the user belongs to, get a list of other members, send them all an email. That would require a lot of API calls, or writing a bespoke method the specific task you want, where that bespoke method's only benefit would be speed yet the downside would be it would be inflexible.

REST solves this by working on complete objects (resources, to use REST theory's terms), rather than the individual properties of objects. To update a user's name, you GET the user object, change its name, and PUT the user back. You might make other changes at the same time as you change the user name too. The more general problem becomes easier to solve, because you can eliminate all those individual calls for updating individual properties of an object: you just load it and save it.

In some ways, this is not unlike RISC architectures on the hardware side. One of the key difference between RISC and CISC (its predecessor) is that CISC architectures tend to include many instructions that operate directly on memory, while RISC architectures tend to operate mostly in registers: in a purely RISC architecture, the only operations on memory are LOAD (copy something from memory into a register) and STORE (take a value from a register and put it into memory).

You'd think that this would mean taking many more trips from registers out to memory, which would slow down the machine. But in practice, the opposite often happens: the processor (client) does more work between trips to memory (server), and this is where the speedup comes from.

Long story short: your colleague is right. This is the way to go. In exchange for a little up-front work, it will dramatically simplify the code for your Website and enable better integration with other Websites and apps. That is a price worth paying.

Further reading:

  1. REST API Design - Resource Modeling
9
  • 8
    Even these have de facto APIs of a sort. They tend to make many other developers blanch in horror, but they're APIs all the same; just not very well-designed ones. Commented Jun 26, 2015 at 12:59
  • 8
    That makes for a really poor API: so poor that many people don't even think of it as an API at all. But it still defines the way that the frontend interacts with the backend, however crude that way might be. Thinking of this as an API helps drive home the importance of doing it well. Commented Jun 26, 2015 at 17:32
  • 1
    I think Linus made git because the Linux community rebelled against the use of the commercial Bitkeeper DVCS that was used for the kernel.
    – gbjbaanb
    Commented Jun 26, 2015 at 22:03
  • 2
    Your first sentence dispels all of my confusion. I associated the term API with a web service and that is the main reason I was so confused.
    – NibblyPig
    Commented Jun 27, 2015 at 0:05
  • 4
    @IanNewson: there is a way to interface with the code, it's called http. It may have a lot of irrelevant requirements and return a lot of irrelevant data, but that is what makes it a lousy API.
    – jmoreno
    Commented Jun 29, 2015 at 6:08
63

I know microservices are all the rage right now, but they aren't always worth it. Yes, loosely coupled code is the goal. But it shouldn't come at the expense of a more painful development cycle.

A good middle ground would be to create a separate data project in your solution. The data project would be a .NET class library. Your ASP.NET MVC project would then add a reference to the data library, and all models would be pulled from the data project. Then when the time came to create a desktop or mobile app, you could reference the same code. So it may not be an official API, but it will function as one. If you wanted to make it accessible as an API, you could create a simple web project that acts as a wrapper on the data project.

Microsoft has been promoting this concept, which they call Portable Class Libraries.

2
  • 16
    I have had to maintain a project where the logic was put in the UI layer, calling the same shared data structures. I have had to fix one bug thirty times because of that ("if we need to use the same logic again we will copy & paste! no need for an API"). Had been there a logic layer (now there is) it would have been enough with just one fix.
    – SJuan76
    Commented Jun 27, 2015 at 17:55
  • 1
    This answer, in addition to wrapping that library into its own NuGet package and hosting your own NuGet package feed/server is a good way to go as well. You don't need to worry about finicky networks and can make all calls local to a thread (and therefore faster), plus introducing proper version to your class lib with NuGet gives other teams flexibility in when they upgrade. Commented Jun 30, 2015 at 13:02
34

No you shouldn't. If you don't have immediate plans to create alternative frontends (like mobile or desktop apps or separate web application) which access the same backend, then you shouldn't introduce a web service layer. YAGNI.

Loose coupling is always desirable (along with high cohesion), but it is a design principle and does not mean you have to physically separate objects on different servers! And a badly designed service API can create tight coupling across server boundaries, so having an API does not guarantee loose coupling.

If the need for a service API should arise in the future you can always introduce it at that point. As long as you keep your code nicely layered (data access and business logic cleanly separated form UI logic), it will not be harder to introduce later than it is now. And the resulting design will be much better when designed to meet actual requirements.


Note I'm assuming the question is if you should create a web service API or not. The question just says API, but API can also just mean the interface of a library, and then of course every layer will have an API by definition. Bottom line is that your business logic and data access layers should be cleanly separated form the UI logic at the design level, but you shouldn't introduce a web service layer if you don't need it.

14
  • 8
    Badly designed anything isn't good. Building an API isn't more time and is more future-proof. The ability to adapt to change being vital nowadays, better build a strong base to fulfill any needs that you don't even know about but that might come sooner than you think...
    – Laurent S.
    Commented Jun 25, 2015 at 21:37
  • 11
    @Bartdude: Introducing needless complexity for the sake of "future-proofing" for a future which will not arrive is just wasting resources.
    – JacquesB
    Commented Jun 26, 2015 at 6:52
  • 6
    @Bartdude adding an api is definitely more time. No idea how you think you can claim otherwise.
    – Ian Newson
    Commented Jun 26, 2015 at 7:19
  • 15
    "you shouldn't introduce a web service layer" API != web service. If you have your business logic behind an API, then you can expose that API as a web service at some point. It's not an up-front requirement, though.
    – Celos
    Commented Jun 26, 2015 at 7:35
  • 2
    @JacquesB : ... so you indeed don't develop features if you're not sure you're going to need it. That's what I understand from YAGNI. Yet architecture is not a feature and bad architectural choices can (and most probably will) lead to a miserable failure. Once again I assume this discussion can even occur, which is sometimes not the case was it for budget, time-to-market, ressources or lack-of-knowledge reasons... I think we can totally agree to disagree on this, although I understand your point as I often had the same discussion with myself ^_^
    – Laurent S.
    Commented Jun 26, 2015 at 8:56
29

My company has one application built like this. Initially we were commissioned to build a back end with API for a front end that another developer was creating. When the other developer couldn't develop that front end we were commissioned to build the front end too. While there are definitely benefits to this approach there is a huge disadvantage: cost. The initial build will be significantly more expensive, and ongoing maintenance will be more expensive, due to more code to maintain and having two separate systems too deploy. Due to the extra cost, this should always be a business decision, not taken on a whim by developers.

To put a figure on it, I'd estimate the project I mention above cost 20% more due to this approach. You don't describe what type of project you're working on what sort of company you work for, but if you're a start up building their product that extra cost could be the difference between shipping a few extra features that make your product a success.

Another reason not to, at least not universally, is that if or when you decide to create that second interface, there's a rarely a one to one mapping of functionality. If you make a mobile app, for example, they tend to have less features. This means some of your API methods won't ever be reused. Therefore a compromise with your colleague could be to decide between you the most crucial/critical calls and add those to an API, and use more traditional methods for everything else.

Another point to consider is that your colleague is saying you won't be able to reuse your existing code, which isn't true if you have some separation of your business logic. You simply need to create a thin web service wrapper around your internal APIs, which isn't a particularly big task. It would be naive to think you could reuse a web service layer for another front end anyway with no changes at all.

22

It depends on the type of application and the type of market you are in.

There are trade-offs and benefits to going this way. It is not a clear-cut answer that one way is better than the other.

I'll talk from personal experience. I was the one who decided to take the codebase that I work on in this direction back in 2007. That codebase is somewhere in the order of a million lines of code now, half of which is server code hidden behind a massive amount of web service API's, the other half is a flotilla of clients, desktop native, desktop web, mobile, back-end integrations, etc... This decision was not without its downsides, but with 20/20 hindsight I can say I would do it again. Let me indicate some of the trade-offs involved.

Benefits

  • Flexibility. Whether it's a request to build a mobile app to augment the desktop experience, or a request to integrate with SAP's back-end, it all becomes easier when you already have an API to call. When you get enough of these requests, you will organically evolve towards an API, and the only question is whether that has a standard web service in front of it, or whether it is an internal API where the web services are tailor-made.

  • Scalability (of the team). In our case we have many different groups of developers all building on top of this API. We even have dedicated API teams, who talk to the different groups, summarize the needs, and construct an all-purpose API out of it. It's gotten to the point where we're not even told anymore that people are building stuff on top of the API, and not everyone who does that works for our company.

  • Security. Having a clear-cut division between the unsafe and safe parts of your codebase is helpful in reasoning out security. Muddling the UI and back-end code together tends to confuse matters.

Trade-offs

  • Flexibility. You have to do the work to "properly" build something into the API. It's not possible to quickly run a DB query from inside the UI code to solve a specific problem. Also, API's which are actually reusable must take so many use-cases into account that the quick solution is usually the wrong solution. The API becomes less flexible to evolve, especially since there is so much client-code already out there (we're transitioning to a versioned API for that reason).

  • Initial development speed. It is slower to develop API-first, without a shred of a doubt. You only win it back when you have enough clients built on top of the API. But then you find that you need 3 different client implementations before your API has evolved to be generic enough. We found that most of our initial API designs were wrong and have had to strongly revise our guidelines for how to build web services.

Red herrings

You mentioned a bunch of these. They don't actually matter in practice.

  • Abstraction. Your API becomes abstract enough to cover all use cases that your product needs to serve, and no more than that. Even without web services you'll either have an internal API which does this, or have lots of duplicate code. I prefer abstraction over duplication.

  • Abandoning the server-side MVC stack. These days almost every system will after a while need a mobile app. When you then build web services to cater to that mobile app, you will have to figure out how to do authentication and authorization in an API context anyway. It is actually less work when you only have one way of doing that, the way you do it in your web services.

  • Bulk operations. Typically solved by creating a bulk API which launches a back-end job and returns a job id for status querying. It's not that big of a deal.

  • Debugging. I found that on the whole it became slightly easier to troubleshoot the system. You can still set breakpoints in both front-end and back-end code, so in practice it's not that harder to step through, and you gain the ability to build automated api tests and to instrument the api for monitoring production systems.

  • Lots of independent operations. That's a matter of how you design things. If you insist on having a pure CRUD API, then yes, you will suffer from this issue. But having some CQRS API's to augment that is typically a good idea, and if you have made sure that you have an internal API for which the services are a front-end, then you can easily reuse that internal API to construct services for those specific scenario's.

In Summary

In a system that is used in enough different contexts, an API will naturally evolve as it is the easiest way to cater to all the needs. But there is definitely a case of YAGNI going on. There are trade-offs and it doesn't make sense until it makes sense. The key point is to not be dogmatic and to keep an open mind towards different approaches in architecture to meet the evolving needs of the product.

2
  • Interesting read, can you elaborate on what you did wrong when designing the API, and what you learned? Commented Jun 27, 2015 at 18:03
  • 3
    The three main mistakes were: (1) overfitting the api to the needs of the primary ui, (2) building up state across multiple requests using sessions (we're gradually becoming sessionless), and (3) only supporting the use of generated db id as identifier where a user-configurable code is often a better identifier (for integrations with external systems typically they want to upload identifiers into our system for later use in api's, instead of vice versa). Those three together with weak documentation and unhelpful error messages made the api impossible to use without assistance. Commented Jun 28, 2015 at 13:18
10

What your colleague is describing is a service oriented architecture. This can be a tremendously scalable, testable and sane way to code, but it really depends on what you are making.

There are some significant benefits to SOA, which I will attempt to ennumerate:

Scalability

Since your back end is decoupled, your front end becomes just a series of templates, even flatfiles. Flatfiles are tremendously quick and cheap to serve from any CDN. They can be minified and precompiled into static HTML, then populated with data clientside.

Your API has to remain consistent, but can be swapped for a faster technology without breaking your stack if you outgrow your existing technology. You could remake it in Go for example. You could rebuild it piecemeal and spread the load across servers. As long as the interface remains the same the technology is abstracted.

Testability

MVC usually starts out clean, but in practice controllers rarely stay focussed on a single resource. The more things your controller methods do the less testable they become.

An API sidesteps this issue. Each API call pulls a resource and serves it. Clean and testable.

Guaranteed separation of concerns

Your front end and back end are fully divorced. You can give the front end to another developer or a designer. This is MVC taken to another level. I'm sure you wouldn't want to give up on MVC. SOA is MVC but more-so.

Downsides

There are of course some downsides. A monolith is often faster to get going with. It may be what you are used to. It may fit more nicely into your stack. Your tools may be optimised for monolith creation.

None of these are particularly good reasons in my opinion, and you may wish to consider retooling if they apply to you.

1
  • This is the clearest answer so far.
    – Tony Ennis
    Commented Jul 4, 2015 at 13:48
7

The point of contention is not if you should use an API, but what an "API" actually is. The only alternative to using a designed API is to use an API which is a random mess of code. You write that an API makes things "too flexible" which in turn makes things unmanageable. This points to a complete and thorough misunderstanding of what an API is. If that misunderstanding is not shared between you and your coworker, then you wasted a lot of time by arguing over completely different things.

By not using a well-defined API you can do whatever you want. By definition this is the most flexible option. Also, by definition "do whatever you want" is still an API. The only job of an API is to remove flexibility. By removing flexibility a good API encourages a user to do similar things in similar ways.

Of course a bad API can either provide too much or too little flexibility, or even both at the same time. A really poorly designed API can kill a project even faster than the "anything goes" approach. However, best practice is simply to have competent programmers who develop and evolve the API alongside your application.

Example

•Lots of independent operations that will require lots of back and forth, for example some code might get the current user, check the user is in the administrator role, get the company the user belongs to, get a list of other members, send them all an email. That would require a lot of API calls, or writing a bespoke method the specific task you want, where that bespoke method's only benefit would be speed yet the downside would be it would be inflexible.

The number of API calls this would require on a decent API would probably be 1. Yes, it's inflexible, but why would you want it to be flexible?

7

There's a good deal of good answers here so I'll just add my implementation experience.

This how I do things:

  • Create a Database Access Layer that handles all/only DB interaction (usually manual SQL is used for speed and control, no ORM). Insert, Update, Delete, Select...
  • Create an interface (virtual class) that exposes/enforces the API functions I need. They will, when implemented, use the highly specialized DBAL functions to achieve the results. It also helps me to enforce the API at compiler level so I make sure the Server + API implementation have all the functions built in.
  • Create a Second Layer that implements the interface (this is the actual API) and enforces security restrictions. You also interact with external APIs here.
  • The Website will use the Second Layer directly (for performance) without going though a remote-accessible API (like SOAP, JSON).
  • A standalone Server is build that implements the interface and exposes the Second Layer as an actual remote-accessible API to external desktop/mobile clients (non-website access). All it does is decode requests and encode responses and manage/disconnect clients. It also supports pushback capabilities to mass-notify clients of events generated by other connected peers (functionality that a website does not usually require).

So, technically, the API is the Second Layer. You use directly it with the website and expose it to remote clients through a server. Code is reused and no reusable chunk of code is ever inline. (live and die by this rule and everything is awesome) Helps with maintainability, testing... everything.

You never connect the website to the desktop/mobile API server (unless your site is AJAX and runs on JSON). But if the site renders dynamic content in the markup, going through an intermediate API will shoot your performance. The website needs to be fast! Remote client access can be a tiny bit more slow.

PS: Yes, maintenance is a bit more complex as more wheels work together but it's easier in the long run. So if your project is meant to live for a while and is slightly complex, always have an API. It's also much easier to test each layer on its own.

1
  • That sounds quite cool and makes a lot of sense, especially putting an interface on your API type functions. I'm gonna try this set up next time I create a project!
    – NibblyPig
    Commented Jun 29, 2015 at 9:25
4

He said that our code was too tightly coupled. For example, if we wanted a desktop application as well, we would not be able to use our existing code.

Well, do you? If not, then that's a pretty irrelevant statement.

I'd say, if you were going to build a new application in 2015, then seriously look into something with a user interface that involves an API and not server generated HTML pages. There are clear costs but also clear benefits.

But if you have an existing site with no concrete plans to have several different interfaces (as far as I can tell), then his comments are just irrelevant.

4

Short Version: Your controller effectively an API no matter what; though ASP.NET may be obscuring that.

Longer Version:

Think about a basic MVC Web App that provides information about beer and optionally sells you one. What do the routes look like?

/sign_in
/sign_out
/beer
/beer/{beer_name}
/order
/order/{order_number}

In a normal web-app, there are likely a few ancillary routes like:

/beer/new
/beer/{beer_name}/edit
/beer/{beer_name}/delete
/order/new
/order/{order_number}/edit
/order/{order_number}/delete

In a Web API those are not required, as they're inferred from the HTTP method.

Given the above symmetry, I think this makes a pretty compelling case that your API and Controller are so close that they may as well be the same thing.

After doing some digging, I've determined that this might be the state of things for you depending on which version of ASP.NET you're using. The older MVC 5 and before lack the conventions and interface to soundly unify the two implementations. In old versions, Web App returns populates a View whereas the API gives an HttpResponse. In either case, though, they're generating the exact same response semantically.

If you're using MVC 6, you get both in a unified controller class that can be smart about what it returns. I haven't found any good ASP example code for this model, but I've found some Rails code with the same pattern. Consider this controller for "likes" from the Diaspora project. Each controller method has routes defined by a "resourceful convention" here that amount to the LCRUD in an API.

If you read the implementations, though, each can possibly respond to HTML, Mobile HTML, or JSON. This, combined with a convention for finding the views, completely unifies the Web App and Web API. You'll also note that not all methods actually provide each response (which makes sense, as the UI may require methods that the API won't, and vice versa).

This is an impedance mismatch because ASP.NET kind of figured all of this out late whereas Rails has embraced the symmetry for some time and makes it very clear.

Speculation:

Your coworker is probably both right and wrong, depending on which ASP version you're using. Under the old MVC version, the difference between the API and App probably did make it a "best practice" to build the API up-front because ASP.NET's model didn't really allow for good code reuse there.

With the newer one, it makes more sense to use unified code because it's been made easier to re-use code with the unified controller base class.

In either case, though, the Controller is effectively the API.

2
  • This question has been answered to death, but I don't think the other answers were quite as clear. The "You cannot possibly avoid building an API." answer was pretty much spot-on, and the accepted answer danced around the same issue; but both didn't address ASP specifically in a way that I felt drove the point home.
    – Jayson
    Commented Jun 30, 2015 at 10:25
  • More replies the merrier, they help to get a well-rounded appreciation of what other people feel about this.
    – NibblyPig
    Commented Jul 1, 2015 at 9:20
2

When I started my career in 2006 this type of architecture was all the rage in the .NET world. I worked on 3 separate projects conceived in the mid 2000s with a web service between the business logic layer and the web frontend. Of course these days the web services were SOAP but it is still the same architecture. The supposed benefits were the ability to switch either front or backend and even develop desktop program. Ultimately YAGNI proved to be true. I never ever saw any of this happen. All this time I only saw cost of splitting the project this way. I even ended up ripping the web service out of one of the projects (took half an year to remove it step by step while doing other things) and the whole team was happy. I never tried that approach since and I will not unless given a very specific reason. 5 years of experience trying this architecture taught me that I ain't gonna need it and no amount of experts telling me the opposite is going to convince me I will. Only a project where I need it may do that.

Now that being said I do try hard to develop a layer between the business logic and the controllers/presenters. For example I have a service layer, I never expose queriables, use interfaces for all my services and inject them in controllers with IoC. If I ever need a web service in my architecture I will be able to introduce it with a reasonable cost. I just don't want to pay this cost in advance.

Also I quite like the idea of microservices but my understanding is that microservices means vertical modules rather than horizontal layers. For example if you are building facebook the chat feature will be a separate service deployed separately on its own servers, etc. This is the type of independent services I would encourage.

2

Third parties will use it? Yes, you should.

You plan to re-use it in a not-so-far future? Yes, you should.
You will be your third party, having a documented - or documentable - or usable-by-third-parties API will provide you with solid reusability and modularity.

You're in a rush? No, you should not.
Refactoring afterwards is easier and faster than most methodologies and teachers predict and tell. It's more important to have something that's working (even with a bad internal design, as it can and will be refactored) than having nothing at all. (but with an incredible internal design, wohoo)

The front-end might never see the light of the day because of reasons? Yes, you should.
I added this reason because, well, this happened to me a lot.
And at least I'm left with my components to reuse and redistribute etc.

1

There are good answers here. I post this as a partial answer; it would perhaps be better as a comment. However sticking the same comment on numerous posts is not good.

One cannot claim YAGNI is a reason for not creating an API.

The API is a natural and logical testing endpoint. Thus right from day 0, there are two applications that use the API: the UI and the testing suite. One is meant for humans, the other is meant for machines. They are necessarily different. Testing front-end behavior is a much different task than testing back-end behavior. Thus the techniques, and probably the tools, are completely different. The API allows the best tool to be used for the job. Further, with the separation afforded by the API, the front-end testers don't have to test back-end functionality.

The API also helps keep the front-end coders out of the back-end coder's concerns, and vice-versa. These are very different skills at our company; the API allows us to focus where we're strongest.

Not the answer you're looking for? Browse other questions tagged or ask your own question.