November 2012 Archives

Use Rails until it hurts

Over the past year, there has been a strong popular push toward what I’ll describe as purely SOLID-based approaches to building Rails apps. While I attempt to adhere to SOLID as a series of guidelines, they are just that: guidelines.

Evidently, once, someone caught me saying “Use Rails until it hurts”. By this, I meant “don’t preemptively implement around perceived Rails weaknesses solely to respect SOLID/your-favorite-OO-principle”. This does not add value to an application.

I recently wrote about #accepts_nested_attributes_for. In that post, I explained that there are clear circumstances where #accepts_nested_attributes_for will save you time and code. However, in many cases, it won’t. And, for those, I began working on an alternative.

Contingencies are good. Once you deviate from Rails’ “golden path”, your work can quickly become challenging. But knowing that a person/tool/technique has a weakness does not mean that you automatically preempt them. It means that you should remain aware of that weakness. You should compensate for weakness when it becomes an issue. To do so sooner smacks of angst.

Let’s consider the discussion here around the Observer pattern versus the benefit of a tightly coupled imperative style. The Observer pattern decouples event producers from event consumers. For that matter, the Observer pattern is similar to Queue-based messaging services such as the CORBA Notification Service, Java Messaging Service(JMS), and all of those that followed save that it is, typically, implemented in a synchronous fashion and within a single process.

As cited in the C2 wiki, the Observer pattern is best used for “dynamic relationships between objects.” There are relatively clear guidelines around when to consider employing it.

So what about when relationships are not dynamic?

Under these circumstances, I posit that tight coupling can be helpful.

What is tight coupling good for? Used selectively, in a word: clarity.

Which is clearer? (Please bear with my non-ActiveRecord ActiveRecord example for the sake of argument)


The Observer (listener)-based example at the top decouples the save event from the pushing the change to the client event. While you can argue that these are two different responsibilties, they are both directly related to the change on the User’s name. I argue that this approach adds unecessary indirection.

To speak more broadly, I argue that our campaign against tight coupling has simply gone too far.

In the latter case, we have less code! This is, often, considered a good thing1. The controller, responsible for performing the change to the User object, also pushes a notification to the client of the change. The tight coupling makes this entirely clear: when I change the user’s name and save the user, I immediately push the change out on a socket to the client.

Yes, you can make a case for extracting the behavior from the UserController#update method into its own method or even class.

Whether to extract the logic out of the controller or not should be a fuzzy decision. Yes, the update method is clearly responsible for more than just routing. This is “bad”, right? Or is it?

If we extract a class to represent the context of the User’s name changing, we’ve just created another file and another class. Also, where does this class go? To me, it’s just a delegate of the controller. It’s certainly not business logic. Pushing a message out on a socket does not represent business logic at all. Instead, it’s just how we interface with our View/Client. Extracting a class, in this case, increases the cognitive burden on ourselves or any developer who comes after us.

If we extract a private method instead of extracting a class, we’ve added a layer of indirection instead of abstraction. Frankly, I’d lean toward something like this.

But, clearly, this will lead to a fat controller! ¡Qué terrible!

Personally, I would instead characterize it as a controller of a healthy weight.

Moderation is key. Noticing its lack is as well.

I hope that, from the above example, you’ve decided to stop factoring everything into another class and, occasionally, give tight coupling a chance. That said, if you’re among those who write “god classes”, “god methods”, and is unfmiliar with “loose coupling”, I strongly suggest reading Working With Legacy Code by Michael Feathers (the man who coined “SOLID”).

Rails isn’t perfect. But it is one of the best solutions for the problem space that most of us work in. Use Rails until it hurts. Don’t preemptively replace Rails features. Use Rails until you find yourself writing more code doing it “The Rails Way” than if you rolled your own solution. Then identify an alternative solution. Use that alternative solution as your application’s fallback convention for when the matching Rails convention fails.

Or, as a peer of mine, wrote:

While Rails provides many solutions out of the box, you should make a concerted effort to keep your own personal toolbox of fallback techniques (such as the Form object) on hand. Share them. Convert them into tools for use by your peers whenever possible.

1 As code itself is a liability!

Posted by evan on Nov 21, 2012

#accepts_nested_attributes_for (often) considered harmful

TL;DR: #accepts_nested_attributes_for is not evil but it should be used infrequently. It often results in brittle code. Consider using the redtape gem (which offers an implementation of the “Form Object” pattern), instead.

As a long time #accepts_nested_attributes_for critic, I was excited when Bryan Helmkamp introduced us to the idea of the “Form obect” in his 7 Patterns to Refactor Fat ActiveRecord Models blog post.

#accepts_nested_attributes_for is used, in ActiveRecord classes, to reduce the amount of code in Rails applications needed to create/update records across multiple tables with a single HTTP POST/PUT. As with many things Rails, this is convention-driven: the ActiveRecord classes expect to receive their POST/PUT parameter according to specific naming conventions used solely for nested data.

While this sometimes results in less code, it often results in brittle code.

In order to benefit from this coupling, we now have to:

  • Write forms/HTTP clients that will send the nested data expected by the model
  • Have the receiving controller action simply passes the data through to the correct “top-level” model’s #new method.
  • Not require additional massaging of the HTTP params otherwise we’re just writing more code which is what #accepts_nested_attributes_for is trying so hard to avoid.

In my experience, use of nested forms often requires at least some massaging of the data if not outright removal of #accepts_nested_attributes_for at a later time in favor of handling the data manually within the controller action.

That is, it’s brittle.

So let’s go on a tangent: “best practices”.

“Best practices” are dangerous. Few, if any, so-called “best practices” are universally best. They’re perhaps best in a particular context. Yet developers often treat them as panaceas (a discussion for another day…).

So let’s put this in context:

Only use #accepts_nested_attributes_for if all of these conditions are met:

  • The form/API data requires no pre-processing prior to hand-off to your ActiveRecord::Base’s #new method.
  • (If you have a UI,) The UI fields can map, one-to-one, to the model fields; You know that you can afford to tightly couple the view and model so that they vary codependently on one another.


Use redtape if you need your UI to vary independently from your model.1.

Consider using redtape if your input data requires pre-processing prior to hand-off to the model. Obviously, you can do this in a private/protected method of your controller as well.

Ultimately, the goal is to have working, maintainable code that satisfies your needs with minimal effort. Choose the simplest path to arrive there. Consider your options and weight them accordingly.

1: I know what some devs out there are thinking: “But, Evan, SRP says I should always allow them to vary independently.” Yeah, well, sometimes you should break the rules but that should be the exception and not the norm. Not that SRP is a “rule” so much as a “guideline”. Pretty much the only “rule” of software development is “thy program should execute deterministically”.

UPDATE 1: I had considered making this argument in my Frustration Driven Development talk but, then, I didn’t have a solution at the time. I hate providing a criticism without presenting an alternative…

UPDATE 2: Redtape::Form includes ActiveModel::Validations. You can add validations to your Redtape::Form just as you would an ActiveRecord::Base subclass. Beware: Don’t duplicate validations from your model in your Redtape::Form. Instead, add validations if your form inputs are raw values requiring processing before being used in your model. Your form can then catch these errors early and provide contextually useful error messages.

Posted by evan on Nov 07, 2012