Mermaidでサクッとダイアグラムを書こう

こんにちは、イオンスマートテクノロジー社フロントエンド開発チームにて開発エンジニアとして参画中の @kyappamu です。
[AEON Advent Calendar 2024](https://qiita.com/advent-calendar/2024/aeon)の10日目の記事になります。

## 対象読者
- ダイアグラムもうちょっと楽に書けるものないか探している方
- Mermaid(人魚さんではありません！)について軽く知っておきたい方

## はじめに
突然ですが皆さん、ダイアグラムは普段どんなツールで書いていますか？
私はPowerPoint, Excel, drawio, Jamboardなどを使うことが多いです。

これらのツールは自由度高く作図できる反面、
- ある程度の品質のものを作り込むまでの手間（慣れてる人は早いかもしれませんが・・）
- 出来上がったあとに発生する修正の手間（図を追加・加工したり位置を入れ替えたり...etc）

これらの課題を感じていて、もっと簡単に作図できる良い感じのツールないかなーとふと触ってみた Mermaid が個人的アタリだったので、以下では Mermaid について紹介したいと思います。


## Mermaidとは
https://mermaid.js.org/

>JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically
>
>JavaScriptベースのダイアグラムおよびチャートツールで、Markdown風のテキスト定義をレンダリングしてダイアグラムを動的に作成および変更します
>(Gemini和訳より)

Mermaid ではマークダウン風のテキストからダイアグラムを作成することができます。
コードでダイアグラムを書くようなイメージですね。
コーディングというとエンジニア向けのツール？と思われる方もいらっしゃるかもしれませんがそんなことはありません。
いくつか記法を覚える必要がありますが、意外に覚えるべきことは少なく、使い始めて数日ですがけっこうスピーディーにダイアグラム書けるなあと実感を得ています。


## 早速ダイアグラムを書いてみる

![1200.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519408/2b3057e1-54ab-6318-a2d6-96633da85940.jpeg)

それでは、いくつかサンプルを見ていきたいと思います。
以下ではシナリオとコード例、実行結果のセットで、いくつかダイアグラムを書いてみました。

### フローチャート

まずは業務フローの図示など使用場面の多い、フローチャートです。

##### シナリオ
ユーザーがウェブサイトにアクセスし、プロフィール画面で自身の情報を更新する。

<details><summary>コード例はこちら</summary>

```markdown
%%{init: {'theme':'forest','themeVariables':{'lineColor': '#ffcc99'}}}%%
flowchart TD
    %% 各フローを定義
    access["ユーザーがウェブサイトにアクセス"]
    profile["プロフィールページに移動"]
    profile_update["更新情報を入力して更新ボタンを押下"]
    profile_update_process@{shape: subproc, label: "プロフィール更新処理"}
    is_update_success{"更新成功？"}
    confirm["更新内容を確認"]
    finish["更新完了"]

    %% フローを描画
    access-->profile-->profile_update-->profile_update_process-->is_update_success
    is_update_success-->|OK| confirm
    is_update_success-->|NG| profile_update
    confirm-->finish
```

- %%{init の部分で図のカスタマイズができます（図の背景色や線の種類、色などなど）
- 指定できるパラメーターは [こちら](https://mermaid.js.org/config/theming.html) にまとめられています
- flowchart の部分は描画する図の種類を指定します。フローチャートの場合はflowchart、他には例えば円グラフの場合は、pieのように指定します
- TDはTop-downの意味で、縦書き描画になります。TB(Top to bottom)でも縦書きになります
- LR(Left to right)のような横書き指定も可能です

定義したフローを「-->」で連結し、直感的にフロー図が書けます。
詳細は以下も合わせて確認してみてください。

https://mermaid.js.org/syntax/flowchart.html

</details>


##### 実行結果
```mermaid
%%{init: {'theme':'forest','themeVariables':{'lineColor': '#ffcc99'}}}%%
flowchart TD
    %% 各フローを定義
    access["ユーザーがウェブサイトにアクセス"]
    profile["プロフィールページに移動"]
    profile_update["更新情報を入力して更新ボタンを押下"]
    profile_update_process@{shape: subproc, label: "プロフィール更新処理"}
    is_update_success{"更新成功？"}
    confirm["更新内容を確認"]
    finish["更新完了"]

    %% フローを描画
    access-->profile-->profile_update-->profile_update_process-->is_update_success
    is_update_success-->|OK| confirm
    is_update_success-->|NG| profile_update
    confirm-->finish
```




### シーケンス図

続いて、シーケンス図です。
システムやプロセスの動作の流れを、時間軸に沿って図示するような場面で使うことが多いですね。

##### シナリオ
ユーザーがECサイトで商品をカートに入れて注文し、決済完了メールを受け取る。

<details><summary>コード例</summary>

```markdown
%%{init: {'theme':'forest','themeVariables':{'signalColor': '#ffcc99', 'signalTextColor': '#b3b3ff'}}}%%

sequenceDiagram
    %% 各登場人物を定義
    participant user
    participant website
    participant database
    participant finance_system

    %% シーケンスを描画
    user->>website: 商品をカートに入れる
    website-->>user: 商品がカートに入る
    user->>website: 商品を注文する
    website->>database: 注文情報をDBに保存する
    database-->>website: 注文情報がDBに保存される
    website->>finance_system: 決済を要求
    finance_system-->>website: 決済結果
    website-->>user: 決済完了通知
```

- シーケンス図を描画する場合は、sequenceDiagramを指定します
- participantの部分で、シーケンスの登場人物を定義します
- あとは「->>」でparticipant同士を繋ぐだけで、直線を描画できます
- 「-」が一つ増えた、「-->>」でparticipant同士を繋ぐと、点線が描画できます
- 「->>」と「-->>」を組み合わせて、participant間の相互通信を表現できます

時間軸に沿ってプロセスを連ねていくことでシーケンス図が描画されます。
こちらも直感的でわかりやすいですね。
他にもループや並列処理など様々な表現ができますので詳しくは以下を見てみてください。
https://mermaid.js.org/syntax/sequenceDiagram.html
</details>


##### 実行結果
```mermaid
%%{init: {'theme':'forest','themeVariables':{'signalColor': '#ffcc99', 'signalTextColor': '#b3b3ff'}}}%%

sequenceDiagram
    %% 各登場人物を定義
    participant user
    participant website
    participant database
    participant finance_system

    %% シーケンスを描画
    user->>website: 商品をカートに入れる
    website-->>user: 商品がカートに入る
    user->>website: 商品を注文する
    website->>database: 注文情報をDBに保存する
    database-->>website: 注文情報がDBに保存される
    website->>finance_system: 決済を要求
    finance_system-->>website: 決済結果
    website-->>user: 決済完了通知
```


### ガントチャート

続いてガントチャートです。WBSを表現するのに使われる場面が多いでしょうか。
私はExcelでガントチャートを作成したことがあります。

##### シナリオ
Webサイトリニューアルプロジェクト

| タスク | 開始日 | 終了日 | 期間 |
|:-:|:-:|:-:|:-:|
| 現状のサイト分析  | 2024/11/01  | 2024/11/07  | 7日  |
| 新デザイン作成  |  2024/11/08 | 2024/11/15  | 7日  |
| 新機能開発  |  2024/11/08 |  2024/11/22 |  14日 |
| デザインと機能の統合  | 2024/11/16  | 2024/11/29  | 14日  |
| テスト実施  | 2024/11/30  | 2024/12/06  | 7日  |
| 本番リリース  | 2024/12/07  |  2024/12/07 | 1日  |


<details><summary>コード例</summary>

```markdown
%%{init: {'theme':'default','themeVariables':{'primaryTextColor': '#ffffff', 'textColor': '#b3b3ff', 'nodeTextColor': '#ffffff'}}}%%

gantt
%% 共通的な定義
title ウェブサイトリニューアルプロジェクト
dateFormat  YYYY-MM-DD
tickInterval 2week
todayMarker off

%% ガントチャート描画
section 設計フェーズ
    現状分析 :a1, 2024-11-01, 7d
    デザイン作成 :after a1, 7d
section 開発フェーズ
    新機能開発 :after a1, 14d
section 統合・テストフェーズ
    デザインと機能の統合 :2024-11-16, 14d
    テスト実施 :2024-11-30, 7d
section リリース
    リリース :2024-12-07, 1d
```

- dateFormatやtickIntervalなどでレイアウトの調整が可能です
- todayMarkerは本日日付に赤の縦マーカーが付きます（デフォルトonなので、明示的にoffを指定しなければマーカーが付きます）
- section内にタスクを定義し、タスクの開始日と期間を明記することで、ガントチャートが描画されます

ガントチャートの詳細については以下も合わせて確認してみてください。
https://mermaid.js.org/syntax/gantt.html

</details>


##### 実行結果
```mermaid
%%{init: {'theme':'default','themeVariables':{'primaryTextColor': '#ffffff', 'textColor': '#b3b3ff', 'nodeTextColor': '#ffffff'}}}%%

gantt
%% 共通的な定義
title ウェブサイトリニューアルプロジェクト
dateFormat  YYYY-MM-DD
tickInterval 2week
todayMarker off

%% ガントチャート描画
section 設計フェーズ
    現状分析 :a1, 2024-11-01, 7d
    デザイン作成 :after a1, 7d
section 開発フェーズ
    新機能開発 :after a1, 14d
section 統合・テストフェーズ
    デザインと機能の統合 :2024-11-16, 14d
    テスト実施 :2024-11-30, 7d
section リリース
    リリース :2024-12-07, 1d
```

- 文字数によってはタイトル部分が外にはみ出す（上記「リリース」の部分）、
- sectionタイトルとタスクの箱が重なる（上記「現状分析」の部分）


など、細かな調整が難しそうな面もありますが、少ない記述量でガントチャートを書けるのは魅力的に思いました。

### システム構成図

最後に、こちらも作成されることの多いシステム構成図です。

##### シナリオ
AWSを使ったECサイトの構成図

![PMWyJUDwbzhbtMEpgsBHec.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519408/e86b9ae8-fd51-b58a-d60e-e2389b9ed0d1.jpeg)


<details><summary>コード例</summary>

```markdown
architecture-beta
    %% システムにアクセスするアクター
    service user(cloud)[user]
    %% サービスを束ねるグループを定義
    group aws(logos:aws)[AWS Cloud]
    group vpc(logos:aws-vpc)[VPC] in aws
    group public_subnet[Public subnet] in vpc
    group private_subnet[Private subnet] in vpc
    group auto_scale[Auto Scaling group] in private_subnet
    %% 使用しているサービスを列挙
    service gateway(logos:aws-api-gateway)[Internett gateway] in aws
    service waf(logos:aws-waf)[WAF] in aws
    service elb(logos:aws-elb)[ELB] in public_subnet
    service ec2_1(logos:aws-ec2)[EC2] in auto_scale
    service ec2_2(logos:aws-ec2)[EC2] in auto_scale
    service ec2_3(logos:aws-ec2)[EC2] in auto_scale
    service aurora_primary(logos:aws-aurora)[aurora_pri] in private_subnet
    service aurora_secondary(logos:aws-aurora)[aurora_sec] in private_subnet

    user:B --> T:gateway
    gateway:B --> T:elb
    elb:L --> R:waf
    elb:B --> T:ec2_1
    elb:B --> T:ec2_2
    elb:B --> T:ec2_3
    ec2_1:B --> T:aurora_primary
    ec2_1:B --> T:aurora_secondary
    ec2_2:L --> R:ec2_1
    ec2_1:L --> R:ec2_3
    ec2_2:B --> T:aurora_primary
    ec2_2:B --> T:aurora_secondary
    ec2_3:B --> T:aurora_primary
    ec2_3:B --> T:aurora_secondary
    aurora_primary:L -- R:aurora_secondary
```

- architecture-betaを指定してシステム構成図を描画できます
- -betaとあるので、今後アップデートがありそうですね。デフォルトで使えるアイコンが５種類（cloud, database, disk, internet, server）と少ないので、この辺りもっと拡大されそうです
- service同士を「-->」で繋いで、service間の連携線を描画できます
- T,B,L,RはそれぞれTop,Bottom,Left,Rightの意味になりますが、
- 例えば、「user:B --> T:gateway」これで上部に配置されたuserから下部に配置されたgatewayへの連携線が描画されます。BとT逆じゃない？って感じてしまって馴染めない・・

現時点ではawsなどのアイコンを表示するには、以下のようなアイコン公開サイトから取得する必要があるようです。
例えばAWS EC2の場合、以下のように記述できます。（「logos:{アイコン名}」のように記述）
ec2(logos:aws-ec2)[EC2]

https://iconify.design/

- AWS
https://icon-sets.iconify.design/?query=aws
- Azure
https://icon-sets.iconify.design/?query=azure
- GCP
https://icon-sets.iconify.design/?query=gcp


</details>


##### 実行結果

![スクリーンショット 2024-12-06 16.07.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519408/d0336229-67a9-322d-f8ec-09c891f28a91.png)


※VSCodeの拡張機能での表示

シナリオの構成図とちょっと違うけど・・それっぽく作れます。

MermaidはGitHubやQiita,ZennやConfluenceなど、様々なプラットフォームが対応しており、コードを貼り付けるだけで描画することができます。
VSCodeでも拡張機能を入れてプレビュー表示可能です。以下に詳しくまとめていただいています。

https://qiita.com/sato_kana/items/2a13f19017576488f017

ちなみに現状、Qiitaで上記のコード例を貼り付けると？表示になってしまうようです。
Mermaidデフォルトで用意されていないアイコンはまだ表示できないようです。

```mermaid
architecture-beta
    %% システムにアクセスするアクター
    service user(cloud)[user]
    %% サービスを束ねるグループを定義
    group aws(logos:aws)[AWS Cloud]
    group vpc(logos:aws-vpc)[VPC] in aws
    group public_subnet[Public subnet] in vpc
    group private_subnet[Private subnet] in vpc
    group auto_scale[Auto Scaling group] in private_subnet
    %% 使用しているサービスを列挙
    service gateway(logos:aws-api-gateway)[Internett gateway] in aws
    service waf(logos:aws-waf)[WAF] in aws
    service elb(logos:aws-elb)[ELB] in public_subnet
    service ec2_1(logos:aws-ec2)[EC2] in auto_scale
    service ec2_2(logos:aws-ec2)[EC2] in auto_scale
    service ec2_3(logos:aws-ec2)[EC2] in auto_scale
    service aurora_primary(logos:aws-aurora)[aurora_pri] in private_subnet
    service aurora_secondary(logos:aws-aurora)[aurora_sec] in private_subnet

    user:B --> T:gateway
    gateway:B --> T:elb
    elb:L --> R:waf
    elb:B --> T:ec2_1
    elb:B --> T:ec2_2
    elb:B --> T:ec2_3
    ec2_1:B --> T:aurora_primary
    ec2_1:B --> T:aurora_secondary
    ec2_2:L --> R:ec2_1
    ec2_1:L --> R:ec2_3
    ec2_2:B --> T:aurora_primary
    ec2_2:B --> T:aurora_secondary
    ec2_3:B --> T:aurora_primary
    ec2_3:B --> T:aurora_secondary
    aurora_primary:L -- R:aurora_secondary
```


## 終わりに
Mermaid で作成できるダイアグラムの一例をご紹介しました。ここで紹介できたのはほんの一部で、他にもユーザージャーニーやクラス図、円グラフ、カンバンボードなど数多く作ることができます。

コードで書くと修正も楽です。
手動でダイアグラム書いている場合、図の位置を移動してサイズ調整して・・ってけっこう大変ですよね。（汗）

作業効率化・時短できるツールは積極的に活用して楽をしていきたいものです。
楽がしたいです。

![main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519408/53a819de-4e3e-17a2-75d3-bb0092f707f5.png)

この記事が何か少し皆さんの参考になれば嬉しいです。
明日の[AEON Advent Calendar 2024](https://qiita.com/advent-calendar/2024/aeon)のご担当は @h-ohta9999 さんです。お楽しみに！

## 参考リンク
https://mermaid.js.org/

https://qiita.com/sato_kana/items/2a13f19017576488f017

https://blog.serverworks.co.jp/learned-to-draw-architecture-diagrams-with-mermaid