Dépendances d'architecture¶
Cette page explique quelles parties de CMonChoix ont le droit de dépendre de quelles autres parties. Elle sert à éviter qu'un composant technique ou spécialisé devienne progressivement indispensable au cœur métier.
Statut¶
Contrat normatif d'architecture.
Pourquoi cette règle est importante¶
Quand on travaille sur un gros projet, il est très facile d'ajouter un require, un appel de fonction ou une dépendance vers le fichier qui contient déjà l'information recherchée.
Cela peut fonctionner immédiatement, mais créer une dépendance dangereuse : le composant appelant commence alors à connaître des détails qu'il ne devrait pas connaître.
À long terme, cela provoque notamment :
- des dépendances circulaires ;
- des composants impossibles à tester seuls ;
- des règles métier dispersées ;
- des changements techniques qui cassent des couches métier ;
- des écritures qui contournent les frontières certifiées.
La règle centrale est donc :
Une couche peut dépendre d'une couche plus fondamentale ou d'un contrat explicitement autorisé. Elle ne doit pas dépendre d'une couche plus spécialisée.
Lire le schéma de dépendances¶
Vérité métier
↓
Domain / Contracts
↓
Application / Vertical Modules
↓
Read Services / Write Services / Pipeline
↓
Infrastructure / Adapters / Runtime / Frontend
Ce schéma ne décrit pas l'ordre d'exécution ni les conteneurs Docker. Il décrit qui peut connaître qui dans le code.
Les couches, en langage simple¶
Domain¶
Le Domain porte les concepts métier génériques et les décisions déterministes.
Il peut utiliser :
- les Contracts ;
- des helpers purs et génériques ;
- la bibliothèque standard du langage.
Il ne doit pas connaître :
- WordPress ;
- SQL concret ;
- le Runtime ;
- le Frontend ;
- le Pipeline ;
- une verticale précise ;
- un marchand particulier.
Contracts¶
Les Contracts décrivent les formes stables utilisées pour communiquer entre les couches : interfaces, DTO, statuts, codes de raison et structures de résultat.
Un DTO (Data Transfer Object) est simplement une structure servant à transporter des données entre composants sans exposer leurs détails internes.
Les Contracts doivent rester neutres. Ils ne doivent contenir ni SQL, ni logique WordPress, ni règle Smartphone, ni orchestration Runtime.
Knowledge¶
Knowledge contient des connaissances métier réutilisables qui enrichissent le sens des données sans orchestrer l'exécution.
Il peut dépendre du Domain et des Contracts.
Application¶
Application coordonne des cas d'usage : elle enchaîne des décisions et services selon une intention précise.
Elle peut dépendre du Domain, de Knowledge et des Contracts.
Elle ne doit normalement pas dépendre directement d'une implémentation technique concrète de l'Infrastructure.
Vertical Modules¶
Les Vertical Modules portent les règles propres aux familles de produits.
Ils peuvent dépendre du Domain et des Contracts.
Une verticale ne doit jamais dépendre directement d'une autre verticale. Si deux verticales ont réellement besoin de la même connaissance, cette connaissance doit être extraite vers une couche commune appropriée.
Read Services¶
Les Read Services font des audits, simulations, comparaisons, diagnostics et rapports.
Ils peuvent dépendre du Domain, des Contracts, des Vertical Modules et de ports de lecture.
Ils ne doivent jamais :
- exécuter
INSERT,UPDATEouDELETE; - appeler un Write Service pour réparer des données ;
- modifier un état Runtime ;
- effectuer une réparation silencieuse.
Write Services¶
Les Write Services sont la frontière des mutations métier contrôlées.
Ils peuvent dépendre du Domain, des Contracts, des Vertical Modules et de ports de persistance.
Une commande CLI, un worker ou un orchestrateur ne doit pas contourner cette frontière simplement parce qu'un ancien writer SQL est plus facile à appeler.
Pipeline¶
Le Pipeline gère l'ingestion, la normalisation, l'enrichissement et la préparation des données.
Il peut dépendre du Domain, des Contracts, des Vertical Modules et de services applicatifs explicitement autorisés.
Il ne doit jamais dépendre du Frontend ni utiliser une règle d'affichage comme source de vérité métier.
Infrastructure¶
L'Infrastructure contient les détails techniques : persistance, queues, locks, stores d'état et intégrations externes.
Elle implémente les ports définis par les couches plus stables. Elle ne doit pas définir la vérité métier.
Adapters¶
Les Adapters traduisent les interactions extérieures vers les contrats de la plateforme.
Par exemple, un adapter WordPress peut transformer une requête ou un contexte WordPress en appel vers un service applicatif.
Un adapter traduit ; il ne décide pas de la vérité métier.
Les adapters WordPress liés à différents contextes — frontend, admin, CLI, HTTP, worker — doivent rester isolés. Un comportement partagé appartient à un service applicatif neutre, pas à un import entre adapters.
Runtime¶
Le Runtime possède la composition et l'orchestration des processus : bootstrapping, planification, workers et exécution.
Il peut dépendre d'Application, Infrastructure, Adapters et Contracts.
Il ne doit pas créer de nouvelle règle métier.
Apps¶
Les Apps sont des points d'entrée exécutables.
Elles déclenchent les cas d'usage, mais ne deviennent pas propriétaires de leur logique métier.
Frontend¶
Le Frontend consomme des projections et modèles de lecture préparés pour l'affichage.
Il ne doit pas dépendre directement :
- des feeds marchands ;
- des internes du Domain ;
- du Pipeline ;
- du Runtime ;
- des Write Services.
Tableau récapitulatif¶
| Couche | Dépendances autorisées principales |
|---|---|
| Domain | Contracts, helpers purs |
| Contracts | types partagés neutres |
| Knowledge | Domain, Contracts |
| Application | Domain, Knowledge, Contracts |
| Vertical Modules | Domain, Contracts |
| Read Services | Domain, Contracts, Vertical Modules, ports de lecture |
| Write Services | Domain, Contracts, Vertical Modules, ports d'écriture |
| Pipeline | Domain, Contracts, Vertical Modules, services Application autorisés |
| Infrastructure | Contracts, bibliothèques techniques |
| Adapters | Contracts, Application, Infrastructure |
| Runtime | Application, Infrastructure, Adapters, Contracts |
| Apps | Application, Adapters |
| Frontend | contrats de projection et read models |
Dépendances explicitement interdites¶
Exemples de directions à ne pas introduire :
- Domain → Vertical Module ;
- Domain → Infrastructure ;
- Domain → Runtime ;
- Domain → Frontend ;
- Vertical Module → autre Vertical Module ;
- Read Service → Write Service ;
- Read Service → mutation SQL ;
- Pipeline → Frontend ;
- Frontend → feeds ou internes du Domain ;
- Adapter frontend → adapter CLI ;
- Runtime → définition d'une nouvelle règle métier.
Frontière entre décision et résultat¶
Lorsqu'une décision traverse plusieurs couches, elle doit passer par un contrat stable.
Un résultat important peut notamment exposer :
- le statut ;
- la valeur normalisée ou l'identité sélectionnée ;
- le niveau de confiance ;
- les preuves ;
- les codes de raison ;
- les conflits ;
- les métadonnées d'audit ;
- la version du contrat ou de la règle.
Les états resolved, unknown, ambiguous et conflict conservent le même sens quelle que soit la couche qui les transporte.
Projection et persistance ne sont pas la même responsabilité¶
Entrées canoniques
↓
Projection Builder
↓
Projection DTO
↓
Projection Write Service
↓
Adapter de persistance
Le Projection Builder construit une représentation. Il doit rester déterministe et sans effet de bord.
Le Write Service possède l'écriture, la validation, les retries, l'idempotence et l'auditabilité.
Cette séparation est importante : construire ce qui devrait être écrit et réellement écrire en production sont deux opérations différentes.
Compatibilité avec l'ancien code¶
Un wrapper de compatibilité est autorisé uniquement s'il :
- respecte déjà la direction canonique ;
- ne contient aucune nouvelle logique métier ;
- a des consommateurs identifiés ;
- correspond à une dette documentée et bornée ;
- peut être retiré sans changer le comportement métier.
Le fait qu'un fichier ancien existe encore ne signifie pas qu'il fait partie de l'architecture active.
Il faut distinguer :
- dépendance Runtime active ;
- wrapper de compatibilité ;
- code dormant conservé comme référence ;
- dette de nettoyage acceptée.
BA-AL-001 — Legacy island CMonChoix\Application¶
BA-AL-001 est une dette d'architecture P2, partiellement résolue, qui couvre les fichiers encore présents sous src/Application et déclarant le namespace historique CMonChoix\Application\.... Composer charge normalement le namespace canonique CMonChoix\Platform\... : cette legacy island n'est donc pas autoloadable par le PSR-4 canonique.
Plusieurs ports et composants ont déjà été migrés vers leurs propriétaires canoniques ou supprimés après certification. Les familles résiduelles restent isolées et aucun point d'entrée plugin ou Runtime de production vers cet îlot n'a été prouvé lors de l'audit. Cet îlot doit rester isolé jusqu'à sa migration ou sa suppression certifiée ; il ne doit pas être considéré comme totalement résolu ni devenir une nouvelle dépendance de production.
Comment vérifier qu'une dépendance est correcte¶
Avant d'ajouter un import, require, appel de service ou nouvelle dépendance :
- identifier la responsabilité du composant appelant ;
- identifier la responsabilité du composant appelé ;
- vérifier que le sens de dépendance est autorisé ;
- rechercher s'il existe déjà un Contract ou un port ;
- vérifier que l'appel ne contourne pas une frontière Read/Write ;
- s'assurer qu'aucune vérité métier n'est dupliquée.
Si une couche générique doit connaître un fichier très spécialisé pour résoudre un problème, c'est généralement le signe que la responsabilité est placée au mauvais endroit.
Exemples valides¶
Verticale Photo
↓
Domain + Contracts
Read Service
↓
Vertical Module + contracts de lecture
Runtime
↓
Application
Frontend
↓
Contrat de projection
Exemples invalides¶
Domain
↓
Verticale Smartphone
Read Service
↓
Writer SQL legacy
Pipeline
↓
Composant Frontend
Adapter Frontend
↓
Adapter CLI
Comment ces règles sont protégées¶
Les dépendances doivent être contrôlées avec plusieurs mécanismes :
- scans de namespaces et imports ;
- tests d'architecture ;
- tests de contrats ;
- garde-fous SQL read-only ;
- tests d'isolation des adapters ;
- détection des writers directs ;
- tests de replay déterministe ;
- audits des points d'entrée Runtime.
Une phrase dans la documentation ne suffit pas : les chemins réellement exécutés doivent confirmer la règle.
Pour la reprise du projet¶
Si vous trouvez un appel direct « étrange » entre deux zones éloignées du code, ne le considérez pas automatiquement comme normal parce qu'il fonctionne.
Commencez par vérifier :
- quelle couche possède la responsabilité ;
- si un Contract existe ;
- si l'appel est historique ou réellement canonique ;
- si l'écriture contourne un Write Service ;
- si cette dépendance est protégée par un test d'architecture.
Une dépendance pratique aujourd'hui peut devenir le blocage principal d'une migration demain.
Documents associés¶
- Vision de la plateforme
- Vue d'ensemble de l'architecture
- Blueprint
- Frontières d'architecture
- Principes d'architecture
- Invariants d'architecture
- Domain Core
- Contracts
- Read Services
- Write Services
- Runtime
Évolution future¶
Une nouvelle couche ou une nouvelle direction de dépendance doit avoir une responsabilité unique et explicite, préserver les invariants existants et être protégée par des tests d'architecture. Elle ne doit jamais réintroduire un couplage précédemment retiré simplement pour faciliter une implémentation locale.