When I first learned Laravel, I was exposed to various software design patterns and principles that was so widely used in the community. Sure, I had known many of them before, but being involved in the community where such things were so strongly agreed to be the “one true way” affected how I think about writing software as well. I was sold to the idea of Domain Driven Design.
I read tons of uncle bob articles and watched dozens of youtube videos on the topic, and I always tried to model the business rules of the software perfectly in the code I write. I started using repositories for every business logic code, and having even a bit of business logic scattered around the controllers code bugs me to no end. I made sure the program can’t go into a state that violates any of the business rules, and of course, I made sure to separate the domain code from the implementation detail so that I can easily switch out the caching or authentication code.
It all went quite well, but I soon realized that sometimes, the frameworks that are meant to help you write code faster and be more productive are starting to get in the way of modelling the business domain. This shouldn’t be too surprising as trying to model the general purpose framework code into your domain would require you to bend a number of features provided by the framework to your needs. Like most people, the active record ORM is the first that gets in the way of separating the business logic and the database storage detail, and soon enough I’m wishing for a micro framework where I can pick and choose the components to be used.
The second thing I realized is that writing a product for a startup company, the business logic change very rapidly, and you need to deliver these changes very quickly to the customers. While it is a good idea to model the software very closely to the domain, you would have to tear down the model and build it over again very often, and soon enough the abstractions are going to leak here and there. Of course there is the side effect on your morale for having to tear down the model that you have designed so toughtfully.
Another unintended side effect is on the barrier of entry to the code. Sure, the code written this way can help managing a pretty high level of complexity, and there is a certain sense of elegance to code, but it is not going to be the easiest code to understand. A new team member would have to learn and understand how the code is structured to begin contributing, and he/she would also need to adhere to the practise or the code would be a mess of a chimera code in no time.
After a while, I started to question myself whats the point of adhering to these practise. It certainly doesn’t make my job easier. Then I remembered one of the reasoning that convinced me to buy into the idea; It is the only way to manage the complexity of the program. And sure, I still agree with that sentiment, but is my program really that complex though?
I recently listened to the an episode of the Full Stack Radio, where DHH, the creator of Ruby on Rails talked about how most web applications is not all that unique or complex, and when I take a second to think about it, I believe it is actually is true.
The conclusion that I came to is most applications, or at least the applications that I write, are not all that complex at all. Most of the time, there is no need to write your code in such a round about way just to keep the code within the model. It is perfectly fine to call your active record model from your controller method. The code you write exists to achieve a certain goal, which most of the time is to make things easier for its user. There is no point in blindly adhering to a practise if it gets in your way of achieving that goal.
Of course, it doesn’t mean that there is no need to put any thought into the code you write, or that Domain Driven Design have no place in writing software. It is still important to keep your code DRY, and if the code to instansiate that new blog post with tags and categories is being repeated many times at different places, it is still a good idea to extract them to a post repository class. It is important not only to know all these software engineering principles, but also to understand why and when they should be applied. Strict adherence to the design discipline of the software have their place, for example when you are writing code for a well-understood domain with little chance for sudden changes, or if you’re writing a library code that would be used in many different situations. The most important thing to keep in mind is not to let these things get in your way of accomplishing your goal. Writing software, like other engineering disciplines, is about trade offs. Just make sure you understand what you’re giving up and what you will gain in exchange.
Earlier I mentioned about frameworks getting in your way of modelling your domain, which should’ve been expected, since if you’re going to write your code to strictly adhere to your domain logic, you would do better starting from scratch and pick up the libraries you need as you go along. Understanding this logic really made me appreciate the thoughts that went into frameworks such as Laravel and RoR even more.
Having learned my lessons, I came to appreciate beautiful clean, simple code even if the code is a 5-line active record model being saved from a controller method.