Aller au contenu

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 :

  1. Héritage d'un système non documente : on veut comprendre la structure du code sans tout lire ligne par ligne
  2. 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 :

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

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

  3. 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).

  4. Automatiser la vérification : utiliser des fitness functions pour vérifier que le code respecte les décisions d'architecture.

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