かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Visual Studio Codeで自由自在にUMLを描こう

追記

私の作ったプラグインよりも、かなり出来がよさそうなものがリリースされています。 そちらを使ったほうが幸せそうです。

marketplace.visualstudio.com

本文

先日PlantUMLというテキストでUMLを描くためのツールのVisual Studio Codeのプラグインを作りました。 テキストをぱちぱち書きながら、プレビューを確認できるツールです。

okazuki PlantUML

ということで、PlantUML + Visual Studio CodeでUMLを描く方法を書いていきたいと思います。

インストール

PlantUML

PlantUMLのサイトからplantuml.jarをダウンロードして任意の場所においてください。

plantuml.com

Graphviz

PlantUMLが内部で使ってるツールです。

Graphviz - Graph Visualization Software

インストールはデフォルトのC:\Program Files(x 86)の下がいいです。 そこにインストールするとPlantUMLは、何も設定しなくても自動的に認識してくれます。 プログラムファイル以下以外にインストールした場合は、GRAPHVIZ_DOT環境変数で場所を教えてあげてください。

Visual Studio Code

ここからダウンロードしてインストールします。

Visual Studio Code

okazuki PlantUML

Visual Studio Codeの拡張機能です。

marketplace.visualstudio.com

Ctrl + Pを押してext install okazukiplantumlでインストールできます。 もっと簡単な方法は、Visual Studio Code画面左側の一番下にある拡張のアイコンをクリックしてUMLあたりで検索したら出てくるokazuki PlantUMLの所でインストールを押すだけです。

以下の環境変数を定義します。

  • JAVA_HOME: おなじみのJavaのインストールフォルダ
  • PLANTUML_HOME: plantuml.jarのあるフォルダ
  • TEMP: 定義されてない人はいないと思うけどv0.1.0から不要になりました

UMLを描こう

ということでUMLを描いてみようと思います。PlantUMLでUMLを描くときには、以下のような感じで書き始めていきます。

@startuml

ここに色々書いていく

@enduml

シーケンス図

ということで、オブジェクト間のメッセージのやり取りを描くシーケンス図の書き方を説明します。基本的にA -> B: messageの書式で書きます。

@startuml
A -> B: message
@enduml

ファイルを保存して、Ctrl + Pを押してPlantUML Previewというコマンドを実行すると、プレビューが開始されます。

f:id:okazuki:20160901203725p:plain

以下のようなシーケンス図が表示されます。

f:id:okazuki:20160901203857p:plain

矢印を点線にしたい場合はB --> A: response messageのように矢印を表す部分の-を2つに増やします。

@startuml
A -> B: message
B --> A: response message
@enduml

f:id:okazuki:20160901204027p:plain

これが基本になります。

分岐・ループ

次に分岐とループの書き方です。alt message ~ else ~ endと書くことで分岐が書けます。

@startuml
A -> B: message
B --> A: response message

alt condition
    A -> B: true case
else
    A -> B: false case
end

@enduml

f:id:okazuki:20160901204247p:plain

ループは、loop condition ~ endと書きます。

@startuml
A -> B: message
B --> A: response message

alt condition
    A -> B: true case
else
    A -> B: false case
end

loop i < 10
    A -> B: insert(i)
end

@enduml

以下のようになります。

f:id:okazuki:20160901204508p:plain

コメント

処理が複雑になってくるとコメントがほしくなってきます。 そしたらシングルクォートでコメントが書けます。複数行コメントは/' ~ '/になります。

@startuml
A -> B: message
B --> A: response message

' 分岐の書き方
alt condition
    A -> B: true case
else
    A -> B: false case
end

' ループの書き方
loop i < 10
    A -> B: insert(i)
end

@enduml

アクター・バウンダリー・エンテティー等

シーケンス図にアクターやバウンダリーなどの図形を表示することが出来ます。 例えば以下のようにA~Eまでを、actor, boundary, control, entity, databaseとして定義してシーケンス図を記述することで、上にあった矩形の形が指定したものに変わります。

@startuml
' 定義
actor A
boundary B
control C
entity D
database E

' 処理
A -> B
A -> C
A -> D
A -> E
@enduml

f:id:okazuki:20160902081801p:plain

矢印の形を変える

代表的なものとして以下のような矢印があります。

@startuml
A ->x B
A ->> C
A -// D
A -\\ E
@enduml

f:id:okazuki:20160901205307p:plain

ナンバリングをする

シーケンス図外部で処理の流れを説明するときに番号がふってあるほうが便利です。 そんなときは、autonumberと書いておくと自動的に番号がふられます。

@startuml
autonumber
A ->x B
A ->> C
A -// D
A -\\ E
@enduml

f:id:okazuki:20160901205444p:plain

ノートを追加する

付箋みたいなノートを追加することが出来ます。note left of ~ end note, note right of ~ end note, note over of ~ end noteで指定できます。

@startuml
autonumber
A ->x B
note right of 
    message1
end note
A ->> C
note over of 
    message2
end note
A -// D
A -\\ E
@enduml

f:id:okazuki:20160901205836p:plain

外部参照

処理がでかいものや共通的なものは外部を参照してくれって書きたくなりますよね。そういうときはref over A, B: messageのように書きます。

@startuml
autonumber
ref over A, B, C: 初期化処理
A -> B: 主処理
B -> C: API呼び出し
B --> A: 結果
ref over A, B, C: 後始末
@enduml

f:id:okazuki:20160901210154p:plain

ライフラインを引く

オブジェクトの生存期間を示すときは、activate XXdeactivate XXもしくはactivate XXdestroy XXを使います。

@startuml
autonumber
ref over A, B, C: 初期化処理
A -> B: 主処理
activate B
B -> C: API呼び出し
activate C
destroy C
B --> A: 結果
deactivate B
ref over A, B, C: 後始末
@enduml

f:id:okazuki:20160901210500p:plain

クラス図

次はクラス図です。

クラスなどの定義

クラス図はクラスの定義、インターフェースの定義などをして、それらの関係性を定義していくという感じになります。クラスの定義は

class Hoge {
}

のように行いインターフェースの定義は

interface IHoge {
}

のように行います。

抽象クラスの定義は

abstract class AbstractHoge {
}

のように行います。

メンバの定義

クラスやインターフェースにメンバを定義できます。書き方はアクセス修飾子 型 名前のような感じになります。アクセス修飾子は+#-~などがあります。 順にpublic, protected, private, package privateになります。

@startuml
class Person {
    -int _age
    -string _name
    +int Age
    +string Name

    +void Presentation(TextWriter w)
}
@enduml

これで以下のようなクラス図がかかれます。

f:id:okazuki:20160901211046p:plain

関連の定義

継承やコンポジションなどの関係を定義できます。--|>で継承、--oでアグリゲーション、--*でコンポジションになります。 --の部分を..にすることで破線にできます。

また、--だと縦線になり-のように1つだと横線になります。

@startuml
interface IFooable {
    + void Foo()
}

class Object {
}

class Foo {
}

class Bar {
}

class Baz {
}

Foo ..|> IFooable: なんか実装
Foo --|> Object: 自動的に継承される
Foo *- Bar
Bar o- Baz
@enduml

f:id:okazuki:20160901211702p:plain

抽象メソッドやstaticの定義

{abstract}{static}で指定します。

@startuml
class Foo {
    {static} -int counter
    {abstract} #void Hoge()
}
@enduml

f:id:okazuki:20160901211949p:plain

関連の線の横に"xxx"と書くことで、関連が1対多なんだよといった注釈をつけることが出来ます。

@startuml
class A {
}
class B {
}

A "*" -* "1" B
@enduml

f:id:okazuki:20160901212800p:plain

ノートの追加

コメントみたいなのを追加できます。note top of XXX: messageと書くかnote "message" as ノートの名前のように書きます。 ノートの名前を付けると、関連の定義で指定したような線をクラスなどに対して引くことが出来ます。

@startuml
class Foo {
}
class Bar {
}

note top of Foo: Fooの説明

note "FooとBarの説明" as NoteName
NoteName .. Foo
NoteName .. Bar

@enduml

f:id:okazuki:20160901212457p:plain

アクティビティ図

最後にアクティビティ図について説明します。 処理の流れを説明するための図なので、業務フローとかを描くのによく使われてるあいつです。

これは簡単で:処理名;を連ねていくだけで基本的に書けます。処理の開始と終了は、startstopで表します。例えば以下のような感じで書けます。

@startuml
start
:処理1;
:処理2;
:処理3;
end
@enduml

これでこんな図が出来上がります。

f:id:okazuki:20160901213048p:plain

if文を書くことで分岐を書けます。

@startuml
start
:処理1;
if (condition) then (label1)
    :処理2;
else (label2)
    :処理3;
endif
end
@enduml

とてもプログラムちっくですね

f:id:okazuki:20160901213410p:plain

elseifを使うこともできます。

@startuml
start
:処理1;
if (condition) then (label1)
    :処理2;
elseif (condigion2) then (label2)
    :処理3;
endif
end
@enduml

f:id:okazuki:20160901213530p:plain

ループ

ループはrepeatと、whileの2つが使えます。前者がdo while文で後者がwhile文にあたります。

@startuml
start

repeat
    :食べる;
repeat while (おなか一杯?)

while (おなか一杯?)
    :食べる;
endwhile

end
@enduml

f:id:okazuki:20160901213824p:plain

並列処理の記述

並列して流れる処理も記述できます。forkfork againend forkを使います。

@startuml
start

fork
    :左手で食べる;
fork again
    :右手で食べる;
end fork

end
@enduml

f:id:okazuki:20160901214017p:plain

ノートの記述

アクティビティ図もノートをおけます。note right ~ note endnote left ~ note endで書けます。floatingを最初につけることで何にも紐づいてない浮いたノートが書けます。

@startuml
start

fork
    :左手で食べる;
    note left
        口は1個じゃね?
    end note
fork again
    :右手で食べる;
end fork

floating note right
    結局口がボトルネックでした
end note

end
@enduml

f:id:okazuki:20160901214252p:plain

矢印に注釈をつける

処理の間に-> message;を挟むことで間の矢印に注釈をつけれます。

@startuml
start
:食べる;
-> 箸を持ってね;
:ひたすら食べる;
end
@enduml

f:id:okazuki:20160902145025p:plain

レーンをわける

アクティビティ図でよくあるのが、やる人が違うとレーンをわけて処理を書きます。これはレーンが変わる処理の前で|レーンの名前|と書くことで実現できます。

@startuml
|担当者|
start
:メールをしたためる;
-> Excel方眼紙をメールで添付すること;
|処理する部署|
:Excel方眼紙を印刷する;
|幹部社員|
:押印;
|処理する部署|
:PDF化;
-> 承認が下りたことを伝える(PDFをメール添付);
|担当者|
:PDFを1年間保管する;
end
@enduml

f:id:okazuki:20160902145214p:plain

まとめ

シーケンス図、クラス図、アクティビティ図の書き方を簡単にですが紹介しました。 ここにあることだけでも、結構色々表現できるようになると思います。

PlantUMLのページには、ここでは紹介しなかったような色の付け方など色々なテクニックや、ここで紹介しなかった図の書き方などが紹介されています。

plantuml.com

一度どんなことが出来るのか流し読みをしてみることをお勧めします。 流し読みしておけば、後でこういうの描きたい!って思ったときに思い出せるので。