Over the weekend, I re-read Corey Haines' book, Understanding the 4 Rules of Simple Design (and other lessons from watching thousands of pairs work on Conways's Game of Life). In the book, Corey discusses the 4 Rules, originally described by Kent Beck in the late 1990's, and how he [Corey] has learned to apply those rules in his own software development. The book is a short and relaxing read, taking only a few hours to complete; but, it offers up some valuable advice on how to evolve the low-level architecture of your software, creating code that's both easy to understand now and easy to change in the future.
| || || |
| || |
| || || |
Simple software is software that is easy to understand and change. And, by implementing the 4 rules, you can create simple design:
- Tests Pass
- Expresses Intent
- No Duplication (DRY)
But, "simple" does not mean "easy". In fact, simple is hard. Just as mark Twain said, "I didn't have time to write a short letter, so I wrote a long one instead" - simple takes more time, more thought, and more analysis. It's easy to throw code in a file and just get the job done. It's hard to find the levels of abstraction that create a semantically meaningful architecture composed of elegant, cohesive features.
That said, one aspects of this book that I really appreciate is that Corey emphasizes the idea of "better design". So often, I fret endlessly over trying to find the "right way" when I build my software. This leaves me with feelings of unnecessary angst and impostor syndrome. But, there are many "right ways" to build software. So, Corey recommends focusing on just building "better" software. Solve the problem that's in front of you right now; then, when the requirements inevitably change, it's OK to change your software as well. The key to simple design isn't to eliminate change - it's to make small choices along the way that make the future changes easier to implement.
It is important to keep in mind that this does not mean you should strive for huge, xml-configuration-based systems, making everything configurable. Quite the opposite. When we plan and build explicit extension - and configurability points, we are going against the idea of simple design. There is a second constant that we know to be true in software development: we don't know exactly what is going to need to change. Every configuration and extensibility point you explicitly plan and build is a belief about the evolution of the system. A concrete statement "this is going to change in the future, so it is worth my investment right now." But, as the old saying goes, "we'll never be more ignorant than we are at this moment." Rather than planning for change points, we build systems, by applying simple design principles, that can change easily at ANY point."
Many of the thoughts in the book revolve around the idea of "reification" - the process in which an idea, poorly expressed in software, is factored out into its own first-class entity with well defined behaviors. Creating these smaller, more expressive bundles of functionality makes the code easier to understand and easier to test. But, because reification also removes the duplication of knowledge - centralizing it in the extracted component - the code becomes easier to change as the representation of that knowledge changes.
By aggressively eliminating knowledge duplication through reification, we often find that we have built classes that naturally accept new behaviors that arise. They not only accept, but attract them; by the time we are looking to implement a new behavior, there is already a type that is an obvious place to put it.
As a corollary to this, we can use this idea to notice potentially missing abstractions. If we are working on a new behavior, but are not sure where to place it -- what object it belongs to -- this might be an indication that we have a concept that isn't expressed well in our system.
I have personally found this thought-process to be both helpful and extremely satisfying. When you suddenly see that a set of behaviors can be extracted out into an object that has better semantics, it feels really good. You're all like, "Nailed it!"
Of course, the book contains more than just reification. There's plenty of other tasty wisdom in there, including thoughts on test driven development (TDD). In fact, the latter half of the book is all about testing. And, how we can use testing to help drive the design of our objects. As Corey puts it in the book, the tests are our first clients - the first consumers of our code. So, they can help us define the behaviors that the application should present.
Understanding The 4 Rules Of Simple Design is good book. But, I don't think it's the kind of book that you read once and you're forever changed. This book will not blow your mind in that sense. But, it will help you think more effectively about making better design choices. I've already read this book twice. And, I'm sure I'll read it again. It seems like the kind of book you'll want to go through from time-to-time as a mental refresher - something to help realign the machinery.