Edit: I received a lot of feedback that this post is a rant. It's probably true. The primary reason is because of frustration. I have been engaging online looking for books and example of code presenting "Good OOP" for studying and refining my views. The previous book I was recommended and read: Growing Object Oriented Software, was a blast. This book was recommended frequently, even more than the previous one, so I reluctantly bought it and then got rather upset about how big of a disappointment it was. It's a book about small scope code refactoring, not really OOP, so it's not even on the point. And even at learning to refactor, I think it uses confusing and counterproductive examples all the way. I read it, I didn't like it, I wrote a short rant why exactly, to get it off my list. If you don't enjoy rants, hit Ctrl+W now.

When asking around "Good OOP" examples a lot of people recommend 99 bottles of OOP book. I was reluctant to buy it. By the name and the description, I could tell that it is going to use the "99 Bottles of Beer" song as an example of some sort... which frankly seemed completely unproductive. But since people keep on mentioning it - I got it. And unsurprisingly, I was right: the book indeed is confusing and just... not good.

TL;DR: Even as a vocal critic of OOP, I can see that this book is doing a huge disservice to anything that could be called a reasonable OOP. Save yourself $40 and don't buy it. If you own it, throw it in the trash. If you've read it - know that you learned a bunch of nonsense about OOP, and maybe some minor stuff about structuring your code and writing tests.

Review

I picked the Ruby version of the book, as I thought it's going to be most OOP. Haha, silly optimistic me.

In the first chapter, the author contrasts 4 versions of a program generating the text of the "99 bottles of Beer" song. They are all effectively the same, with 3 of them being slightly too clever, and one being a clear simplicity winner.

I will dare to paste the simplest one verbatim here:

class Bottles
  def verses(upper, lower)
    upper.downto(lower).map {|i| verse(i)}.join("\n")
  end

  def verse(number)
    case number
      when 0
        "No more bottles of beer on the wall, " +
        "no more bottles of beer.\n" +
        "Go to the store and buy some more," +
        "99 bottles of beer on the wall.\n"
      when 1
        "1 bottle of beer on the wall, " +
        "1 bottle of beer.\n" +
        "Take it down and pass it around, " +
        "no more bottles of beer on the wall.\n"
      when 2
        "2 bottles of beer on the wall, " +
        "2 bottles of beer.\n" +
        "Take one down and pass it around, " +
        "1 bottle of beer on the wall.\n"
      else
        "#{number} bottles of beer on the wall, " +
        "#{number} bottles of beer.\n" +
        "Take one down and pass it around, " +
        "#{number-1} bottles of beer on the wall.\n"
    end
  end
end

The thing that strikes me is that there's absolutely nothing OOP about this code (or any other versions of it). This class is not an object in any meaningful OOP sense. It's just a piece of code decomposed into two functions. It might as well be a pure FP program or a procedural programming code. It's so trivial that it doesn't matter.

The author spends the entire chapter discussing unimportant differences between all four presented versions of this code.

Chapter 2 is about testing/TDD. Of that trivial code. I was already rolling my eyes and regretting spending $40 on the book. It's not that the writing is bad or unintelligent. It's just given the triviality and absurdity of the code being tested, the whole exercise turns into a mockery, IMO.

In Chapter 3 the author announces that they are going to take the code version from Chapter 1 that was deemed the simplest and best and do some further OOP work on it. Because of... changeability! Ha! That's probably the most OOP-thing about the book: taking some abstract goal like "maintainability", "reusability", "changeability", "isolation", "encapsulation" and then turning everything into a terrible mess trying to achieve it.

users have requested that you alter the 99 Bottles code to output "1 six-pack" in each place where it currently says "6 bottles."

The cynical and irritated me would like the author to take that simple version, add the when 6 corner case and be done with it. But I do realize that the author is trying to make a point, and needs some reason to go on for another 6 chapters. 6 chapters of terrible, misguided ill-understood OOP-butchery of a slightly naive and simplistic, but otherwise kindhearted and innocent piece of code!

Along with Chapter 4 it all comes down to over-analyzing what's the best way to skin this cat. Again - it has nothing to do with OOP, just with adding quite a bit of complexity to support some arbitrary parametrization requirement. In the process author somehow involves The Liskov Substitution Principle, even though there are no interfaces or inheritance hierarchies in sight, but only a handful of functions without any meaningful self.

In Chapter 5 the author invents a BottleNumber class, that just wraps the number and puts the conditional logic in its methods. No meaningful OOP to be seen, still. 🤷

In Chapter 6 the author tries to introduce openness through employing polymorphism. Of course. Too bad that it's explained using class Number0, class Number1, class Number6 and class BottleNumber with inheriting gluing them together. And a factory from a number to into a given class.

I get it - how else would the author talk about polymorphism. But this is completely ridiculous and confusing. People read this stuff, think that's literally the way to do stuff, and then go wreak havoc for years in software shops! That's exactly the kind of shit that made me go on a crusade against OOP.

In Chapter 7 author makes the classes register themselves in the factory method via self.inherited hook (Ruby feature that I had to look up). A practical example, I guess. Maybe. If I wasn't so against the book, and OOP as a whole anyway that is.

Chapter 8 and Chapter 9 are a catch-all for things that didn't fit into previous chapters. At this point, I'm out of motivation to go through them and describe my problems with some stuff there, sorry.

Contrasting with the other books

I'm quite sure the author of Elegant Objects (would/does) dislike the 99 Bottles of OOP. As much as I disliked that book either, it had some form of an idea about OOP and seemed to complain exactly about the sort of non-really-OOP-actually-procedural-code that 99 Bottles presents.

So far GOOS is very much the best OOP book I've read, and 99 Bottles the worst. Even Elegant Objects seems more reasonable, and that's a pretty low bar, I have to tell you. Elegant Objects was just a list of rather arbitrary opinions and the author couldn't present any arguments to support them. But at least it seemed to be about some idea of OOP.

The whole 99 Bottles in essence is ruined by a meaningless example code it has to work with. While I complained about ignoring data persistence or even data model altogether in Growing Object Oriented Software, at very least it was working on some real-like code with a clear vision of what's OOP about it, and not a meaningless two-function caricature of software.

Anyway, I hope I have saved you $40, and even more so the time and effort needed to unlearn this stuff. Or was it already too late?

#oop #software #book