About the Authors
This is usually something that goes at the end of the book, but I’m honestly just a huge fanboy. Sandi and Katrina are well known for their fantastic talks, at least in the Ruby world. They’re both experienced programmers-turned-trainers-turned-authors and I nearly passed out when I heard they were doing this collab. Seriously, take some time to watch Sandi and Katrina (I find this last one really good for programmers coming from any background).
Don’t skip the opening exercise!
A few pages into the book, they give a 30 minute exercise to the reader related to the song, “99 bottles of beer on the wall”, and encourage the reader not to read on without attempting it. I’m personally someone who has emotional hurdles when it comes to context switching (why are you making me go to my computer when I’m in bed with my kindle!?) but I was committed to doing this right. So naturally, I put the book down and didn’t pick it up for six months.
Then I came back to it, did the exercise, and read on. I’m so glad I did it this way. The first chapter covers four possible approaches to solving the problem, and you won’t believe number four. I’ve run this exercise as a workshop twice now, and every time it generates a load of discussion. The chapter predicts the approaches people take so well, explains what’s wrong with each and then ultimately (no spoilers) shows us a better way.
What’s in the Book?
99 Bottles of OOP is about changing code (because we almost never get to write anything from scratch) in a way that is as painless and predictable as possible. They start with some ideas about what makes code good or bad, and show how a TDD approach can be used to generate what they think is the best solution to the opening exercise. The rest of the book is really one big exercise in making code easy to change. Once the code is easy to change, the easy change is made. This may sound redundant, but it’s remarkably elegant.
Making the change easy is done by removing one bad idea (code smell) at a time. They painstakingly work through the code resulting from the opening exercise, improving it bit by bit while talking about code smells and the appropriate treatment (e.g. introduce an object to replace a data clump).
Every single change is made one line at a time. This ends up being one of the most important lessons of the book: if you make changes one line at a time, it’s far more difficult to get lost in your changes. If you change a line and the tests don’t pass, you know exactly what you changed that broke the code. In order to keep the tests permanently green without ever changing more than one line, you end up needing to work in a somewhat counterintuitive way. I found it quite gratifying to learn these tricks.
It’s worth noting that the book is not a comprehensive reference to code smells or refactoring, but it left me with what feels like a really good handle on why they’re helpful.
Why you might not (always) relate
So many coding tasks these days are about plugging third party services and code together, one or two lines here, five lines somewhere else. In that environment, the “big picture” of this book might not be directly applicable. I’ve only a few times in the months since I read 99 Bottles had the opportunity to really apply the ideas. It’s quite a joy when I do, and the lessons I learned served me well.
Why you should definitely still read it
In every chapter there are nuggets of coding gold that are worth the price of the book on their own. This benefited me immediately, despite so much of the book being about learning a new way to code that requires long-term practice. Most of the time I felt that I had some vague understanding of the nuggets already, but Sandi and Katrina have expressed themselves in an entirely new and brilliant way. It seemed like I’d witnessed the birth of pure programming knowledge come fully formed into the world out of Zeus’s split skull.
Here are a few examples (I hope my obvious exaggeration does not affect your enjoyment).
As tests become more concrete, code becomes more abstract: consider these assertions in a test suite.
expect(my_func(1)).to eq(1) expect(my_func(2)).to eq(3)
With only the first assertion, the function
my_func might as well be hardcoded to
return 1. With the second more abstraction is needed, at the very least an if statement. Now, the tests are more concrete (or specific), and the code is more abstract (or general). Anyone who has written a test suite has observed this, but this is a neat way of putting it. It also reminds us: if the tests are becoming more abstract, we’re moving in an unhelpful direction.
Ask yourself what your code tells you about the business domain: this is a great way of assessing readability. Chances are, your documentation is not going to be read, or it will be out of date. Does your code make it easier, or harder to understand the problem that you’re solving?
It’s better to tolerate duplication than to anticipate the wrong abstraction: If you have five pieces of code that look like they follow a pattern, and you can think of a way to DRY up two of them, resist the temptation. There is something you’re missing about what exactly the pattern is, and DRYing out a few of them hides the information.
Duck types must satisfy liskov: All possible return values of a method must be able to receive the same messages. In fancy OO speak, duck types must obey the Liskov Substitution Principle.
In code, compare this:
def num_bottles(num) # does not obey Liskov, calling num_bottles.capitalize sometimes breaks: return "no more" if num == 0 return num end
def num_bottles(num) # obeys Liskov, all possible return values can receive the same messages: return "no more" if num == 0 return num.to_s end
Part of what I loved about this is that Liskov is normally applied to types in an inheritance hierarchy, so it is unusual to see it applied in this way.
There’s so many more great ideas in the book. I’ve read it twice, had many conversations about the ideas, and will definitely re-read again. I encourage you to buy the book from sandimetz.com!