Managing Architecture Decision Records with ADR-Tools

May 27th, 2018 by

Every software project includes a set of architecture decisions defining boundaries and constraints for further design and implementation.

It’s important to document those decisions somehow or else a development team might not know which decisions where made and with which assumptions.

Or they know the decision but are missing the context and the consequences and therefore decisions are blindly accepted or blindly changed.

In the following short tutorial I will show how to structure architecture decisions in so called Architecture Decision Records and how to manage them with a simple tool named ADR-Tools.

Architecture Decision Records

Architecture Decision Records

 

Architecture Decision Records (ADR)

The Agile Manifesto states that “Working software over comprehensive documentation” but this does not mean that there should be no documentation at all.

Especially for agile software projects where the architecture might adapt to new knowledge, market situations or technologies it is important to know what decisions were made, why they were made and with which assumptions.

The main problem with documentation is, that it needs to be close to the project and it needs to be short and concise or else it won’t be read or won’t be updated.

What are significant decisions that we should document in this scope?

According to my favorite author, Michael T. Nygard (Release it), significant decisions are those who “affect the structure, non-functional characteristics, dependencies, interfaces, or construction techniques

Therefore each record describes a set of forces and a single decision in their response, forces may appear in multiple Architecture Decision Records (ADR) and we store them in our project directory in doc/arch/adr-NNN.md and we number them sequentially and monotonically.

When reversing a decision, we keep the old ADR file but we’re marking it as superseded because it still might be relevant to know that there was such a decision.

The ADR file contains these typical elements:

  • Title: The ADR file have names consisting of short noun phrases, Example: ADR 1: Use Hystrix to stabilize integration points.
  • Date: The ADR’s creation date
  • Status: The decision’s status, e.g.: “accepted“, “proposed” (if stakeholders have not approved yet), “deprecated” or “superseded
  • Context: A description of the forces at play (organizational, political, cultural, technological, social, project-local…)
  • Decision: The response to these forces, active voice, full sentences.
  • Consequences: The resulting context after applying the decision with all consequences, positive as well as neutral or negative ones.

For more detailed information, please feel free to read Michael T. Nygard: Documenting Architecture Decisions.

Of course other formats for ADRs exist, please feel free to visit https://adr.github.io/ for other tools and formats.

Installing ADR-Tools

We will be using ADR-Tools to manage our ADRs so we need to install it.

Using Mac, we may simply use the following command (using homebrew):

brew install adr-tools

Another choice e.g. for Linux is to download the latest release from GitHub here, untar the archive and add the src-path to your PATH.

ADR-Tools are a collection of bash scripts.

Initializing a Project

The first step is to initialize ADRs for our project (in this example it’s a typical Maven project).

We use adr init to initialize ADRs for our project within the specified directory …..

$ adr init doc/architecture/decisions
doc/architecture/decisions/0001-record-architecture-decisions.md

Afterwards, our project directory structure looks similar to this one:

├── doc
│   └── architecture
│       └── decisions
│           └── 0001-record-architecture-decisions.md
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   └── resources
    └── test
        └── java

As we can see, a first decision already has been added to the project: It’s the decision to record our architecture decisions.

When opening the ADR file we’re able to read the following Markdown file:

# 1. Record architecture decisions
 
Date: 2018-05-26
 
## Status
 
Accepted
 
## Context
 
We need to record the architectural decisions made on this project.
 
## Decision
 
We will use Architecture Decision Records, as described by Michael Nygard in this article: http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions
 
## Consequences
 
See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's _adr-tools_ at https://github.com/npryce/adr-tools.

Creating new Architecture Decision Records

We’re ready now to create our first ADR. The command adr new allows us to create a new ADR with the given title.

$ adr new Use Hystrix to stabilize integration points
doc/architecture/decisions/0002-use-hystrix-to-stabilize-integration-points.md

This is what the generated Markdown file looks like:

# 2. Use Hystrix to stabilize integration points
 
Date: 2018-05-26
 
## Status
 
Accepted
 
## Context
 
Context here...
 
## Decision
 
Decision here...
 
## Consequences
 
Consequences here...

We’re adding another ADR:

adr new Use Thrift for data serialization between system a and system b
doc/architecture/decisions/0003-use-thrift-for-data-serialization-between-system-a-and-system-b.md

Listing Architecture Decision Records

We may list existing ADRs using adr list like this:

$ adr list
doc/architecture/decisions/0001-record-architecture-decisions.md
doc/architecture/decisions/0002-use-hystrix-to-stabilize-integration-points.md
doc/architecture/decisions/0003-use-thrift-for-data-serialization-between-system-a-and-system-b.md

Superseding a Decision

Now we will supersede a decision, for example if a new ADR supersedes our decision #3, we would type in the following command:

$ adr new -s 3 Use Avro for data serialization between system a and system b
doc/architecture/decisions/0004-use-avro-for-data-serialization-between-system-a-and-system-b.md

This produces the following new ADR file with a reference to the superseded ADR.

# 4. Use Avro for data serialization between system a and system b
 
Date: 2018-05-26
 
## Status
 
Accepted
 
Supersedes [3. Use Thrift for data serialization between system a and system b](0003-use-thrift-for-data-serialization-between-system-a-and-system-b.md)
 
## Context
 
Context here...
 
## Decision
 
Decision here...
 
## Consequences
 
Consequences here...

Of course our old decision is changed, too including a reference to the new ADR and setting its status to “Superseded”.

# 3. Use Thrift for data serialization between system a and system b
 
Date: 2018-05-26
 
## Status
 
Superseded by [4. Use Avro for data serialization between system a and system b](0004-use-avro-for-data-serialization-between-system-a-and-system-b.md)
 
## Context
 
Context here...
 
## Decision
 
Decision here...
 
## Consequences
 
Consequences here...

Generating Graphs

To gain an overview of our ADR’s relations we may generate a graph in the DOT format using adr generate graph like this:

$ adr generate graph
digraph {
  node [shape=plaintext];
  _1 [label="1. Record architecture decisions"; URL="0001-record-architecture-decisions.html"]
  _2 [label="2. Use Hystrix to stabilize integration points"; URL="0002-use-hystrix-to-stabilize-integration-points.html"]
  _1 -> _2 [style="dotted"];
  _3 [label="3. Use Thrift for data serialization between system a and system b"; URL="0003-use-thrift-for-data-serialization-between-system-a-and-system-b.html"]
  _2 -> _3 [style="dotted"];
  _3 -> _4 [label="Superceded by"]
  _4 [label="4. Use Avro for data serialization between system a and system b"; URL="0004-use-avro-for-data-serialization-between-system-a-and-system-b.html"]
  _3 -> _4 [style="dotted"];
  _4 -> _3 [label="Supercedes"]
}

We may write this output to a file e.g. adr generate graph > generated/graph.dot

From this DOT file we may create an image e.g. using GraphViz like this:

dot -Tpng generated/graph.dot -ogenerated/graph.png

Another choice is to use an online tool like  webgraphviz here so you don’t need to install another tool.

This is what the generated graph looks like as png-image:

ADR generated graph of architecture decisions

ADR generated graph of architecture decisions

Generating Table of Contents

To include the ADRs in other documents we may generate a table of contents for our ADRs using adr generate toc like this:

$ adr generate toc

This returns the following Markdown code:

# Architecture Decision Records
 
* [1. Record architecture decisions](0001-record-architecture-decisions.md)
* [2. Use Hystrix to stabilize integration points](0002-use-hystrix-to-stabilize-integration-points.md)
* [3. Use Thrift for data serialization between system a and system b](0003-use-thrift-for-data-serialization-between-system-a-and-system-b.md)
* [4. Use Avro for data serialization between system a and system b](0004-use-avro-for-data-serialization-between-system-a-and-system-b.md)

Linking Architecture Decision Records

When ADRs are linked somehow we want to document this and adr link eases this for us.

Let’s use an example where ADR #4 amends ADR #2 so that we could link both with the following command:

$ adr link 4 Amends 2 "Amended by"

Now our graph looks like this:

adr generate graph
digraph {
  node [shape=plaintext];
  _1 [label="1. Record architecture decisions"; URL="0001-record-architecture-decisions.html"]
  _2 [label="2. Use Hystrix to stabilize integration points"; URL="0002-use-hystrix-to-stabilize-integration-points.html"]
  _1 -> _2 [style="dotted"];
  _2 -> _4 [label="Amended by"]
  _3 [label="3. Use Thrift for data serialization between system a and system b"; URL="0003-use-thrift-for-data-serialization-between-system-a-and-system-b.html"]
  _2 -> _3 [style="dotted"];
  _3 -> _4 [label="Superceded by"]
  _4 [label="4. Use Avro for data serialization between system a and system b"; URL="0004-use-avro-for-data-serialization-between-system-a-and-system-b.html"]
  _3 -> _4 [style="dotted"];
  _4 -> _3 [label="Supercedes"]
  _4 -> _2 [label="Amends"]
}

Or as an image:

Updated Architecture Decision Graph

Updated Architecture Decision Graph

In addition both ADR files were updated:

ADR #2 now looks like this one:

# 2. Use Hystrix to stabilize integration points
 
Date: 2018-05-26
 
## Status
 
Accepted
 
Amended by [4. Use Avro for data serialization between system a and system b](0004-use-avro-for-data-serialization-between-system-a-and-system-b.md)
 
## Context
 
Context here...
 
## Decision
 
Decision here...
 
## Consequences
 
Consequences here...

ADR #4 has been changed to this:

# 4. Use Avro for data serialization between system a and system b
 
Date: 2018-05-26
 
## Status
 
Accepted
 
Supercedes [3. Use Thrift for data serialization between system a and system b](0003-use-thrift-for-data-serialization-between-system-a-and-system-b.md)
 
Amends [2. Use Hystrix to stabilize integration points](0002-use-hystrix-to-stabilize-integration-points.md)
 
## Context
 
Context here...
 
## Decision
 
Decision here...
 
## Consequences
 
Consequences here...

Alternatives

Other alternatives as tool or syntax/format exist. There are even tools where you write the decisions as Java annotations in a class (not sure if I like it)…

Y-Statements – Sustainable Architectural Decision Records

More information: GitHub Project

Markdown Architectural Decision Records (MADR)

More information: InfoQ

e-adr

Documentation via Java annotations: GitHub

Tutorial Sources

Please feel free to download the tutorial sources from my Bitbucket repository, fork it there or clone it using Git:

git clone https://bitbucket.org/hascode/adr-examples.git

Resources

Search
Categories