I am opening up “Uncle” Bob Martin‘s Clean Code for my third reading. This programming classic serves as a foundational cover-to-cover read as well as a great topical desk reference. There have been times in the last few years that I wish I could reallocate my university tuition towards memorizing and applying every practice Martin outlines in this work rather than my coursework. I have and continue to sludge through so much bad code in my career, that being able to sense and “clean” is one of the most valuable technical skills I can provide.
In this pass through the book, I wanted to jot down some notes to reinforce the skills and techniques Uncle Bob shares. I was inspired by the guys over on Coding Blocks who recently podcast-ed through Uncle Bob’s Clean Architecture. There is no shortage of references to this book on the blogs, and I do not think my posts on the book will be particularly useful to the general public. By forcing myself to re-regurgitate what I read, however, I hope to sharpen my code-sense.
Cost and Lifecycle of Messy Code
Martin kicks off this book with an example and walkthrough of an all-to-common application lifecycle plagued with bad code. He described an unnamed company with a “killer app” that was eventually shut down because they could not ship features and resolve bugs fast enough later in its life. One of the developers described the reason as:
They had rushed the product to market and had made a huge mess in the code.
Projects are almost always under tremendous pressure by layers of management, product owners, and other stakeholders to move fast. Efficiency is indeed essential, but when developers succumb to the pressure and move too quickly, they allow technical debt to build and future costs to increase.
If messes grow to be too expensive to fix and extend, the team is ultimately forced to consider shutting the product down or incurring the cost of a complete “grand redesign in the sky.” The elite tiger team chosen to tackle the rebuild incurs the same messiness over time if they do not consistently have the stance of defending cleanliness.
It is the job of managers and product owners to deliver value to customers. It is the job of professional developers to guard the quality of the code and provide valid estimates of cost. This responsibility can, at times, mean saying “no” to managers.
To drive this point home, what if you were a doctor and had a patient who demanded that you stop all the silly hand-washing in preparation for surgery because it was taking too much time? Clearly the patient is the boss; and yet the doctor should absolutely refuse to comply. Why? Because the doctor knows more than the patient about the risks of disease and infection. It would be unprofessional (never mind criminal) for the doctor to comply with the patient.
So too it is unprofessional for programmers to bend to the will of managers who don’t understand the risks of making messes.
Clean Code Defined
Martin reached out to some software legends to provide definitions of “clean code.” Pick up a copy of this book for yourself to read them all, but my personal favorite is from Michael Feathers (author of Working Effectively with Legacy Code):
Clean code always looks like it was written by someone who cares. There is nothing obvious that you can do to make it better. All of those things were thought about by the code’s author, and if you try to imagine improvements, you’re led back to where you are, sitting in appreciation of the code someone left for you—code left by someone who cares deeply about the craft.
Authors and the Read/Write Ratio
Uncle Bob describes programmers as a type of author, responsible for communicating well. The vast majority of our time (10:1) is spent reading the code, so when we do write, we must make it clear and expressive. Without being able to read the existing code, there is no way to write more.
(Boy) Scout Rule
Martin closes out the first chapter by sharing an adapted Boy Scouts of America rule:
Leave the campground cleaner than you found it.
Whether or not you choose to include “Boy” when referring to it going forward, this classic rule can provide immense value to a development team that follows it. Code naturally wants to rot entropically, so it takes continual effort to keep it clean.
I love this principle, and I try to implement it in every commit. I do experience tension, though, when working in legacy (no unit tests) applications. What levels and scopes can I or should I safely clean while resolving issues?
TDD purists might say not to make changes of any kind without unit tests. I am personally comfortable performing things like renaming and method extraction if I am primarily using refactoring tools like what IDEs (Visual Studio) and IDE extensions (ReSharper) provide. If the cleaning would require me to type changes manually, I try not to trust myself to do so in a non-unit-tested codebase.
Defining the Developer’s “Done”
For me, this book is all about defining what “done” means to the software developer. Sure, “done” should involve steps such as QA validation and acceptance testing. However, at what point are the developer’s changes indeed code complete?
Code that is “done” should not just work. It should be expressive, easy to navigate, and a breeze to extend.
Any mediocre programmer can make something work. Master developers write code that is artful, not only so that it is aesthetically pleasing, but so that it is easy to locate and squash bugs, extend functionality, and pivot entire modules in the future. Professional developers have a long-term view and author code that reflects that.