Pourquoi nous construisons d'abord les ERP comme des monolithes modulaires
Le découpage arrive généralement trop tôt, pour la mauvaise raison
La première réunion d'architecture d'un projet ERP se déroule presque toujours de la même façon : stock, commandes, facturation et gestion clients sont dessinés comme des services séparés, parce que c'est à quoi ressemblent les schémas des conférences. Six mois plus tard, la même équipe déboggue une transaction qui traverse trois services juste pour décrémenter un stock, créer une commande et poster une ligne de facture. Cette session de débogage prend plus de temps que n'en aurait pris la construction de la fonctionnalité en une seule application. La plupart des projets ERP échouent pour des raisons architecturales, pas techniques, et le problème commence généralement dès la première semaine.
Nous construisons d'abord les ERP comme des monolithes modulaires. Nous n'avons regretté cette décision sur aucun projet. Le but n'est pas d'éviter la complexité. C'est de faire correspondre l'architecture à ce qui doit réellement changer ensemble et à ce qui doit réellement rester cohérent.
Où passe la frontière des modules
Un monolithe modulaire n'est pas une base de code indifférenciée. Sur un ERP Java/Spring Boot typique, nous traçons la frontière par capacité métier : stock, commandes de vente, achats, facturation, fiches clients. Chaque module possède son propre paquet et son propre ensemble de tables, souvent son propre schéma au sein de la même base PostgreSQL. Un module n'atteint un autre que par une interface explicite, jamais en interrogeant directement les tables d'un autre module.
- Le stock possède les niveaux de stock, les réservations et les mouvements.
- Les ventes possèdent les commandes, la tarification et le statut de livraison.
- La facturation possède les documents de facturation et le statut de paiement.
- Les fiches clients possèdent les données de contact, les conditions de paiement et l'historique de correspondance.
La revue de code impose une seule règle : un module peut appeler l'interface de service d'un autre module, mais ne peut pas interroger ses tables. Cette règle unique est ce qui rend possible une extraction ultérieure, car la frontière est déjà façonnée comme un appel réseau dès le premier jour, avant même qu'un appel réseau existe.
Ce qui doit rester dans une seule transaction
Les opérations qui doivent être atomiques dans un ERP sont exactement celles qu'il est difficile de rendre atomiques entre services : réserver du stock et confirmer une commande, poster une facture et mettre à jour le statut d'une commande, appliquer un paiement et lever un blocage de crédit. Dans un monolithe modulaire, ces opérations tournent dans une seule transaction de base de données avec les garanties ACID habituelles. Dans un système découpé trop tôt, la même opération demande une saga, des étapes de compensation et une fenêtre où le système reste incohérent. La plupart des tickets de support viennent exactement de cette fenêtre.
Nous utilisons bien un mécanisme d'événements entre modules, écrit dans une table outbox au sein de la même transaction et traité de façon asynchrone, mais uniquement pour les effets qui peuvent tolérer un délai : envoyer une notification, mettre à jour une projection de reporting, déclencher une génération de document. Tout ce que l'utilisateur doit voir à l'écran suivant reste à l'intérieur de la frontière transactionnelle.
Quand nous découpons réellement
Deux raisons justifient d'extraire un module vers son propre service : un profil de montée en charge réellement différent, ou une équipe réellement différente qui en est propriétaire. Un module de reporting qui doit exécuter une agrégation lourde sur une réplique de lecture plutôt que sur le cœur transactionnel monte en charge différemment, c'est donc généralement la première pièce que nous extrayons. Une vitrine client construite sur le même catalogue ERP est un autre découpage naturel, car elle a besoin de son propre rythme de mise en production et de son propre objectif de disponibilité, et aucun des deux ne devrait dépendre d'une tâche d'import par lots tournant en back-office.
Comme les frontières étaient déjà propres, l'extraction devient mécanique : l'interface interne devient un contrat HTTP ou de messagerie, le module obtient son propre pipeline de déploiement, et le reste du système continue d'appeler la même interface qu'avant. Nous l'avons fait sur des systèmes clients en production sans réécriture.
Notre recommandation
Commencez chaque ERP comme un monolithe modulaire avec des frontières internes strictes et une seule base de données. Gardez le cœur transactionnel, la partie qui doit réellement rester cohérente dès maintenant, à l'intérieur de cette frontière aussi longtemps que nécessaire. N'extrayez un module vers son propre service que lorsque vous avez une raison concrète de montée en charge ou de propriété d'équipe, pas parce qu'un schéma le suggère. Le travail de délimitation fait dès le premier jour est ce qui transforme ce découpage ultérieur en une étape peu coûteuse plutôt qu'en une réécriture.