Guide de syntaxe du modèle C4 pour PlantUML

Qu’est-ce que le diagramme du modèle C4 ?

Le Diagramme du modèle C4 est un cadre architectural hiérarchique en quatre niveaux conçu pour documenter l’architecture logicielle avec des degrés variés de détail. Créé par Simon Brown, le C4 évite les boîtes et lignes floues en structurant les cartes système en quatre lentilles d’abstraction explicites : Contexte (portée au niveau du système), Conteneur (Applications et magasins de données), Composant (modules internes), et Code (implémentations au niveau des classes).

Pour mettre en œuvre efficacement ce modèle dans du texte, les ingénieurs utilisent la bibliothèque officielle C4-PlantUML extension de bibliothèque standard. Cette bibliothèque remplace les formes UML brutes par des macros spécialisées qui injectent automatiquement des couleurs distinctes, des formes et des champs de métadonnées pour les utilisateurs, les systèmes et les bases de données. Avec VPasCode, vous pouvez définir ces environnements imbriqués de manière propre dans le code. Le moteur de mise en page route dynamiquement les vecteurs de connexion et redimensionne les champs de texte sans altérer votre géométrie de mise en page.

Guide de syntaxe principale : éléments et constructions

La construction d’un modèle C4 valide à l’aide de PlantUML repose sur l’importation des fichiers de bibliothèque corrects, le choix des macros structurelles, la définition des frontières et l’utilisation de liens relationnels spécialisés.

1. Importation des fichiers de la bibliothèque standard C4

Le C4-PlantUML extension est divisée en fichiers individuels qui correspondent directement aux niveaux distincts du modèle d’abstraction. Pour éviter les ralentissements de performance ou les erreurs de compilation, vous devez importer uniquement la couche de fichier spécifique que votre diagramme cible :

@startuml
' Inclure le fichier de couche C4 spécifique requis
!include <C4/C4_Context>
' Utiliser C4_Container ou C4_Component pour des cartes architecturales plus détaillées

2. Déclaration des acteurs et systèmes principaux (niveau Contexte)

Au niveau supérieur du contexte système, vous modélisez les composants internes, les dépendances externes et les utilisateurs humains. La bibliothèque standard fournit des macros spécifiques qui acceptent un ID, une étiquette visuelle et une balise descriptive facultative :

  • Person(id, "Étiquette", "Description") — Représente un profil d’utilisateur humain ou un acteur système.
  • System(id, "Étiquette", "Description") — Représente une application logicielle interne principale ou un écosystème de services.
  • System_Ext(id, "Libellé", "Description") — Représente un système externe ou une dépendance vers une API tierce (affiché dans une palette de couleurs grises explicite).
@startuml C4_Elements
!include <C4/C4_Context>
Person(client, "Client bancaire", "Un client possédant un compte bancaire personnel")
System(systeme_bancaire, "Système bancaire principal", "Gère les transactions financières")
System_Ext(service_mail, "Service de messagerie", "Passerelle de notification SMTP interne")

3. Éclatement des limites (niveaux Conteneur et Composant)

Lorsque vous approfondissez le niveau Conteneur, vous modélisez des applications web, des microservices et des bases de données. Vous pouvez isoler ces éléments internes dans une boîte de limite logique explicite en utilisant la macroSystem_Boundary() enveloppe macro :

!include <C4/C4_Container>

System_Boundary(c1, "Écosystème du système de commerce électronique") {
    Container(application_web, "Application monopage", "React & TypeScript", "Fournit les fonctionnalités utilisateur via une vue web")
    ContainerDb(base_donnees, "Base de données relationnelle", "PostgreSQL", "Stocke les profils utilisateurs et les historiques de comptes")
}

4. Cartographie des relations techniques

Au lieu de compter sur des lignes pointillées basiques, C4 utilise un format de macros de communication explicite tel queRel(ID_Source, ID_Cible, "Libellé", "Technologie"). Cela maintient vos cartes d’architecture très lisibles en imposant que chaque connexion précise son objectif et son protocole de transport sous-jacent (par exemple HTTPS, gRPC ou AMQP) :

!include <C4/C4_Container>

Person(client, "Client bancaire", "Un client possédant un compte bancaire personnel")
System(systeme_bancaire, "Système bancaire principal", "Gère les transactions financières")
System_Ext(service_mail, "Service de messagerie", "Passerelle de notification SMTP interne")

System_Boundary(c1, "Écosystème du système de commerce électronique") {
    Container(application_web, "Application monopage", "React & TypeScript", "Fournit les fonctionnalités utilisateur via une vue web")
    ContainerDb(base_donnees, "Base de données relationnelle", "PostgreSQL", "Stocke les profils utilisateurs et les historiques de comptes")
}
Rel(client, application_web, "Utilise les fonctionnalités du magasin via", "HTTPS")
Rel(application_web, base_donnees, "Lit et écrit les données transactionnelles via", "SQL/TCP")

Meilleures pratiques pour des architectures C4 lisibles

  • Ne jamais mélanger les niveaux d’abstraction :Maintenez vos diagrammes centrés sur un seul niveau. Ne mélangez pas des composants logiciels internes à granularité fine dans une carte contextuelle de système de haut niveau. Si un système devient trop complexe, divisez-le en un diagramme dédié au niveau Conteneur, distinct.
  • Définissez explicitement les technologies :Utilisez toujours le quatrième paramètre de vos macrosRel() pour préciser la technologie ou le protocole exactement utilisé (par exemple,"JSON/HTTPS" ou "JDBC"). Cela donne à votre équipe un contexte d’implémentation essentiel d’un coup d’œil.
  • Utilisez les substitutions de disposition directionnelles : Si vos composants commencent à s’empiler de manière inconfortable, utilisez des macros de relation directionnelle (comme Rel_D() pour le bas, Rel_R() pour la droite, ou Rel_L() pour la gauche) pour nettoyer manuellement votre flux architectural.

Exemples réels de PlantUML C4

Exemple 1 : Disposition de contexte système de haut niveau (Niveau 1)

Ce plan fonctionnel modélise un diagramme standard de contexte système de niveau 1, détaillant comment un client interagit avec une application de banque en ligne et ses dépendances externes.

@startuml
!include <C4/C4_Context>

title Diagramme de contexte système pour le système de banque en ligne

Personne(client, "Client de banque personnelle", "Un client de la banque possédant des comptes personnels.")
Système(systeme_bancaire, "Système de banque en ligne", "Permet aux clients d'afficher des informations financières et d'effectuer des transferts.")
Système_Ext(systeme_mail, "Sous-système e-mail", "Le cluster de serveurs e-mail internes de l'entreprise SendGrid.")

Rel(client, systeme_bancaire, "Utilise le tableau de bord en ligne via")
Rel_R(systeme_bancaire, systeme_mail, "Envoie des alertes et des codes de vérification en utilisant", "SMTP")
@enduml

Analyse de la syntaxe : Ce diagramme se concentre uniquement sur la portée de haut niveau. La System_Ext macro applique automatiquement un profil de couleur grise au service e-mail, le séparant visuellement du système central des dépendances externes. La Rel_R macro force le moteur de disposition à placer le nœud e-mail directement à droite du bloc système bancaire.

Exemple 2 : Topologie des conteneurs de microservices en profondeur (Niveau 2)

Ce plan d’entreprise avancé décompose un système en ses applications conteneurs constitutives et ses magasins de données isolés, montrant comment le trafic web circule à travers une passerelle API jusqu’aux microservices backend.

@startuml
!include <C4/C4_Container>

title Diagramme de conteneurs pour la passerelle de portail de paiement

Personne(marchand, "Partenaire marchand web", "Intègre les points de terminaison de paiement de la plateforme sur leurs sites web.")

BordureSystème(portail_portee, "Écosystème de passerelle de paiement") {
    Conteneur(passerelle_api, "Proxy de routage API", "Nginx", "Intercepte les appels entrants, gère les limites de taux et équilibre les nœuds.")
    Conteneur(service_auth, "Microservice d'identité", "Go & OAuth2", "Valide les jetons API et les portées des développeurs.")
    Conteneur(service_tx, "Registre des transactions", "Java Spring Boot", "Traite les paiements et gère les comptes du registre.")
    ConteneurBaseDonnees(registre_db, "Magasin de données du registre", "CockroachDB", "Implémente des schémas de tables distribuées conformes aux règles ACID.")
}

' Route les flux de trafic de manière claire vers les cibles internes de conteneurs
Rel(marchand, passerelle_api, "Soumet les charges utiles de paiement via", "HTTPS/JSON")
Rel_D(passerelle_api, service_auth, "Valide les jetons entrants via", "gRPC")
Rel_D(passerelle_api, service_tx, "Transfère les actions de paiement vers", "gRPC")
Rel_R(service_tx, registre_db, "Persiste les entrées du registre via", "SQL/TLS")
@enduml

Analyse syntaxique : En utilisant la System_Boundary enveloppe macro, les composants internes sont regroupés proprement à l’intérieur d’une boîte de périmètre claire. La macro spécialisée ContainerDb macro affiche le magasin de données avec une icône explicite de cylindre de base de données, rendant la distinction entre les environnements d’exécution de calcul et les couches de stockage persistant claire à première vue.

Retour en haut