This book was recommended to me by 2 different people. Several years ago Nancy recommended this book to me when I was first learning OOP. I generally trust Nancy’s recommendations (she has made some very good recommendations in the past such as XUnit Test Patterns and Continuous Delivery) and at that point in time, it probably would have been a very good book for me. More recently one of my Mastermind participants Ryan mentioned he had read this book and thought it was pretty good. He cautioned that he wasn’t sure how much I’d get out of it since it was a topic I was already pretty familiar with. I didn’t listen to him and decided to read it anyway.
I very much agree with the premise of the book. The premise is that it’s one thing to write object-oriented code, but in order to really take advantage of OOP, you have to change the way you think. I very much find that to be true. When people are learning OOP they tend to not get it at first. They understand the mechanics of creating objects and using objects but they don’t really understand the reasoning behind it. Then one day they have this epiphany and it all suddenly makes sense because they have started thinking about the problem differently.
Let me start by saying if I had read this book when I was brand new to OOP, it might have gone over better. As it was, I was underwhelmed. I’m not sure what I expected. This book bills itself for people who are just starting with OOP. I always say “The better you know the basics, the more advanced you are.” so I thought I’d still be able to get something out of it. Maybe there would be some epiphany in there or some little detail that I’d missed or some explanation that would just make things click in a different or better way. I thought I’d at least come out of it more prepared to talk about OOP with beginners or perhaps with a better resource to point them to. I’m not sure all that happened. I did manage to pull out a few small nuggets, so maybe it served its purpose, even if it left me feeling a little unsatisfied. Maybe it was just mismatched expectations.
It felt like any other cliche OOP book I have read. It had the same poor examples: shapes, cars, talking animals. There were several points that left me confused. It wasn’t always clear exactly what the author was trying to point out with some of his examples. His use of terminology also detracted from the book. He kept referring to what I would call the API of a class (all of its public methods) as its interface while being very careful to differentiate that from a Java interface. And then at a later point, he did dive into Java-style interfaces, so it was never totally clear whether he was referring to a class API or an Interface. With the curse of knowledge, I was able to follow him, but it was still incredibly confusing. If he would have used the term API for the public methods, it would have been much clearer. There were a few other spots where he could have chosen his words more carefully, but that was the main one and the most distracting.
To the author’s credit, he does manage to capture a little of the difference in thought process when using OOP versus procedural programming. The book talks quite a bit about good design principles. He mentions favoring composition over inheritance and the SOLID principles. He also talks about things like dependency injection and MVC and does explain association versus aggregation well. Those discussions could use some better examples in spots, but overall they are very useful for beginners and experts alike. Those sections are definitely worth reading. I guess for me personally they were underwhelming because there was not much new there that I hadn’t already read elsewhere.
Some small nuggets
I did take away a few small nuggets worth noting. All in all, these made the book worth reading. In no particular order:
Inheritance Weakens Encapsulation
On page 115 there is a section entitled “Inheritance Weakens Encapsulation”. The author explains that the idea behind encapsulation is that the internal details of a class are hidden away. The only thing the user knows about is the public API. If you change the internals of the class, but the API stays the same, the end-user has no idea. The problem is that when you have child classes, they are extra sensitive to changes in the parent class. In that way, it weakens encapsulation. This is one of the reasons why people argue for using composition over inheritance. I’d always heard favor composition over inheritance, but this explained why better than most other explanations I have heard.
Behavorial vs Implementation Inheritance
On page 63 there is a side note that I found quite interesting. It mimics something I heard from Allen and/or Stephen once. It talks about behavioral and implementation inheritance. I found it key to understanding the difference between parent classes and interfaces and when to use each in LabVIEW. When you inherit from a parent class you are inheriting the implementation. You have the ability to override it, but that is what you are inheriting. When you inherit from an interface you are inheriting the behaviors themselves. The way I remember that is that classes have implementations, but interfaces do not.
OOP versus Structural Programming
The author lays out early on the fundamental concepts of OOP:
These shouldn’t be new to most people reading this blog, but if you are new to OOP, they are good to know and understand. On page 98 the author lays out basic constructs of structured programming
These are also not new, but I just don’t think I’ve ever seen them written down quite like that. This is where some of you realize I am not a CS major because this is probably CS101. It was probably mentioned in one of my programming classes in high school or college, but I must have slept through that lecture. Anyway in the pages after that, the author goes on to talk about various ways in which you can mix and match OOP and structured programming. I thought that was somewhat interesting and would be particularly useful to OOP beginners.
Stubs and testing
On page 88, the author mentions creating stubs and then using them for testing. He doesn’t mention unit testing, but it fits right in there. One of the main reasons I like using objects for hardware is that it is very easy to create a child class, also known as a stub, for manual testing and simulation, but also for unit testing. That way I can run and test the code without having access to the actual hardware.
Almost No Class Lives in Isolation
On page 82 the author states “almost no class lives in isolation.” I have mixed feelings about this statement. I often do actually make classes that live in isolation in that they do 1 function and that’s it. They don’t have any accessory or helper classes that they interact with. They don’t really care who calls them. Sure, often it is other objects, but it could be anything. They may act as helper classes for other classes, but they weren’t designed for that specific purpose. I do like that isolated style of design. It makes it very easy to test those classes. I guess he does qualify it with “almost” so maybe we aren’t so far apart in our views here.
However, thinking about classes in terms of a group of classes that interact together does give you a lot of rich design patterns like the GOF patterns. I think the author is trying to get people to think along those terms, which is actually quite useful, particularly for beginners.
OO design is an iterative process
This quote is from page 38. I would say this about design in general. I am a huge fan of iterative design. Unfortunately, I feel like OOP as implemented in LabVIEW does not lend itself to iterative design. The lack of refactoring tools makes it really painful to make big changes to your class hierarchy. Instead of refactoring, it’s more like making one design, noting everything you don’t like about it, and then starting from scratch with what you learned from the first design. It works, but it is not very efficient.
Well written code is, in itself, the best documentation
Also on page 38. This is just a great quote. One of the main reasons I like writing unit tests is related to this idea and that is code doesn’t lie. It’s easy to forget to update documentation, but tests never lie. They either pass or they don’t. A close second is self-documenting code. Although you can also forget to rename variables and methods so it could still be misleading, its a good start and a good goal to aim for. If you can combine self-documenting code with tests I think you have a real winner.
A better choice
If you are a complete beginner to OOP, this isn’t a terrible book to read, but it’s also not the best. If you already have a copy, go ahead and read it, but if you don’t I would consider some other options first. I happen to be a huge fan of refactoring guru’s Design Patterns book. It might not be the most beginner-friendly, but I like it because it gives very good practical examples. If you combine that with NI’s OOP course, I think you would be pretty well off. In fact, I just had someone new join my Mastermind Group and ask about the best way to learn OOP and that is exactly what I recommended to him.
After posting this, I had a bunch of people tell me how much they liked the book and how useful they found it. It must just be a case of timing and unrealistic expectations on my part.