Navigating the Maze of Technical Documentation: Best Practices for Keeping Your Code Up-To-Date

cover
25 Jul 2024

The majority of software development companies have technical documentation. Some companies may update it regularly, but most just use it from time to time, and stored data there becomes outdated. That is a known issue because developers change code frequently, and keeping an eye on documentation prolongs the development lifecycle, which is already long. Moreover, the disaster will not happen if any documents are a bit outdated. Someone may claim that outdated documentation is better than nothing. Indeed, this statement has a point of truth. On the other hand, anything outdated may confuse developers, and it will be a waste of time considering the number of useless pages on Confluence, as many people as many opinions. From my perspective, having valid documentation and not having anything redundant is the best scenario. In order to achieve that, we need to understand three things: what we need to document, what we don’t need to document, and decide how to perform regular updates. Here, I will describe my point of view regarding technical documentation only, nothing related to management, company culture, access levels, etc. Just for clarity, documents like the code of conduct, team structure, and employee responsibilities I consider as management.

What you need to document

Let’s start with the most important thing: your first day at the company. What will you need the most? Understanding how to start development!


Technical onboarding


This means having access to technical onboarding documentation that outlines how to properly configure your system for coding and testing. This documentation may include the following:


  • A general introduction to the development infrastructure.

  • Links to download the source code.

  • Instructions for installing. and configuring third-party software

  • Steps to compile the source code, if required.

  • An overview of the development flow and branch strategies.

  • Guidelines for code review processes.

  • Instructions for deploying code to development and staging environments and promoting it to production.

  • Additional requirements for testing your changes.


Ideally, new employees should be able to read the documentation and prepare their environment for active development. I firmly believe that even onboarding to complex systems can be effectively documented. Do you need to order access to a remote environment to test changes? No problem. Just include a link to the technical documentation on how to do it and proceed from the point where you already have credentials.


Do you need additional access to certain repositories? Provide a separate link for creating a ticket.

I can’t imagine a situation where employees encounter problems with onboarding steps, assuming the documentation is written carefully. Moreover, having someone assist with technical onboarding can waste time and introduce risks. No one remembers everything, and there will be plenty of questions after onboarding. However, with proper documentation, most of these questions can be avoided.


People responsible for technical onboarding might get sick or leave the company. Newcomers could spend too much time figuring out how to provision a system for development instead of implementing features. Once you think the onboarding documentation is ready, you must test it. There’s a good chance you’ve forgotten to add something. Ask a colleague to follow the documentation and see how it goes, or try reprovisioning in a separate environment yourself. Always check your work.


Your code needs policies.


Assuming you have good technical onboarding documentation and people can start working without help, you need to document the technology stack and your approach to feature development and maintenance to ensure productive work. Creating separate policies for these aspects can be highly beneficial. Each policy must be signed by the CTO or Head of Engineering, though any developer can prepare the policy itself.


While policies are typically associated with large companies, even when you have 5–10 teams, the technology stack can become uncontrolled. It may take several hours to write one policy, but it can save much more time in the long run. Developers often experiment with new technologies that may not fit business needs. Restricting the technology stack to reliable frameworks, databases, message queues, architectural principles, and even cloud platforms can reduce disputes and increase software quality.


Software Design


The most important part of the documentation is to explain how the system works and how to maintain it. There is no one-size-fits-all approach to this; it completely depends on your architecture.


If you use microservices, you could start with a C4 container diagram. Each service should have its own document describing its general purpose, API, dependencies (databases, message brokers, third-party systems, and other services). For the API, provide a link to Swagger if available; otherwise, document the endpoint’s name, address, and description. Avoid copying all SQL requests, function names, and code into your documentation. Instead, document the minimum valuable information to keep it up-to-date with less effort.


If your architecture is monolithic, I suggest dividing it into several independent modules, at least at the documentation level. This approach requires you to describe the same dependencies on databases, message queues, and third-party systems. The key difference is that the independent modules will communicate via function calls. The quality of your monolith’s design matters significantly; even a complex monolithic system can be well-designed with a clear separation of responsibilities.


Regardless of whether you have a monolithic or microservice architecture, it is essential to have a template for documenting the technical parts of each service or entity to follow it consistently. For example, the following items could be part of your documentation template:


  • C4 containers diagram / UML modules diagram

  • Infrastructure scheme

  • Infrastructure data (VM addresses, configuration parameters)

  • Important links for logging and monitoring

  • Service API

  • Dependencies on databases

  • Dependencies on message queues

  • Dependencies on third-party services

  • Dependencies on other services


You can decide how detailed you want to be with this list. Without a structured approach, your documentation can become an accumulation of irrelevant information.


If you need to document additional findings, you can create a separate page and add proper links to other documents that reference these findings.


Architectural Decision Records & Postmortems


Additionally, two types of documents can be very useful for documentation: Postmortems and Architecture Decision Records (ADR). Both are event-specific and should not be updated.


ADR is used to describe the impact and risk of any architecture-related changes. It helps you understand why something was built or revised.


A Postmortem helps you understand mistakes by documenting what went wrong and how to avoid similar issues in the future. Postmortem reports can be useful for every team member to review, and ideally, familiarity with them should be mandatory. They are beneficial not only immediately after an incident but also for later review. They are especially helpful for newcomers to learn about potential mistakes to avoid.

What you don’t need to document

I mentioned that technical documentation can become overwhelmed with unnecessary information. Here are the most important data points you should definitely avoid adding to your documentation. Let’s go step by step.


Empty Pages


Especially relevant when using Confluence. It’s really surprising when you search for information only to find an empty page.


Duplicated Pages

Having duplicated pages is much worse than having empty ones. Developers waste time figuring out the source of truth, only to find out that the pages are duplicates. The worst scenario is partially duplicated pages, where developers create new pages without checking for existing similar information. Always double-check if the information has already been documented, and if so, consider expanding the existing page.


Don’t copy your repository


Don’t add anything to your documentation that can be found in the repository. This avoids the need to update changes in two places. If you have important comments on some code, leave them in the code and simply add a link in the documentation. The same applies to infrastructure; if you use GitOps and the infrastructure is described there, don’t document it additionally.


Don’t copy existing API documentation


Don’t document or describe APIs if you have Swagger. This is similar to copying code comments or the code itself. A well-configured Swagger can comprehensively describe your API.


Don’t document credentials


Never keep credentials in Confluence. You can include VM addresses and usernames, but definitely not passwords. It can be very hard to control access to such a page, and you might not even notice how many people have access to this sensitive information.


Verify what you document


Don’t document anything unless you are sure about it. If you use third-party software and are not confident about the integration details, double-check them. Your documentation might be used by many developers in the future, and they expect it to be accurate.


How to update documentation

The most difficult part is keeping documentation up to date. I completely agree; it’s a challenge. Here are some strategies to help manage this task effectively.


Find a responsible person to update specific parts of the documentation.


I like the RACI approach, where every part of documentation has a Responsible, Accountable, Consulted, and Informed person. This makes the update procedure an obligation rather than a “nice to have.” Document who is responsible for each part of the documentation. It must be one person; if a team is responsible, it means no one is responsible. Determine when to update the documentation and how to avoid missing updates. Here is one of the options.


Label tickets in your management systems like Jira or Trello.


For example, a task requiring database interaction could have a “database integration” label; similarly, use labels for “message queue,” “third-party API,” etc. If no integration is necessary, use a “no integration” label. At the end of the sprint, the responsible person can review each label and update the necessary parts of the documentation based on your structured template. This task can be very beneficial for interns and junior developers as it helps them understand how the system works. You can also set up your management system to prevent closing tickets without integration labels to ensure nothing is missed.


Manual tickets review and update


A less reliable but still useful method is to dedicate one day in a month for the responsible person to review committed tickets and check if the basic documentation is up to date. While this approach may not be as effective, it can be a starting point to include this task in your milestones.


I am not suggesting that you should only follow the principles mentioned here or document only certain things. It is entirely up to you how you choose to document. My goal is to highlight ways to avoid situations where documentation becomes a complete mess that no one wants to fix. I understand that, sooner or later, documentation will become messy, especially in large tech companies. However, even in such environments, it is possible to maintain a core set of documentation that is always up-to-date and reliable.