Intégrations internes et externes

Les intĂ©grations connectent l’application gĂ©nĂ©rĂ©e par Lino Ă  d’autres modules, services internes et systĂšmes tiers. Le choix entre appel synchrone, intĂ©gration in-process, HTTP et Ă©vĂ©nements doit tenir compte du couplage, de la latence, de la fiabilitĂ© et de la propriĂ©tĂ© des donnĂ©es.

L’objectif n’est pas seulement d’appeler un autre systĂšme. Il s’agit de dĂ©clarer une frontiĂšre : qui fournit la donnĂ©e, qui la consomme, quel contrat est public, ce qui se passe en cas d’échec et si l’opĂ©ration doit ĂȘtre immĂ©diate ou peut ĂȘtre traitĂ©e plus tard.

Créer des intégrations

Les intĂ©grations reprĂ©sentent une communication explicite avec un autre contexte, un service interne ou un systĂšme externe. Elles doivent avoir un nom, un contrat, une authentification, un timeout, une stratĂ©gie d’erreur et une responsabilitĂ© claire.

lino integration new --name <ServiceName>
lino integration list

Utilisez integration list pour vĂ©rifier les intĂ©grations existantes avant d’en crĂ©er une autre. Évitez les intĂ©grations gĂ©nĂ©riques, comme CommonIntegration, car elles tendent Ă  accumuler des responsabilitĂ©s sans limite claire.

Avant de crĂ©er une intĂ©gration, dĂ©finissez le problĂšme qu’elle rĂ©sout : consulter un registre externe, envoyer une facturation, valider un abonnement, synchroniser un utilisateur, consommer un module interne ou publier des donnĂ©es vers un autre systĂšme. Si l’intĂ©gration n’a pas d’intention spĂ©cifique, elle n’est probablement pas encore prĂȘte Ă  devenir un contrat gĂ©nĂ©rĂ©.

  • Nommez par le contexte intĂ©grĂ© : prĂ©fĂ©rez Billing, Identity, Catalog ou Shipping aux noms gĂ©nĂ©riques.
  • SĂ©parez contrat et implĂ©mentation : le domaine et l’application ne doivent pas dĂ©pendre directement des dĂ©tails de transport.
  • Supposez les dĂ©faillances externes : toute intĂ©gration distante peut devenir lente, indisponible, retourner une erreur partielle ou changer son contrat.

Resources d’intĂ©gration

Les resources représentent des objets exposés ou consommés par une intégration, comme customers, invoices, tenants, subscriptions, users ou documents.

lino integration resource new --service <ServiceName> --module <ModuleName> --entity <EntityName>
lino integration resource list --service <ServiceName> --module <ModuleName> --entity <EntityName>

Un resource d’intĂ©gration n’a pas besoin d’ĂȘtre identique Ă  l’entitĂ© de domaine. Il s’agit souvent d’un contrat d’échange de donnĂ©es, d’une vue externe ou d’une reprĂ©sentation minimale nĂ©cessaire Ă  la communication entre contextes. Copier toute l’entitĂ© dans le contrat externe expose souvent des dĂ©tails internes et augmente le coĂ»t d’évolution.

  • ModĂ©lisez le resource avec le vocabulaire du systĂšme intĂ©grĂ©.
  • N’exposez pas les entitĂ©s internes comme contrat externe.
  • DĂ©finissez quels champs sont des identifiants, des filtres et des donnĂ©es retournĂ©es.
  • Documentez la pagination, l’authentification et les limites d’appel lorsqu’elles existent.

Lorsque le resource reprĂ©sente des donnĂ©es d’un autre module, incluez seulement ce qui est nĂ©cessaire au consommateur. Le mĂȘme principe apparaĂźt dans les shadow entities : le module consommateur conserve une petite copie locale, alignĂ©e sur son propre cas d’utilisation, au lieu de dĂ©pendre du modĂšle complet du module producteur.

OpĂ©rations d’intĂ©gration

Les opĂ©rations dĂ©crivent les actions disponibles sur un resource d’intĂ©gration : crĂ©er, consulter, mettre Ă  jour, annuler, envoyer, synchroniser ou valider.

lino integration operation new --service <ServiceName> --module <ModuleName> --entity <EntityName>
lino integration operation list --service <ServiceName> --module <ModuleName> --entity <EntityName>

Chaque opĂ©ration doit dĂ©finir son intention, son entrĂ©e, sa sortie, sa mĂ©thode d’appel, son comportement d’erreur et si elle peut ĂȘtre rĂ©exĂ©cutĂ©e en sĂ©curitĂ©.

  • Les requĂȘtes doivent avoir un timeout et une gestion de l’indisponibilitĂ©.
  • Les commandes distantes doivent ĂȘtre idempotentes lorsque c’est possible.
  • Les dĂ©faillances externes ne doivent pas casser la transaction principale si le mĂ©tier accepte un traitement asynchrone.
  • Utilisez des logs et un correlation id pour tracer les appels entre systĂšmes.

L’idempotence est particuliĂšrement importante dans les opĂ©rations d’écriture. Si une tentative Ă©choue aprĂšs que le systĂšme externe a exĂ©cutĂ© l’action, une nouvelle tentative peut dupliquer une facturation, crĂ©er un enregistrement rĂ©pĂ©tĂ© ou envoyer un message deux fois. Lorsque c’est possible, utilisez des clĂ©s d’idempotence, des identifiants externes ou des rĂšgles de rĂ©exĂ©cution documentĂ©es.

Consommer des intégrations

AprĂšs avoir modĂ©lisĂ© une intĂ©gration, un resource et une opĂ©ration, utilisez la consommation pour connecter l’application au contrat gĂ©nĂ©rĂ©. L’objectif est de faire dĂ©pendre le cas d’utilisation d’une abstraction nommĂ©e, avec une entrĂ©e et une sortie prĂ©visibles, au lieu de disperser les appels HTTP, l’assemblage d’URL, les headers, le parsing de rĂ©ponse et la gestion d’erreur dans plusieurs handlers.

lino integration consume

Les Use Cases doivent dĂ©pendre d’abstractions, pas de dĂ©tails HTTP dispersĂ©s dans le code. Cela facilite les tests, le remplacement d’implĂ©mentation et la gestion uniforme des dĂ©faillances. Cela Ă©vite aussi que chaque endpoint de l’application rĂ©invente diffĂ©remment timeout, authentification, correlation id, sĂ©rialisation et mapping d’erreur.

  • Validez les donnĂ©es avant d’appeler un service externe.
  • Utilisez cancellation token et timeout.
  • Mappez les rĂ©ponses externes vers des erreurs internes prĂ©visibles.
  • N’enregistrez pas un payload externe brut comme rĂšgle de domaine sans transformation.

HTTP vs. in-process

L’intĂ©gration in-process est simple et rapide lorsque les modules s’exĂ©cutent ensemble. HTTP crĂ©e un contrat plus explicite entre processus, mais ajoute de la latence, des dĂ©faillances rĂ©seau et un besoin de rĂ©silience.

L’intĂ©gration in-process ne doit pas signifier un accĂšs libre Ă  tout. MĂȘme dans le mĂȘme runtime, le consommateur doit communiquer par contrat, et non par entitĂ© interne, DbContext ou repository d’un autre module. Le coĂ»t rĂ©seau est plus faible, mais le risque de couplage existe toujours.

ScénarioChoix courantObservation
Modules dans le mĂȘme monolithe modulaireIn-process ou contrat internePrĂ©servez la frontiĂšre ; Ă©vitez de partager entitĂ© et persistance.
Service séparé avec son propre déploiementHTTP ou messagerieTraitez réseau, authentification, versionnement et indisponibilité.
Processus asynchrone et tolĂ©rant au dĂ©laiÉvĂ©nement d’intĂ©grationConcevez des consommateurs idempotents et traçables.

HTTP est plus adaptĂ© lorsque le producteur et le consommateur ont des runtimes sĂ©parĂ©s ou lorsque vous voulez rendre la frontiĂšre opĂ©rationnellement explicite. In-process est adaptĂ© lorsque la mĂȘme application hĂ©berge les contextes et que la rĂ©ponse doit ĂȘtre immĂ©diate, Ă  condition que la dĂ©pendance reste dĂ©clarĂ©e par contrat.

ÉvĂ©nements vs. intĂ©grations synchrones

Utilisez une intĂ©gration synchrone lorsque la rĂ©ponse est nĂ©cessaire pour terminer l’opĂ©ration en cours. Utilisez un Ă©vĂ©nement lorsque le consommateur peut rĂ©agir plus tard et que la consistance Ă©ventuelle est acceptable.

Ce choix est une dĂ©cision mĂ©tier avant d’ĂȘtre une dĂ©cision technique. Si une commande ne peut ĂȘtre créée qu’aprĂšs confirmation d’autorisation par le service de paiement, l’appel synchrone peut ĂȘtre une partie essentielle du cas d’utilisation. Si la crĂ©ation de la commande doit seulement dĂ©clencher une notification, une mise Ă  jour de projection ou une synchronisation vers un autre module, un Ă©vĂ©nement tend Ă  ĂȘtre plus appropriĂ©.

BesoinApprocheAttention technique
Réponse immédiate obligatoireIntégration synchroneTimeout, fallback, erreur prévisible et contrat stable.
Effet ultĂ©rieur tolĂ©rant au dĂ©laiÉvĂ©nement d’intĂ©grationOutbox, idempotence, retries et logs de corrĂ©lation.
Lecture fréquente de peu de données externesShadow Entity ou projection localeSynchronisation, mise à jour éventuelle et modÚle minimal.
Une erreur non gérée est survenue. Rafraîchir 🗙