Remco
By Remco
May 12, 20254 min read

Ruby on Rails:
A critical look at seven 'bad practices'

RailsSoftware Development

Ruby on Rails is a mature Glossary · In brieffull-stackFull-stack describes software development that covers both the frontend and backend of an application. It can refer to a developer, team or technical tool.Read more web Glossary · In briefframeworkA framework is a coherent foundation for software development, providing reusable code, a defined structure and conventions for building an application.Read more with a pleasant syntax that lets you build something very quickly. My name is Remco, and hoping I never run into them again, at least within 10KB, I gave a workshop on bad practices in the Rails ecosystem. Because just because Ruby allows it does not mean you should approach it that way.

Just because Ruby allows it does not mean you should approach it that way.

What is Ruby on Rails?

Ruby on Rails is a full-stack web application framework built on the MVC architecture principle. It is known for Convention over configuration, DRY (Don't Repeat Yourself) and the speed with which you can get something into production. RoR delivers a cartload of built-in solutions for things like:

  • Routing
  • View rendering
  • Form processing
  • Database schema management
  • Background jobs
  • Email handling

The framework is deliberately 'opinionated' in design: it makes clear choices about how you are supposed to approach things.

Experiences from developers

Within 10KB I asked a few colleagues for their unvarnished opinion on the strengths and weaknesses of Ruby on Rails. Those conversations produced this:

Nice about RoRails

  • Ruby gives a lot of freedom
  • Elegant syntax (like 'unless')
  • No compiler
  • Developer happiness ranks high
  • 'Automagic' and predictable
  • Good scalability
Remco's presentation

Annoying about RoRails

  • Magic autoloading
  • Automatic chaining (method, callback, dependent)
  • Metaprogramming (Define_method)
  • Poor IDE integration
  • Modest concurrency compared with Node.js
  • Long test files
  • No static types
  • A fervent community

About that IDE integration

There are a few ways to integrate your development environment better. A paid package is RubyMine. For VS Code/Cursor there are several alternatives:

I have not tested them all myself, so feel free to try them out and let me know if you know other options.

On to the "bad practices"

Just because so much is possible does not mean it is smart. Such judgements are extremely subjective. What one person sees as 'a handy tool' makes another cry with misery. The following seven things at least make me cry:

1. Monkey Patching

When you modify or override third party code you quickly get unpredictable behaviour and code that is barely maintainable. It may be allowed, but more often it pays to respect existing functionality and extend it through the proper channels.

2. Metaprogramming

With define_method and dynamic class creation you sacrifice readability, and that is a shame. Especially Class.new(self) and eval constructions quickly result in spaghetti that nobody can make sense of. Debugging is then out of the question.

3. Concern Mazes

Using concerns too freely creates tangled Glossary · In briefdependencyA dependency is a software component or system that other software needs in order to build or run, such as a library, framework or external service.Read more and code paths you can no longer follow. Be sparing with concerns and keep the structure of your application clear above all.

4. Validation Overrides

Bypassing model validations with methods like .update_all() or .save(validate: false) invites inconsistent data. It is crucial to honour your validations, they protect your data after all. Only in very exceptional situations do you leave them aside.

5. Custom Database Types

Defining your own Glossary · In briefdatabaseA database is a structured collection of data that software can store, retrieve and modify. A database management system controls access to that data.Read more types sounds handy, but that way you quietly create a heavy dependency on one specific database implementation. You do not notice until the moment you want to migrate to another database. Trust me...

6. Callback Hell

Rails is full of callbacks: before_validation, after_save, around_destroy and I could go on. Before you know it you have spaghetti of hidden code paths that nobody can make sense of. Use callbacks sparingly and make sure the flow of your application stays crystal clear.

With great power comes great responsibility.

7. &block Passing

Passing code blocks as an argument is a powerful trick, and that makes the temptation to sprinkle them around large. But the logic rarely becomes more readable and testing quickly becomes a headache. Save that technique for the moments when it really adds something.

Conclusion

Ruby on Rails is a flexible framework for web development, that much is beyond dispute. But to quote Voltaire: 'with great power comes great responsibility'. If you recognise the built-in pitfalls and the bad practices of the framework and then neatly avoid them, you write code that lasts longer and that your colleague will thank you for.

In practice

Want to get hands-on with these ideas yourself? Here you will find a special repo full of exercises: workshop-rails-10kb. Have fun!

Ewout

Contact person: Ewout

Work together?

Have a software question or a project in mind? Get in touch with Ewout to discuss what you need and how we can help.

CONTACT

Get in touch with us

Have a question or want to discuss your software? Leave your details and we will get back to you soon.