The Much-Maligned Docs

Ambrose Little
Software Developer
Published in
7 min readMay 6, 2017
This was not a particularly planned pic. Can’t believe I still have a few of these…

I’m old enough to remember when Agile was still a newish thing in software development, at least before it became more or less the de facto approach. One of the principles of the Manifesto is “Working software over comprehensive documentation.”

I agree with that principle as stated, and much of what you should derive from it. But I’ve run into plenty of folks who seem to think this means “NO DOCUMENTATION. EVAR.” Or something maybe only slightly less extreme, which practically amounts to the same thing — don’t bother writing any docs.

In fact, the principle above really is more geared towards up-front documentation (that is, reams and reams of requirements and design documentation) than it is for documentation written post hoc to help other project contributors more quickly come up to speed and/or effectively use reusable code.

I spent ten years working for a software development tools company where docs were a full on discipline, even having groups of people dedicated to it, and for which I was in various roles more or less responsible. I have closely observed the docs of many companies like Microsoft (who it must be said generally produces exceptionally good dev docs), Google, open source, and prior competitors/smaller vendors. Great docs are both significantly difficult to produce and maintain and immensely valuable.

I myself have written more articles and given more presentations than I care to count, not to mention contributing to a few books — i.e., docs. There’s a whole booming industry around tech writing (and much more free online). Docs are a thing. Writing things down to help your future self, others, etc. better and more quickly do what they need to do, is a thing.

Writing things down to help your future self, others, etc. better and more quickly do what they need to do, is a thing.

I’ve seen the results of poor or no docs way too many times. No code is entirely self-documenting (although aspiring to that is absolutely important and worthwhile), just like all user interfaces should be designed with a goal of users never having to consult docs. And yet you still do need docs for those cases where there are too many competing concerns or too many potential mental models.

What to Doc for Every Software Project

So what kind of docs are important for almost any software project/product? Here I am talking mostly about internal docs, the kind I loosely call “contributor guidelines.” This is the “readme,” and it should include the following:

  1. An architectural overview of the project, this is the high level pieces and how they play together.
  2. A tools overview — what significant tools, frameworks, libraries, etc. are leveraged, for dev, build, test, deploy. This isn’t a laundry list of dependencies like you can get from a packages file. This is big picture stuff.
  3. A patterns overview — as with tools, the focus is on big picture patterns that are leveraged and/or patterns that are extensively used. If you use dependency injection everywhere, that’s worth mentioning together with the DI library you chose and a link to it. Covering specific design choices in how you apply the patterns/how contributors should apply them is also important.
  4. Project structure overview — hopefully this is somewhat self-documenting, particularly if you’re following some framework convention, but it still doesn’t hurt to give big picture organization principles. You do want your code to stay organized as more and more devs contribute, right?
  5. Coding/testing/docs guidelines. Basically, think about the things that are important for consistency across a codebase, the kinds of things you might reject a PR for if they are not done. With styling, of course, if you can automate enforcement, do it, and this would be where you’d say you do that and what rule sets you use/where you deviate from the norms for the de facto set, if one exists.
  6. How to get the code, how to build, run, test, and deploy the code. Hopefully the majority of this is automated, e.g., “clone and run/build/test/deploy.” If it’s not, you should work on that for sure.

For all of the above, think about where you could draw a picture. This is especially useful for architectural overview. It never ceases to amaze me how rare it is to come across a simple arch diagram on projects, even those run by very senior devs. There are few things more useful in aiding understanding of code than drawing a picture. In fact, if you do nothing else, draw a picture of how your system works — just the chunky bits and what they talk to. Even a pic of a whiteboard or napkin is 1000x better than nothing, but you can also use https://www.draw.io/. There is no excuse!

There are few things more useful in aiding understanding of code than drawing a picture.

Everyone worries about docs getting out of date, but the things above are going to rarely change for a given software project, and when they do — it’s important for people to know about it. This is not tons of docs. We’re talking about a few pages at most. Not doing this stuff is sheer laziness and lack of professionalism. Not doing this stuff slows down forward momentum much more than you gain by thinking that you’re not gonna do it because it takes time away from feature work — especially as teams scale and teams change. There is no YAGNI for these things.

Where to Put These Docs?

The general principle for where to put project documentation is as close to the code as possible. The caveat here is it needs to be easily discoverable while not getting in the way of actually working on the code.

The general principle for where to put project documentation is as close to the code as possible.

  1. High-level contributor guidelines — GitHub has made this a no-brainer. This stuff goes in your readme, or at least should be linked from there. If you have a big, multi-repo project, you can use GitHub Pages, or make a central separate docs repo (might as well use Pages if you’re doing that), or use something like Raneto or some other KB app like Notion as an entry point/landing page, then link off to your relevant repos. Each repo should have any repo-specific guidelines on its readme. Leverage GitHub’s repo wikis for any other high-level docs relevant to that repo.
  2. Reusable code docs — these are some minimal docs that help devs know what’s available for reuse, what it is for, and how/when to use various reusable chunks of code in your project. Something like GitHub repo wiki can be good for the intro-level stuff on this, but especially for API, if you can put the relevant docs right with the code, that’s best. .NET’s XML docs and the equivalents in other platforms. Anything that can be consumed in Intellisense and/or used to produce docs like Swagger are preferred over separate docs.
  3. Feature/feature-area overview docs — maybe you have a big repo with largish feature areas within it that may have their own concerns/organization. In that case, GitHub to the rescue again — you can just put a readme in the top-level folder. GH is cool this way because it will show the readme for any folder (not just repo home) when you navigate to it. Or if you don’t have GH/something like it, just some docs in a common format located in the root of the area. Shout out to my buddy, Craig Shoemaker, for heading up the development of LiveWire as a very useful docs tool at Infragistics. I can also recommend MacDown for markdown on Mac.

In general, the closer you get to the code, the more you should strive for the code to explain itself. But don’t naively assume it does — even inside of functions. Don’t be afraid to add a brief comment giving some extra context or, especially, if you’re doing something that might cause someone to scratch their head when reading the code. Or if you are diverging from an established pattern/convention. Adding just a little explanation will make your future self and others immensely grateful.

In general, the closer you get to the code, the more you should strive for the code to explain itself. But don’t naively assume it does — even inside of functions.

Executable Docs

Self-documenting code is great, and an extension of that is so-called “executable docs.” This usually means automated tests. Well-written tests can indeed be helpful in explaining design intent, at least from an expectations point of view, but again, I would caution thinking that this is in and of it self good enough. Test, especially unit/micro-unit tests, tend to get unwieldy as a means for understanding a codebase, and they are still external to the code. I’m just saying, don’t think that “I wrote some unit tests” means that your code is easily grokkable. You still need to think about whether or not it is.

Don’t get me wrong, I’m not advocating for commenting every line of code. Far from it. Once you’ve documented the high-level stuff above and any important reusable code and APIs, that’s the bulk of it. Just don’t forget to be thoughtful and considerate of others — including yourself — who will inevitably visit your code in the future. You should be doing that to achieve the goal of self-documenting code, so it should be relatively obvious to you when you cannot do that and so need to augment it with some comments and/or a wiki page here and there.

Finally, I’m sure there are folks for whom what I’m saying is painfully obvious, and if so, you probably have your own ideas/suggestions on these things. Please feel free to comment and/or write your own similar guidelines/linking to them. The more good advice in this area, the better, as far as I’m concerned.

To everyone else, get with the program! :)

--

--

Ambrose Little
Software Developer

Experienced software and UX guy. Staff Software Engineer at Built Technologies. 8x Microsoft MVP. Book Author. Husband. Father of 7. Armchair Philosopher.