That giant mess of
if statements keeps staring you in the face. You feel like you should be able to simplify it, except for that Business Logic that keeps getting in the way.
For example, say you have a sales platform where you build
Quotes, which have many
LineItems. Except, you can have a quote with duplicate line items if they’re ads, but if you have multiple websites, you have to sum the prices together and have it show up as a single line item. Oh and also, if you buy a website and already have five ads in your quote, you have to give them a 20% discount on the website.
I can hear you throwing your laptop through the window from all the way over here.
You could write a bunch of
if statements to handle these rules:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
But I think we can agree that that’s just terrible. How can you possibly untangle something like that?
You could decompose the method into a bunch of smaller methods, but that’s like shoving all your toys in your closet so your mom thinks you cleaned your room. And those
kind_of?s would still bother me a lot.
But what if you started seeing things from the line item’s perspective, instead of the quote’s? If instead of asking what kind of line item you’re dealing with and adding it to the quote, you just told the line item to add itself to the quote?
Reverse your methods!
One of my favorite ways to refactor code is to try reversing the caller and the callee. Here’s an example, using the code above:
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
It’s not perfect.
website.rb still needs a lot of refactoring help, and I’m not happy with how reversing the methods broke encapsulation of
But you’ve removed the first layer of complexity. You can now put code on the
LineItem or the
Quote, depending on where it makes the most sense. The
LineItem objects can use inheritance and mixins to handle similarities and differences between each
LineItem subclass. Plus, it’s now really easy to add new
LineItem subclasses without bloating your
Your code is a little cleaner, and a lot more flexible. So generally, I’d call it a win.
Where you might not want to use this pattern
As useful as Reversing Method is, there are some reasons you might not want to use this pattern:
It can break encapsulation. You might have to expose attributes on the
Quoteobject that you didn’t want to expose publicly.
It can increase coupling. Both
Adnow need to know about each other. And depending on how much they need to know about each other, it can make your code more complicated.
It can violate the Single Responsibility Principle on
Ad, because now
Adhas the responsibility of knowing how to add itself to a
You can usually work around these problems. But you should be aware of them, because you don’t want refactoring to make your code worse!
Why it’s one of my favorites
Even with those problems, this is one of my favorite refactorings. The code I write after using this pattern tends to be clearer and more confident.
But even when it isn’t, using this pattern makes me think about the relationships between my objects in a different way. When I get into the “this feature is awful, I can’t believe I have to write this terrible code to handle it” rut, it kicks my brain into seeing new ways I can solve those problems. It forces me to think about how I could structure my code differently, and that’s incredibly useful.
Give it a try in your own code
Like many of my favorite patterns, I first came across Reversing Method in Smalltalk Best Practice Patterns, and it’s been a valuable tool ever since.
Next time you have a hard time dealing with similar objects that have slightly different behavior, give it a try! If you like the new code better, keep it. Even if you don’t, though, it’ll take your mind down a path that will lead you to better code.
Don't miss out on my next essay
Sign up below to get my free weekly Ruby column. I'll send you original articles and advice every Friday to help make you a smarter, better Ruby developer.