Cargo Cult MVC

Wikipedia describes “cargo cult programming” as “a style of computer programming characterized by the ritual inclusion of code or program structure that serve no real purpose”.

I believe that MVC web frameworks have essentially forced a cargo cult mentality on programmers.

The Problem

Pretty much all MVC web frameworks use the notion of a front controller.

The front controller has the responsibility of handling every web request, and then gives that request to the proper controller.

For example, in CakePHP the default configuration is to use convention names to choose routes. Suppose I had the following piece of code

The front controller for CakePHP would automatically associate PostController::index() to the url /posts/index

The front controller’s strategies for dispatching work to controllers is pretty arbitrary. However, the most typical strategies are to use xml file configuration, annotations, naming conventions, or fluent interfaces.

Typically, we try to organize our code around use cases because it is a technique that we know promotes loose coupling and high cohesion. A use case in this context is any single useful thing the system must do. For example, “edit an article” would be a use case for a blogging system.

However, there is no guarantee that a single url will always be associated with a single use case. Consider the case of a web search form. Imagine that we have a url of product/search?q=some_search_term. That web request would then be passed to a controller like the following

The problem is that the controller actually has 5 use cases:

  • show zero results
  • show one result
  • show many results
  • show lots of results
  • opps

To understand why, consider how an average person would expect the system to respond.

  • Case Zero: If there were no results for a search then I would want to see a dedicated page telling me that there were no results.
  • Case One: If there was only one result then I would want the system to immediately show me the details of that single item.
  • Case Many: If there were many results that could fit on a single page then I would just like to see a listing of those results so that I can choose to drill down into a specific item.
  • Case Lots: If there were too many results to list on a single page then I would want to see some sort of pagination.
  • Case Opps: If something bad happened which prevented the system from responding to my request then I would want the page to tell me that.

Rather than being MVC, we know have MVVVVVC. This isn’t exactly what we want from an engineering perspective, but it is what we were forced to do in order to satisfy the business requirement.

We can work around that situation pretty easily with the proper use of design patterns. For example, we would simplify the controller logic with the use of the strategy pattern. However, in so doing we are no longer using the MVC paradigm. It would be “Model StrategyContext View Controller”.

Not all cases are that simple to work around, though. Consider the situation where you have different roles for a system, and that each roles is allowed to view different things, and perform different work. Now consider that you wanted to expose that kind of functionality through a single url. How painful would that code be?

The Solution

Do not treat MVC like it is a silver bullet solution. There are plenty of alternative architectures out there. Google the following terms to see

  • Hexagonal Architecture (aka ports and adaptors)
  • Onion Architecture
  • Clean Architecture
  • Lean Architecture
  • DCI Architecture
  • CQRS
  • Naked Objects

Conclusion

Everything has it’s time and place. It is your job as a developer to think. Blind adherence to a framework will not save you.

I should also point out that MVC architectures themselves are not bad. How we use it is bad. MVC architectures definitely had their usefulness, and they probably still do.

For example, MVC architectures are really good at doing very simple data entry system because a single use case can actually fit into a url.

Consider the following mappings between a URL and a Use Case

URL Use Case
/article/create Create
/article/:id: Read
/article/:id:/edit Update
/article/:id:/delete Delete

In this case, each url maps very well to a single use case; so, MVC would probably be a really good choice to power an app like this.

However, in my opinion, most systems will not be this simple. Most systems are now very sophisticated and if they are not sophisticated then they eventually will evolve to something that is. You might as well architect your system with something that you know can help you evolve.

Advertisements