← Tous les articles

🧭 ADR – Documente enfin le « pourquoi » de tes choix techniques

🪧 Introduction

Tu viens d’arriver sur un projet. Tu ouvres le code et tu tombes sur un choix qui te paraît étrange : pourquoi PostgreSQL, alors que toute l’équipe connaît MySQL ? Pourquoi ce module n’a-t-il pas le droit d’utiliser Spring ?

Tu fais un git blame. Tu trouves un commit de 2022 : chore: switch datasource to postgresql. L’auteur a quitté l’entreprise. Tu sais ce qui a été fait, mais personne ne peut te dire pourquoi.

C’est exactement le problème que résolvent les ADR, les Architecture Decision Records.

Dans cet article, on va voir :

  • ce qu’est un ADR et à quoi il ressemble ;
  • son cycle de vie et quand en écrire un ;
  • où les ranger et comment les outiller ;
  • comment faire respecter une décision avec un test ArchUnit ;
  • les pièges qui rendent les ADR inutiles.

1. 🧩 Git sait le quoi, pas le pourquoi

Git sait qui a modifié quelle ligne, quand, et dans quel commit. Mais un message de commit tient en une ligne, et une pull request se referme puis s’oublie.

👉 Ce qui disparaît, c’est le raisonnement : les contraintes du moment, les options comparées, les compromis acceptés. Il vit dans la tête des personnes qui ont décidé. Quand elles partent, il part avec elles.

Imagine la suite de notre exemple : un nouvel arrivant propose de « simplifier » en revenant à MySQL, que tout le monde maîtrise. Personne ne se souvient que la recherche de magasins à proximité a été la raison du choix. La migration est lancée, et c’est en production que la recherche se met à lire toute la table. Un document de deux pages aurait évité ce coût.

2. 📄 C’est quoi, un ADR ?

Un ADR est un document court, d’une à deux pages, qui décrit une seule décision technique : son contexte, la décision elle-même et ses conséquences. Le concept a été formalisé par Michael Nygard en 2011. Son constat : personne ne lit les gros documents d’architecture, mais tout le monde souffre quand les raisons d’un choix sont perdues.

Trois règles de base :

  • une décision par fichier ;
  • un fichier figé une fois la décision acceptée ;
  • un seul endroit pour tous les ADR, connu de toute l’équipe.

👉 La documentation classique répond à « comment ça marche ? ». L’ADR répond à « pourquoi c’est comme ça ? ».

3. 🏗️ Anatomie d’un ADR

Il existe plusieurs formats d’ADR. Les deux plus répandus sont celui de Nygard et MADR.

Le format Nygard, le format d’origine, tient en cinq parties :

  • Titre : numéroté, court, qui nomme la décision ;
  • Statut : proposé, accepté, remplacé… ;
  • Contexte : les forces en jeu, décrites de façon neutre ;
  • Décision : la réponse, à la voix active (« Nous utiliserons… ») ;
  • Conséquences : tout ce qui en découle, le positif comme le négatif.

Voici, au format Nygard, l’ADR qui aurait répondu à la question de l’introduction :

# 2. Utiliser PostgreSQL avec PostGIS plutôt que MySQL

Date : 2026-10-12

## Statut

Accepté

## Contexte

Nous démarrons une application de retrait en magasin. Sa fonctionnalité
principale est « trouver les magasins à moins de X km de moi ».

L'équipe connaît MySQL et PostgreSQL. Nous avons testé la recherche par
rayon sur 50 000 magasins avec MySQL 8.4 et PostgreSQL 17 + PostGIS 3.5 :

- avec PostGIS, ST_DWithin prend un rayon en mètres et utilise l'index
  spatial ;
- avec MySQL, ST_Distance_Sphere n'utilise pas l'index spatial : la
  requête lit toute la table, sauf à écrire soi-même un pré-filtre
  géométrique.

## Décision

Nous utiliserons PostgreSQL avec l'extension PostGIS. Les positions sont
stockées en geography(Point, 4326), avec un index GiST.

## Conséquences

- La recherche par rayon tient en une requête, lisible et indexée.
- Une partie de l'équipe devra se former à PostgreSQL et à PostGIS.
- L'hébergeur doit proposer PostGIS, ce que toutes les offres
  PostgreSQL managées ne font pas.

Côté code, la recherche ressemble à ceci :

-- Magasins à moins de 5 km du point (longitude 2.3470, latitude 48.8590)
SELECT nom,
       ST_Distance(position, ST_MakePoint(2.3470, 48.8590)::geography) AS distance_m
FROM magasin
WHERE ST_DWithin(position, ST_MakePoint(2.3470, 48.8590)::geography, 5000)
ORDER BY distance_m;

👉 Le futur développeur qui se demande « pourquoi pas MySQL ? » a sa réponse, avec la mesure qui l’appuie.

Le format MADR (Markdown Any Decision Records) reprend celui de Nygard et ajoute quelques sections utiles : les critères de choix, écrits avant de comparer, les options considérées avec leurs avantages et inconvénients, et la confirmation (comment on vérifie que la décision est respectée).

👉 Nygard et MADR sont des conventions, pas des obligations. Ton équipe est libre d’adopter le format qui lui convient. Ce qui compte, c’est le contenu : le choix technique, les options écartées avec leurs pour et leurs contre, et les conséquences de la décision.

💡 Important

Une section « Conséquences » qui ne contient que des points positifs n’est pas un ADR, c’est un argumentaire commercial. Toute décision a un coût.

4. 🔄 Statuts et cycle de vie : on n’efface jamais

Un ADR est proposé, puis accepté ou rejeté. Plus tard, il peut être déprécié (le sujet n’existe plus) ou remplacé par une nouvelle décision.

Et voici la règle d’or : un ADR accepté n’est jamais modifié. Si le contexte change, tu écris un nouvel ADR qui remplace l’ancien. L’ancien passe en « Remplacé par ADR-0012 » et reste lisible.

👉 Dans deux ans, tu ne verras pas seulement la décision actuelle : tu verras l’histoire des décisions, et pourquoi chacune a été remise en cause.

5. 🎯 Quand écrire un ADR ?

Pas pour tout. Un nom de variable ne mérite pas un ADR. Le choix d’un framework, d’une base de données ou d’une stratégie de branches Git, si.

Stéphane Robert propose un petit test. Pose-toi ces cinq questions :

  1. Changer d’avis plus tard coûtera-t-il cher ?
  2. Plusieurs personnes ou équipes sont-elles concernées ?
  3. La décision sera-t-elle encore pertinente dans deux ans ?
  4. Plusieurs options ont-elles été évaluées ?
  5. Quelqu’un pourrait-il mal comprendre ce choix ?

👉 Trois « oui » ou plus : écris un ADR. Et un repère encore plus simple : une discussion technique de plus de trente minutes mérite un ADR.

6. 🛠️ Mettre en place un ADR

Étape 1 – Choisir l’emplacement

Il n’y a pas d’emplacement imposé : le dépôt de code, une page Notion, un espace Confluence ou un dossier partagé.

  • dans le dépôt : l’ADR est versionné avec le code et relu en pull request ;
  • dans un outil partagé : il est accessible aux personnes qui n’ouvrent jamais le dépôt (produit, direction, support).

👉 Ce qui compte, c’est que tous les ADR soient au même endroit, que toute l’équipe sache où les trouver, et que le README du projet y mène.

Dans le dépôt, la convention est un dossier dédié, avec un numéro sur quatre chiffres :

docs/adr/
├── 0001-record-architecture-decisions.md
├── 0002-utiliser-postgresql-avec-postgis.md
└── 0003-domaine-independant-du-framework.md

Étape 2 – Outiller avec adr-tools

adr-tools, de Nat Pryce, gère la numérotation et les liens à ta place :

# Initialise le registre (crée aussi l'ADR 0001 : « on utilise des ADR »)
adr init docs/adr

# Crée un nouvel ADR numéroté et l'ouvre dans ton éditeur
adr new Utiliser Flyway pour les migrations SQL

# Crée un nouvel ADR qui remplace l'ADR 4, et met à jour le statut de ce dernier
adr new -s 4 Passer a Liquibase

💡 Important

adr-tools n’évolue plus depuis 2020, et génère un template en anglais. Tu peux fournir le tien dans docs/adr/templates/template.md, mais garde le titre ## Status tel quel : c’est lui que l’outil cherche pour mettre à jour les liens de remplacement.

7. ✅ Faire respecter une décision avec ArchUnit

Un ADR décrit une décision. Mais qui vérifie que le code la respecte, six mois plus tard ? En Java, la meilleure confirmation, c’est un test.

Prenons l’ADR-0003 : « le domaine métier ne dépend ni de Spring ni de JPA ». Avec ArchUnit (com.tngtech.archunit:archunit-junit5:1.4.1), cette décision devient un test :

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

@AnalyzeClasses(packages = "com.example.shop")
class ArchitectureDecisionsTest {

    // ADR-0003 : le domaine métier ne dépend ni de Spring ni de JPA
    @ArchTest
    static final ArchRule domaine_independant_du_framework =
            noClasses().that().resideInAPackage("..domain..")
                    .should().dependOnClassesThat()
                    .resideInAnyPackage("org.springframework..", "jakarta.persistence..")
                    .because("voir docs/adr/0003-domaine-independant-du-framework.md");
}

Si quelqu’un transforme une classe du domaine en entité JPA (@Entity, @Id), le build échoue avec un message qui pointe vers l’ADR :

Architecture Violation [Priority: MEDIUM] - Rule 'no classes that reside in a package
'..domain..' should depend on classes that reside in any package
['org.springframework..', 'jakarta.persistence..'], because voir
docs/adr/0003-domaine-independant-du-framework.md' was violated (2 times):
Class <com.example.shop.domain.Commande> is annotated with <jakarta.persistence.Entity> in (Commande.java:0)
Field <com.example.shop.domain.Commande.id> is annotated with <jakarta.persistence.Id> in (Commande.java:0)

🎯 Résultat : le développeur qui casse la règle ne reçoit pas juste un « non ». Il reçoit le pourquoi.

8. 💥 Les pièges à éviter

  • L’ADR roman : plus de deux pages, c’est probablement plusieurs décisions. Découpe-le.
  • L’ADR sans alternatives : documente au moins deux options, y compris « ne rien faire ».
  • L’ADR post-mortem : écrit trois mois après, il a perdu le contexte. Écris-le au moment où tu décides.
  • L’ADR orphelin : personne ne l’ouvre. Cite son numéro dans les pull requests, le README et le code.
  • L’ADR réservé aux experts : un nouvel arrivant doit pouvoir le comprendre seul. C’est pour lui que tu écris.

🏁 Conclusion

Les ADR ne demandent presque rien : un endroit partagé, une page par décision, une demi-heure d’écriture. En échange, ils donnent à ton projet ce que Git ne sait pas conserver : la mémoire des décisions.

Le meilleur moment pour commencer, c’est ta prochaine discussion technique. Et le premier ADR à écrire est tout trouvé : celui qui décide… d’utiliser des ADR.

📚 Sources & lectures recommandées