Over the last five years I have been a part of a rapidly growing software development team. During this period, the team has grown from fewer than 20 developers to over 200. While this team has managed to remain effective there have been some growing pains. Of late, I have been thinking about some best practices for this team and have found some inspiration in an unlikely source.
In particular, the American legal system provides some principles and practices which can guide technical decision making on fast growing teams. At all times, teams must balance between remaining flexible and ensuring that changes are made intentionally. A team that is constantly re-evaluating every question of design will be ineffective and paralyzed by constant churn. And the converse situation is just as dangerous. If a team never re-examines their design decisions, they continue to make a bad design worse and worse.1
The legal system operates on the principle of precedent. This means that the previous decisions of other courts should be applied in subsequent related matters in other courts. Software teams should operate under a similar model. When intentional design decisions are made, it is important that they not be changed unintentionally.
To that end, when architectural decisions are made, they need to be documented. And further, the opinion needs to be documented. A team cannot rely on the presence of the person who made the decision in order to understand its purpose. Michael Nygard described some concrete steps to document these sorts of decisions on the Relevance blog in 2011.2 3 He proposes keeping Architectural Design Records (ADR) within your codebase to store information about decisions that have been made. I think this process is an excellent starting point for the sort of deliberate, precedent-based decision making I'm arguing for.4
Within the legal system, it is still possible to break with precedent. This is generally done by the Supreme Court in questions of Constitutionality. Because the burden to modify the Constitution is so high, the court is able to overturn existing precedent. Many of the highest profile decisions of the court are like this. Additionally, the court is able to make decisions without establishing precedent. And the court uses opinions to attempt to clarify their intent in making decisions and establishing precedent.
To follow these principles within the context of a software team means that there must be processes in place to re-interpret or amend an ADR as necessary. A strict constructionist interpretation of ADRs will lead to heartbreak. Additionally, it is important to be able to identify decisions that are made that do not mean that a precedent is being set.
Finally, assuming you are convinced of the value of this approach, the question remains of how to actually begin to put this approach into place. Obviously, you will not begin with a huge body of existing documents. So instead, an engineer or team that is looking to make a change in design and wants to establish a new precedent should begin with a good faith effort to justify the current design. In effect, backfill the ADR for the existing design and then amend it or re-interpret it to reflect the proposed new design. Concretely, people in technical leadership positions will need to accept the responsibility of monitoring the usage and adoption of this process. For example, they should be engaging in code review keeping these decisions in mind. Additionally, it is their responsibility to ensure that the contents of the decision documents are understood and socialized.
Whether teams implement this process using ADRs as described by Nygard or something else is an implementation detail. If you disagree with that particular format, feel free to read thing you like better for the rest of the post. ↩