A story for Junior Developers on challenges of MVC apps (Rails/Laravel/Sails)
You realize you want to start building a web application. So, you reach for PHP. It’s the days before rails and Laravel. Starting out is easy, the setup is easy, coding is simple. The LAMP stack is common, and lots of tutorials exist. It’s only a couple of files to get a new website started! This is great! You just keep writing HTML in-line with the PHP and the website works!
A few months into the project, the few files have turned to many. They are a mess. Where you once developed a new page quickly, it now takes five times as long. Most of the time is trying to make sure you don’t break old pages, and manually testing them before you do a release of your code.
A few years later, you find out about a thing called Ruby on Rails and it’s (kind of) clone in PHP: Laravel. It gives you a way to seperate different pages, and “model” — something you kind of did before but didn’t explicitly exist. It answers the questions of “who is responsible for saving my model?” Itself!
It feels good to structure your code this way, you don’t even have to think about it — it’s second nature — MVC (model view controller). You even get generators to start moving fast, a migration doesn’t seem that hard!
It’s been a few years of developing in Laravel, the migration went well, MVC has worked well for you. When looking at your app, the controller folder is packed. You know when new developers start it will take some time for them to figure out what models relate to what features. It’s a bit hard to navigate with such a flat structure, but it’s a lot better than your previous PHP app. You wouldn’t be happy if you were still working on that mess. But still… somethings missing. Something is starting not to feel quite right.
You business has grown! The app has too. Accounting wants to answer questions about users that users don’t care about. The marketing team wants to find out about demographics, and traits of our customers. At the root, these questions are about customers — so I guess we should put them in the User model? Now I just have to find the right spot in this 800 line file…
Suddenly a new request, marketing wants to release a mobile app.
It feels like the straw that broke the camel’s back. You’ve been telling marketting it’s on the road map for a while. Now you really have to do it. We have to make each of our controllers serve JSON HTTP requests or, at least, create new controllers. First of all, it doesn’t feel like Laravel was made for this but there seems to be ways of getting it done.
After you spend a while adding the right stuff to allow JSON requests to come in through controllers. It’s actually not so bad. But the new flows of authentication use JWTs. JWTs, you assume, must mean Jackasses with Tridents — based on how hard it was to figure out and implement. But that’s fine. Now it is setup the long term maintenance is low.
The two problems you are still running into:
1. There is a bunch of useful logic inside of your htmls. Things like, countries to select, currency formatting, forms, and input validations. They are almost completely written into your view HTML — and you’ve got to redo it. Some logic can go into your controller, and then added to the JSON payload. Or, the mobile developers have to completely redo (duplicate) it in whatever swifty-java’y framework they use.
2. The last problem feels daunting, and you don’t really have a solution. Your user model is over 1000 lines long. A few other models are getting large too. Accounting, marketing, and all your apps depend on the User — but it’s hard to maintain. It’s also getting harder to navigate which controller and models do what, unless it’s painfully obvious. I can’t blame Rails for this, it didn’t force me to structure my code this way… but it definitely nudged me to do it.
Your friends tell you about service objects for complex tasks that operate on many models, but they don’t seem extendable — or object oriented. They seem to have one method and don’t have dependency injection. Besides, Facade objects seem similar but aligns more with OOP.
But that won’t help us figure out our User model, all of this stuff really does have to do with the user. What do we do?
A friend tells you about Domain Drive Design, he doesn’t really know much about it other than we should try to write our code in contexts that somewhat map to the real world. And that the less we force to make the business domain fit our code the less we translation errors we make. So, what should I do in my(rails/laravel/Sails) app? I guess I can start to make models based on the user table, but that seperate the functionality based on domain? This seems ok — but what parts of other models are also part of that domain? Should I do the same for my small models? It starts to feel a bit overwhelming.
Another friend comes along and says “heya! Give Elixir and Phoenix a try…”
This post was meant to give a bit of context as to how I see our modern web frameworks —and some criticisms of common approaches. The next article will talk about Phoenix’s slightly different approach, that solves those extra problems. But I hope you learned a few things from the links and enjoyed the article! If you see something that could be more clear please let me know and I’ll attempt to correct it.