What is “good” code? Some define it as “beautiful.” Some equate it with experience. Some with cleverness. Some can’t tell you what it is. Others know it when they see it. For me, “good” means maintainable.
Good code, yes, has grace and beauty. But what makes it worthwhile is that it’s easy to work with. It’s easy to add to good code. It’s easy to take away. It’s easy to make changes. It’s easy to fix bugs. And bugs are rare. Good code does what you want it to, usually the first time. Good code is a joy, not a burden.
This should be the normal state of software. How many developers live in the opposite state? They think that adding a feature always takes a long time and many lines of code. They think that getting cozy with your debugger is part of the process. They think that long hours sitting in front of the computer screen means you’re doing your job. It doesn’t. Long hours means you’re doing your job poorly.
Consider these truths of quality code. The best developers know them without thinking. To them, good code is second-nature. They’ve internalized these truths. They’ve reached nirvana. They are one with the code.
I consulted on one project that the developers complained needed to be “cleaned up.” But when I looked at the code, it wasn’t that bad. This project had good developers on it. They felt the need to keep the code good. Just a little bit of badness was enough to disturb them.
I’ve worked on code much worse. Functions were hundreds of lines long, or even thousands. To add a simple feature, you’d need to change lines in many places. And to find these places, you needed to forage around for hours with a debugger, or even days. Lucky was if you could understand how the logic was supposed to work. Its syntax was dense and incomprehensible, more so than you can probably imagine.
Here I thought these developers were dealing with bad code like this. That’s what I heard them tell me. I discovered an enlightened truth. If the developers know enough to complain, they know what good code is, and they pursue it. They can’t help but pursue it. Because they cannot be one with perpetually bad code. They must improve the code. This is part of their nature. But the projects in trouble are those whose developers do not pursue good code. They may not even know good code. And they neither ask for counsel nor accept it.
These truths are not for them. These are for you, good developer. If you desire more engineering and less debugging, if you feel the passion of good code, meditate on these truths.
Understanding is as important as coding. Spend as much time thinking about your design as you do coding it. Never code around a design flaw; such is the essence of hack. If you get stuck, always go back to the drawing board. But then follow through with your conclusions.
Flow and design: yin and yang. Code is more than a series of statements. It is also a relationship of parts. Stepping through your code with a debugger is not how to understand what it does. You must understand the design as well. Don’t think like a debugger, or your code will be incomplete. Think abstractly as well as concretely.
Together belongs together; separate belongs apart. Remember first principles: high cohesion and loose coupling. Parts that work closely together, keep close to each other. Parts that work separately, keep apart. In general, avoid printf-style formatting, as it separates parts (insertion point and insertion variable) that are closely linked.
Each part is harmonious with itself, but complements other parts. Each piece of code is a musical chord, in harmony with itself. Switch statements that combine disharmonious elements are evil. Use polymorphism to group harmonious elements into a coherent whole. Sequester dependencies between unlike things into as thin a slice as possible.
Form follows function. Only relevant coding standards are effective. Indentation, brace style, spacing, blank lines, these all communicate information. Use a consistent style that tells future programmers how the design works.
Maintaining unused code is more expensive than rewriting it. You need to maintain unused code, modify it, tweak it. But you cannot test it, because it is unused. You cannot know whether unused code still actually works. This is an unnecessary burden. Delete unused code, even if you may need to use it again someday. You can always write it again if you need to.
Comments tell why, not what or how. Add comments to explain why the code does what it does. Never add a comment to describe what the code does or how it does it. Instead, use descriptive function and variable names. If you need a comment to tell what or how, your design is flawed.
Be one with the code, grasshopper.