Documenting your code is vital when working on a project involving a whole team. When you join a new team, you would hope that the work is in a state that would allow you to fairly comfortably pick up and roll with. As such, people should always strive to code with empathy for the other people on the team, both current and future.
The level of detail and format of the documentation you provide is context dependent. These may include comments in code, tickets, commit messages, READMEs, ADRs, etc.
Iāve worked on codebases where thereās been no comments, or close to none. This in itself doesnāt necessarily mean the project is in a bad state, but it can be an indication that future developers on the project may be at a disadvantage.
Equally, Iāve seen code where thereās endless comments describing everything that has been done, which is a lot of noise. When I was in my first year of university, I found myself commenting on almost every line of code I wrote. I cringe at the thought nowadays! š
My basic view is that:
Code is the what, comments are the why
Code should be as descriptive as possible, telling the other developers what itās doing without them having to read it as if they were a compiler. Comments should be used to document noteworthy decisions that have been made. We will see shortly that thereās some exceptions.
Code is a set of instructions for the computer to perform. In higher level languages, it becomes more descriptive and verbose. For example, while
loops and if/else
blocks can typically be understood by anyone. Code pretty much tells a story, particularly for imperative coding styles. That said, most paradigms correspond to real world concepts.
Function and variable names are chosen by the developer, and make up the majority of the code you read or write. That means, itās important that you use meaningful names. For example, I avoid using variable names like count
or x
. The former is ambiguous, why not numOfUsers
instead? x
means absolutely nothing. That said, you may choose to use i
for an iterator inside a single-purpose function, where the value of i
itself has little meaning in itself.
For the most part, with good descriptive names, your code should be largely understandable by other developers. If another developer canāt understand the code from reading it, itās a sign that the code is overly complex, badly organised, and needs to be refactored.
This is one of a handful of possible exceptions. Now these beauties are incredibly powerful, and I couldnāt imagine a world without them, but oh boy are they difficult to read. Sure, if you have a \d+
matcher, I wouldnāt necessarily feel the need to comment, especially if your function name is something like getIdFromWorkspace
.
But if you have something more complex, a decent descriptive function name is going to be difficult to come up with. This is where a comment goes a long way. In fact, itās ESSENTIAL!
Letās just say, Iāve seen some crazy regex around with no comments, and Iāve wanted to cry! š
/=(?:[^\[\|]*?(?:\[\[[^\|\]]*(?:\|(?:[^\|\]]*))?\]\])?)+(?:\||\}\})/
How do you document decisions youāve made in your code? You might read some code and wonder why the developer did it a particular way. This is particularly the case where the developer has done something a little different from the norm. Of course, sometimes doing something against the norm is a red flag, but in other cases, there may be legitimate reasons.
For example, you may have made the decision not to optimize some code because thereās no need for it to scale. You might warn a future developer not to copy and paste this code for other features because of that limitation. Developers are lazy, they copy and paste all the things.
I like to write comments in code where Iāve made a decision like this. Some people will argue that comments become out of date, but so does code. If your code is going to change, the comments that decorate it will likely change or be removed anyway. Itās not a reason to avoid comments.
However, the most effective way is to put a short comment and link to a ticket (e.g. Jira or Github Issue), where you can put a lot more detail. You should also always try to put the ticket number in your commit message. That way, the developer can see the full discussion.
I canāt count the number of times Iāve struggled to work out why something was done the way it was, and not had any way to find out more. What if the original developer has left the company? All those business decisions are lost. Be an empathetic developer!
Comments in code and discussions in tickets are great, but for more visibility on larger decisions, itās best to document them somewhere more central, and in particular, accessible by product owners and other main stakeholders.
If youāre using Atlassian products, Confluence is quite a good choice for this. We also use our own product, Huddle, to store project documents. Since we are a secure team collaboration application, itās the perfect choice for us.
As part of our software development lifecycle, we document project decisions in an Architecture Decision Records (ADR). At the start of the project, we review the requirements and possible solutions to achieve the end goal, using ATAM. We may consider things like security, performance, testability. maintainability, etc. The ADR allows us to document what we have considered, and the final decision we made. Itās a living document, so we can update it throughout the project.
This document is really useful because I can look up past features weāve implemented and identify why we did something a particular way, and see the alternatives we considered.
You can understand a lot about an application from looking at tests cases. Theyāre usually written in BDD or TDD form, like describe
and it
blocks, so they are easy to read. The implementation details are blackboxed because all we see are the input and outputs. Once we understand that, when we need to update the code, we already have some context.
As weāve seen, there are many ways to effectively document your code. Where possible, code should be self-documenting, but in a few cases, comments are definitely required. Noteworthy decisions may be documented as comments in code, with deeper discussions linked to via a ticket reference. For larger architectural decisions, storing them centrally provides greater visibility. Tests provide an understanding of the applicationās requirements.
By following sensible practices, we can help other members of the team, current and future, understand the code weāve written, and the reasons behind decisions that were made.
Code with empathy, donāt make me cry like regex does! š¤