Mermaid - Diagrams as a Code

Mermaid – Diagrams as a Code

Opublikowano Kategorie Backend, Czysty kod, FrontendCzas czytania 12min

Obok kodu źródłowego i testów, dokumentacja to moim zdaniem kluczowy element powstający w procesie wytwarzania oprogramowania. Dobra dokumentacja to nie tylko korzyść dla klienta, ale też dobry materiał marketingowy. Myślę również, że nowe osoby wdrażane do projektu również będą wdzięczne za dobrą dokumentację.

Często nieodłącznym elementem dokumentacji są diagramy. Parafrazując znany slogan reklamowy — „jeden obrazek może wyrazić więcej niż tysiąc słów”. Dobrze zaprojektowany diagram może stanowić lepsze przedstawienie kodu lub architektury niż obszerne opisy, interfejsy czy komentarze w kodzie. W tym artykule przedstawię Ci kilka argumentów za tym, dlaczego warto korzystać z diagramów, jakie są główne problemy z pracą z diagramami. Pokażę Ci narzędzie Mermaid, które pozwala w prosty i przyjemny sposób zarządzać diagramami w postaci kodu, a także pokażę Ci jak szybko postawić aplikację serwującą dokumentację wzbogaconą o diagramy wykonane w Mermaid.

Diagramy – dlaczego warto?

Programista, który swoje doświadczenie zbierał tylko na studiach, po wielogodzinnym rysowaniu diagramów na laboratoriach, może przeżyć zderzenie z rzeczywistością po trafieniu do pierwszej pracy. W wielu przypadkach będzie brakować nawet dokumentacji, więc diagramów nie znajdzie się tam tym bardziej. Nawet gdy dokumentacja istnieje, to diagramy można w niej znaleźć dość rzadko. Także w dokumentacjach popularnych bibliotek obecność diagramów nie stanowi reguły. Nie twierdzę jednak, że jest to jednoznacznie złe.

Jestem zwolennikiem, by dokumentować tylko to, co konieczne i to, co warto udokumentować. Dotyczy to również dokumentacji z wykorzystaniem diagramów. Mija się z celem dokumentowanie każdej klasy czy sekwencji w aplikacji. Osobiście stawiam na dokumentowanie najbardziej kluczowych komponentów aplikacji, zależności, sekwencji oraz dokumentowanie struktury aplikacji i systemu, bez zbytniego zagłębiania się w szczegóły.

Diagramy nie tylko są przydatne w dokumentowaniu kodu. Diagram to również świetny sposób na dokumentowanie decyzji architektonicznych. Spojrzenie na dany problem z poziomu diagramu czasami pozwala lepiej zrozumieć czynniki jakie miały wpływ na konkretną decyzję architektoniczną.

Innym, świetnym zastosowaniem diagramów jest prezentacja własnych pomysłów. Pomysł, który wymagałby obszernego opisu, czasami da się przedstawić za pomocą prostego diagramu. To nie tylko pozwala oszczędzić czasu na pisaniu, ale też często łatwiej zrozumieć prezentowany pomysł. Również listę kroków czasami lepiej przedstawić jako diagram sekwencji.

Problemy z diagramami

Zasadniczy problem stanowi utrzymanie i aktualizacja diagramów. Kod ma to do siebie, że żyje i przez to często się zmienia. Zmiany w kodzie mogą wymagać odzwierciedlenia na diagramach. Nie zawsze programista będzie pamiętał, by nanieść modyfikacje na diagramy, a inni programiści mogą tego nie wyłapać w trakcie code review. Wielokrotne powtarzanie się takiego zjawiska powoduje działanie teorii rozbitych okien, która mówi, że brak reakcji na łamanie norm społecznych powoduje wzrost przestępczości w okolicy na zasadzie zaraźliwości. Przekładając to na diagramy i dokumentację, gdy zmiany w projekcie nie są nanoszone do dokumentacji na bieżąco, to zwiększa się szansa, że kolejne zmiany również nie będą nanoszone. Dlatego też warto zadbać o to, by tworzenie dokumentacji stwarzało jak najmniej problemów.

Praca z narzędziami do zarządzania diagramami i nasienie zmian może być uciążliwa. W jednym ze swoich projektów próbowałem tworzyć diagramy z wykorzystaniem draw.io. Samo narzędzie jest całkiem przyjemne i pozwala tworzyć wiele rodzajów diagramów. Problem stanowiło jednak utrzymanie pliku roboczego (plik w formacie .drawio) oraz konieczność generowania nowego pliku graficznego z diagramem po każdej zmianie. Po kilku dniach pracy nad projektem poddałem się i przestałem dokumentować dalsze zmiany. Podobny problem miałem z Miro, innym popularnym narzędziem do tworzenia diagramów. Konieczność każdorazowego generowania plików graficznych powoduje, że na dłuższą metę utrzymanie diagramów w tego typu narzędziach jest irytująca.

Kolejnym problemem, jaki widzę, jest dystans między diagramem a fragmentem kodu, którego dotyczy diagram. Najgorsza sytuacja to gdy dokumentacja jest w osobnym repozytorium. Taka sytuacja powoduje, że łatwiej jest zapomnieć zaktualizować dokumentację. Wygodniej, gdy dokumentacja jest w tym samym repozytorium, a jeszcze lepiej, gdy diagramy trzymane są maksymalnie blisko kodu, którego dotyczą. Widząc plik z diagramem bezpośrednio obok pliku z kodem, istnieje większa szansa, że programista nie zapomni zaktualizować go.

Mermaid — Diagram as a Code

Rozwiązaniem problemów z aktualizacją diagramów jest Mermaid, czyli oparte na JavaScript rozwiązanie pozwalające w formie kodu tworzyć wykresy i diagramy. Diagramy wykorzystujące Mermaid możesz uruchomić, korzystając z gotowego środowiska live. Diagramy Mermaid inspirowane są językiem znaczników Markdown. Język Markdown używany jest to tworzenia dokumentów zawierających takie struktury jak nagłówki, tabele, linki, fragmenty kodu, proste style i wiele innych. Wiele narzędzi do tworzenia treści, a nawet niektóre komunikatory umożliwiają tworzenie treści w języku Markdown. Jeśli praca Markdown nie sprawia Ci problemu, to praca ze składnią Mermaid również pójdzie Ci gładko.

Diagramy Mermaid świetnie współgrają z plikami Markdown. Świetnym przykładem integracji Mermaid z plikami Markdown jest wsparcie dla Mermaid na GitHub-ie. Zarówno w issuesach, pull requestach, jak i plikach w formacie md publikowanych na GitHub-ie istnieje możliwość wykorzystania Mermaid. Wystarczy przekazać kod z definicją diagramu w formie code blocka, a GitHub wyrenderuje z niego diagram. Będąc przy GitHub-ie, warto wskazać kolejną zaletę Diagrams as a Code — śledzenie zmian w diagramach z wykorzystaniem systemów kontroli wersji jest znacznie prostsze, niż ma to miejsce np. w plikach graficznych.

Lista dostępnych integracji Mermaida jest całkiem długa i zawiera takie aplikacje jak GitLab, Notion, Obsidian, a nawet plugin integrujący Mermaid z Google Docs. Dzięki temu Mermaid sprawdzi się nie tylko w pracy programisty, ale też w innych branżach.

Diagram w postaci kodu oznacza również, że można aktualizować diagramy z poziomu edytora. Dodanie do edytora, w moim przypadku VSCode, pluginu umożliwiającego podgląd tego, jak wyglądają zmiany wprowadzone na diagramie, sprawia, że praktycznie nie trzeba wychodzić z edytora. Jest to znacznie szybsze i wygodniejsze niż wyklikiwanie zmian w jakimś narzędziu graficznym.

Mermaid oferuje wiele rodzajów diagramów, w tym artykule poznasz, moim zdaniem te najciekawsze i najbardziej przydatne. Każdy diagram i wykres w Mermaid zawiera definicję jego typu, a następnie definicję struktury. Opcjonalnie, na samym początku, można przekazać obiekt pozwalający dostosować style diagramu.

Flowchart

Flowchart to chyba najczęściej wykorzystywany przeze mnie typ diagramu. Jest to na tyle generyczny typ diagramu, że można z jego pomocą dokumentować zarówno strukturę algorytmów, aplikacji, jak i całych systemów. Na flowcharty składają się węzły (nodes) reprezentowane przez różne figury geometryczne, a relacje między nimi można obrazować, korzystając z linków lub strzałek. Przy definiowaniu można zdefiniować kierunek przepływu w diagramie (góra/dół/lewo/prawo). Poniżej znajdziesz uproszczony diagram aplikacji z mojej pracy magisterskiej.

flowchart RL
    Analyst(Analyst) -- passes account ID ----> App[Application]
    App -- returns report --> Analyst
    subgraph Application
        ComponentA[Component A] <---> App
        ComponentB[Component B] <---> App
        ComponentC[Component C] <---> App
        Mongo[MongoDB] <---> App
        API[External service REST API] <---> ComponentA
    end

"Mermaid

Diagram klas

Mermaid umożliwia tworzenie diagramów klas zgodnych z UML, tzn. definiować klasy, metody, właściwości i zależności między nimi. Za przykład posłuży mi kod, który wykorzystałem do wygenerowania diagramu klas, na potrzeby artykułu, gdzie przedstawiam wzorzec projektowy Mediator.

classDiagram
    Mediator <|-- John
    Mediator <|-- Bob
    Mediator <|-- Tom
    Mediator : -Person[] people
    Mediator: +send()
    Mediator: +addPerson()
    class John {
      -Mediator mediator
      +String name
      +receive()
      +send()
    }
    class Bob {
        -Mediator mediator
      +String name
      +receive()
      +send()
    }
    class Tom {
        -Mediator mediator
      +String name
      +receive()
      +send()
    }

Wzorzec projektowy mediator - zmodyfikowany diagram

Diagram sekwencji

Podobnie jak w przypadku diagramów klas, Mermaid umożliwia tworzenie diagramów sekwencji zgodnych z UML. Poniższy przykład również pochodzi z mojej magisterki i przedstawia sekwencję czynności w dla pomyślnej ścieżce działania aplikacji.

sequenceDiagram
    actor User as Analyst
    participant Application
    participant Controller
    User->>Application: Passes Id
    Application->>Controller: Runs
    loop Components
        Controller->>Controller: Runs all components
    end
    Controller-->>Application: Returns results
    Application-->>User: Returns report

Mermaid - diagram sekwencji

Gitgraf

Gitgraf pozwala na zobrazowanie historii commitów i struktury gałęzi w Gicie. Każdy Gitgraf tworzony jest z domyślną gałęzią main. Składnia kodu definiującego Gitgraf jest bardzo podobna do komend używanych do pracy z Gitem, dzięki czemu tworzenie Gitgrafów jesz bardzo intuicyjne. Domyślnie, każdy commit będzie generowany z domyślnym id, aby to zmienić wystarczy, nadpisać właściwość id commita. Na podobnej zasadzie można zdefiniować typ commita czy tagi. Gitgraf pozwala nawet na pokazanie cherry pickingu na grafie.

gitGraph
   commit id: "Init commit"
   commit id: "Bootstrap project"
   branch feature-1
   checkout feature-1
   commit id: "Add feature"
   commit id: "Add tests"
   checkout main
   merge feature-1
   commit id: "Release" tag: "1.0.0"

Mermaid - Gitgraf
Ten typ diagramów może przydać się w opisywaniu Git flow panującego w danym projekcie, a także w materiałach edukacyjnych. Nic nie stoi na przeszkodzie, by obrazować historię realnych gałęzi na podstawie odpowiednio przeparsowanego rezultatu z git log do formatu diagramu Mermaid, jeśli zaszłaby taka potrzeba.

Prezencja danych

Możliwości Mermaida dotyczące prezentacji danych wyglądają biednie. Do dyspozycji są wykresy kołowe, ćwiartkowe, oraz po wykonaniu pewnych akrobacji możliwe jest wygenerowanie wykresu słupkowego.

Wykres kołowy wymaga zdefiniowania elementów składowych i podania wartości numerycznych przedstawionych elementów.

pie title Node.js adoption
    "20" : 276
    "18" : 456
    "16 or older" : 89

Mermaid - Pie chart
Z kolei wykres ćwiartkowy możesz kojarzyć np. z macierzy Eisenhovera czy kompasu politycznego. Wykres składa się z osi x i y tworzących cztery ćwiartki.

quadrantChart
    title Eishenhover matrix
    x-axis Not Urgent --> Urgent
    y-axis Not Important --> Important
    quadrant-1 Do ASAP
    quadrant-2 Do later
    quadrant-3 Eliminate
    quadrant-4 Delegate
    Buy Christmas gifts: [0.3, 0.6]
    Pay rent: [0.57, 0.69]
    Book a flight: [0.78, 0.34]
    Redecorate the old bookshelf: [0.20, 0.34]
    Read Clean Code: [0.35, 0.78]

Mermaid - Quadrant chart
Mermaid domyślnie nie wspiera tworzenia wykresów słupkowych. Można jednak w tym celu wykorzystać diagram Gantta. Niestety możliwe jest wygenerowanie diagramu tylko w orientacji poziomej, a możliwości edycji takiego wykresu są ograniczone. Pokazuję ten rodzaj wykresu raczej w ramach ciekawostki niż jako realny przypadek użycia.

gantt
    title Egzamin - algorytmika - wyniki
    dateFormat  X
    axisFormat %s
    section 2
    10   : 0, 6
    section 3
    9   : 0, 9
    section 4
    8   : 0, 8
    section 5
    5    : 0, 5

Mermaid - bar chart

Wykorzystanie Diagram as a Code w praktyce — Docsify

Aby pokazać, jak można szybko przygotować zalążek dokumentacji projektowej, wykorzystam Docsify. Jest to całkiem popularny i łatwy w wykorzystaniu generator dokumentacji. Docsify wykorzystuje składnię Markdown, dzięki czemu można w łatwy sposób dodawać do dokumentacji diagramów Mermaid. Dodatkowo istnieje gotowy plugin umożliwiający renderowanie diagramów na podstawie przekazanego kodu.

Aby rozpocząć pracę z Docsify, wystarczy zainstalować docsify-cli, zainicjalizować i wystartować projekt.


npm i docsify-cli -g
docsify init ./docs
docsify serve docs

W rezultacie utworzony zostanie katalog z dokumentacją, a sama dokumentacja będzie dostępna pod adresem http://localhost:3000. Po odwiedzeniu wskazanego adresu pokaże się aplikacja typu „Hello, World”. Pojedyncza strona z dokumentacją dość szybko stanie się nieczytelna, więc na samym początku myślę, że warto dodać nawigację i dodatkowe podstrony. Aby dodać nawigację, należy utworzyć plik _sidebar.md będący definicją sidebara oraz włączyć sidebar w konfiguracji Docsify znajdującej się w wygenerowanym pliku index.html.


<script>
    window.$docsify = {
      loadSidebar: true
    }
</script>

Chcąc dodać dodatkowe podstrony, wystarczy utworzyć nowe pliki md i dodać listę z linkami odwołującymi się do nich w pliku _sidebar.md, kierującymi do poszczególnych podstron.


* [Home](/)
* [Example](example.md)

Ostatnim brakującym klockiem jest dodanie integracji Docsify z Mermaid. Konieczne będzie załadowanie Mermaid oraz skryptu z integracją. Całość sprowadza się do wklejenia kilku linijek kodu w pliku index.html. Testowałem zamieszczanie skryptu w sekcji head i na końcu sekcji body. Diagramy nie renderowały się poprawnie, jeżeli dołączenie skryptu z kodem docsify-mermaid znajdowało się przed definicją $docsify, więc przy integracji zwróć na to uwagę. W repozytorium docsify-mermaid można również znaleźć gotowy przykład integracji.


<script type="module">
    import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
    window.mermaid = mermaid;
  </script>
  <script src="//unpkg.com/[email protected]/dist/docsify-mermaid.js"></script>

Chcąc wyeliminować dodatkową zależność, możesz spróbować zaimplementować integrację Docsify z Mermaid samodzielnie, wzorując się na przedstawionej bibliotece.

Aby wyrenderować diagram w Mermaid, wystarczy dodać do pliku md code block z językiem zdefiniowanym jako mermaid.


```mermaid
graph LR
    A---B
    B-->C[Error]
    B-->D[Success];
```

Pisząc o problemach z diagramami, wspomniałem o dystansie między kodem a diagramie. Integracja Mermaid i Docsify umożliwia trzymanie diagramów bezpośrednio obok kodu. Wystarczy w dokumentacji podać ścieżkę do pliku zawierającego diagram i zdefiniować jego typ jako mermaid. W takim przypadku zalinkowany plik powinien zawierać wyłącznie kod do wyrenderowania (bez znacznika code block i dodatkowych opisów)!


[mermaid](./super/nested/folder/example.mermaid ':include :type=mermaid')

Ostatecznym rezultatem jest działająca dokumentacja z dwoma diagramami na osobnej podstronie.
Integracja Docsify z Mermaid - rezultat

Podsumowanie

Mermaid to genialne rozwiązanie, z którego korzystam na co dzień w pracy. Integracja Mermaid z popularnymi rozwiązaniami dokumentacyjnymi albo jest już wbudowana, tak jak w przypadku np. Notion, albo zajmuje dosłownie kilka minut. Czy znałeś/aś Mermaid już wcześniej? Czy znasz jakieś ciekawe alternatywy? A może jesteś fanem tradycyjnego rysowania diagramów? Tego chętnie dowiem się z Twojego komentarza! 😁

Źródła i materiały dodatkowe

Dominik Szczepaniak

Zawodowo Senior Software Engineer w CKSource. Prywatnie bloger, fan włoskiej kuchni, miłośnik jazdy na rowerze i treningu siłowego.

Inne wpisy, które mogą Cię zainteresować

Zapisz się na mailing i odbierz e-booka

Odbierz darmowy egzemplarz e-booka 106 Pytań Rekrutacyjnych Junior JavaScript Developer i realnie zwiększ swoje szanse na rozmowie rekrutacyjnej! Będziesz też otrzymywać wartościowe treści i powiadomienia o nowych wpisach na skrzynkę e-mail.

Subscribe
Notify of
guest

4 komentarzy
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Tomasz
Tomasz
1 year ago

Świetny pomysł, świetny artykuł!
Możliwe, że użyję raczej PlantUML (https://www.dandoescode.com/blog/plantuml-vs-mermaid).

Kasia
Kasia
7 months ago

Jako że post jest z października ’23, w marcu ’24 daję znać zainteresowanym, że mermaid w tej chwili już pozwala tworzyć „XY chart” 🙂