Aller au contenu principal

4. La complexité : le coût caché du changement

Pourquoi ce chapitre existe

La plupart des systèmes ne deviennent pas difficiles à faire évoluer parce qu'une décision unique était manifestement mauvaise. Ils le deviennent par accumulation de dépendances raisonnables à court terme : une exception ajoutée pour un client, une règle recopiée dans un second service, une table dont le sens varie, une intégration qui ne tolère plus aucune indisponibilité. Chacune économise du temps localement ; ensemble, elles font grimper le coût de comprendre avant même de modifier.

La complexité est donc un risque. Elle augmente la probabilité de mauvaise décision et le coût de correction. Pour la maîtriser, il faut distinguer ce qui est inhérent au problème de ce que le système s'impose à lui-même.

Les idées essentielles

  • La complexité essentielle vient du domaine et de ses contraintes ; la complexité accidentelle provient de nos représentations, couplages et outils.
  • Un système est complexe lorsqu'un changement nécessite de connaître trop d'éléments éloignés pour être réalisé en sécurité.
  • Le couplage n'est pas mauvais en soi. Un couplage invisible, large ou sans propriétaire rend le changement dangereux.
  • Les abstractions sont des engagements. Elles réduisent une répétition présente mais peuvent figer des variations encore mal connues.

La complexité est une charge cognitive distribuée

Dire qu'un système est « complexe » ne suffit pas. Il faut demander : complexe pour accomplir quelle tâche, pour quelle personne, avec quelles informations ? Un module de calcul peut être sophistiqué mais bien délimité, documenté et testé. Il restera abordable pour l'équipe qui le maintient. À l'inverse, une modification de trois lignes peut être très complexe si elle dépend de conventions implicites réparties dans plusieurs services.

La charge cognitive augmente notamment lorsque :

  • le même concept porte des noms différents selon les composants ;
  • une donnée change de sens sans que son contrat ne le dise ;
  • les effets de bord sont cachés derrière une opération qui paraît locale ;
  • un flux dépend de l'ordre, du temps ou de tentatives de reprise non documentés ;
  • la connaissance nécessaire ne peut être détenue par aucune équipe identifiable.

Ces signaux ne pointent pas forcément vers une réécriture. Ils indiquent où investir pour rendre le prochain changement plus sûr : clarifier un contrat, déplacer une responsabilité, isoler une dépendance, ajouter une trace ou supprimer une variation devenue inutile.

Un modèle simple de propagation

Lorsqu'un composant A dépend d'une décision interne de B, A ne dépend pas seulement de l'interface de B ; il dépend de sa manière de changer. Si B impose à A de comprendre ses détails, le coût cognitif de B se propage. Plus cette propagation traverse d'équipes et de cycles de déploiement, plus elle ralentit le système entier.

L'objectif n'est pas d'éliminer les dépendances ; un logiciel utile en a nécessairement. L'objectif est que les dépendances importantes soient explicites, stables à l'échelle appropriée et accompagnées d'un chemin de changement connu.

Gérer un budget de complexité

Toute capacité ajoutée consomme un budget : concepts à expliquer, scénarios à tester, données à migrer, alertes à maintenir, dépendances à surveiller. Le coût ne disparaît pas parce que l'implémentation initiale est courte. Une option configurable, par exemple, crée des combinaisons de comportements, des états invalides possibles et une question permanente : qui est autorisé à changer ce paramètre ?

Le budget de complexité n'est pas un nombre universel. C'est une discipline de conception : avant d'ajouter un mécanisme, chercher le problème précis qu'il justifie et le coût qu'il introduit. La meilleure simplification est souvent de supprimer une capacité, une variante ou une dépendance plutôt que de masquer sa complexité par une abstraction.

DécisionGain immédiatDette de compréhension possibleQuestion de contrôle
Ajouter un flagLivraison graduelleÉtats combinatoires, nettoyage oubliéQuelle est sa durée de vie et son propriétaire ?
Dupliquer une règleRapidité localeDivergence des règles métierLes deux contextes évolueront-ils réellement ensemble ?
Créer une abstractionPoint d'extensionGénéralisation prématuréeQuelles variations observées unifie-t-elle ?
Appeler un service synchroneSimplicité apparenteDisponibilité et latence coupléesQuel comportement lors de sa défaillance ?

Les quatre coûts de la complexité

La complexité se manifeste sous plusieurs formes qui appellent des réponses différentes. Les confondre conduit à une solution esthétique mais inefficace.

CoûtSymptômeRéponse souvent pertinente
CompréhensionSeuls quelques experts peuvent expliquer un fluxLangage de domaine, carte de scénario, exemples et documentation de décision
CoordinationPlusieurs équipes attendent ou déploient ensembleContrat, délégation, compatibilité, frontière mieux placée
VérificationUn changement exige un environnement entier ou une recette manuelleDécision isolée, test de contrat, données de test et observabilité
RécupérationUne erreur nécessite une intervention artisanale sur plusieurs systèmesTransition séquencée, réconciliation, runbook et source de vérité

Ces coûts se renforcent. Une dépendance difficile à comprendre est souvent mal testée ; elle devient difficile à opérer ; l'incident qui suit exige alors une coordination de personnes qui ne partagent plus le même modèle. L'amélioration la plus rentable peut être très modeste : nommer une source de vérité, rendre une erreur traçable ou retirer une variante jamais utilisée.

Lire l'historique des changements

Les diagrammes montrent une architecture déclarée. L'historique des changements montre une architecture vécue. Examiner les dernières évolutions d'un périmètre permet de constater : quels fichiers ou services changent toujours ensemble ; quelles revues attendent le même expert ; quels déploiements sont coordonnés ; quels incidents reviennent autour des mêmes données. Ces observations sont plus fiables qu'une intuition selon laquelle un système serait « trop monolithique » ou « pas assez modulaire ».

Une simple revue trimestrielle de quelques changements difficiles peut suffire à identifier une frontière à clarifier ou un contrat à extraire. Le but n'est pas de mesurer une pureté architecturale ; c'est de trouver le coût qui rend le prochain changement dangereux.

Anti-patterns

L'architecture comme diagramme sans coût de changement

Un diagramme de composants peut paraître net alors que chaque modification exige plusieurs équipes, déploiements coordonnés et connaissances privées. L'architecture réelle se lit dans le chemin nécessaire à un changement : qui doit savoir quoi, quelles interfaces peuvent casser et quels déploiements doivent être synchronisés.

Généraliser dès la première occurrence

Une première répétition est parfois un hasard. Créer trop tôt un cadre générique capture des similitudes superficielles et rend les différences futures coûteuses. Répéter intentionnellement pendant un temps peut être une stratégie saine pour apprendre les vraies variations.

Déclarer une « dette technique » sans mécanisme

Cette expression devient un fourre-tout si elle ne précise ni le coût actuel, ni le risque encouru, ni la trajectoire de réduction. Une dette utilement nommée relie une décision passée à une friction observable : délais de changement, incidents, incapacité à tester, dépendance à une personne ou coût de plateforme.

Bonnes pratiques

Protéger les frontières par des contrats compréhensibles

Un contrat dit ce qu'un consommateur peut attendre et ce qu'il doit fournir, y compris les erreurs, les versions, les délais ou les sémantiques de cohérence lorsque celles-ci sont importantes. Il permet aux équipes de changer l'implémentation interne sans négocier chaque détail. Un contrat vague déplace simplement la complexité dans des conversations privées.

Rendre le changement fréquent moins cher

Les zones qui changent souvent méritent des frontières plus claires, des tests plus ciblés et une meilleure observabilité. À l'inverse, sur-isoler une zone stable peut créer un coût permanent sans bénéfice. La structure doit suivre le rythme de changement, pas uniquement une esthétique architecturale.

Supprimer avant d'ajouter

Lorsqu'un comportement est difficile à modifier, demander d'abord si toutes ses variantes, intégrations et états sont encore nécessaires. La suppression est une décision de conception puissante, à condition de vérifier les usages réels et d'organiser une dépréciation responsable.

Checklist — Évaluer la complexité d'un changement

  • Quels concepts, états et dépendances ce changement ajoute-t-il ?
  • Une personne nouvelle dans le périmètre peut-elle expliquer le chemin d'exécution pertinent ?
  • Les frontières et contrats affectés sont-ils explicites, versionnés et testables ?
  • Quelle connaissance devra être partagée entre équipes pour le prochain changement ?
  • Une simplification, une suppression ou une duplication temporaire serait-elle moins coûteuse ?
  • Qui porte la responsabilité de retirer les mécanismes provisoires introduits ?

À retenir

La complexité n'est pas le nombre de fichiers ni le nombre de services. C'est le coût de savoir assez de choses pour changer le système sans le casser. L'ingénierie la maîtrise en limitant la propagation des détails, en traitant les abstractions comme des engagements et en supprimant ce qui n'a plus de raison d'être.