Many of us who love writing code are less enamored with writing documentation. We view it as a necessary evil. And writing documentation is expensive. It takes time and pulls us away from other activities, so we want to make sure that the documentation we write is valuable. But in many of the organizations I work with, I find that they often document the wrong things and fail to document some critical pieces.
Agile software development is a lightweight process. This doesn’t mean that we should abandon all documentation, but we do value working code over other documents because our customers value working code more than documents. “Barely sufficient documentation” is the phrase we use, and if we apply good technical practices, then the software we write should be clear enough that it won’t need a lot of internal documentation.
Naming is my first line of defense for writing quality software. Everything in an object-oriented program has a name, including the data types we define and the behaviors we invoke by calling methods in code. Each name that we assign is an opportunity to clarify exactly what the software is doing.
I prefer to find ways of making my code expressive so I don’t need a lot of additional comments. I do this by using intention-revealing names in my code that clearly communicate what the code is doing. This has a huge side benefit of supporting high-quality software development. If I can name a behavior well so it’s clear and concise in the concept it represents, it usually won’t bleed into other code.
Code can express what we want to accomplish, but sometimes it’s a little bit more difficult to express why we’re doing something in the first place. This is an entirely justifiable and valuable reason for comments in code, so I like to distinguish between what comments and why comments. If I use a lot of what comments, my readers may tend to read comments rather than code, and I don’t want that. Code is executable and reflects what’s really happening, whereas comments can easily and quickly get out of date.
Some what comments are important. For example, some system APIs don’t behave exactly as documented, so it’s useful to say how we’re using an API if it diverges from its own documentation. Still, I find that most what comments are usually unnecessary when the code is clear and well written.
Why comments, on the other hand, can be quite valuable because they explain why we’re taking a particular approach, and that’s where I find most software maintenance breaks down. The people who maintain code are often not the people who originally wrote it, so it can be difficult to understand the original author’s intention when reviewing code. Why comments help set a context and give us clues as to what the author was thinking when they came up with a particular design, guiding us when we’re faced with the task of extending it.
More often than not, the original author has considered the possibility of extending software in the way we want to extend it now or will want to extend it in the future. But if the people who are revising the software don’t have a sense of the original author’s intention, they can end up working against the grain of a system, special-casing situations that might have been incorporated into the design in the first place.
I’ve often seen developers and teams go overboard in documentation because they use a lot of artifacts to build the system. But once the system is built, the need for those artifacts is usually much less, so knowing which documents we don’t need to maintain after we write a system can save us an enormous amount of time and money.
The best kind of internal documentation I’ve encountered is unit tests.
When a developer practices test-driven development correctly, it has several advantages when reviewing their code. First of all, I know with absolute certainty that their code works by simply running their tests. I can look at their test coverage and verify that all their code, or at least the majority of their code, is under test. I can look at their tests and see how they intended their methods to be called. I can look at the sequence of tests and see how the developer emerged their system to build the feature. All these things let me get into the developer’s head so that I understand not just what decisions they’ve made, but why they’ve made those decisions.
Unit tests are the perfect expression of all these ideals. A handful of unit tests can communicate so much in terms of what the developer intended when writing the code. I often learn far more than reading reams of paper filled with prose about a system, and it takes far less time. When I work on systems where the developers are good at writing unit tests, I find that I can learn the system and become productive with it in a tiny fraction of the time it would have taken me otherwise. I don’t have to wonder if something works or how to use it because it’s all embodied in the unit test. And unit tests are code—and we developers love writing code.
Of course, different systems require different levels of documentation, depending on who needs to be involved and how critical the functionality is. But even on mission-critical systems, I see companies spend an enormous amount of money in documentation but fail to document some of the most important aspects of the system. If we’re going to maintain a system, we have to get into the heads of the people who wrote it, and traditional documentation is not ideal for this purpose.
One cheap and easy way to get the team to express the why is to take a video camera to an end-of-project party or retrospective and interview the key people. Ask open-ended questions: Why did you choose to take this approach? What did you find most valuable, challenging, or interesting about the project? What are you most proud of? What would you change if you could do it all over again? Then just let them talk. You’ll get insights that are far deeper than any documents they would have written.
Show this video to the developers who are going to maintain the system. It’ll give them a link to the personalities behind the system as well as a deeper understanding of the values and challenges in creating it. I’ve gotten feedback in several different cases that the video I created, and which cost the company virtually nothing, was one of the most important factors in learning a system that developers were going to maintain.
So document the why as well as the how. Find ways to make it fun and interesting. Get people to speak passionately about their work, and it will help engage the developers who inherit a system.