Du modèle au code¶
Garantir que le modèle et le code racontent la même histoire — et décider quels modèles meritent de survivre.
Le problème fondamental¶
On a modélisé les acteurs, les processus, les données, les comportements, la structure et les flux. Les diagrammes sont propres, valides en revue, approuves par les parties prenantes. Puis le développement commence — et en quelques sprints, le code diverge du modèle.
Ce n'est pas un échec. C'est inevitable. Le code est confronte à la réalité : des contraintes techniques imprevues, des cas limites non anticipes, des optimisations nécessaires. Le modèle, lui, reste fige dans un wiki ou un outil de modélisation que personne ne met à jour.
La question n'est pas "comment empêcher la divergence" — c'est "comment gérer la divergence de manière pragmatique". La réponse passe par trois axes : la traçabilité, la génération de code, et le choix explicite des modèles qu'on maintient vs ceux qu'on jette.
Traçabilité modèle vers code¶
La traçabilité est la capacité de suivre le fil entre une exigence, un modèle et le code qui l'implémenté. Sans traçabilité, on ne peut pas répondre a deux questions essentielles :
- Impact analysis : si on modifie ce modèle, quel code est affecte ?
- Vérification : ce code implémenté-t-il bien ce que le modèle spécifié ?
Mécanismes de traçabilité¶
| Mécanisme | Description | Effort de maintenance |
|---|---|---|
| Convention de nommage | Le nom de la classe reprend le nom du concept du modèle | Faible |
| Annotations / commentaires | Référence au modèle dans le code | Moyen |
| Tags dans l'outil de modèle | Lien vers le fichier source correspondant | Moyen |
| Tests d'acceptation | Le test reprend le scenario du cas d'usage | Moyen (mais valeur élevée) |
| ADR + référence au modèle | L'ADR cite le modèle qui justifie la décision | Faible |
| Matrice de traçabilité | Tableau exigence → modèle → code → test | Élevé |
Traçabilité pragmatique¶
En pratique, la matrice de traçabilité complète est rarement maintenue — son coût de maintenance dépassé sa valeur sauf dans les contextes reglementes (medical, aeronautique, defense). Pour un projet standard, la combinaison suivante est un bon compromis :
graph LR
REQ[Exigence / User story] --"se traduit en"--> MODEL[Modele d'architecture]
MODEL --"guide"--> CODE[Code / Tests]
REQ --"verifie par"--> TEST[Test d'acceptation]
CODE --"reference dans"--> ADR[ADR] L'exigence est tracee vers le test d'acceptation (outil de gestion de projet). Le modèle d'architecture guide le code (convention de nommage). Les décisions significatives sont documentees dans des ADR qui referencent le modèle. On ne maintient pas de matrice séparée — la traçabilité emerge des pratiques existantes.
Model-Driven Architecture (MDA)¶
Le MDA est une approche de l'OMG (Object Management Group) qui propose de placer le modèle au centre du processus de développement, avec une génération automatique du code.
Les trois niveaux¶
| Niveau | Nom | Contenu | Independance |
|---|---|---|---|
| CIM | Computation Independent Model | Modèle métier, indépendant de toute informatique | Totale |
| PIM | Platform Independent Model | Modèle logique, indépendant de la plateforme | Technique partielle |
| PSM | Platform Specific Model | Modèle spécifique à la plateforme cible | Aucune |
graph TD
CIM[CIM - Modele metier] --"transformation"--> PIM[PIM - Modele logique]
PIM --"transformation"--> PSM[PSM - Modele technique]
PSM --"generation"--> CODE[Code executable] Promesses du MDA¶
- Séparer les preoccupations métier et techniques
- Régénérer le code lors d'un changement de plateforme (de Java EE a .NET, par exemple)
- Augmenter le niveau d'abstraction et réduire le code manuel
- Réutiliser les modèles CIM et PIM independamment de la technologie
Réalité du MDA¶
Le MDA a produit des résultats inegaux. Voici les raisons :
| Promesse | Réalité terrain |
|---|---|
| Changement de plateforme | Rarement nécessaire, et quand ca l'est, le PIM ne suffit pas |
| Réduction du code manuel | Le code généré nécessité souvent des ajustements manuels |
| Modèles comme artefact principal | Les développeurs préfèrent le code au modèle |
| Outillage mature | Les outils MDA sont coûteux et a courbe d'apprentissage élevée |
| Gain de productivité | Réel pour le CRUD, discutable pour la logique complexe |
MDA aujourd'hui
L'approche MDA pure (tout générer depuis le modèle) est peu adoptee en dehors de niches spécifiques (systèmes embarqués, telecom, banque). Mais ses idées ont infuse : les generateurs de code (OpenAPI, Protobuf, GraphQL schéma), les ORM, les frameworks low-code s'en inspirent sans en revendiquer l'étiquette.
Génération de code depuis les modèles¶
Même sans adopter le MDA complet, la génération de code depuis des modèles est une pratique courante et utile.
Cas d'usage rentables¶
| Source | Généré | Outil |
|---|---|---|
| Schéma OpenAPI | Client HTTP, stubs serveur, types | openapi-generator, Kiota |
| Schéma Protobuf | Stubs gRPC, classes de serialisation | protoc |
| Schéma GraphQL | Types, resolvers, hooks client | graphql-codegen |
| Schéma JSON Schéma | Classes de validation | quicktype, json-schéma-to-ts |
| Schéma de base de données | ORM entities, migrations | Prisma, SQLAlchemy, Hibernate |
| Diagramme d'états | Machine a états (code) | XState, Spring Statemachine |
Avantages¶
- Cohérence : le code généré est toujours conforme au schéma
- Productivité : pas de code boilerplate a écrire manuellement
- Contrat first : le schéma est le contrat, le code en decoule
Limites¶
- Code généré = code a maintenir : le code généré fait partie de la base de code, il doit être teste et versionne
- Round-trip imparfait : modifier le code généré et régénérer ecrase les modifications
- Complexité de build : la génération ajoute une étape au pipeline de build
- Abstraction qui fuit : le code généré peut ne pas correspondre aux idiomes du langage cible
Règle du round-trip
Si on modifie le code généré à la main, on a perdu le benefice de la génération. Deux approches : (1) générer le squelette et écrire la logique dans des fichiers séparés (partial classes, extensions), ou (2) ne jamais modifier le code généré et configurer le generateur pour qu'il produise exactement ce qu'on veut.
Reverse engineering¶
Le reverse engineering est l'opération inverse : produire un modèle à partir du code existant. C'est utile dans deux situations :
- Héritage d'un système non documente : on veut comprendre la structure du code sans tout lire ligne par ligne
- Vérification de conformité : on veut comparer le code réel au modèle théorique
Ce que le reverse engineering produit bien¶
- Diagrammes de classes à partir du code source (héritage, associations, dépendances)
- Diagrammes de déploiement à partir de l'infrastructure as code (Terraform, Kubernetes manifests)
- Schémas de base de données à partir du SGBD (pg_dump, mysqldump)
Ce que le reverse engineering produit mal¶
- Diagrammes de sequence : l'ordre d'exécution dépend du runtime, pas du code statique
- Modèles de domaine : le reverse engineering montre les classes telles qu'elles sont, pas telles qu'elles devraient être
- Architecture intentionnelle : le code montre le "comment", rarement le "pourquoi"
Outils¶
| Type | Outils |
|---|---|
| UML depuis code Java/.NET | Enterprise Architect, IntelliJ IDEA, Visual Studio |
| Dépendances entre modules | Dependency-cruiser (JS), JDepend, Structure101 |
| Schéma depuis base de données | DBeaver, pgModeler, SchemaSpy |
| Architecture depuis IaC | Inframap (Terraform), k8s-diagrams |
Maintenir la cohérence dans le temps¶
Le défi n'est pas de créer des modèles — c'est de les garder coherents avec le code au fil du temps. Voici les stratégies, du plus pragmatique au plus ambitieux.
Architecture as code¶
Le modèle est écrit dans un format texte versionne avec le code. Structurizr DSL, C4-PlantUML ou Mermaid dans les fichiers Markdown. Le modèle vit dans le même repository que le code et suit les mêmes processus (PR, review, CI).
Architecture fitness functions¶
Des tests automatises verifient que le code respecte les règles d'architecture. ArchUnit (Java), NetArchTest (.NET), Dependency-cruiser (JS) permettent d'écrire des assertions comme "aucune classe du domaine ne doit dépendre de l'infrastructure".
Reviews d'architecture périodiques¶
A intervalle régulier (trimestriel par exemple), on compare le modèle au code. Les ecarts sont soit corriges dans le modèle (le code a raison), soit corriges dans le code (le modèle a raison), soit documentes comme des décisions conscientes (ADR).
graph TD
CODE[Code source] --"fitness functions"--> CHECK{Conforme au modele ?}
CHECK --"Oui"--> OK[Coherence maintenue]
CHECK --"Non"--> DECIDE{Decision}
DECIDE --"Le code a raison"--> UPDATE_MODEL[Mettre a jour le modele]
DECIDE --"Le modele a raison"--> REFACTOR[Refactorer le code]
DECIDE --"Decision consciente"--> ADR[Documenter dans un ADR] Modèles vivants vs modèles jetables¶
C'est la décision la plus pragmatique de ce chapitre : tous les modèles ne meritent pas d'être maintenus. Certains sont des outils de réflexion — une fois la réflexion terminee, le modèle a rempli son rôle.
Critères de décision¶
| Critère | Modèle vivant | Modèle jetable |
|---|---|---|
| Audience | Multiple (équipes, ops, sécurité) | L'auteur et son équipe proche |
| Durée de vie | Tant que le système existe | Le temps de la conception |
| Niveau d'abstraction | Architecture (C4 niveaux 1-2) | Conception détaillée (classes, sequences) |
| Coût de mise à jour | Faible (peu d'éléments, stables) | Élevé (beaucoup d'éléments, volatils) |
| Conséquence de l'obsolescence | Décisions basées sur de fausses hypothèses | Peu de conséquence |
| Generabilite | Non generable depuis le code | Generable par reverse engineering |
Recommandations concrètes¶
| Type de modèle | Statut recommande | Justification |
|---|---|---|
| C4 niveau 1 (contexte) | Vivant | Change rarement, valeur communicationnelle élevée |
| C4 niveau 2 (conteneurs) | Vivant | Référence pour les ops et les nouvelles recrues |
| C4 niveau 3 (composants) | Semi-vivant | Mis à jour lors de changements structurels |
| Diagramme de classes du domaine | Semi-vivant | Utile pour l'onboarding, mis à jour si le domaine change |
| Diagramme de sequence détaillé | Jetable | Outil de conception, le code et les tests suffisent |
| Diagramme de déploiement | Vivant | Référence pour les ops, la sécurité, la conformité |
| DFD avec zones de confiance | Vivant | Indispensable pour la sécurité et les audits |
| Modèle entité-relation détaillé | Jetable | Le schéma de la base est la source de vérité |
| Diagramme de cas d'usage | Jetable | Utile en analyse, remplacé par les user stories |
Un modèle obsolète est pire que pas de modèle
Un nouveau développeur qui se fie a un diagramme d'architecture obsolète prend des décisions basées sur de fausses hypothèses. C'est pire que de ne pas avoir de diagramme du tout — au moins sans diagramme, il ira lire le code. La règle est simple : si on ne peut pas maintenir un modèle, on le supprimé.
Approche pragmatique¶
En synthèse, voici l'approche que l'expérience recommande :
-
Modéliser pour comprendre : utiliser les diagrammes comme outils de réflexion pendant l'analyse et la conception. Tous les types de modèles sont utiles à ce stade.
-
Sélectionner ce qu'on garde : à la fin de la phase de conception, décider explicitement quels modèles seront maintenus. Documenter cette décision.
-
Versionner les modèles vivants : les modèles maintenus vivent dans le même repository que le code, au format texte (Structurizr DSL, Mermaid, PlantUML).
-
Automatiser la vérification : utiliser des fitness functions pour vérifier que le code respecte les décisions d'architecture.
-
Jeter sans culpabilite : les modèles jetables ont rempli leur rôle. Les garder "au cas où" crée du bruit. On les archive si on veut, mais on ne les présente pas comme documentation actuelle.
graph LR
ANALYSE[Phase d'analyse] --"tous les modeles"--> CONCEPTION[Phase de conception]
CONCEPTION --"selection"--> VIVANTS[Modeles vivants - maintenus]
CONCEPTION --"archivage"--> JETABLES[Modeles jetables - archives ou supprimes]
VIVANTS --"versionnement"--> REPO[Repository code]
VIVANTS --"verification"--> CI[Pipeline CI - fitness functions] Le modèle parfait n'existe pas. Le modèle utile est celui qui répond a une question, est à jour, et est lu par quelqu'un. Tout le reste est du bruit.
Checklist avant de clore la modélisation¶
| Question | Si oui | Si non |
|---|---|---|
| Ce modèle sera-t-il lu par quelqu'un dans 6 mois ? | Maintenir, versionner | Archiver ou supprimer |
| Ce modèle peut-il être généré depuis le code ? | Ne pas le maintenir manuellement | Le maintenir si utile |
| Ce modèle documente-t-il une décision d'architecture ? | Le lier a un ADR | S'assurer que l'ADR existe |
| Ce modèle est-il la source de vérité pour quelque chose ? | Le protéger, le versionner | Identifier la vraie source |
Chapitre suivant : Structurer — topologies, frontieres et intégration de systèmes.