Vol. 0 · № 04 · Un atelier d'architectureAn architecture workshop

Le bistouri et la tronçonneuseThe scalpel and the chainsaw

La règle « sois paresseux » coupe la plomberie — et l'organe avec, parce qu'elle ne compte que les lignes. Avant de tailler, classe : accessoire ou essentiel ? L'un se taille au bistouri, l'autre se juge par ce qu'il protège.The 'be lazy' rule cuts the plumbing — and the organ with it, because it only counts lines. Before cutting, classify: incidental or essential? One is trimmed with the scalpel, the other is judged by what it protects.

AudienceAudience
Dev à l'aise en code, qui veut raisonner architectureDev fluent in code, ready to reason about architecture
Format
Self-paced
ChapitresChapters
5
Date
Juin 2026June 2026
≈ 18 min●○○○MéthodeYAGNIComplexitéTradeoff
SommaireContents ·
№ 01CadrageFraming3 min

« Sois paresseux » est une tronçonneuse. Elle coupe la plomberie — et l'organe avec.'Be lazy' is a chainsaw. It cuts the plumbing — and the organ with it.

Ton agent sur-construit : tu demandes un sélecteur de date, il installe une librairie, écrit un wrapper et ouvre un débat sur les fuseaux horaires. Le remède à la mode est une règle « sois paresseux / YAGNI » qui supprime tout ce qu'elle peut. Elle marche sur la plomberie — et mutile le domaine, parce qu'elle ne sait pas distinguer un objet-valeur Money d'une classe EmailValidator de 27 lignes : elle compte les lignes, alors elle coupe les deux. Il manque une chose à la règle paresseuse : le discernement. Classe le code avant de le couper.Your agent over-builds: ask for a date picker and it installs a library, writes a wrapper, and opens a debate about timezones. The fashionable cure is a 'be lazy / YAGNI' rule that deletes whatever it can. It works on plumbing — and maims the domain, because it can't tell a Money value object from a 27-line EmailValidator class: it counts lines, so it cuts both. The lazy rule is missing one thing: discernment. Classify the code before you cut it.

Nomme la matière avant de taillerName the material before you cut
Accessoire · la plomberieIncidental · the plumbing
  • Cast DTO → modèleDTO → model cast
  • Retry, logging, configRetry, logging, config
  • Wrapper de librairieLibrary wrapper
→ le bistouri taille fort, c'est ici que l'agent gonfle→ cut hard, this is where the agent bloats
Essentiel · le domaineEssential · the domain
  • Objet-valeur Money (pas de mélange de devises)Money value object (no mixed-currency math)
  • Port PaymentGateway (frontière + couture de test)PaymentGateway port (boundary + test seam)
  • Validation au passage du réseauValidation at the network boundary
→ jugé par ce qu'il protège, jamais par sa taille→ judged by what it protects, never by its size
Le réflexe du numéroThe issue's reflex

« Ce code est-il accessoire ou essentiel ? » L'accessoire — la glue, le transport, le formatage — se taille au bistouri sans regret. L'essentiel — un invariant, une frontière, une couture de test — ne se juge pas au nombre de lignes : une abstraction à une seule implémentation peut être exactement à sa place. Coupe la plomberie. Défends le domaine.'Is this code incidental or essential?' The incidental — glue, transport, formatting — is cut with the scalpel, no regret. The essential — an invariant, a boundary, a test seam — isn't judged by line count: a single-implementation abstraction can be doing exactly its job. Cut the plumbing. Defend the domain.

Pourquoi ce numéro prolonge la méthode.Why this issue extends the method.

Vol 0 #1 dit où placer la couture, #2 ce qu'une couche coûte, #3 quand trancher. Les trois supposent qu'on sait déjà reconnaître ce qui mérite une couture. C'est la question de ce numéro : avant de couper au nom de YAGNI, distinguer la plomberie qu'on gonfle de l'organe qu'on protège. Sans ce tri, les trois précédents se retournent contre toi.Vol 0 #1 says where to put the seam, #2 what a layer costs, #3 when to decide. All three assume you can already recognize what deserves a seam. That's this issue's question: before cutting in the name of YAGNI, tell the plumbing you bloat from the organ you protect. Without that sorting, the first three turn against you.

№ 02La douleurThe pain4 min

Deux erreurs symétriques : gonfler la plomberie, éventrer le domaine.Two symmetric errors: bloating the plumbing, gutting the domain.

L'outil unique se trompe dans les deux sens. La tronçonneuse à laquelle on a dit « construis » gonfle l'accessoire : une factory, une interface et un fichier de config pour cinq lignes de comportement. La même tronçonneuse à laquelle on a dit « sois paresseux » éventre l'essentiel : elle supprime l'objet-valeur Money parce qu'il n'a « qu'une seule devise aujourd'hui » — et le calcul de devises se disperse partout. Une seule lame ne peut pas faire les deux gestes. Il en faut deux.The single tool errs both ways. The chainsaw told to 'build' bloats the incidental: a factory, an interface, and a config file for five lines of behaviour. The same chainsaw told to 'be lazy' guts the essential: it deletes the Money value object because it has 'only one currency today' — and currency math scatters everywhere. One blade can't make both cuts. You need two.

Erreur A — le gonflementError A — the bloat

On traite de la plomberie comme du domaine. Un UserService qui ne fait que relayer vers userRepo.findById, une factory pour un type au constructeur public, une interface extraite « par symétrie ». De la plomberie déguisée en domaine : chaque couche ajoute un nom à apprendre et un fichier à ouvrir, et ne décide rien.You treat plumbing as domain. A UserService that only forwards to userRepo.findById, a factory for a type with a public constructor, an interface extracted 'for symmetry'. Plumbing in a domain costume: each layer adds a name to learn and a file to open, and decides nothing.

Erreur B — l'éventrationError B — the gutting

On traite du domaine comme de la plomberie. On inline l'objet-valeur Money « parce qu'une seule implémentation = YAGNI », et l'invariant « pas d'arithmétique entre devises » n'est plus appliqué nulle part. La complexité n'a pas disparu : elle s'est relocalisée sur chaque site d'appel, sans garde-fou.You treat domain as plumbing. You inline the Money value object 'because one implementation = YAGNI', and the invariant 'no cross-currency arithmetic' is no longer enforced anywhere. The complexity didn't vanish: it relocated to every call site, with no guardrail.

Le diagnostic.The diagnosis.

L'erreur n'est jamais « trop » ou « pas assez » d'abstraction dans l'absolu — c'est la lame appliquée à la mauvaise matière. Le gonflement et l'éventration sont la même faute : ne pas avoir classé le code avant de le couper. « Une seule implémentation » n'est pas le test. Le test, c'est : qu'est-ce que ça protège ?The error is never 'too much' or 'too little' abstraction in the absolute — it's the blade applied to the wrong material. Bloat and gutting are the same mistake: failing to classify the code before cutting. 'One implementation' isn't the test. The test is: what does it protect?

№ 03Le piège de la relocalisationThe relocation trap5 min

Supprimer une abstraction essentielle ne retire pas la complexité — elle la déplace.Deleting an essential abstraction doesn't remove complexity — it moves it.

Voilà le piège qui rend l'éventration si tentante : à l'instant de la coupe, le diff rétrécit. On a « simplifié ». Mais un objet-valeur ne portait pas de la complexité décorative : il appliquait un invariant à un seul endroit. L'inliner ne supprime pas l'invariant — il l'éparpille sur tous les sites d'appel, où plus rien ne le fait respecter. L'animation fait avancer le temps après la coupe.Here's the trap that makes gutting so tempting: at the moment of the cut, the diff shrinks. You 'simplified'. But a value object wasn't carrying decorative complexity: it enforced an invariant in a single place. Inlining it doesn't delete the invariant — it scatters it across every call site, where nothing enforces it anymore. The animation advances time after the cut.

Animation — l'invariant après la coupe, dans le tempsAnimation — the invariant after the cut, over time
Avant — Money est en placeBefore — Money is in place
1 endroit applique l'invariant · 9 sites l'utilisent1 place enforces the invariant · 9 sites use it
Invariant appliqué (objet-valeur)Invariant enforced (value object)appliqué à un endroitenforced in one place
Sites sans garde-fou (inliné)Sites with no guardrail (inlined)surface de bugbug surface
incidentincident
L'objet-valeur Money refuse l'addition de deux devises différentes et arrondit correctement. Les 9 sites d'appel héritent de l'invariant gratuitement : il est appliqué à un seul endroit.The Money value object refuses to add two different currencies and rounds correctly. All 9 call sites inherit the invariant for free: it is enforced in a single place.

1 / 5
Le test du bistouriThe scalpel test

Avant de couper une abstraction, ne demande pas « est-ce que ça fait moins de lignes ». Demande : si je supprime ça, un invariant devient-il inapplicable, une frontière disparaît-elle, une couture de test se ferme-t-elle — ou est-ce que j'inline juste un passe-plat ?Before cutting an abstraction, don't ask 'is this fewer lines'. Ask: if I delete this, does an invariant become unenforceable, a boundary disappear, a test seam close — or do I just inline a pass-through?

Le motif transférable.The transferable pattern.

Quand une coupe rétrécit le diff mais multiplie les endroits qui doivent « se rappeler » de faire la bonne chose, tu n'as pas simplifié : tu as relocalisé. La vraie question n'est pas combien de code part, mais combien de garde-fous partent avec.When a cut shrinks the diff but multiplies the places that must 'remember' to do the right thing, you didn't simplify: you relocated. The real question isn't how much code leaves, but how many guardrails leave with it.

№ 04Le piègeThe trap4 min

« Une seule implémentation » n'est pas le test. Ce que ça protège l'est.'One implementation' isn't the test. What it protects is.

Les deux extraits regardent exactement les mêmes deux abstractions : un port PaymentGateway et un UserService.get_user, chacune avec une seule implémentation. La tronçonneuse applique la même règle aux deux — « une impl → delete » — et tue le port en même temps que le passe-plat. Le bistouri pose une autre question, abstraction par abstraction : qu'est-ce que je perds si je supprime ça ? Bascule le toggle.Both snippets look at the exact same two abstractions: a PaymentGateway port and a UserService.get_user, each with a single implementation. The chainsaw applies one rule to both — 'one impl → delete' — and kills the port along with the pass-through. The scalpel asks a different question, abstraction by abstraction: what do I lose if I delete this? Flip the toggle.

# deux abstractions, UNE seule implémentation chacune.
# le bistouri ne compte pas les lignes : il demande ce que ça protège.

# PORT PaymentGateway → GARDÉ
#   protège une frontière (le domaine ignore Stripe)
#   et une couture de test (on teste sans réseau)
class PaymentGateway(Protocol):
    def charge(self, money: Money) -> Receipt: ...

class StripeGateway:                  # la seule implémentation, aujourd'hui
    def charge(self, money): ...      # un jour : Adyen, un fake en test

# PASSE-PLAT UserService.get_user → COUPÉ
#   ne protège rien : il relaie, point.
user = user_repo.find_by_id(id)       # on appelle le repo directement
Pourquoi c'est justeWhy it's right

Le bistouri garde le port à une seule implémentation parce qu'il protège deux choses réelles : une frontière (le domaine ne sait rien de Stripe) et une couture de test (on substitue un fake sans toucher au réseau). Et il coupe le passe-plat sans hésiter : UserService.get_user ne faisait que relayer vers le repo — le supprimer n'enlève aucun garde-fou, juste un saut de pile. Paresseux sur la plomberie, ferme sur le domaine.The scalpel keeps the single-implementation port because it protects two real things: a boundary (the domain knows nothing of Stripe) and a test seam (swap in a fake without touching the network). And it cuts the pass-through without hesitation: UserService.get_user only forwarded to the repo — deleting it removes no guardrail, just a stack hop. Lazy on the plumbing, firm on the domain.

La règle qui tranche.The rule that settles it.

L'effort de conservation suit ce qui est protégé, pas le nombre d'implémentations. Un port, un objet-valeur, une validation de frontière à une seule implémentation se gardent — déléter ne retire pas la complexité, il la relocalise. Un service qui relaie, une factory pour un constructeur public, une interface « par symétrie » se coupent — même dans la couche domaine. C'est de la plomberie en costume de domaine.Keep-effort follows what's protected, not the implementation count. A port, a value object, a boundary validation with one implementation are kept — deleting doesn't remove complexity, it relocates it. A forwarding service, a factory for a public constructor, an interface 'for symmetry' are cut — even in the domain layer. That's plumbing in a domain costume.

№ 05Bilan & éditoWrap-up & editorial2 min

Couper la plomberie au bistouri, défendre l'organe par ce qu'il protège.Cut the plumbing with the scalpel, defend the organ by what it protects.

Deux natures de code, deux lamesTwo natures of code, two blades
Accessoire · plomberieIncidental · plumbingEssentiel · domaineEssential · domain
CritèreTestl'échelle YAGNIthe YAGNI ladderqu'est-ce que ça protègewhat does it protect
ExempleExamplecast, retry, wrapper, configcast, retry, wrapper, configobjet-valeur, port, invariantvalue object, port, invariant
Une seule impl ?One impl?→ supprime (YAGNI)→ delete (YAGNI)→ non concluant, regarde ce qu'elle garde→ inconclusive, look at what it guards
GesteMovele minimum qui marchethe minimum that worksgarde si ça protège, coupe si passe-platkeep if it protects, cut if pass-through
La fauteThe mistakele gonflement (sur-construire)the bloat (over-build)l'éventration (relocaliser l'invariant)the gutting (relocate the invariant)

Coupe sans remords quand…Cut without remorse when…

  • le code est accessoire : glue, transport, formatage, orchestration — applique l'échelle (besoin réel ? stdlib ? une ligne ?) et arrête-toi au premier barreau qui tient.the code is incidental: glue, transport, formatting, orchestration — run the ladder (real need? stdlib? one line?) and stop at the first rung that holds.
  • l'abstraction ne protège rien : un service qui relaie, une factory pour un constructeur public, une interface extraite « par symétrie ». C'est de la plomberie en costume de domaine, même dans la couche métier.the abstraction protects nothing: a forwarding service, a factory for a public constructor, an interface extracted 'for symmetry'. It's plumbing in a domain costume, even in the business layer.

Garde, même à une seule implémentation, quand…Keep, even at one implementation, when…

  • supprimer rend un invariant inapplicable, fait disparaître une frontière, ou ferme une couture de test : la complexité ne part pas, elle se relocalise sur les sites d'appel sans garde-fou.deleting makes an invariant unenforceable, removes a boundary, or closes a test seam: the complexity doesn't leave, it relocates to the call sites with no guardrail.
  • c'est une validation de frontière, une gestion de perte de données ou d'échec partiel, de l'authn/authz, ou l'unique invariant qui, brisé, corrompt l'état en silence. Paresseux n'est pas négligent.it's a boundary validation, data-loss or partial-failure handling, authn/authz, or the one invariant that, broken, silently corrupts state. Lazy is not negligent.

Mot de l'éditeurFrom the editor

La règle « sois paresseux » a presque toujours raison — sur la plomberie. Son erreur est de croire que la paresse est une métrique : moins de lignes, moins d'implémentations, donc mieux. Mais une abstraction essentielle ne porte pas des lignes, elle porte une décision : un invariant, une frontière, une couture. La supprimer ne retire pas la décision, elle la disperse là où plus personne ne la fait respecter.The 'be lazy' rule is almost always right — on plumbing. Its error is believing laziness is a metric: fewer lines, fewer implementations, therefore better. But an essential abstraction doesn't carry lines, it carries a decision: an invariant, a boundary, a seam. Deleting it doesn't remove the decision, it scatters it where no one enforces it anymore.

« Accessoire ou essentiel ? » est la première question, avant « combien de lignes ». Le bon agent — comme le bon architecte — n'a pas une main plus légère, il a deux mains : la tronçonneuse pour la plomberie, le bistouri pour l'organe. Et il sait, à chaque coupe, laquelle il tient.'Incidental or essential?' is the first question, before 'how many lines'. The good agent — like the good architect — doesn't have a lighter hand, it has two hands: the chainsaw for the plumbing, the scalpel for the organ. And it knows, at every cut, which one it's holding.

Les voisins que ce numéro débloqueThe neighbors this issue unlocks

  • Complexité essentielle vs accidentelle (Brooks)Essential vs accidental complexity (Brooks) — « No Silver Bullet » : la complexité accidentelle se réduit (outils, abstractions), l'essentielle est irréductible. Couper l'accidentel, jamais l'essentiel.'No Silver Bullet': accidental complexity can be reduced (tools, abstractions), essential complexity is irreducible. Cut the accidental, never the essential.
  • Objet-valeur (DDD)Value object (DDD) — un type qui rend un état illégal irreprésentable : Money qui refuse l'arithmétique entre devises. Une implémentation, mais un invariant gardé à un seul endroit.a type that makes an illegal state unrepresentable: Money refusing cross-currency arithmetic. One implementation, but one invariant enforced in a single place.
  • Ports & adapters (Vol 1)Ports & adapters (Vol 1) — le port à une seule implémentation n'est pas du YAGNI : c'est une frontière et une couture de test qui font exactement leur travail.the single-implementation port isn't YAGNI: it's a boundary and a test seam doing exactly their job.
  • YAGNI sain (Vol 0 #3)Healthy YAGNI (Vol 0 #3) — la réversibilité disait quand attendre ; ce numéro dit quoi garder. Ensemble : ne décide pas trop tôt, et ne coupe pas ce qui tient le mur.reversibility said when to wait; this issue says what to keep. Together: don't decide too early, and don't cut what holds the wall up.