To MVC, Or Not To MVC?
The Big Question
Okay, so here I am using closure functions in a routes.php file to serve up a couple of endpoints. Nothing too out of the ordinary for a small application. And this works just fine for a small application with only a few pages or endpoints, but it will quickly become unruly when I add more logic and lots more endpoints.
Now I know upfront that this project will become much larger and more involved as the client grows. So how do I design for scaleability and maintainability? The answer to this is, of course, to break your application into smaller, more logical pieces. Pieces that handle the different aspects of the software and that interact nicely with each other.
What was that? Ah, someone said we should use MVC. Well, yes, and no. What do I mean by that? Let me explain.
So Many Design Patterns.
Most frameworks try to use the Model-View-Controller (MVC) design pattern to lay things out. Almost any developer that has used a framework in the past 10 years has probably worked with an attempted implementation of this design pattern. It is so prevalent now that it has almost become nothing more than a buzz word.
There are also a lot of alternative patterns flying around the Internet right now claiming to be the best way of designing your codebase. This acronym hell includes HMVC, ADR, MVVM, MVP, MVA, PAC, RMR, etc. I will leave it to you to research exactly what each of these is and what they do, if you are really that interested, as that is outside the scope of this article.
I have found, however, that most of these design patterns do not fit well with what we actually do down here in the inter-webs. In reality, a web call can be split into so many smaller and smaller parts, and those parts grouped together in so many ways, that these so-called patterns start to become meaningless. In the end, it's all just the same execution path.
The Path Of The Web.
Here is a basic example of what I actually see happening, from Request to Response, during a web request in most applications.
<-> Domain (The Business Logic)
<-> Data (The Business)
-> Presentation or Adapter
Request comes in and is routed to the correct Controller. The Controller has two simple functions, calling the proper Services for the Request and passing the returned data to the Presentation layer.
The Service layer interfaces with the Domain and the Data and is where all your processing is done.
The Domain holds all of the Business Logic and Rules for how the application works. Although it does very little aside from telling the Service how to deal with the input and output data, the Domain is the heart of the application and defines what makes it unique. Its tasks include setting rules, validation, and the throwing of Exceptions.
Once the business rules are determined, the Service layer will then interface with your Data if necessary. It then processes and compiles all the information the Presentation layer will need, formats it, and passes it back to the Controller. The Controller can now pass the processed data to the correct presentation.
Presentation is the dumb layer, in other words, it does no processing at all. It simply creates a formatted display of the data it is given and sends it to the Response layer for presentation. This presentation can be the rendering of an HTML page, returning JSON or XML data as an API endpoint, or sending email notifications.
Looking at it this way; MVC, and the other patterns, end up being nothing more than a high-level representation and grouping of the actual execution flow. And not even represented in the correct order. In reality, you want to break your application down even further than Model-View-Controller.
Model = Services, Domain, and Data (The Workers)
View = Presentation and/or Adapters (The Delivery Men)
Controller = Request, Routing, and Controller (The Traffic Cops)
Separation Of Concerns.
So, What do all these patterns mean to us as developers? Not as much as some would have you think. The more important thing to be concerned about is what is referred to as Separation of Concerns. In other words, keeping like functionality together. Don't let anyone part do too much.
All of these patterns are just different ways of implementing this. Different people's views on how it all fits together. In ninety-nine percent of the implementations I've seen, it's just the simple path I laid out earlier. Your greatest concern should be these three basic principles.
Keep your code Simple, Clean, and Decoupled.
Simple: Neither our classes nor their methods should do too much. Classes should handle one object, entity, or intention. If it starts to affect more than the one its time to create another class. Likewise, all of the methods in a class should do one and only one thing, do it well, and then return control to whatever called it. This will also make your methods reusable.
Clean: Your code should be readable. Always use expressive variable and method names that say exactly what they are. Syntax and expressions should be clear and consistent. Don't use cool construct X just because it makes you look cool or smart. Six months from now when I'm tracking down a critical bug in the code I would rather see a multi-line conditional statement that I can read clearly and quickly.
Decoupled: Our classes should not rely to heavily on each other. Always pass objects into a class instead of creating them inside of it. Whenever possible use interfaces and type hint to those interfaces. If you do this it will make your code more understandable. It will also make it easier to change out our classes later on. Say if you find something that does 'X' more efficiently, you just need to make sure it complies with the interface rules, or extend it so that it does.
The only real principles or concepts that we as object-oriented developers should be concerned about are the S.O.L.I.D. concepts, also known as the "five basic principles of object-oriented programming and design." These principles where developed by Robert C. Martin (Uncle Bob), the author of the book Clean Code: A Handbook of Agile Software Craftsmanship. If there is one book that I would recommend to all web developers, regardless of language, it would be this one.
If you follow the "Path" that I outlined above you can cease to worry about what patterns you are following, because it really doesn't matter. Break your application up at each of these logically outlined levels. Then by sticking to the big three principles that I described, you will end up with an application that is easy to maintain and extend over time.
Okay? Cool, Let's get back to taking over the world.