Why do we even need any documents in the development process?
What about this statement that the code documents itself?
Let's consider the most common scenario: the system's code (be it a program, project, or product) is being written over a long period, and the team gradually changes during this process, taking certain knowledge about the system with them as developers leave.
What can we do in such a case?
The simplest answer is to write a specification that captures all the implementation details to ensure the system meets the original requirements.
However, such a document is very difficult to write in advance, and during the development process, some implementation details may change (adapting to the market/new requests for mechanics, etc.). So, what can we devise to improve the bus factor?
Let's try to follow a flow that could be one of the possible solutions to address the problem mentioned above.
First, we need to describe the initial design based on requirements from stakeholders and document it. After that, this document can be shared with other teams and their feedback requested: ask to implement certain features, comment on the initial design, fix a certain interface, etc. Such a document can be called an RFC.
RFC, or "Request for Comments," is a document distributed among interested parties—including developers, architects, and other teams—to collect feedback, comments, and suggestions. It is less detailed than a specification and includes only the initial problem, task, and solution domain. Being more flexible, it allows for actively accepting changes in the design ensuring a deep understanding of the task and facilitating quality and thoughtful decision-making.
Okay, we've defined technical requirements and gathered requirements from other teams. What's next?
At this stage, it's necessary to finalize the system design and all the main functions it will perform. For this purpose, we write an ADR.
ADR, or "Architecture Decision Record," is a document that records important architectural decisions made during the software development process. Each ADR describes a specific high-level architectural decision, its context, alternatives considered, the decision made, and the motivation for choosing these specific details over others.
Such a document allows every team member (and other teams as well) to understand the principles and values that underpin the design. If a new developer joins the team years later and asks, "Why did you do it this way?", they can be shown this document, which will answer all their questions.
Now it's time to write the code and its specifications. At this stage, we thoroughly work through each feature, simultaneously compiling all the information and implementation details into a special document. This document should reflect the current low-level requirements for the system.
An important point: during the software lifecycle, such a specification can change significantly, and that's okay. However, it's very important to still stay within the original design and architecture to prevent the codebase from becoming something unmanageable.
Why is it needed? It is critical for a test plan to be built not on the basis of code that was written according to the specification (we write code and tests for this code so that they pass), but on the basis of a design that includes critical scenarios that must be processed correctly. It is also very convenient that you can submit such a test plan for review to other teams (for integrations or just for additional testing), making it clear how the system will behave in different situations.
What does it include?
All possible system operation scenarios
All possible invariants that must be maintained during system operation
Acceptance tests to check the system state at the start (should consider the environment, e.g., data on the network)
We've finalized the design, written the code and specification, and compiled the test plan. Sounds pretty solid already! But what else could we add?
Such a plan might be needed to some extent to improve the bus factor and create conditions in which any team member can deploy the system and verify it's state.
Why can't we do without it? We can, but in the real world, large teams where many people are responsible for different parts of the system, and the deployment process might be fully delegated to DevOps. What's wrong with that, since we've written tests, put them in CI, and checked for vulnerabilities, do we need anything else? Maybe not, but often tests do not consider the current state of the system and test not quite what we would like.
What deployment plan might contain:
Nothing complicated, right? Having such a document for a specific update can significantly improve the bus factor and prevent reliance on specific individuals. Isn't that what we want?
In the software development process, it's important not just to write code, but also to create documentation that ensures understanding and consistency throughout all stages of development. The documentation may be the code itself, but experience has shown that documentation is very important to maintain the quality, stability and future scalability of the system, especially when the team changes during development, and also when the project evolves and adapts to new requirements.
Documentation includes RFC (Request for Comments), ADR (Architecture Records), Specification, Test Plans, Deployment Plans, and more. This will guarantee the retention of knowledge in the team, simplify the process of integrating new employees into the project, and increase the overall reliability and resistance of the system to changes.