Software Architecture: Architecture Decision Record & C4

Capturing and storing architectural decisions

Raphaël Tahar
Decathlon Digital
11 min readJul 3, 2024

--

Documenting and storing architectural decisions

We’ve previously detailed the retro-action between solutions and problems and how to apply the most relevant discovery methodology depending on change archetypes.

Let’s now examine how to capture architectural decisions thanks to Architecture Decision Records and C4 diagram-as-code solutions.

📖 Series table of content

Through 4 posts, this series dissects the complex machinery behind architectural decision-making.

  1. Making Decisions
  2. Recognizing Scopes and Boundaries
  3. 👉 Architecture Decision Record & C4
  4. Social and Organizational Dynamics

Why Does Capturing Architectural Decisions Matter❓

Have you already felt this unique combination of sadness and anger when discovering a new codebase including a wide range of eccentricities? Until one of your teammates reminds you that past maintainers surely had their reasons, which is, by the way, most of the time true.

Let’s say that Architecture Decision Records are precisely here for this never to happen again. They bring traceability and ensure proper handover after staffing turnover.

Besides, Architecture Decision Records also serve as a means to mitigate duplicated efforts and break down silos by leveraging the work of other teams. Sometimes, a solution may only be pertinent to a specific problem within a particular context, and Architectural Decision Records provide a mechanism for capturing the contextual details of a decision. Having a document that encapsulates the context enables teams to verify that their specific problem aligns with the context of the team that originally made the decision.

Finally, ADRs play a crucial role in validating or invalidating previous decisions by capturing essential contextual elements such as the considered options, their respective advantages and disadvantages, the resulting consequences, and pertinent references to documentation that aid in comprehending the problem-solving scenario.

Besides, short-term solutions are less likely to transition into long-term strategies due to the discontinuity in remembrance.

Note: As you‘ve surely noticed, ADRs come at the end of the discovery process to capture research outputs. If you start your technical investigations with an ADR either you completely master your subject, or you’re probably starting on the wrong foot.

Tooling & Documentation as Code 🛠️

To store their Architecture Decision Records and C4 Systems modelizations, several Decathlon Domains opted for centralized repositories using Structurizr.

This open-source tool builds upon “Diagrams as Code” and provides a DSL (Domain Specific Language) to describe diagrams in a written form. Several visualizations are available: Structurizr diagrams & graphs, PlantUML, C4-PlantUML, Mermaid, and Ilograph.

To illustrate this, the following model:

workspace {

model {
user = person "User"

softwareSystem = softwareSystem "Software System" {
webapp = container "Web Application"
db = container "Database Schema"
}

user -> webapp "Uses"
webapp -> db "Reads from and writes to"
}

views {
systemContext softwareSystem "SystemContext" {
include *
autolayout lr
}

container softwareSystem "Containers" {
include *
autolayout lr
}

styles {
element "Person" {
shape person
}
}
}

}

… generates the following “Structurizr diagram” view:

Structurizr diagrams example

For more information on the DSL please consult the official documentation here.

To enhance the overall Developer eXperience many Domains also use structurizr-site-generatr to statically generate a website rendering the diagrams’ visual representations (courtesy of Damien Raude-Morvan).

Example: Structurizr-site-generatr auto-generated website

It also handles Markdown or AsciiDoc documentation and embeds Decisions sections to display Architecture Decision Records under different granularities (at the Workspace aka the whole repository or System levels).

You might be wondering if centralizing ADRs and C4s is a good idea. Storing them in a common repository has several advantages:

  • teams are more exposed to the latest additions
  • documentation and best practices are shared cross-team
  • ADR can be promoted to higher scopes
    (from team to Sub-Domain or Domain levels)
  • referencing a System's external dependencies (C1 to C1 links)
  • central CI quality gate (checking DSL syntax and ADR compliance)

But of course, having governance and a good file system structure is mandatory when several teams collaborate on a single resource such as a common repository.

Here’s the one we ended up using 👇

domain-c4-architecture/
├─ decathlon/
│ ├─ domain/ // Domain
│ │ ├─ sub-domain-1/ // Sub-Domain
│ │ | ├─ team/ // Team
│ │ | | ├─ product/ // Product
│ │ | | | ├─ adrs/ // Product-level ADR
│ │ | | | ├─ docs/ // Product-level Documentation
│ │ | | | ├─ model.dsl // Product C1 & C2 (C3 & C4 are optional)
│ │ | | | ├─ views.dsl // Product C1 & C2 (C3 & C4 are optional)
│ │ | | ├─ adrs/ // Team-level ADR
│ │ | | ├─ docs/ // Team-level Documentation
│ │ │ ├─ adrs/ // Sub-Domain-level ADR
│ │ │ ├─ docs/ // Sub-Domain-level Documentation
│ │ ├─ sub-domain-2/
│ │ ├─ adrs/ // Domain-level ADR - Not yet handled in structurizr-site-generatr
│ │ ├─ docs/ // Domain-level Documentation - Not yet handled in structurizr-site-generatr
├─ assets/
│ ├─ templates/
│ │ ├─ MADR.md

Its structure is recursive, each layer is composed of two files: model.dsl and views.dsl, and two folders: adrs and docs. Splitting Model and Views files allows a better separation of concerns and easier export/import compositions (conceive them as Barrel files).

Layers are Decathlon’s structural organizational units: Domain, Sub-Domain, Team, and deployed Container. Adapt this taxonomy to your organization's specificities. Anchoring the structure of an organization in reality by mirroring it in its documentation is a powerful move that brings a lot of clarity and is self-sufficient (time-resistant and onboarding-friendly).

Now that we picture how to store documentation more clearly, let’s talk about the elephant in the room: the ADR content.

ADR Formats 📜

There are abundant formats and templates of ADR on the market, and they can still be split into two opposed approaches: some are very lightweight while others are more verbose.

On the one hand, one school of thought represents ADRs as pure output logs that should be browsed quickly and not drown its readers under a substantial flow of information, while another envisions them as documentation records of a whole thinking process.

It’s possible to have the best of both worlds by structuring ADRs to bubble up every key piece of information, including the conclusion, at the top of the document, leaving the thinking process details in the second half. This way, hurried readers will catch relevant information immediately, while readers searching for more details can still find them by continuing their read.

Among the long list of available formats, we decided to use the MADR one, as it embeds the appropriate level of detail required to frame a technical and functional discovery process unambiguously.

To loop back on the last posts Garbage Can model and the System Thinking paradigm, ADRs should be the final step of a chaotic discovery process, rearranging a non-linear systemic thinking flow into a linear one.

Here’s the template that my Domain is currently using:

# AD: {Architecture Design Record Topic}

<!--
to be interpreted by Structurizr, the date has to be on a line of its own, in the format
-Date: {YYYY-MM-DD}
-->

Date: YYYY-MM-DD

[TOC]

| Item | Value |
| ---------- | ----------------------------------------------- |
| Writer | {WriterName} |
| StaffEng | {Referent Staff Engineer} |
| Priority | [LOW, MEDIUM, HIGH] |
| Deciders | (!writer), {Stakeholder1}, {Stakeholder2} |

<!--
available status (by Structurizr)
- Draft
- Proposed
- Rejected
- Accepted
- Deprecated
- Superseded -> superseded is an automatic status when a new ADR replace an existing one

To be interpreted by Structurizr, the format is :
- ## Status
- Draft
-->

## Status

Draft

## Context and Problem Statement

{ Describe the context and problem statement, e.g., in free form using two to three sentences or in the form of an
illustrative story. You may want to articulate the problem in form of a question and add links to collaboration boards
or issue management systems. }

## Decision Drivers

1. {decision driver 1}
2. {decision driver 2}
3. {decision driver 3}
4. ...

## Considered Options

1. {title of option 1}
2. {title of option 2}
3. {title of option 3}
4. ...

## Decision Outcome

Chosen option: "{title of option 1}", because {justification. e.g., only option, which meets k.o. criterion decision
driver | which resolves force {force} | … | comes out best (see below)}.

## Architecture Committee Recommendations

{ Space for the Architecture Committee to insert its recommendations }

## Consequences

- Good,
- Good,
- Bad,
- Bad,
- ...

## Pros and Cons of the Options

### Option 1

Pros:

- {Pros #1}
- {Pros #2}
- ...

Cons:

- {Cons #1}
- ...

### Option 2

Pros:

- {Pros #1}
- {Pros #2}
- ...

Cons:

- {Cons #1}
- ...

## More Information

- [Link to additional documentation #1]()
- [Link to additional documentation #2]()
- ...

## Validation

{ Date in the future to validate that the decision was right or rightly implemented. A list of stakeholders. }

Each stage of the Garbage Can Dreamed flow is represented in this template (the last step being the decision which is the ADR itself):

  • Choice Opportunity -> Context and Problem Statement & Decision Drivers
  • Decision Alternatives -> Considered Options
  • Consequences -> Decision Outcomes & Consequences
  • Consequences vs Objectives -> Pros and Cons of the Options
Garbage Can: The dreamt flow

Note that we also took the liberty to enrich it with several new sections:

  • the “Architecture Committee Recommendations” for capturing any higher order recommendations like global guidelines impacting the decision or relevant cross-domain/team context
  • Validation”, to book a post-implementation timeslot to verify that theory and practice matched, or amend the ADR if not
  • and a few structurizr-site-generatr specific bits and pieces (like the Date and Status).

Let’s illustrate how we would have captured the previous post’s cross-systems C1 change example.

Example: Capturing The Decision

The decision opportunity was the following: Smooth the User Experience coherence of a user journey involving multiple Systems maintained by several teams while preserving high team autonomy.

Applying the System Thinking discovery process to that problem led to the following conclusion:

System Thinking discovery output

Let’s pick up where we left off, and transform this output into an Architecture Decision Record. Here’s what it’d look like 👇

# AD: Smoothing the coherence of cross-systems user experiences

Date: 2024-05-14

[TOC]

| Item | Value |
| ---------- | ----------------------------------------------- |
| Writer | XXX |
| StaffEng | XXX |
| Priority | HIGH |
| Deciders | XXX |

## Status

Proposed

## Context and Problem Statement

Product teams noticed that the conversion rate dropped by X% on user journeys A, B and C.
These journeys are implemented across:
- two Systems: E-commerce website & Membership platform
- and maintained by two teams: team 1 & 2
The root cause of the conversion rate drop comes from the lack of coherence of user experiences.

This decision opportunity leads to searching for ways to enforce the coherence of UI components running in different Systems maintained by different teams.
This ADR aims at capturing the most optimal technical solution for that problem.

### Additional context

Systems tech particularities:
- E-commerce website -> Svelte, SSR, Vite
- Membership -> React, CSR, Webpack
- The Systems' traffic is considered high with important daily and yearly spikes {numbers xxx}

Teams' compositions:
- team 1 -> 4 backend, 3 frontend, and 1 fullstack
- team 2 -> 3 backend, and 4 frontend

The product vision for these Systems gathered from PMs is the following:
- Pages will be autonomous and served in isolation
- At some point, components may interact in a cross-application fashion

Considering the above points, we'll be narrowing down the choice opportunity to:
- Vertical Micro Frontends techniques
- Compatible with SSR and CSR capabilities
- Supporting artifacts built with Vite and Webpack

## Decision Drivers

1. Increase components' visual and functional coherence
2. Limit duplication costs
3. Preserve team autonomy (separate release life cycles)
4. Compatible with SSR and CSR

## Considered Options

1. Edge Side Includes
2. Client Side Includes
3. Server Side Includes
4. Web Component
5. Open Component
6. Native Federation
7. Governance & Duplication
8. SingleSPA
9. Iframe + Bus

## Decision Outcome

Chosen options: Design System - Web Component - SSI - Native Federation

Implementing a Design System in Web Components inherently increases coherence (single centralized source of truth).
Mutualized development efforts will be required but this will ensure a compatibility between the two Systems' technologies (Svelte and React).
Last but not least, SSI and Native Federation allow SSR and CSR compatibility at both build and run time while preserving team autonomy.

## Architecture Committee Recommendations

The architecture committee is aligned with the decision-making process and the conclusions.
With a minor warning on the usage of Web Component that might be challenging:
- every browsers do not support Declarative Shadow DOM, a polyfill policy should be created
- and components' browser post-rendering hydration is challenging for SSR Systems (the Design System must include this behavior by design)
Besides, SSI will require the caching strategy to be optimized and well tested (CDN), the teams' compositions include enough backend engineers to opt for this solution (will require fullstack knowledge).

## Consequences

- Good, duplication costs drastically reduced by mutualizing components' implementation within a Design System
- Bad, team autonomy is slightly impacted (synchronization required to implement and/or update the Design System)
- Good, Web Component allow CSR and SSR renderings
- Good, SSI & Native Federation are compatible with SSR and CSR
- Good, Native Federation doesn't block the product vision, allowing a smooth transition from vertical to horizontal MicroFrontend

## Pros and Cons of the Options

### Edge Side Includes

{ Obfuscated, pretty straight forward }

### Client Side Includes

{ Obfuscated, pretty straight forward }

### Server Side Includes

{ Obfuscated, pretty straight forward }

### Web Component

{ Obfuscated, pretty straight forward }

### Open Component

{ Obfuscated, pretty straight forward }

### Native Federation

{ Obfuscated, pretty straight forward }

### Governance & Duplication

{ Obfuscated, pretty straight forward }

### SingleSPA

{ Obfuscated, pretty straight forward }

### Iframe + Bus

{ Obfuscated, pretty straight forward }

## More Information

- [Edge Side Includes documentation link](https://blog.cloudflare.com/using-edge-side-includes-with-workers-for-high-availability)
- [Server Side Includes documentation link](https://httpd.apache.org/docs/2.4/en/howto/ssi.html)
- { Any other links pointing to relevant documentation for understanding the decision }

## Validation

The 2 teams inlvolved are invited to present a post implementation feedback in a dedicated meeting.
It has been agreed to meet again 2 weeks after the release.
Considering the current projections, this leads to the {Day Month Year}.

Takeaways 🌯

Decathlon uses ADRs and C4 to capture architectural decision documentation through a “Diagram and Documentation as Code” approach. Centralization in a single repository enhances collaboration, breaks silos, and smoothes documentation quality.

ADRs should capture every factor influencing a decision. They can be technical, functional, organizational, or social contexts.

Start writing an ADR only after searching for an exhaustive list of alternatives. If you begin a technical discovery with an ADR you’re either an expert or starting on the wrong foot. You’ll most likely fall into one of the social or organizational shortcomings described in the last post of this series (the last dimension of the Garbage Can Model: the decision-makers).

Thanks for reading! 🙏🏼
👏🏻👏🏻👏🏻 Give a few claps and “
follow” if you enjoyed this series.

💌 Follow Decathlon’s latest posts on Twitter and LinkedIn and discover our latest stories on Medium 🚀

--

--

Raphaël Tahar
Decathlon Digital

Staff Engineer, Sociotechnical Architect, author and philosophy enthusiast. Proud dog father 🐶. Opinions are my own.