Farewell to Rails-way: When Rails-way does not work anymore?
When Rails-way does not work anymore?
I recently published an article on why I decided to explore an alternative way of writing Rails apps compared to the Rails-way, and what the Rails-way really is when we look at how people and 37signals write applications. In this article, I will discuss bold signs that it's time to let go of writing Rails apps the old way and start exploring alternative paths.
First of all, you can’t say that Rails-way works for some types of apps, like Fintech or E-commerce, and not for others from the beginning. This is the totally wrong angle to look at it. Rails-way is great for all types of apps up to some point.
High-level and organizational signs
You work on a Rails application, the business is growing, so is your application and the team. During the process, you may observe the following situations:
Developers lose their confidence in introducing changes - it’s taking longer from passing PR to code review to the deployment, and the reason is not that your developers have gotten worse over time.
The AI adoption among developers is not as rapid as you expected - the benefits are obvious. Still, the developers do not seem to be taking advantage of it, and the pace of introducing new changes has not increased much over the last few months.
It’s hard to split developers into smaller teams - you would like to manage smaller teams focused on certain aspects of the app, but it’s hard to do the split logically, or teams are getting into code conflicts over and over again.
Onboarding takes weeks, not days - you may have the documentation in place and other people to help, but even senior developers are not able to ship their first PR within the first few days.
The business can’t get straight answers - you struggle with explaining to the business how the application and their own rules are working.
This won’t happen overnight; those signs will accumulate over time and will visibly decrease your ability to evolve applications as the business grows.
Low-level and technical signs
Technical debt will significantly affect the team's efficiency, regardless of team members' experience or the business direction. You may not incur the debt directly by going for shortcuts or agreeing to temporary solutions, but it will still grow indirectly. Here are the symptoms:
The more features you ship, the more you deal with database performance issues - developers deal with multiple N+1 issues or attempt to refactor complex JOINs more often.
The test suite becomes a tax - slow and flaky, consuming the CI minutes and making the whole cycle of delivery slower.
Simple changes have an unknowable blast radius - you may change just one field in a model, but it affects so many other places that you are not able to predict the consequences and places where the test should be conducted.
Business rules are duplicated across multiple places, making answering questions and making changes harder; refactoring rarely happens despite the feature having been tested.
Unfortunately, I have also recently realized that many developers do not consider those symptoms to be wrong; they treat them as an integral part of working on any Rails application.
Why Rails-way does not work anymore
The core idea of Rails was always to ship quickly and make coding a pleasure and a fun experience. You'll agree it does it better than any other solution in any technology currently out there. However, the speed and fun usually end when we meet real complexity: a business with many departments and tons of edge cases. At that moment, the double-edged sword can hurt us really badly.
A model good for everything is good for nothing
According to Rails-way, models are a first-class place for business logic. They serve as a DB table mapping, an object with business behavior, a validation container, and lifecycle events emitter via callbacks. Most likely, in many apps you will also find two God objects: User (or some variation of it) and the model that represents the business domain; for the events app, it will be Event, for the blogging app it will be Article, and so on.
They also often mix the entity state with the process state. A common and well-known example is using enums, for example, in Order - it can be paid, delivered, or aborted.
With the model conventions, you can ship very quickly; the interface is easily accessible, and it’s clear how to extend it. Going through multiple contexts is an advantage, but it becomes a curse as complexity grows. You are not only dealing with performance issues but also with a loss of confidence in introducing changes. One change in the model’s method can affect multiple places in the app that you are not even aware of.
When standard conventions are not enough, you invent your own
As soon as Rails conventions do not cover your needs, you start inventing your own conventions. This is the reason why we have endless discussions...