Article

Dépendances entre modules : choisir qui dépend de qui

Une dépendance détermine quels modules devront changer ensemble. Un exemple de facturation pour choisir son sens, isoler les détails et éviter les cycles.

Changer de fournisseur de courriels devrait surtout modifier le code qui envoie les messages. Si cela oblige aussi à retoucher les règles de facturation, les deux parties sont trop liées. Pour éviter cette situation, il faut choisir ce que chaque module connaît des autres. Le plus souvent, les détails techniques doivent s'adapter aux besoins du métier, exprimés dans un contrat stable.

Prenons un module qui crée une facture après une vente. Il calcule les montants, applique les règles de taxe et enregistre le résultat. Un autre module prévient le client par courriel. Les deux participent au même service rendu, mais leurs raisons de changer sont différentes : une nouvelle règle de calcul d'un côté, un nouveau fournisseur de messagerie de l'autre.

Leur séparation sera utile si vous pouvez modifier l'envoi sans rouvrir le calcul des factures. C'est ce que le sens des dépendances aide à obtenir.

Une dépendance commence par ce qu'un module doit connaître

Un module dépend d'un autre lorsqu'il a besoin de connaître une partie de son fonctionnement pour faire son travail. Cette connaissance peut être le nom d'une opération, les données attendues ou le sens d'un message.

Dans un schéma, la flèche part du module qui utilise cette connaissance vers celui qui la fournit. La notation « A connaît B » signifie donc que A dépend de B.

A connaît B : la dépendance va de A vers B.
A connaît B : la dépendance va de A vers B, et B ignore A.

Cette relation apparaît dans plusieurs échanges courants :

  • Une commande demande une action, par exemple « envoyer cette facture ».
  • Une requête demande une information, par exemple « quel est le montant de cette facture ? ».
  • Un événement annonce un fait, par exemple « cette facture vient d'être créée ». Le module qui le reçoit doit comprendre ce fait et les données qui l'accompagnent.
Les trois façons dont A connaît B : commande, événement, requête.
Les trois gestes par lesquels A connaît B. La dépendance pointe toujours vers B, même quand l'événement voyage de B vers A.

Le sens de circulation des données peut donc différer du sens de la dépendance. La facturation envoie un événement à la messagerie, mais c'est la messagerie qui doit connaître la signification de cet événement. La facturation peut ignorer quels modules le reçoivent.

Martin Fowler décrit cette différence : l'émetteur ne connaît pas les abonnés, tandis que chacun d'eux se conforme à l'interface de l'événement. Ajouter des événements réduit certaines dépendances ; le contrat du message reste à maintenir.

Un contrat stable permet de changer les détails

Un contrat décrit ce qu'un module accepte et promet en retour. Par exemple : les informations nécessaires pour envoyer une facture, le résultat de l'envoi et les erreurs possibles. Il permet à deux modules de travailler ensemble sans partager leur code interne.

Si le calcul des factures utilise directement les options propres à un fournisseur de courriels, changer de fournisseur peut l'obliger à changer aussi. Si ces options restent dans le module d'envoi, la modification reste localisée.

Cette séparation guide le découpage proposé par David Parnas en 1972 : identifier les décisions susceptibles de changer, puis les cacher derrière les interfaces des modules. Le fournisseur de messagerie est précisément une décision que la facturation n'a pas besoin de connaître.

Je recommande de partir des changements que vous voulez pouvoir faire séparément. La question devient concrète : si le fournisseur d'envoi change demain, quels fichiers et quels tests faudra-t-il reprendre ?

Pour la facturation, deux séparations sont possibles

La première consiste à définir, du côté du métier, une interface qui exprime le besoin d'envoi. La facturation l'appelle ; le code propre au fournisseur la réalise. Le métier connaît le service attendu, mais ignore sa mise en œuvre technique.

C'est une application du principe d'inversion de dépendance, formulé par Robert C. Martin en 1996 : les règles de haut niveau et les détails techniques dépendent d'abstractions. L'interface permet ici de remplacer le fournisseur sans modifier les règles de facturation.

La seconde consiste à publier un événement lorsque la facture est créée. Le module de messagerie s'y abonne et prépare le courriel. Cette solution convient lorsque la facturation peut terminer son travail sans attendre l'envoi.

OrganisationCe que connaît la facturationConséquence d'un changement de fournisseur
Appel direct au fournisseurSon interface et ses optionsLe code de facturation peut devoir changer
Interface définie selon le besoin métierLe contrat d'envoiLe changement peut rester dans l'implémentation de cette interface
Publication d'un événementLe fait métier qu'elle publieLe changement peut rester dans le module abonné

L'événement ajoute des questions de livraison et de suivi des échecs. Si le courriel n'arrive pas, un traitement doit pouvoir le détecter et le relancer. Inverser une dépendance n'oblige donc pas à adopter une messagerie asynchrone : une interface peut suffire.

Repérer les dépendances qui reviennent au point de départ

Une boucle apparaît si A dépend de B et B dépend de A. Elle peut aussi passer par plusieurs modules : A utilise B, B utilise C et C utilise A. Chaque liaison semble raisonnable prise séparément ; leur combinaison complique les changements.

Si ces modules doivent être construits ou livrés indépendamment, la boucle risque de les obliger à évoluer ensemble. C'est le problème traité par le principe des dépendances acycliques de Martin. « Acyclique » signifie simplement « sans boucle ».

La portée de cette règle compte. Deux classes livrées dans un même module ne posent pas forcément le même problème que deux bibliothèques destinées à être distribuées séparément. Vérifiez les dépendances à l'échelle où vous avez besoin d'autonomie.

Vérifier une liaison avant de l'ajouter

Pour chaque liaison entre modules, notez ce que le premier doit connaître du second et pourquoi. Puis essayez un changement plausible : remplacer un fournisseur, ajouter un destinataire ou modifier une règle métier.

  • Quels modules devraient changer pour une raison métier ?
  • Lesquels changeraient seulement parce qu'ils connaissent un détail technique ?
  • Une interface ou un événement permettrait-il de limiter cette connaissance ?
  • La nouvelle liaison referme-t-elle une boucle avec des dépendances existantes ?

Les quatre organisations de dépendances donnent plusieurs réponses possibles. Gardez toutefois un appel direct lorsqu'il exprime clairement la responsabilité et que son contrat convient : ajouter un intermédiaire sans changement à isoler peut compliquer le code sans faciliter son évolution.

Sources

Explorer

Sur le même sujet

Choisis dans l’index d’après les étiquettes de cet article — les plus proches d’abord, hors de sa série. Rien n’est écrit à la main : un article publié demain avec les mêmes étiquettes y prendra place.

Laisser un commentaire

Elle n'est jamais affichée ni publiée. Elle sert à regrouper vos commentaires et, si vous vous inscrivez un jour avec elle, à vous les rendre.

Votre commentaire sera relu avant d'être publié.