Conception du code
Concevez des modules profonds : beaucoup de comportement derrière une interface réduite, placée à une jointure où les appelants et les tests se rencontrent. Visez un effet de levier pour les appelants, une localité pour les mainteneurs et des tests qui survivent aux refontes.
Règles
- La profondeur est une propriété de l'interface, pas de l'implémentation. Un module profond peut être construit à partir de petites parties interchangeables ; elles ne font simplement pas partie de son interface. Il peut avoir des jointures internes pour ses propres tests ainsi que la jointure externe à son interface.
- Effectuez le test de suppression. Imaginez supprimer le module. Si la complexité disparaît, c'est un module de passage. Si la complexité réapparaît chez les appelants, il mérite sa place.
- L'interface est la surface de test. Les appelants et les tests traversent la même jointure. Si vous devez tester au-delà de l'interface, le module a probablement la mauvaise forme.
- Un adaptateur signifie une jointure hypothétique ; deux la rendent réelle. N'ajoutez une jointure que là où quelque chose varie réellement, généralement en production et en test.
- Rétrécissez l'interface. Moins de méthodes, des paramètres plus simples, plus de complexité cachée à l'intérieur.
- Acceptez les dépendances au lieu de les créer. Passez la passerelle de paiement plutôt que de la construire à l'intérieur de la fonction.
- Renvoie des résultats au lieu de produire des effets secondaires là où la conception le permet.
Vocabulaire
Utilisez ces termes exactement. Ne remplacez pas par « composant », « service », « API » ou « frontière ».
- Module : tout ce qui a une interface et une implémentation, à n'importe quelle échelle : une fonction, une classe, un paquetage ou une tranche à travers les couches.
- Interface : tout ce qu'un appelant doit connaître pour utiliser correctement le module : types, invariants, ordre, modes d'erreur, configuration requise et performances. Pas seulement la signature.
- Implémentation : le code à l'intérieur d'un module. Un petit adaptateur peut avoir une grande implémentation (un dépôt Postgres), et un grand adaptateur une petite (un faux en mémoire).
- Profondeur : effet de levier à l'interface, c'est-à-dire le comportement qu'un appelant ou un test peut exercer par unité d'interface qu'il doit apprendre. Un module est profond lorsque beaucoup de comportement se trouve derrière une interface réduite et peu profond lorsque l'interface est presque aussi complexe que l'implémentation.
- Jointure (Michael Feathers) : un endroit où le comportement peut changer sans modifier cet endroit ; où vit l'interface d'un module. Choisir la jointure est une décision en soi.
- Adaptateur : une chose concrète qui remplit une interface à une jointure. Il nomme un rôle, pas le contenu.
- Effet de levier : ce que les appelants gagnent de la profondeur. Une implémentation rembourse sur de nombreux sites d'appel et tests.
- Localité : ce que les mainteneurs gagnent de la profondeur. Les changements, bugs, connaissances et vérifications se concentrent en un seul endroit.
Cadres rejetés : la profondeur comme rapport entre les lignes d'implémentation et les lignes d'interface, car cela récompense le gonflement ; « interface » comme uniquement un mot-clé de type ou les méthodes publiques, car c'est trop étroit ; « frontière », car cela entre en conflit avec le contexte délimité du DDD.
Si le projet conserve un glossaire CONTEXT.md, utilisez ses termes de domaine en parallèle avec ceux-ci.
Aller plus loin
- Pour approfondir un ensemble de modules peu profonds par type de dépendance, lisez DEEPENING.md.
- Pour comparer plusieurs interfaces radicalement différentes, lisez DESIGN-IT-TWICE.md. Il lance trois sous-agents ou plus, donc utilisez-le uniquement lorsque l'utilisateur le demande.