Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Chapitre 3 sur 12 · Intermédiaire

Principes et fondamentaux de conception

Toute architecture repose sur les mêmes quelques idées de structure : comment diviser un système en parties, ce que ces parties doivent savoir les unes des autres, dans quel sens leurs dépendances doivent pointer et comment garder l’ensemble aussi simple que le problème le permet. Ce chapitre enseigne ces idées à toutes les échelles, d’une classe Python à un composant, puis à une flotte de services : modularité, couplage et cohésion, masquage de l’information, gestion des dépendances, SOLID, connascence, loi de Conway, simplicité et métriques qui mesurent la structure. Il s’adresse aux développeurs qui veulent raisonner avec précision sur la conception, et aux architectes qui ont besoin d’un vocabulaire commun pour les revues.

Introduction vidéo au chapitre 3

6 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

Bienvenue dans le chapitre 3 : Principes et fondamentaux de conception. Toute architecture repose sur les mêmes quelques idées de structure. Comment diviser un système en parties, ce que ces parties doivent savoir les unes des autres, dans quel sens leurs dépendances doivent pointer, et comment garder l’ensemble aussi simple que le problème le permet. Ce chapitre enseigne ces idées.

Le chapitre 2 a décrit les qualités qu’une architecture doit fournir. La plupart d’entre elles, et la modifiabilité avant tout, dépendent moins d’une technologie particulière que de la structure. Une équipe peut choisir le framework le plus en vogue et se retrouver malgré tout avec un système où chaque changement touche dix endroits. Ces principes sont de vieilles idées. Le masquage de l’information date de mille neuf cent soixante-douze, et la loi de Conway de mille neuf cent soixante-huit. Elles ont survécu parce qu’elles décrivent quelque chose qui ne change pas : le coût d’un changement dépend de la distance qu’il doit parcourir. Ce qui a changé, c’est l’échelle. Le principe qui vous dit de garder privés les champs d’une classe vous dit aussi de garder privée la base de données d’un service. Chaque section montre donc chaque idée deux fois : dans un petit morceau de code, et à l’échelle des composants et des services.

Ce chapitre s’adresse aux développeurs qui veulent raisonner avec précision sur la conception. Il s’adresse aussi aux architectes qui ont besoin d’un vocabulaire commun pour les revues de conception. Savoir lire de courts exemples en Python est utile. Il s’appuie sur les attributs de qualité du chapitre 2, que ces principes aident à atteindre. Il est utile d’avoir lu la section zéro point trois, sur l’organisation du code, et la section deux point six, sur la conception pour le changement. Et il mène au chapitre 4, qui montre comment décrire une structure pour que d’autres puissent la comprendre et la remettre en question.

Les quatre premières sections posent les fondations. La section trois point un se demande ce qu’est un module et où doivent passer ses frontières. David Parnas a montré que diviser un système selon les étapes de traitement échoue, et que le diviser selon les changements probables réussit. La section trois point deux vous donne le vocabulaire pour juger les frontières : les niveaux classiques de couplage et de cohésion, et les formes de couplage qui n’apparaissent qu’entre services. La section trois point trois examine l’interface elle-même : le masquage de l’information, les contrats, les abstractions qui fuient, et pourquoi chaque comportement visible d’une interface populaire finit par faire l’objet d’une dépendance. La section trois point quatre s’intéresse au sens : dans quelle direction doivent pointer les dépendances, comment mesurer la stabilité, comment rompre les cycles, et comment vérifier tout cela automatiquement.

Ce schéma de la section trois point deux montre ce vocabulaire à l’œuvre, dans une vraie refactorisation. À gauche, la conception avant : un module de commandes et un module de facturation. Commandes appelle Facturation directement, en lui passant un indicateur qui choisit l’un de deux comportements. Commandes doit donc connaître cet indicateur, et ne peut pas accepter une commande si Facturation est lent ou en panne. Pire encore, les deux modules utilisent la même table des commandes. Toute modification de sa structure, de ses codes de statut ou de ses règles de TVA doit être faite dans les deux modules à la fois. À droite, la conception après. Commandes publie un événement OrderPlaced vers un courtier de messages, qui transporte exactement les faits dont Facturation a besoin. Facturation s’y abonne, et chaque service possède ses propres données. Le couplage n’a pas disparu : Facturation dépend toujours de la signification de cet événement. Mais il est désormais explicite, étroit et versionné, et c’est ce que signifie un couplage faible en pratique.

Les quatre sections suivantes s’appuient sur ces fondations. La section trois point cinq couvre les cinq principes SOLID, chacun illustré dans le code et entre services, ainsi que les critiques qu’ils suscitent lorsqu’on les applique mécaniquement. La section trois point six présente la connascence, une mesure plus fine du couplage, avec un ensemble clair de règles pour la rendre plus faible et plus locale. La section trois point sept élargit le regard à l’organisation : la loi de Conway, les données qui l’étayent, et l’arithmétique des canaux de communication. La section trois point huit conclut sur la simplicité et la mesure : la complexité qui appartient au problème et celle que nous ajoutons nous-mêmes, le prix du maintien des options ouvertes, et les limites de toutes les métriques.

Voici la loi de Conway en une seule image. À gauche, une organisation. Une équipe du paiement et une équipe du catalogue doivent passer par une équipe commune d’administrateurs de bases de données pour chaque modification de schéma. À droite, le système qu’elles construisent : un service de paiement et un service de catalogue qui lisent et écrivent tous deux dans une base de données partagée. La structure du système reproduit la structure de la communication. Ainsi, quand vous concevez un système, vous concevez aussi qui doit parler à qui, et l’inverse est tout aussi vrai.

Lues ensemble, les huit sections forment un seul argument. Le changement est le coût dominant du logiciel : une bonne structure est donc une structure dans laquelle les changements probables restent locaux. Chaque principe du chapitre est une manière d’y parvenir. C’est aussi pourquoi les principes entrent parfois en conflit, et pourquoi aucun n’est absolu. Le savoir-faire professionnel consiste à se demander, pour un changement probable dans ce système, quelle distance il devrait parcourir, et quel principe raccourcit cette distance au moindre coût.

Si la conception est nouvelle pour vous, suivez les sections dans l’ordre. Chacune commence par une courte explication tirée de la vie quotidienne. La lecture du chapitre entier prend environ trois heures. Si vous êtes un ingénieur expérimenté, vous préférerez peut-être commencer par les exemples commentés, comme la boutique en ligne de la section trois point un, ou le calcul des métriques de la section trois point quatre. Ils sont conçus pour être discutés. Chaque section se termine par quelques questions d’autoévaluation. Répondez-y de tête avant de regarder. Quand vous êtes prêt, passez le test facultatif du chapitre : vingt questions à choix multiples et deux réponses rédigées, en quarante-cinq minutes environ. La note de réussite est de quatre-vingts pour cent.

Voilà la carte du chapitre 3. Commencez par la section trois point un, sur la modularité, où nous verrons comment diviser un système pour que les changements attendus restent à l’intérieur d’une seule partie. À très vite.

Télécharger le chapitre (PDF)Lire dans l’application

En un coup d’œil

Vous apprendrez à

  • Expliquer le critère de Parnas pour décomposer un système en modules et l’appliquer pour comparer deux décompositions candidates.
  • Classer les dépendances selon les niveaux classiques de couplage et de cohésion, et identifier le couplage temporel, de déploiement et sémantique entre services.
  • Distinguer le masquage de l’information de l’encapsulation, spécifier une interface comme un contrat et concevoir des API stables qui tiennent compte des abstractions qui fuient et de la loi de Hyrum.
  • Calculer l’instabilité, le degré d’abstraction et la distance à la séquence principale, et s’en servir avec les principes des dépendances acycliques, des dépendances stables et des abstractions stables pour corriger des structures de dépendances.
  • Appliquer les principes SOLID et les principes de cohésion des composants à l’échelle des classes, des composants et des services, et reconnaître quand ils sont appliqués de façon dogmatique.
  • Utiliser la connascence pour décrire la force, la localité et le degré du couplage, et choisir des refactorisations qui l’affaiblissent.
  • Expliquer la loi de Conway, les données qui l’étayent et la manœuvre de Conway inversée, et calculer les canaux de communication d’une équipe.
  • Distinguer la complexité essentielle de la complexité accidentelle, calculer la complexité cyclomatique et transformer des règles structurelles en fonctions d’aptitude sans tomber dans le piège de la loi de Goodhart.

Avant de commencer

Les chapitres 0 à 2, en particulier la section 0.3 (organiser le code), la section 1.7 (dette technique) et la section 2.6 (modifiabilité). Savoir lire de courts exemples en Python est utile.

Durée

Environ 3 heures de lecture ; 45 minutes pour le test.

Termes clés

modularité · masquage de l’information · couplage · cohésion · couplage afférent et efférent · abstraction · conception par contrat · Loi de Hyrum · Principe des dépendances acycliques · instabilité et degré d’abstraction · SOLID · connascence · Loi de Conway · complexité accidentelle

Pourquoi des principes, et pourquoi à toutes les échelles

Le chapitre 2 a décrit les qualités qu’une architecture doit fournir. La plupart d’entre elles, et la modifiabilité avant tout, dépendent moins d’une technologie particulière que de la structure : la façon dont un système est divisé en parties, ce que chaque partie sait des autres et le sens dans lequel vont les dépendances entre elles. Une équipe peut choisir le framework le plus en vogue et la meilleure plateforme cloud, et se retrouver malgré tout avec un système où chaque changement touche dix endroits, parce que les parties ont été découpées aux mauvais endroits. Les principes de ce chapitre sont le savoir accumulé en plus de cinquante ans sur la manière de bien les découper.

Ce sont de vieilles idées, et c’est une force. Le masquage de l’information date de 1972, le couplage et la cohésion des travaux de conception structurée de la fin des années 1960 et des années 1970, la loi de Conway de 1968. Elles ont survécu parce qu’elles décrivent quelque chose qui ne change pas : le coût d’un changement dépend de la distance qu’il doit parcourir. Ce qui a changé, c’est l’échelle à laquelle les architectes les appliquent. Le même principe qui vous dit de garder privés les champs d’une classe vous dit de garder privée la base de données d’un service ; le même raisonnement qui interdit un cycle de dépendances entre deux paquets interdit deux services qui ne peuvent être mis en production qu’ensemble. Chaque section montre donc chaque idée deux fois : dans un petit morceau de code, et à l’échelle des composants et des services.

Organisation du chapitre

Les quatre premières sections posent les fondations. La section 3.1 se demande ce qu’est un module et où doivent passer ses frontières ; elle s’appuie sur l’exemple KWIC de David Parnas pour montrer pourquoi une décomposition selon les étapes de traitement échoue et une décomposition selon les changements probables réussit, et elle distingue les modules logiques des unités physiques que l’on construit et que l’on déploie. La section 3.2 donne le vocabulaire pour juger les frontières : les niveaux classiques de couplage et de cohésion, le couplage afférent et efférent, et les formes de couplage qui n’apparaissent qu’entre services. La section 3.3 examine l’interface elle-même : masquage de l’information et encapsulation, contrats, abstractions qui fuient, modules profonds et loi de Hyrum. La section 3.4 s’intéresse au sens des dépendances : les principes de Robert C. Martin pour les dépendances entre composants, les métriques d’instabilité et de degré d’abstraction, la manière de rompre les cycles, l’organisation en couches, et la façon de vérifier tout cela automatiquement.

Les quatre sections suivantes s’appuient sur elles. La section 3.5 couvre les cinq principes SOLID et les principes de cohésion des composants, chacun illustré dans le code et entre services, ainsi que les critiques qu’ils suscitent lorsqu’on les applique mécaniquement. La section 3.6 présente la connascence, une mesure plus fine du couplage, assortie d’un ensemble clair de règles pour la rendre plus faible et plus locale. La section 3.7 élargit le regard à l’organisation : la loi de Conway, les données qui l’étayent, l’arithmétique des canaux de communication et la manœuvre de Conway inversée. La section 3.8 conclut sur la simplicité et la mesure : complexité essentielle et complexité accidentelle, KISS, YAGNI et DRY bien compris, le prix du maintien des options ouvertes, les métriques structurelles comme la complexité cyclomatique, et les limites de toutes les métriques.

Une seule idée sous-jacente

Lues ensemble, les huit sections forment un seul argument. Le changement est le coût dominant du logiciel : une bonne structure est donc une structure dans laquelle les changements probables restent locaux. Chaque principe du chapitre est une manière d’y parvenir. Parnas dit de placer chaque changement probable à l’intérieur d’un seul module. Le couplage et la cohésion disent de garder proches les choses qui changent ensemble et d’éloigner celles qui changent séparément. Le masquage de l’information dit de veiller à ce que ce qui peut changer soit invisible de l’extérieur. Les principes de dépendance disent de faire pointer les dépendances vers ce qui change le moins. La connascence dit de garder aussi proches que possible deux morceaux de code liés par un accord fort. La loi de Conway ajoute que les personnes font partie de la structure : un changement qui exige l’accord de deux équipes n’est pas local, quelle que soit l’organisation du code.

Cet argument explique aussi pourquoi les principes entrent parfois en conflit et pourquoi aucun n’est absolu. Supprimer une duplication peut augmenter le couplage ; ajouter des interfaces pour inverser une dépendance peut rendre un module moins profond ; scinder un composant pour améliorer sa cohésion peut créer un saut réseau. Le savoir-faire professionnel ne consiste pas à appliquer chaque principe partout, mais à se demander, pour un changement précis qui est probable dans un système précis, quelle distance il devrait parcourir, et quel principe raccourcit cette distance au moindre coût.

Comment utiliser ce chapitre

Si la conception est nouvelle pour vous, vous pouvez suivre les sections dans l’ordre ; chacune commence par une courte explication tirée de la vie quotidienne et renvoie à la section 0.3, où les bases ont été présentées. Les ingénieurs expérimentés voudront peut-être commencer par les exemples commentés : la décomposition d’une boutique en ligne dans la section 3.1, la refactorisation des commandes et de la facturation dans la section 3.2, l’interface de paiement dans la section 3.3 et le calcul des métriques dans la section 3.4 sont conçus pour être discutés. Les principes présentés ici servent dans tout le reste du cours : les styles architecturaux des chapitres 5 et 6 sont pour une large part des réponses différentes aux questions de savoir où placer les frontières et dans quel sens pointent les dépendances, et le chapitre 11 fait des vérifications automatisées introduites ici une pratique de gouvernance grâce aux fonctions d’aptitude.

Les 8 sections

3.1 · Intermédiaire · 22 minModularitéCe qu’est un module à chaque échelle, pourquoi on divise les systèmes en modules, la règle de Parnas qui consiste à décomposer selon les changements probables, modules logiques et modules de déploiement, granularité, et comment faire respecter les frontières dans le code.Lire →3.2 · Intermédiaire · 24 minCouplage et cohésionLes deux plus anciennes mesures d’une bonne structure : les niveaux classiques de couplage et de cohésion, le couplage afférent et efférent, les formes supplémentaires de couplage dans les systèmes distribués et les tactiques pour le relâcher, avec un exemple commenté de refactorisation.Lire →3.3 · Intermédiaire · 24 minMasquage de l’informationPourquoi les modules doivent cacher des décisions, en quoi le masquage de l’information diffère de l’encapsulation, les interfaces comme contrats et la conception par contrat, les abstractions qui fuient, les modules profonds, la loi de Hyrum et comment garder stables les API entre composants.Lire →3.4 · Intermédiaire · 25 minDépendancesDans quel sens les dépendances doivent pointer et pourquoi : les principes des dépendances acycliques, des dépendances stables et des abstractions stables de Robert C. Martin, les métriques d’instabilité, de degré d’abstraction et de distance, la suppression des cycles, l’organisation en couches et les vérifications automatisées des dépendances.Lire →3.5 · Intermédiaire · 26 minSOLID à grande échelleLes cinq principes SOLID expliqués avec précision, chacun illustré en Python puis à l’échelle des composants et des services, ainsi que les principes de cohésion REP, CCP et CRP, leur triangle de tensions et la critique honnête de SOLID.Lire →3.6 · Intermédiaire · 22 minConnascenceLa connascence de Meilir Page-Jones nomme les accords cachés entre les parties d’un système, les classe par force et les évalue selon leur localité et leur degré, des paramètres positionnels jusqu’à la synchronisation entre services.Lire →3.7 · Intermédiaire · 22 minLoi de ConwayL’observation faite en 1968 par Melvin Conway selon laquelle les systèmes reproduisent la structure de communication des organisations qui les conçoivent, les données issues de la recherche, l’arithmétique des canaux de communication, la manœuvre de Conway inversée et la charge cognitive des équipes.Lire →3.8 · Intermédiaire · 25 minSimplicité et mesureLa complexité essentielle et la complexité accidentelle, KISS, YAGNI, DRY comme principe portant sur la connaissance plutôt que sur le texte, la réversibilité comme option, et comment mesurer la structure avec la complexité cyclomatique, le LCOM, le couplage de changement et les fonctions d’aptitude sans tomber dans le piège de la loi de Goodhart.Lire →

Test du chapitre

Vérifiez votre compréhension du chapitre 3

Facultatif : 20 questions à choix multiples et 2 courtes réponses rédigées, tirées à chaque fois d’une banque de 72 questions. Note de réussite : 80 %. Réussir tous les tests de chapitre, puis l’évaluation finale, donne droit au Certificat de fin de formation Be Wise.

Passer le test du chapitre 3 dans l’app

Lectures complémentaires