In all of the years (since 1977 believe it or not) I have been programming in one form or another, I have seen many different techniques come and go. No sooner does a new programming paradigm appear, than it becomes the fashionable new kid on the block, and everyone comes on board. My first programming efforts involved punched cards, then along came paper tape, magnetic tape, disk drives, and suddenly everyone was jumping on this new programming language called Pascal which was going to solve all of the problems caused by COBOL, Fortran, etc.
Fads came and went. We learned about object-oriented (OO) programming. Even when we had a non-OO language (Pascal or Algol, or even COBOL), people started writing OO code. Then along came “Booching” named after one of the first pioneers of OO, Grady Booch. We gave our classes or generics (for those coding in Ada, one of the first real OO languages) fanciful names like “positional_bounded_linked_list_with_unique_identifiers” (yes, really). Along came better ways to organise our code, test harnesses, separate front end and back end components. We had client-server programming, then the internet appeared, and then suddenly it was Model-View-Controller (MVC). MVC first gained popularity starting in the mid 1990s and by the middle of the next decade there were multiple MVC frameworks for various different programming languages.
What is MVC?
Just as a quick reminder, this is what MVC is supposed to look like from a software architecture point of view:
MVC is designed to solve the development team scaling problem, in a huge, monolithic, full-stack web application. It separates the architecture of an application into three different parts. The first is the Model, the part of the code that deals with the data. The front end of the application, that part that the user interacts with, is called the View. In the middle, joining them together, is the Controller layer where all of the thinking happens. We thought that we’d cracked it, we could now develop code faster, collaborate between development teams better, and we had some level of independence between these layers.
Every time one of these new paradigms comes along, we think that we have solved all of the world’s problems. We think that the solution is here to stay. However things move pretty quickly in the software world, and these paradigms disappear as fast as they appear.
Just like back in the 1970s when we thought that COBOL was here to stay, today we probably think that MVC is here to stay too. It’s not. It’s dead, just like COBOL is dead.
Front End vs Back End
The majority of new development now uses separate front end and back end stacks. Our back end applications have now moved to a different set of tasks entirely. They are no longer full stack applications, they are simple services, or in many cases they are becoming micro-services. We no longer have many monolithic full stack applications being built. Instead, we have micro service back ends and separate front end applications that consume those back ends via REST APIs.
Back End MVC
So now what do we do with our back end? Do we still use MVC?
Let’s look at what MVC might look like from a code structure point of view, and it becomes quickly apparent what the inherent problems with it are. For the sake of argument let’s pretend that we have some kind of eCommerce system, with customers, products, orders, some kind of inventory management, stock handling, and a delivery system for routing of deliveries to the end customer. In an MVC structure, the application ends up looking like this:
Let’s say we find a bug in Customer handling. Is it in the controller or in the model class, or in some kind of “repository” or “view model” class where the business logic is stored? You’ll end up with database logic in the controller class and business logic in there too, so it could be anywhere. When you look at the directory tree in that MVC structure, the repository, the controller and the model are all in different places in the tree. Everyone knows that any developer is going to spend 90% of their bug fixing time just finding the bug, only 10% of the time fixing it. So you’ve made the job of finding the bug much harder.
Unfortunately I still see very many back end applications and micro-services built this way. It is not a good architecture for micro-services and actually hinders, rather than helps, clean development.
MVC was developed for full stack applications because it neatly separates out the business logic from the controllers, the database logic, and the views. Now I’m not convinced that MVC was ever a great idea for full stack apps, for various reasons (do a google search for “fat controller” and ignore all of the Thomas the Tank Engine references), but for micro-services it’s a really bad idea. Look through a typical micro-service using a framework such as Spring, Laravel (or Lumen), or similar, and see how the MVC layers are applied. There are actually very few models, there are no Views (a micro-service is an API that talks JSON so there is no need for HTML responses with decorators, CSS, etc), and so pretty much everything is in the Controllers. So instead of MVC you have mvC where C does 90% of the work. The m is pretty much a stub and the v is non-existent. Applying that MVC pattern has achieved nothing.
Modular Architecture (MAP)
You’re better off with a modular architecture where you separate everything into sub trees, one for each domain model object. Then you’ll have the Customer controller, the business logic and the model all in one place, but separated out from the Product domain or the Order domain. Developers only have to look in one place for Customer bugs and you’ve shaved down that 90% of bug hunting time.
This is why purpose built micro service API frameworks do away with the MVC model completely. For micro services you’re better to do things module by module and you’ll get better code, easier to maintain and faster because the framework isn’t dancing around the MVC model trying to search for views that aren’t there. A more modular code structure baed on domain modelling (Modular Architecture Process or MAP) looks like this:
How Do We Define Our Modules?
Defining the micro services and modules to use in our back end is reasonably easy. To do that, we first have to start with a Domain Model. In my article on Domain Models I explained how to do that. In turn, having a Domain Model relies on us having analysed the functional requirements and built a Project Glossary — for that part of the process see What is a Project Glossary.
Once you have a Domain Model then it’s a matter of opinion how you would divide that into your micro service structure. Let’s look again at our sample Domain Model:
Using this as a reference, it would be possible to divide up the work many different ways. For example:
- Have a separate micro-service for each Domain Model object. For example there would be micro-services for Customer, Gateway, Payment Tokens, Transactions, Refunds, Payments, etc.
- Have one larger service controlling everything, with modules within that service for the domain model objects.
- Do something part way in between. For example have a Transaction handling micro-service and within that have modules for Payments and Refunds. Similarly have a Customer micro-service and build Payment Token handling as a module within that.
My inclination in this example would be to choose the third option — aggregate some closely related modules together into single micro services for each aggregation, and then separate each Domain Model object out as a separate module within that micro-service. How you actually do the divisions of work within your application may involve asking many questions such as how the overall architecture of the system works, what programming language and framework you use, etc.
MVC is dead. Long live MAP.