Diagram som kod

Squeeds Julkalender | 2022-12-11 | Andreas Jonsson
Det är ganska vanligt att använda grafiska verktyg för att rita diagram som förklarar hur mjukvarusystem fungerar. Att istället beskriva mjukvarusystem med hjälp av kod, som i sin tur genererar diagram, kan vara både lättare och mindre manuellt arbete. Med dagens agila arbetssätt passar inte heller alltid de traditionella diagrammen så bra för att beskriva och dokumentera system. I den här luckan hittar vi en kort guide för hur man kan använda C4-modellen och PlantUML för att rita användbara arkitektoniska mjukvarudiagram som kod.
flow_charts.png

(bild lånad från xkcd)

C4-modellen

2018 publicerade mjukvaruarkitekten Simon Brown en artikel “The C4 Model for Software Architecture” som populariserade hans teknik för att rita arkitektoniska mjukvarudiagram: C4-modellen. Den bygger vidare på tidigare rittekniker som t.ex. Unified Modelling Language (UML) eller Entity Relationship Diagram (ERD), men är gjord för att fungera bättre med dagens agila arbetssätt. Grundtanken är att visa ett mjukvarusystem från olika hierarkiska vyer och bryta ner dessa i behållare (containers) och komponenter (components), samt beskriva sambanden (relations) mellan dessa och eventuella personer (persons) som är med i bilden.

Vyerna består av fyra abstraktionsnivåer som har olika publik i åtanke: lägre nivåer innebär mer tekniska detaljer. Det ska vara lätt att förstå vad bilderna visar om man tittar på de högre nivåerna utan att ha några djupare tekniska kunskaper. Namnet C4 kommer från namnen på vyerna som alla börjar med bokstaven C:

  1. Context - första och högsta nivån visar systemlandskapet, hur systemen i detta samverkar med varandra och hur eventuella personer använder dessa.
  2. Containers - andra nivån är inzoomat på ett av dessa system nedbrutet i olika behållare och sambanden mellan dessa och externa system och personer som fortfarande syns. En behållare symboliserar t.ex. en applikation eller en databas.
  3. Components - tredje nivån är inzoomad på en behållare och visar komponeterna i den, vilka relationer dessa har mellan varandra och externa behållare, system eller personer som fortfarande syns.
  4. Code - fjärde och lägsta nivån zommar in på kodflöden i en av komponterna och här återanvänds andra rittekniker (t.ex. UML) för att visa flödesscheman, sekvensdiagram o.s.v.

C4-modellen lägger ingen vikt vid vilken form eller färg som används i bilderna. Det viktiga är inramningen och relationerna mellan objekten är tydliga och att det finns bra beskrivande texter och etiketter för att undvika missförstånd.

PlantUML - diagram som kod

PlantUML är ett verktyg som låter dig skapa diagram som kod. Programmet är skrivet i Java och licensierat som öppen källkod och kostar ingenting att använda. Det finns stöd för att skapa en mängd olika sorters diagram, t.ex. UML och ERD som tidigare nämnts, men framför allt finns det också stöd för C4 i det medföljande standardbiblioteket. Det går alltså att skapa C4-modeller med PlantUML utan att behöva installera något extra.

Var skriver man då koden för att skapa diagram? Det finns stöd för PlantUML i många applikationer, ofta som något sorts tillägg till applikationen. I exempelvis textredigeraren Visual Studio Code går det att installera tillägget från Visual Studio Marketplace genom att först öppna kommando-panelen (CTRL + P) och där ange kommandot:

ext install plantuml

Ibland behöver man också installera Java och Graphviz som PlantUML behöver, men om du använder Visual Studio Code i Windows så följer dessa med tillägget. Det går också att ställa in så att bilder ska renderas på en annan dator och då är ett alternativ att köra igång en Docker-container med PlantUML för detta.

Om man sedan skapar en ny fil med filändelsen .puml förstår “Code” att det är en PlantUML-fil. Skriv sedan lite kod för att rita ett sekvensdiagram och välj att förhandsgranska nuvarande fil (ALT + D), så öppnas en bild med det renderade diagrammet vid sidan om koden:

PlantUML + C4 = ❤️

Nu när vi vet hur C4-modellen hjälper oss att skapa diagram som är lättare att förstå och PlantUML som ett språk för att skriva diagram som kod, följer här ett par exempeldiagram som representerar de två högsta nivåerna i C4-modellen av ett fiktivt system som passar för säsongen.


Context

Först har vi högsta nivån som överblickar hela sammanhanget:

@startuml system-context
!include <C4/C4_Context>

title "System context for Christmas gift logistics"
LAYOUT_WITH_LEGEND()

Person(santa, "Santa Claus")
Person(elf, "Elf")
Person_Ext(child, "Child")

System_Ext(workshop, "Workshop", "Manufactures presents on demand")
System(xgms, "Christmas Gift Management", "Manages wish lists, keeps track of who has been nice and dispatch manufacturing orders")

Rel(child, santa, "Wishes for presents from")
Rel_R(santa, xgms, "Enter wishes into")
Rel_L(elf, child, "Keeping an eye on")
Rel(elf, xgms, "Records kind or naughty actions in")
Rel(xgms, workshop, "Ordering gift production from")
Rel(workshop, santa, "Delivers manufactured presents to")
Rel_U(santa, child, "Surprise")

@enduml


Container

Sen om vi zoomar in på systemet i fokus:

@startuml xgms-containers
!include <C4/C4_Container>

title "Container diagram for Christmas Gift Management System"
LAYOUT_WITH_LEGEND()

Person(santa, "Santa Claus")
Person(elf, "Elf")

System_Ext(workshop, "Workshop", "Manufactures presents on demand")
System_Boundary(xgms, "Christmas Gift Management") {
    Container(app, "Mobile App", "C#, MAUI", "Santa's Little Helper")
    Container(web, "Web Application", "HTML/JS, SvelteKit", "Easy-to-use web interface for managing wish lists")
    Container(api, "Gifts API", "Rust, Rocket", "Provides CRUD functionality and dispatches manufacturing orders when kindness is high enough")
    ContainerDb(db, "Database", "PostgreSQL", "Store wish lists and children's kindess levels\n")
}

Rel(santa, web, "Enter wishes into", "HTTPS")
Rel(elf, app, "Records kind or naughty actions in")
Rel(app, api, "Makes API calls to", "JSON/HTTPS")
Rel(web, api, "Makes API calls to", "JSON/HTTPS")
Rel_L(api, db, "Persist state in", "SQL, Diesel")
Rel(api, workshop, "Ordering gift production from")
Rel_U(workshop, santa, "Delivers manufactured presents to")

@enduml


Det hade givetvis varit möjligt att zooma vidare in i systemets behållare ner till tredje nivån och titta på komponenterna och vidare därifrån, ner till kodnivå. Det beror på hur mycket tid som man vill lägga på detta och vilket djup som behövs. Det finns såklart också alternativ till PlantUML, t.ex. Structurizr som är lite mer avancerade verktyg och därmed har mer finesser, men kostar pengar och kanske kräver lite mer för att komma igång med.

Hoppas att den här korta introduktion till hur man kan rita diagram som kod har bidragit med någonting bra inför julhelgen. God Jul!

Länkar