Le langage DSL
Le Structurizr DSL est un langage textuel dont le seul rôle est de décrire un workspace : les éléments, leurs relations, et les vues à en tirer. Sa syntaxe tient en une page, et c’est délibéré.
L’ossature
Trois blocs, dont le troisième est optionnel.
Les commentaires s’écrivent //, #, ou /* ... */. Les mots-clés sont
insensibles à la casse — softwareSystem et softwaresystem sont équivalents —
mais la convention en camelCase se respecte par lisibilité.
Warning
Le DSL est orienté ligne, et cela a deux conséquences qui surprennent :
- une accolade ouvrante doit terminer sa ligne, et la fermante être seule sur la
sienne.
model { }oumodel { /* ... */ }sur une seule ligne ne compilent pas — seuls les blocsstyleséchappent à la règle ; - les mots d’un commentaire en fin de ligne comptent comme des arguments. Une
déclaration
containeracceptant au plus quatre arguments,db = container "Base" // un deux trois quatreéchoue sur un « Too many tokens » parfaitement déroutant, alors que le même commentaire en deux mots passe.
La règle sûre est donc de placer les commentaires sur leur propre ligne. Les
expressions à argument unique — include, exclude — n’ont pas ce problème.
Un exemple minimal complet
Le plus court fichier qui produise quelque chose d’utile :
Quinze lignes de modèle produisent deux diagrammes cohérents. Ajouter un troisième
— déploiement, dynamique — ne demande que quelques lignes dans views, sans
retoucher au modèle.
Les éléments du modèle
Chaque type d’élément suit la même forme : un mot-clé, puis des arguments positionnels, tous optionnels sauf le nom.
| Élément | Signature |
|---|---|
person | person <nom> [description] [étiquettes] |
softwareSystem | softwareSystem <nom> [description] [étiquettes] |
container | container <nom> [description] [technologie] [étiquettes] |
component | component <nom> [description] [technologie] [étiquettes] |
group | group <nom> { ... } — un regroupement visuel |
L’imbrication reproduit celle du modèle C4 : les container se déclarent dans un
softwareSystem, les component dans un container.
L’affectation à un identifiant — api = ... — est nécessaire dès qu’on veut
référencer l’élément dans une relation ou une vue. Un élément jamais référencé peut
être déclaré sans identifiant.
Les groupes
Un group rassemble visuellement des éléments sans créer de niveau
d’abstraction — pratique pour matérialiser une équipe, un
contexte délimité
ou une zone réseau.
Les relations
Une flèche, une description, et de préférence une technologie.
Les arguments sont, dans l’ordre : description, technologie, étiquettes. La description est ce qui distingue un diagramme lisible d’un plat de spaghettis : une flèche sans texte n’apprend rien.
Une relation peut aussi se déclarer dans un bloc, ce qui permet de lui donner des propriétés :
Note
Structurizr crée automatiquement les relations implicites entre parents. Une
relation web -> api entre deux conteneurs induit une relation entre leurs systèmes
respectifs si ceux-ci diffèrent — ce qui fait qu’une vue de niveau 1 se remplit sans
qu’on ait déclaré quoi que ce soit à ce niveau. C’est exactement le bénéfice du
modèle unique, et cela se règle par la directive !impliedRelationships false si le
comportement gêne.
Les identifiants
Par défaut, les identifiants sont plats : tous vivent dans le même espace de
noms, et deux conteneurs nommés db dans deux systèmes différents entrent en
collision. Sur un modèle qui grossit, cela impose des noms comme
billetterieApiDb.
La directive !identifiers hierarchical corrige cela : les identifiants deviennent
relatifs à leur parent, et se référencent par chemin.
C’est le mode à activer systématiquement dès que le modèle dépasse un système. Le coût est nul, et l’inverse — migrer un modèle plat devenu grand — est fastidieux.
Les étiquettes
Les étiquettes (tags) sont le mécanisme central de Structurizr : elles servent
à styler, à filtrer les vues, et à porter de la sémantique. Chaque élément en reçoit
d’office selon son type — Element, Person, Software System, Container,
Component — et l’on ajoute les siennes.
Il vaut la peine d’y réfléchir un peu en amont : une étiquette Externe,
Hérité, Déprécié ou Donnée personnelle permet ensuite de produire des vues
thématiques — les systèmes tiers, la trajectoire de décommissionnement, la
cartographie RGPD — sans toucher au modèle.
Le déploiement
Les nœuds de déploiement forment une hiérarchie parallèle, dans laquelle on instancie les conteneurs déjà déclarés.
| Mot-clé | Rôle |
|---|---|
deploymentEnvironment <nom> | Un environnement : production, recette, développement |
deploymentNode <nom> [desc] [techno] [étiquettes] [instances] | Un nœud : région, cluster, machine, conteneur d’exécution |
containerInstance <identifiant> | Une instance d’un conteneur du modèle |
softwareSystemInstance <identifiant> | Une instance d’un système entier |
infrastructureNode <nom> [desc] [techno] | Un élément d’infrastructure sans code applicatif : répartiteur, pare-feu, DNS |
Le dernier argument de deploymentNode est le nombre d’instances, affiché sur
le diagramme. Les relations entre conteneurs sont reprises automatiquement entre
leurs instances ; celles qui impliquent un infrastructureNode se déclarent à la
main.
Tip
Le même modèle peut porter plusieurs environnements — production, recette,
local — et donner autant de vues de déploiement. C’est un moyen très économique de
documenter les écarts entre environnements, qui sont d’ordinaire décrits nulle part.
Modularité et directives
Les directives commencent par !. Ce sont elles qui permettent à un modèle de
rester lisible au-delà de deux cents lignes.
| Directive | Rôle |
|---|---|
!identifiers hierarchical | Identifiants relatifs au parent |
!include <fichier|dossier|url> | Insère un fragment de DSL |
!const <nom> <valeur> | Définit une constante, réutilisée par ${nom} |
!docs <chemin> | Rattache une documentation Markdown ou AsciiDoc |
!adrs <chemin> | Rattache un répertoire d’Architecture Decision Records |
!extends <fichier|url> | Étend un workspace existant au lieu d’en créer un |
!impliedRelationships <true|false> | Active ou coupe les relations implicites |
!script <fichier> | Exécute un script sur le modèle — Groovy, Kotlin, Ruby, JS |
!plugin <classe> | Branche une extension Java |
Découper un gros modèle
L’organisation qui tient à l’usage :
!include accepte un dossier, dont il inclut alors tous les .dsl par ordre
alphabétique — pratique, mais l’inclusion explicite fichier par fichier documente
mieux l’ordre, qui compte puisqu’un élément doit être déclaré avant d’être
référencé.
Le squelette à réutiliser
Un point de départ complet, prêt à adapter :
Les vues, les expressions de filtrage et les styles font l’objet de la page suivante.
Références
- https://docs.structurizr.com/dsl/language — la référence exhaustive du langage
- https://docs.structurizr.com/dsl/cookbook/ — recettes courtes, très efficaces pour démarrer
- https://github.com/structurizr/dsl