Vivek Vishwanath
Appear Here Product Engineering
3 min readMar 1, 2019

--

Ruby-on-Rails monolith: how to maintain?

How do you make your codebase easier to work with, easier to add new features and easier to spot and fix bugs? A codebase that has been built over the years invariably begs these questions and the answer is not always a straight forward one. Code refactoring could be one of the options, but how do we go about doing it? These were some of the questions we asked ourselves a few months ago as a team and we started looking out for answers.

We considered various approaches we could take for code refactoring. With buzzwords like micro-services architecture and SOA (service-oriented-architecture) in the air, we had to be careful about the path we would take. All those design patterns have their own strengths and weaknesses. Our codebase is a Rails app, so we looked into the Ruby-on-Rails community too for a possible answer.

CBRA for the WIN

Then one among the team suggested we try out component-based-rails-application, CBRA for short, and we all thought we should give it a try. We found some parts of the code already provided well-isolated functionality and didn’t really need to communicate with each other. And there were other areas of code which required a little bit of refactoring to achieve the same level of isolation. All these indicated our codebase would be a good candidate to become a component-based-rails-application.

With the CBRA approach, it definitely requires a slightly more complicated setup, so various things took a little more time. But things that generally take longer feel like you’re just paying it forward for benefits down the line. With our fairly large codebase and many more features in the pipeline, CBRA has made our app better structured and for any new engineer joining the team, the components (Rails engines in our case) are in some ways have become intention revealing.

For those who aren’t already aware of what is a Rails engine, it’s a stand-alone Rails app that can be mounted by another Rails app. Creating a Rails engine itself is super easy, with engine name becoming default namespace for all the classes it contains. Our approach is as follows:

  • We have an engines/ folder that contains all the isolated components (various engines).
  • Models, services, decorators or any other type of classes a standard Rails app can contain could all be added to our engine and they are defined within modules of the engine’s namespace.
  • Each engine will have its own .gemspec that will specify dependencies. Those can be internal dependencies (other engines), or they can be external like gems.
  • We also have an engine called legacy, which contains some commonly shared functionalities with a plan to slowly refactor that out

The way we load our engines on our Rails app is through bundler, i.e by adding the following snippet of code to the GEMFILE:

Dir['engines/*/*.gemspec'].each do |gemspec_path|
engine_path = File.dirname(gemspec_path)
gem_name = File.basename(engine_path)
gem gem_name, path: engine_path
end

Another benefit of using bundler is it prevents circular dependencies. If we were to create any circular dependencies, the bundler would flag it by refusing to load and throw an error.

Engine as a magic bullet?

Do we treat the engine as a magic bullet for all our maintainability and scalability woes, certainly not. Apart from the added setup time, we now have additional worries about how to create and run our database migrations.

However, the benefits are we now have better-encapsulated code which can be treated as independent components. Not forgetting, crafting an app with engines did make us think about various dependencies and enabled us to isolate things right from the beginning for newer features.

Conclusion

After building a few important and complex features using CBRA, we feel we have successfully avoided having a bloated architecture. It did take some effort for us to break out our first engine, but all in all, we are on the path of having a much more maintainable and scalable codebase. We do realise it’s still work in progress, but overall we felt it was a short mental leap for us from working on standard Rails monolith to a Rails app based on CBRA principles.

--

--