Clean Code: A Handbook of Agile Software Craftsmanship, By Robert C. Martin is a book every software developer should read. Moreover, it should be on every programmer’s desk as a reference, within reach during intense coding and refactoring sessions.
The book states right in it’s introduction “Learning to write clean code is hard work“. You should be familiar with at least one programming language, and have at least some experience in the industry to truly appreciate the value of this book. This book is of greatest value for to those that have worked in “dirty code”, but it essentially posits that even clean code can be cleaner.
“This is a book about humble concerns whose value is nonetheless far from small” – James O. Coplien
Chapter one discusses what clean code is. Chapters two through thirteen describe the principles, practices, and patterns of writing clean code (Martin). Justification for why each principle should be applied, how the application of the principle lead to more readable and maintainable code, and what the the consequences of violating it are, are discussed in detail. Chapters fourteen, fifteen, and sixteen are case studies of increasing complexity (Martin). Chapter seventeen is a list of code smells which should be refactored upon recognition, as well as a list of heuristics to keep our code clean and maintainable.
The code examples in the book are written in Java, but the concepts can be applied to any programming language.
Chapter one attempts to answer the question “What is clean code?” Right away it makes the assertion that there will always be code, challenging the notion that code will somehow disappear and business people will be able to generate code from “specifications”. The conclusion of the authors argument is both simple and direct: the code IS the specification, and writing a specification detailed enough that a machine can understand it IS programming.
Since there is and always will be code, it logically follows that there will be bad code. The author states that any programmer of any experience level has at some point been impeded by bad code. He then drops the bomb on us:
“Of course you have been impeded by bad code? So then — why did you write it?”
He then lists a series of circumstances that led us to write bad code, leaving one to walk away with the impression that bad code is rarely the result of incompetence (at least in terms of technical ability). Far more often, we were rushing either because we were under intense scheduling pressure, or we were tired of working with that particular application or module and wanted to move onto something else. He then charges us with being unprofessional.
After the initial sting of such an accusation wears off, and we give ourselves time to reflect on what we’ve just read, and upon further reading, we are inclined to agree. All the excuses that we are accustomed to making, such as blaming managers for unreasonable schedules, and blaming customers for providing poorly written or incomplete specifications, no longer applies. It’s our job to defend code, which ultimately IS the specification.
Part One: Chapters two – thirteen
In chapter two the author instructs us to use meaningful names in our code. He argues that names should reveal the intent of our code, avoid disinformation, and make meaningful distinctions. They should be pronounceable and searchable in our chosen IDE or text editor. Encoding information into names, such as prefixing type information into a variable should be avoided. Class names should be nouns or noun phrases, method or function names should verb or verb phrases, we should use solution domain names and problem domain names, and add meaning context while avoiding gratuitous context.
In chapter three the author tells us how to write clean functions. He starts by showing an example of a large utility function pulled from the Fitnesse application that is difficult to understand after reading it within a few minutes. By the end of the chapter he shows us an example of a class made of methods that illustrate the principles he had just covered. These principles include:
- Functions should be small.
- Functions should do one thing.
- One level of abstraction per function.
- Switch statements should be avoided when possible, or buried in a low level class to facilitate polymorphic object creation.
- Functions should have few arguments.
- Flag arguments should be avoided.
- Command operations should be separate and distinct from query operations.
Chapters four covers commenting, and in summary argues that there are a few scenarios when comments are a good idea, such as when they are legally required, explain intent when good naming won’t suffice, and to provide clarification. Bad comments, such as those that are redundant, or commented out code, etc., should be avoided.
Chapter five covers code formatting. It includes an interesting discussion about vertical and horizontal density, and argues for certain practices when constructing functions and classes. For instance, variable declarations should be close to their usage as possible, but instance variables should be declared at the top of the class. Functions that depend on other functions should be vertically close to them.
Things start to get interesting with in chapter six with the distinction that is made between objects and data structures. The discussion centers on the anti-symmetry between a data structure, which exposes its data and has no functions, and objects, which hide their data data behind abstractions and expose functions for operating on that data (Martin). The distinction between procedural code and object-oriented code is touched on here, and the author argues that each technique can be used at different times in a complex system. The Law of Dementer is also discussed.
Chapter seven introduces a new author, Micheal Feathers, to discuss the topic of Error Handling. Practices such as writing the try-catch-finally statement first, avoiding checked exceptions, not returning null or passing it as an argument, are advocated.
The complexity of the books content continues to rise, as chapter eight, written by James Grenning, discusses establishing proper boundaries between modules, chapter nine discusses the topic of writing clean unit tests. Chapter ten, authored by Jeff Langr, discusses the advanced topic of writing cohesive classes that have a single responsibility. Chapter eleven, written by Dr. Kevin Dean Wampler, piggybacks off topic topics of chapter’s eight and ten to discuss creating systems. Chapter twelve, also authored by Jeff Langr, ties everything together, and argues for using the rules of test driven development mentioned in chapter nine to produce an emergent design. Chapter thirteen and Appendix A, written by Brett L. Schuchert, are dedicated to the topic of concurrency.
Part Two: Chapters fourteen – sixteen
In this section things get really challenging. Chapter fourteen is the first case study regarding a command line argument parser. The author first gets something working and successively walks through cleaning the code applying the principles studied in part one of the book. Chapter fifteen critiques an example of the drawn from the JUnit test framework, and refactors it. Chapter sixteen pulls the class SerialDate from the JCommon library, and again refactors it.
Part Three: Chapter Seventeen
Chapter seventeen is a list of smells and heuristics that codify the principles and practices covered throughout the book. This is the part of the book that you should refer to throughout your career.
Clean Code: A Handbook of Agile Software Craftsmanship contains a ton of knowledge and wisdom that’s of value to every developer. I strongly recommend this book for anyone programmer that cares about the quality of the code they produce.