It is usually not rails’ fault
In the recent past it appears as blaming rails for productivity issues in larger projects has become quiet popular. Usually I do not really care much about these trends. However this time it happened that I came a blog post that is kind of representable for most of the criticism towards rails these days.
Before I want to comment, I just wanted to shortly say, that I have been working with rails since 2006 as part of my job as a software engineer. I believe I have a solid understanding of the trade offs and most of the pros and cons of certain aspects of rails, and its biggest component active record.
That said, I hope it is clear, that my goal is not to protect rails (as a project or as a community). I think we should focus on the real facts that might be downsides and not get lost in speculation and irrational or inconsistent arguments.
Rails, frameworks and architecture
Rails is not your architecture
I think it is important to understand, that rails does not force a certain architecture. Rails is a framework and thus it pushes you into a certain direction. However, no matter which framework, libraries you use of if you decide to write all code you self. It is your (teams) responsibility to ensure a proper design and software quality. This includes your architecture as well as coding styles and guidelines.
here are some sources about this topic:
- Some Design suggestions
- The lost 10 years (bob martin)
- Expecting Professionalism(bob martin)
There is also some great information on thoughtbot upcase and other thoughtbot sources that show that rails and a proper architecture can go hand in hand
I just want to bring this point up shortly, because I will come back to it later.
Rails quality and your app’s quality
I think we should really distinguish between issues with the rails code base and its internals and problems the Rails design is creating in application build with it. Thus the amount of methods in ActiveRecord is not really a problem in projects I work on. However I still don’t like it as a developer.
On the other hand there are issues with the API that rails offers. This could be for examples the inability to instanciate controller classes ( or actions / services / interactors) directly. This leads either to before/after actions or rack middleware being added. The same goes for the way templates and controllers are tight together. However I think the later issue can be properly addresses by using proper OO abstractions like form objects.
Other issues like ActiveSupport magic might indicate bad design/software engineering practices, but, they would push you towards a bad design, since it is the developers decision, which tools to use. Even within a framework.
Finally rails is a framework and it locks you into a certain structure, as every other framework would. And thus there are also issues that just arise from the fact of using a framework. These issues should also be discussed separately, or at least be understood as what they are.
My opinion on most of the blaming
My comments will mainly focus on this article. However as I already mentioned there a various sources that almost refer to the same points.
Some good points
I think the article really some points I totally agree with. But these make up only a small part of the article.
- I really discourage monkey patching. – However the fact that active support features are migrated into the language might show issues with ruby as a language – This is true for try and the existence of nil, as well of Enumerable.pluck and the missing type safety in ruby
- Having no control over the instantiation of the controller and thus having to use before/after is a not great
- The fact that associations can be loaded lazily caused tons of N+1 query bugs, which should at least be allowed to disable
There are some more points that cant be avoided and annoy me, but these are some examples, some of them can be found in the article.
The Complexity caused by rails
The article points out that rails introduces unnecessary complexity, which of course is a bad thing. There are some examples for it:
- Monkey patching
- The public methods amount of active record classes
- Focus on adding features
Most of the other sentences hardly have any points.
I think these points are issues, that I also do not like. However I am not sure, why this should really be a problem because as I mentioned above, its your team that makes the call. Monkey patches ( ActiveSupport additions to core classes), don’t have to be used, so if you do not like using monkey patching just don’t use it.
There is also no reason to expose ActiveRecord methods to controllers. You can happily create service objects or use ActiveRecord to implement a repository your self.
In addition to that, its unfortunate that active record classes provide too many public methods. However this indicates issues with ActiveRecord and should not cause issues in your application. Usually there are multiple ways to do a certain thing and within a project the team should be consistent about it. This eliminates a large amount of public methods from actual use. I think it’s again the responsibility of the developer to ensure a proper code base and a consistent use of the libraries and tools the project is using.
When it comes to views, I really think there are some design issues in rails that create an API that pushes towards coupled code. However experienced developers should notice that and use a proper solution. Simply following Sandi Metz’ rule to only pass one object to your view solves most of the problems less experienced developers have.
With regards to ActiveRecord, I don’t really expect a skilled software developer to massively use ActiveRecord callbacks or implement business logic into the persistence layer.
Doing so would really quickly cause trouble. However I think the time when the community or the rails developers advocated this way of programming are over for years.
The rails way
Often people refer to ‘the rails way’ or to how ‘the rails community’ is doing things. As I just said, I think things really shifted around 2010 or so, which proved bob martin’s statement about the lost 10 years kind of correct. In the last year I listend to all episodes of:
and watched all the ruby related content on thoughtbots weekly iteration as well as the upcase ruby content from thoughbot.
This was really a good time investment, since I learned that a huge part of the ruby community, the rails community and the rails core team really care about the quality of their projects and that the time of ‘fat models’ has passed a long time ago. In addition to that the core team really does a great job on simplifying the internals and provide easier and more explicit APIs to rails components.
I am really happy to learn that thoughtbot and other companies with a lot of rails experience offer advice howto design your rails application to ensure a good architecture as wells as thinks like fast test suits and much more.
This really made me change my opinion about how hard it is to build proper (well designed / maintainable) applications with rails.
Mixing framework and language issues
When comparing frameworks it is easy to take language differences and project them on frameworks / libraries This often happens in the rails vs phoenix discussion, where many points are often about ruby vs elixir or even about the benefits of functional programming.
This might effect your choice of using ruby+rails vs elixir+phoenix or similar, but this is not a thing that can be attributed to rails. This is true, for things like Object#try, due to the fact that ruby supports nil. However its also true that large method interfaces are a general ruby issue. Of course still active record adds may too many methods. However this is more a topic for discussing rails internals or improving rails and not about reasons your application might be in a bad state.
A word on “The core team”
Throughout the article the author over and over repeats his opinion on the ‘philosophy’ of the core team. I am not sure with which members he is actively communicating, but these statements are just generalizations of statements and decisions that mostly DHH made, which of course has a special opinion about rails. However his task is more or less to sell rails and not to be an rails architecture consultant. I think if somebody disagrees with that direction, he should at least refer to DHH and not always talk about the ‘core team’. This really shows a lack of respect towards core members that spent months and years on simplifying active record, the rails router and other rails components within the last years.
Its even worse to talk about the DHH/TDD discussion or his focus on simple over easy within an article about rails. It might also be a bad thing just during thinking whether rails is a good choice or not. This is simply a topic that is totally unrelated to a proper decision on which framework to choose (if any)
Rails killed merb and data mapper
Original quote < These projects were killed by rails
I think this point is hardly worth commenting. However I think it is important to point this out anyway, so that reader that may buy this argument have a chance to rethink it.
Though it is true that merb kind of disappeared after the merge, this is what one would expect when two projects are merged. In addition to that, this merge caused quiet a lot of changes in rails. On the other side the fact that merb or data mapper (which is not dead at all but just did not took off), is hardly rails’ fault but a decision by the ruby community on which tools they want to use. I am really not buying the fact that it is rails fault that
< building anything new in the ruby ecosystem turned out to be extremely difficult., Since peoples’ attention is < Rails-focused, new projects have been highly influenced by Rails
I think bigger companies and ruby shops did shift to other libraries and web frameworks. Also sinatra gained more and more attention and adoption. And those projects usually do not use active record as a data source.
This article, as well as this years railsconf talk about ecto, mentioned the trailblazer project. I don’t want to rant too much, but I hardly cant take any rails criticism serious that also promotes this project.
If complexity is an issue, than adding a framework on top of a too big framework makes things just worse. It also makes things more fragile and make it harder for people to test early rails version, since it is highly coupled to rails.
But it gets worse
In my opinion this component is the worse attempt of implementing a serializer I ever had to work with. Its overly complicated, inheritance is misused and overused. Especially the entire attempt to mix a presenter into a model instance is totally bizarre. However the other option to have a wrapper around a model instance also introduces a lot of complexity. In addition to that the API is way too huge. Everything can be adjusted via metaprogramming/DSLs and besides that its by far the slowest serializer I worked with. I had to dig deep into it for month and I really discourage anybody from using it.
OO Design and inheritance
I watched a video about using trailblazer and I got confused when for the controller related content inheritance was introduced. Especially in a way that the purpose was to share code and the subtypes also stubbed out methods from the original class. Calling this ‘returning to good OO practices’ was the worse part of it. Its obvious that this kind of decision does not really sound like a well designed framework that reduces the application’s complexity. Again I think that trailblazer here introduces a worse architecture on top on an architecture that is criticised.
I could go way more into detail but I can only say, that I would think twice before adding this additional indirection and complexity to my project. And its kind of intuitively clear. Why would adding a set of components on top of something that might be too big and complex solve the issue?
So is all nice and good ?
Rails really has some issues when it comes to its implementation and its design. However this really has orthogonal to the application rails users have in their applications. And if you are really concerned about it, you can always contribute to it.
On the other side there are also some API/Design issues that push parts of the application towards a tightly coupled design. I think most of these issues can be addressed properly with proper designs and a good architecture.
The last thing that might be important, even though it is obvious, is the fact that rails is not a good match for every problem. It surely has its sweetspot and there are problems were it does not shine. I think this is especially the case where elixir is currently really taking off.
Ruby itself has its limitation that are thus also limitations for rails. And when it comes to performance or large scale requirements, you should really check how much of the rails stack you actually need.
If that is not at least ‘most of it’, it might be a bad choice in the first place.
Bad projects I worked on
The worst code base that paralyzed a company was a php project I entered that did not allow to introduce a permission management in more than 6 months of work. This project suffered from so many issues and it did not use any framework at all.
The worse rails projects I worked on were mostly implemented by me, mostly in a stage of my career I would not consider myself of being able to make proper architectural decisions. Or a time when I was still listening to management when they wanted me to “go faster”. This has totally changed and the above video from bob martin about professionalism is a great resource for this topic.
To summarize, I would say that there are really some things I don’t like about rails. However I have to be aware of the fact, that I am no longer excited about ruby as well. So this does blur my opinion. However there are other voice in the ruby community, that are really experienced and they agree with these points.
That is the reason why there were so great improvements to the state of active record, including the adequate record refactoring or the attributes API, which is even nicer, when used without symbols so that the object creation is explicit.
That said there are way too many blog posts and voices out there at the moment complaining and blaming rails for their bad architecture. I think we should really start thinking about what we as the person who wrote the code did wrong and then analyze the role of the framework.
Most of the complains mix comparisons of languages with frameworks. Or compare frameworks with different feature sets. In addition to that, issues with the rails implementation are mixed with issues that really impact the design of the application.
However there are things I do not like about rails and about the direction DHH is moving rails to. I really not like monkey patching, callbacks, implicit object management, redundant interfaces, the focus on easy over simplicity, preferring features over improvements.
And still I am able to write rails application were all these things almost not impact me, because I can chose what to use and what not.
I personally prefer having my framework (be it open source or just company internal), to default to a proper architecture, so that I don’t have to write all the boilerplate to setup repositories and interactors and all the components I use. However if I don’t know these concepts these frameworks wont help me create an application that will stay maintainable on the long term.