Book Review: The Four Rules of Simple Design

The Game of Life reveals truths about the Game of Code

Posted by Grace on October 25, 2021

Header image source: Tyler Elliot Bettilyon

The Four Rules of Simple Design provided some essential guidance for programmers. This guidance takes four basic rules and elaborates on them through different scenarios of The Game Of Life. The book also details how to implement these practices through a code retreat. The author, Cody Haines, has a philosophy that there is no one style of “Good Design,” but there are ways to make design Better.

Coderetreat

Code can continually be improved, but there’s not one single right way to write code. Moreover, when trying to get something done in production, it’s hard to justify taking time to rewrite something. As a result, programmers become attached to their code.

The purpose of a Coderetreat is to pair-program under different severe constraints. Haines suggests working on Conway’s Game of Life. The programmers delete their code at the end of each session and start afresh. The goal is not to finish the Game of Life but to learn more from the different approaches and reflect on your own programming choices. Sample constraints for the pairing sessions include:

  • Ping-pong pairing: where one person writes tests, and the other writes the code.
  • Trying a new language.
  • Limit compiling and running to two instances; in the middle of the session and at the end. We then emphasize paying attention to syntax.
  • Only doing three lines of code per method.

These exercises are supposed to help programmers try- and re-try design solutions to a simple problem and hopefully learn something new about designing their software.

The author recommends that you follow The four rules of code design by Kent Beck:

Tests Pass

Programmers should create automated, fast tests. Cody notes that you can’t make changes to your system very quickly if you’re waiting hours for a test suite to complete.

Expresses Intent

The names of variables, methods, functions, objects, tests, and so on should all be descriptive and readable. Good variable names allow you to understand what’s going on in a codebase and make the required changes quickly.

No Duplication

Haines has a more sophisticated take on the classic aphorism DRY - Don’t Repeat Yourself. The underlying principle is not necessarily to never have the exact phrase of code repeated twice - there are instances in which this makes sense - but rather to make sure to have one representation of each piece of core knowledge to the program.

Small

Keep that codebase under control! There are many instances in which a developer might write a new function only to have it sit unused, taking up the time and confusing future programmers who are reading the codebase. By keeping things small, the developer will make sure that his code is readable and manageable. Haines mentions combining duplicated abstractions and removing vestigial code as important steps to fulfilling this rule.

The Game of Life and Simple Design

The bulk of the book is examples of making parts of Game of Life using the 4 Rules.

Some of my favorite examples:

In the chapter “Test Names Should Influence Object’s API,“ Haines encourages us to take time to name our tests well. The names should describe the behavior of the test and what we expect to return. Thus, the name should be as close to the behavior of the test as possible.

In the next chapter, he uses the example of grid coordinates (x,y). One way to handle these would be to pass an x and y coordinate separately to each function that needs them. However, it would be more elegant and readable to put x and y into a location object passed from function to function. While most people know that x and y are coordinates, this solution removes the code smell of “data clumps.”

He also talks about how test suites become fragile when functions or methods are changed. A test that worked before may start failing if the function it called changes. For example, if you have a test that checks if a new world object is empty after being made, and then a test that checks that the new world object stays empty after a round of the game, then the second test assumes that the new world object will be empty. Rather than assuming the previous test results are always true, Haines suggests you make it explicit. In this case, you are calling an explicitly empty world instead of a new world for the new test. That way, you won’t have hidden assumptions breaking your tests as a surprise.

Another idea is that while it’s good to keep code DRY, you should not oversimplify in a naive fashion. Similar-looking code can serve important separate purposes. The best thing to do to avoid this confusion is to name the concepts with expressive variables explicitly.

He also meditates on arranging objects, whether to use inheritance and what is more readable. For example, should a Cell object include whether it is dead or alive (as two separate variables), or should there be two objects, Dead Cell and Alive Cell? While there’s no correct answer, Haines invites us to consider the implications of these design choices.

Conclusion

This book gave me some great insight into the sometimes subtle choices that can make a design better. After reading this book, I found myself naming my variables and functions with far more care. Through careful consideration of many facets of The Game of Life, the author shows how the canny developer can create more thoughtful designs. It showed that there are always new angles to consider to make your code more readable and elegant.