Le problème
Une recommandation d'architecture se termine souvent par une liste de bénéfices. Elle explique pourquoi l'option retenue est la bonne, sans dire ce qu'elle coûte. Elle paraît alors partiale, même quand la comparaison a été faite, et le lecteur part chercher lui-même les coûts qui manquent.
Prenons une boutique en ligne découpée en services. La recommandation : publier les événements de commande par une table outbox, écrite dans la même transaction que la commande. Elle règle la perte d'événements, mais elle a un prix que le texte ne mentionne pas.
Ce prix se découvre plus tard, de l'une de ces trois façons.
Le coût arrive comme une surprise. Le
relais de l'outbox republie un événement après un arrêt, et
le service stock réserve deux fois la
marchandise d'une même commande. Le doublon était une
propriété connue du choix, et il apparaît comme un incident.
On ne distingue plus un coût accepté d'un oubli.
Le service shipping reçoit les commandes avec
un léger retard, le temps que le relais passe. Rien ne dit
si ce délai a été pesé lors du choix : chaque retard remet
alors tout le choix en question.
Rien ne dit quand revenir sur le choix. Aucun seuil n'indique à partir de quel retard l'outbox ne convient plus. Le choix est alors réexaminé trop tôt, sur une impression, ou trop tard, quand le retard gêne déjà les clients de la boutique.
Les options
Pas de section de compromis
- Ce qu'elle règle : la recommandation reste courte et se lit vite.
- Ce qu'elle coûte : les coûts se découvrent en production. Le lecteur doit les reconstituer seul, et la recommandation perd son crédit au premier coût découvert.
Une liste générique de risques
La recommandation se termine par une section « Risques » : « complexité accrue », « courbe d'apprentissage », « impact sur les performances ».
- Ce qu'elle règle : elle montre que des risques ont été envisagés.
- Ce qu'elle coûte : ces lignes conviennent à n'importe quel choix. Aucune ne se vérifie dans le système, et aucune ne dit quand revenir sur la décision.
Une liste de risques a sa place à l'échelle d'un système entier : arc42 lui consacre une section, où les risques sont classés par priorité. Elle complète les compromis d'une décision, elle ne les remplace pas.
Des compromis écrits, chacun avec son signal de réexamen
- Ce qu'elle règle : chaque coût est nommé, attribué et borné dans le temps. Un signal dit à quel moment le choix doit être réexaminé.
- Ce qu'elle coûte : du temps d'analyse et d'écriture. Les signaux mesurables demandent une requête, un tableau de bord ou une alerte.
Notre recommandation
Chaque recommandation écrit ses compromis : ce que l'on perd, qui le porte, jusqu'à quand, ce qui le limite, et le signal de réexamen.
Dans notre méthode, la section «
Les compromis assumés » suit la recommandation en une phrase
et précède le plan de mise en œuvre. Cette section change la
nature du coût. Le doublon reçu par stock n'est
plus un incident : c'est un comportement prévu, contenu par
un
consommateur idempotent.
La section rend aussi la recommandation crédible. Une option sans inconvénient n'existe pas : un texte qui n'en montre aucun laisse penser que la comparaison n'a pas été faite. Les formats reconnus de décision d'architecture le prévoient, sous des noms différents :
- le format de Michael Nygard termine chaque décision par ses conséquences, positives, négatives et neutres ;
- le gabarit MADR liste les conséquences en « Good, because » et « Bad, because », et compare les options avec leurs avantages et leurs inconvénients ;
- le Y-statement d'Olaf Zimmermann tient une décision en une phrase, qui se termine par « accepting that » : le prix accepté ;
- la méthode ATAM du SEI recherche les points de compromis : là où une décision améliore une qualité du système au détriment d'une autre.
Le signal, enfin, rend la décision révisable. Martin Fowler conseille de noter dans la décision les changements de contexte qui doivent la faire réévaluer. Sans signal, un compromis n'a pas de date de fin.
Les articles de cette série appliquent la règle. Notre article sur la topologie RabbitMQ assume une queue qui mélange les événements d'un service. Il nomme aussi le signal qui doit faire découper cette queue : un retard mesuré sur des messages critiques.
Les compromis assumés
Cette pratique a aussi son prix.
Une section de plus à écrire et à lire. La recommandation s'allonge. Nous la limitons aux compromis qui changent le comportement du système ou son coût d'exploitation, pas à tout ce qui pourrait arriver.
La recommandation montre ses faiblesses. Les coûts apparaissent dès la première lecture, bien avant les bénéfices, qui ne se voient qu'en production. Un coût écrit peut faire préférer une autre option : mieux vaut le savoir avant la mise en œuvre qu'après.
Des signaux à outiller. Un signal mesurable demande une requête, un tableau de bord ou une alerte. D'autres se constatent, comme un consommateur incapable de dédupliquer : ils ne servent que si les compromis sont relus à chaque nouveau besoin.
Le signal qui doit faire réexaminer cette pratique : des compromis recopiés d'une recommandation à l'autre, sans lien avec le choix. Ou des signaux que rien ne mesure jamais. La section est alors devenue un rituel : il faut la raccourcir, ou outiller ses signaux.
Mise en œuvre
1. Partir des options écartées
Les coûts de l'option retenue se lisent dans la comparaison avec les autres. Ce qu'une option écartée faisait mieux est souvent ce que l'on perd. Publier juste après le commit envoie l'événement tout de suite : l'outbox perd cette immédiateté.
Pour chaque option écartée, posez une question : qu'apportait-elle que la recommandation n'apporte pas ? Chaque réponse est un compromis candidat. Ne gardez que ceux qui changent le comportement du système ou son exploitation.
2. Nommer ce que l'on perd
Ce que l'on perd est une propriété observable du système : une garantie, un délai, une capacité, une simplicité d'exploitation. « De la complexité » n'en est pas une. « Une table et un processus de plus à surveiller » en est une.
Le test : peut-on constater la perte dans le système ou dans le code ? Si ce n'est pas le cas, la formulation reste trop vague.
3. Dire qui le porte, et jusqu'à quand
Un coût est toujours porté quelque part : un service, une activité (développement, exploitation, support) ou les utilisateurs de la boutique. Nommez ce porteur. Un coût sans porteur désigné n'est traité qu'une fois découvert en production.
« Jusqu'à quand » s'écrit avec une condition plutôt qu'une date : « tant que le relais lit la table par intervalles », ou « jusqu'à la v2 du contrat ». Un coût permanent se déclare comme tel : il ne disparaîtra pas avec le temps.
4. Écrire ce qui limite le coût
Un compromis assumé n'est pas un coût subi : écrivez ce qui le contient. Pour les doublons, l'idempotence des consommateurs ; pour la latence, une alerte sur l'âge de la plus ancienne ligne non publiée. Si rien ne le limite, écrivez-le aussi.
5. Fixer le signal de réexamen
Le signal dit à quel moment le choix doit être réexaminé. Quand c'est possible, il est mesurable : une mesure, sa source, et un seuil écrit dans la recommandation. Le seuil vient du besoin métier, pas d'une valeur par défaut.
Pour la latence de l'outbox, la mesure se lit dans la table elle-même :
-- Délai de publication sur la dernière heure (table outbox du service order)
SELECT
max(published_at - occurred_at) AS max_delay,
percentile_cont(0.95) WITHIN GROUP (ORDER BY published_at - occurred_at) AS p95_delay
FROM outbox
WHERE published_at IS NOT NULL
AND occurred_at > now() - interval '1 hour';
Les lignes non publiées n'y figurent pas : un relais arrêté relève de l'alerte sur la plus ancienne d'entre elles.
Sinon, le signal décrit un fait : un consommateur dont l'effet sort de sa base (e-mail, appel HTTP), ou un besoin régulier de rejeu. Ce type de signal se vérifie à chaque nouveau besoin, en relisant les compromis.
Un signal déclenche un réexamen, pas un changement automatique. Le réexamen se termine par une décision attendue : confirmer le choix, l'ajuster ou le remplacer.
Le gabarit MADR prévoit une section « Confirmation » : comment vérifier que la décision est bien appliquée. Le signal de réexamen pose la question suivante : la décision convient-elle encore ?
6. Un modèle à remplir
Compromis : <titre court>
Ce que l'on perd : <une propriété observable du système>
Qui le porte : <un service, une activité ou les utilisateurs>
Jusqu'à quand : <une condition, ou « permanent »>
Ce qui le limite : <la parade en place, ou « rien »>
Signal de réexamen : <une mesure et son seuil, ou un fait observable>
Où le lire : <la requête, le tableau de bord ou l'alerte>
7. Trois exemples
Les deux premiers viennent d'une recommandation d'outbox
pour publier order.order.placed.v1. Le
troisième vient d'une API construite avec API Platform, où
les ressources sont des DTO séparés des entités Doctrine.
Compromis : doublons possibles
Ce que l'on perd : la livraison unique de chaque événement
Qui le porte : les services consommateurs, stock et shipping
Jusqu'à quand : permanent, base et broker sans transaction commune
Ce qui le limite : une table des événements traités par consommateur
Signal de réexamen : un effet appliqué deux fois, ou un consommateur
dont l'effet sort de sa base sans clé d'idempotence
Où le lire : une requête qui cherche deux réservations par ligne de commande
Compromis : latence de publication
Ce que l'on perd : la publication immédiate de l'événement
Qui le porte : shipping et l'écran de suivi de commande
Jusqu'à quand : tant que le relais lit la table par intervalles
Ce qui le limite : une alerte sur la plus ancienne ligne non publiée
Signal de réexamen : le délai entre occurred_at et published_at
dépasse le seuil écrit dans la recommandation
Où le lire : la requête de délai sur la table outbox
Compromis : plus de classes par ressource
Ce que l'on perd : la concision d'une entité exposée directement
Qui le porte : le développement de chaque nouvelle ressource de l'API
Jusqu'à quand : tant que les mappers sont écrits à la main
Ce qui le limite : une structure identique d'une ressource à l'autre
Signal de réexamen : des mappers qui recopient champ à champ des
ressources presque identiques à leurs entités
Où le lire : le code des mappers, à chaque nouvelle ressource
Le troisième signal ne se mesure pas : il se constate à la lecture du code. Il suffit pourtant à dire quand un mapping automatique redevient une option.
8. Réexaminer sans réécrire
Quand un signal se déclenche, nous écrivons une nouvelle recommandation qui renvoie à l'ancienne. L'ancienne reste lisible, avec le statut « remplacée ». Nygard et Fowler décrivent ce statut : on sait quelle décision a valu, et pendant combien de temps.
Un index des recommandations, avec leur statut, montre celles qui sont en vigueur. Les compromis de chacune y restent consultables, avec leurs signaux.
Checklist
- Une section « Les compromis assumés » dans chaque recommandation.
- Chaque option écartée relue : ce qu'elle faisait mieux figure parmi les compromis.
- Chaque compromis nomme une propriété observable, pas « de la complexité ».
- Chaque compromis dit qui le porte : un service, une activité ou les utilisateurs.
- Chaque compromis dit jusqu'à quand, ou se déclare permanent.
- Ce qui limite chaque coût est écrit, ou son absence est dite.
- Un signal de réexamen par compromis, avec un seuil écrit quand il est mesurable.
- Chaque signal mesurable a sa requête, son tableau de bord ou son alerte.
- Un réexamen produit une nouvelle recommandation, qui remplace l'ancienne sans la réécrire.
Sources
- Michael Nygard, Documenting Architecture Decisions (Cognitect, 2011) : le format contexte, décision, statut, conséquences, et le statut « superseded ».
- Architectural Decision Records : définitions et formats d'enregistrement des décisions d'architecture.
- MADR, version 4.0.0 : sections Consequences, Confirmation et Pros and Cons of the Options.
- arc42, section 9, Architecture Decisions : lister toutes les conséquences, documenter les options écartées.
- arc42, section 11, Risks and Technical Debt : une liste de risques classée par priorité, avec les mesures qui les limitent.
- Olaf Zimmermann, Design Practice Repository, Y-Statement : une décision en une phrase, terminée par le prix accepté.
- Martin Fowler, Architecture Decision Record (2026) : remplacer une décision plutôt que la modifier, et noter ce qui doit la faire réévaluer.
- SEI, Architecture Tradeoff Analysis Method : risques, points de sensibilité et points de compromis.
-
PostgreSQL,
fonctions d'agrégat
:
percentile_contsur un intervalle.