Going off the Rails

Going off the Rails

I have been known to compare writing software to building houses. The more I do, the more situations I find in which it fits. So I couldn't resist dusting off the analogy once again to discuss Rails. Or more specifically, to answer the question of why some people rave about Rails and others, well, don't.

So how is creating software like building a house? For the purposes of this topic the answer is ‘uncertainty’. What I mean by uncertainty is, “how similar is the problem you’re trying to solve to other problems that have been solved previously?”

Imagine that you've decided to build your own home. You engage a few construction companies to quote for the job. Each arrives separately to give you their pitch.

The first company says that they can use tried and tested techniques, bricks, wood and cement to build you a home. They'll build you a house with four walls, windows and bedrooms.

The second company sits down in your living room and says 'My last project was a cathedral conversion. We'll build everything with reclaimed stone and have a world renowned architect draw up some incredible and unique architecture. Of course we'll need to fly in specialists from around the world to work with the special materials that we'll use but what you'll have will be unique and last forever'

Now, some of you may already be excited about option two. Mostly because, as engineers, we prefer the idea of building incredible and unique architectures. Also, engineers can have a tendency to act like hammers. And to a hammer everything looks like a nail. By which I mean that we write code and can be guilty of seeing writing code as the solution to all problems.

But as enticing as option two sounds, which one is more likely to result in a home that you can actually live in? And, perhaps more importantly, that will be delivered on time and on budget? It begs the question, 'Am I building a house or a cathedral'? This is where Rails steps in.

The Doctrine

The Rails doctrine, which I would highly recommend reading before starting any Rails project, has a fairly strong view on this.

“You’re not a beautiful and unique snowflake”

It’s a bold statement. But what does it mean? Well, if we stick to our analogy, it means that the vast, VAST majority of the time we're building houses, not cathedrals.

This may sound a little disheartening. After all, doesn’t everyone want to test the limits of their ability? Engineering isn’t supposed to be repetitive. It’s supposed to be creative. But the honest truth of the matter is that so much of what we do is repetitive.

In all honesty, I found this fact to be more liberating than upsetting. Because if ninety nine percent of my project is going to be repetitive house building, I’d rather get it done as quickly as possible. That way I can spend more time on the parts of the build that genuinely do require creativity and ingenuity.

Rails has a simple solution for getting you through the boring bits. Follow the conventions wherever you can. Stay ‘on the Rails’

Convention over Configuration, the double edged sword.

Rails likes to guess at things. If you follow the conventions, it will guess correctly. Rails actually does this quite extensively, all the way down to understanding how to go from plural to singular and back when you reference other classes.

Telling your model that it ‘belongs to a user’ will have Rails guessing that the corresponding model is called User. It will even guess that the foreign key column will be called user_id. It does this everywhere.

If, however, you go ‘off the Rails’, for example by having a different foreign key column name, one that doesn’t match the model. it will guess incorrectly and you’re back to configuring; which takes time and effort.

So why make it hard for Rails to guess? What is Rails expecting? At its core Rails believes that MVC, CRUD and REST will handle most problems. And interestingly, it does. And it guesses continually that that is what you’ll be doing.

CRUD design is actually a really nice way to think about architecture. The four actions that we most commonly take with any resource are:

Create, Read, Update, Delete

But what if I went a step further and decided that these were the only four actions we can use. Rails knows how to handle all of these actions out of the box. So if we stick to those four Rails suddenly makes a lot more sense.

Here’s an example. Imagine you’ve created a hotel review site. One of the actions guests can take is to ‘like’ a hotel. You’ve already created the CRUD for creating a hotel, but how are we going to handle liking and unliking?

There are few ways we could do this. We could add ‘like’ and ‘unlike’ methods to our hotel controller. And that is a pattern I’ve seen quite commonly. The trouble is it’s not CRUD or RESTful. So Rails won’t guess that these actions exist.

If, however, I map ‘like’ and ‘unlike’ to CRUD actions, Rails will be there to help. I could create a ‘Like’ object that links a user and a hotel to represent ‘liking’. Unliking would then be deleting that object. The power of doing things this way may not be immediately obvious. But we are now supported by every helper, every base class, every generator.

And not just Rails. Other systems will intuitively know how to work with your resource. Active Admin can produce screens for managing likes, Factory Bot will generate factories, we can use Active Record validations to decide who can like what etc etc. The building blocks are all there. We just have to choose to use them. The work then becomes ‘tweaking’ rather than ‘building’

Convention over configuration seems strange to a lot of people new to Rails. A greenfield Rails project can do quite a lot with barely any code. Leaving some eager learners ( who don’t read the docs from cover to cover ) wondering how it all works. And perhaps this is the biggest problem with Rails. It has strong opinions loosely enforced. There’s nothing to stop you from naming things whatever you like, designing architectures however you like and writing as much code as you please; which is what frequently happens.

Staying ‘on the Rails’ and following convention has benefits beyond the code too. Onboarding new engineers becomes a lot easier. It allows junior engineers to work on much larger chunks of your codebase and makes it much easier to train them too.

You can also upgrade to the latest versions more easily. I’m sure many of you have worked on applications that are one or even two major versions behind but can’t be upgraded because of the sheer number of things that break when you try.

Unfortunately my experience with Rails in different companies, from finance to healthcare, has been largely ‘off’ not ‘on’ the Rails. And, perhaps, this is its biggest downfall. It’s relatively easy to keep a small team of engineers working the same way. But once your teams get bigger it becomes increasingly more difficult.

More engineers means more design preferences and patterns and Rails won’t argue with a single one of them. It will quietly guess, incorrectly, what they’re trying to do and then give up; forcing them to write ever more code.

But if you can keep everyone on the Rails, in my opinion, there’s nothing better, faster or more powerful. That’s why so many engineers choose to call Rails home.