Article

Modularité et microservices : deux décisions à distinguer

Rendre le code modulaire ne demande pas forcément de créer des services. Une interface claire et des dépendances maîtrisées peuvent déjà isoler les changements.

Vous voulez remplacer le moteur de calcul des tarifs sans retoucher les commandes, les factures et tous les écrans. La première question est ce que ces parties connaissent de ce moteur. Une interface bien choisie peut limiter cette dépendance dans la même application. Le déployer en service indépendant répond à une autre série de besoins.

Un module cache les détails qui peuvent changer

Dans son article de 1972, David Parnas propose de découper un système autour des décisions de conception que l'on souhaite cacher. Les consommateurs utilisent une interface, sans dépendre de toute son implémentation.

Pour les tarifs, une opération « calculer le prix de cette commande » peut éviter d'exposer les tables, les formules et les étapes intermédiaires du calcul. Le contrat doit tout de même décrire les entrées, le résultat et les erreurs possibles.

La frontière est utile si une modification interne reste principalement locale. Elle ne garantit pas que tout changement sera invisible : une nouvelle règle métier peut légitimement faire évoluer le contrat.

Deux critères pour examiner un découpage

La cohésion décrit à quel point les éléments du module répondent à une même responsabilité. Le couplage décrit ses dépendances envers d'autres parties.

Un module de tarifs possède une bonne cohésion si ses règles changent pour des raisons liées à la tarification. Son couplage augmente si ses consommateurs doivent connaître les détails de chaque formule.

Ces notions, développées notamment dans Structured Design en 1974, donnent des questions à poser au code. Elles ne produisent pas automatiquement le découpage idéal.

Plusieurs outils peuvent faire respecter une interface

Plusieurs moyens de contrôler une frontière de module, des appels dans le processus à la séparation en services réseau.
Plusieurs moyens de faire respecter une frontière : conventions, contrôles de modules et séparation en services. La distribution ajoute des contraintes d’exploitation, avec des bénéfices possibles à évaluer.

Les langages et les environnements proposent différentes limites : visibilité des types, paquets, modules compilés, bibliothèques ou processus séparés.

MécanismeCe qu'il peut isolerCe qu'il laisse partagé
Modules et visibilité du langageL'accès aux détails internes du code.Le processus et souvent le déploiement.
Composants chargés dans un même environnementCertains contrats et cycles de vie des composants.Des ressources du processus.
Services séparésLe déploiement et certaines ressources d'exécution.Les contrats réseau et d'éventuelles dépendances externes.

Les types abstraits étudiés par Barbara Liskov, les modules de différents langages et les composants OSGi illustrent cette diversité. Il n'est pas nécessaire de parcourir toute leur histoire pour retenir le principe : contrôler ce qui est visible de l'extérieur.

Le schéma représente une progression vers des frontières plus physiques. Les coûts réels varient selon le système ; un appel local n'est pas littéralement gratuit, et les outils ne procurent pas tous les mêmes garanties.

Prévoir comment les modules se composent

Une application utile doit aussi réunir ses modules dans des parcours. Les outils Unix montrent une forme de composition : la sortie d'un programme peut devenir l'entrée d'un autre selon un format partagé.

Dans une application métier, un contrat peut de même permettre à plusieurs consommateurs d'utiliser une capacité sans connaître son fonctionnement interne. Il faut néanmoins s'accorder sur le sens des données, les erreurs et les règles d'évolution.

Multiplier de petites unités ne suffit donc pas. Si chaque parcours doit connaître leurs détails et leur ordre exact, le système peut rester fortement couplé.

Ce qu'un service indépendant ajoute

Un service peut être livré, dimensionné et exploité séparément. Ces possibilités sont utiles lorsque les besoins opérationnels divergent réellement.

En contrepartie, les échanges traversent le réseau. Ils peuvent être lents, échouer ou produire une réponse perdue après une opération réussie. L'équipe doit prévoir les délais, les reprises et les traces nécessaires au diagnostic.

Les transactions locales restent disponibles dans chaque service. Ce sont les opérations qui franchissent la nouvelle frontière qui demandent de réexaminer leurs garanties.

Le réseau n'empêche pas une interface mal conçue. Des services qui doivent changer et être livrés ensemble peuvent garder un couplage important malgré leur séparation physique.

Choisir la frontière qui répond au besoin

Pour rendre les modifications plus locales, commencez par le contrat et le sens des dépendances. Les règles du langage et les contrôles d'architecture peuvent suffire à les faire respecter.

Si le besoin concerne des livraisons indépendantes, des ressources distinctes ou une isolation particulière, examinez l'extraction en service. Comparez-la aux options disponibles dans le monolithe.

Une équipe peut posséder un module sans posséder un service. À plus grande échelle, la séparation des déploiements peut réduire la coordination entre équipes. Cette décision dépend de leur travail réel, pas du seul nombre de dossiers ou de développeurs.

Le monolithe modulaire permet de travailler les interfaces tout en conservant un déploiement commun. C'est une option pour obtenir des changements plus faciles à comprendre et à maîtriser.

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é.