技術文書をコードで書く、UML実行環境を作る@Windows

# この記事は
あなたの現場、文書はどうやって書いてますか？
エクセル？しかもエクセル方眼ですって？うーん、実を言うと私もたくさんそういう現場を歩いてきたけど、いい加減もうやめたい。と思っているんですよね。どうでしょう？
マークダウンはいいですね、でも図が必要なときってどうしてますか？もうすこし表現力のあるツールが必要だと感じるときはありませんか。

そこで、扱ってみようと思うのがUML（統一モデリング言語）。ER図、クラス図、ネットワーク図といった構成面の設計から、フローチャート、シーケンス図といった手順の設計まで全てコードで表現できる言語規格です。

今回はUMLの中でもPlantUMLという言語をVisual Studio Code(VSCode)で使うための環境をWindows/WSLでセットアップします。PlantUMLの動作にはJavaとGraphvizが必要なのですが、これらをWindows環境や既存のWSL環境には入れたくないので新たにWSLインスタンスを作って、そのインスタンス上に環境を立ててVSCodeから繋ぐ、という趣旨の記事です。

# おことわり
コピー元のWSLのインスタンスは人によって異なる可能性があります。

私もコピー元のWSLのインスタンスにいくつかインストールしてあるコマンドがあります。例えば手順の中でnanoエディタを使っているのですが、デフォルトだと入っていないかもしれません。（覚えていません…）
なるべく環境に依存しないように書いていますが、インスタンス内でのunixコマンドに関しては入っていなければ代替のコマンドを利用するかコマンドをインストールしてください。

# 基礎知識
## VSCodeでPlantUMLを書くために必要なもの
VSCodeには"PlantUML"という拡張機能があり、この拡張機能1個でOKです。ただし、実際にUMLが実行されてグラフが描画される為にはPlantUMLを実行するためのJavaとGraphvizが環境にインストールされている必要があります。

## WSLの基礎知識
WSLはWindows上で仮想環境を動かすためのMicrosoft公式のアプリケーションです。それなりに前からあるアプリケーションですが、2020年辺りでインストール方法がかなり改善されて導入しやすくなっているので、なるべく新しい記事で導入方法を調べる事をお勧めします。

WSL1と2があり互換性がありません。現在の標準はWSL2で、1はレガシーです。本記事内では断りがない限りWSL2のことをWSLと表記していますし、他の新しい記事でもその傾向があります。

WSLには環境の設計図になるディストリビューション（distro）と、それを使って作られた環境であるインスタンス、という2つの概念があります。Dockerでいえばイメージとコンテナ、AWSでいえばAMIとインスタンスです。標準的なディストリビューションはMicrosoftから配布されておりUbuntuが一般的に使われています。

ディストリビューションはDockerイメージ等と少々異なるところがあって、ディストリビューションファイル1つに対してインスタンス1つしか生成できないようです。ですのでインスタンスを複数作る場合はディストリビューションファイルも複製が行われます。

## VSCcodeがWSL環境で動く仕組み
VSCodeは通常立ち上げるとローカル環境でしか動きません。この状態では、例えばgitがローカル環境に入っていない場合、WSL環境にgitが入っていてもgitは使えません。また、保存したファイルはローカル環境のフォルダに保存されます。

しかし、VSCodeは別の環境とリモート接続することで、リモート接続先の環境でファイルを保存したりコマンドを実行したりできる拡張機能があります。SSHで接続するリモートサーバに繋ぎたい場合は"Remote SSH"、今回のようにWSLと繋ぎたい場合は"Remote WSL"をインストールします。どちらも入っている"Remote Development"というパッケージもあります。

# 手順
さあやるぞ。
## WSLディストリビューションをエクスポートして複製する
PlantUML用のWSLインスタンスを作るためにディストリビューションを複製します。で、配布されているUbuntuを複製したらいいのでは?と思うのですが、どうやらそういった方法は現状存在しないようです。ですのでUbuntuから作られたインスタンスを一旦ディストリビューションとしてエクスポートして、それを更に複製インポートする、という手順を踏みます。

なお、エクスポート時には元のインスタンスが停止するので、インスタンスで実行途中の作業がないか注意してください。

まずはPowerShellを立ち上げて、wslコマンドを確認しておきましょう。
```
wsl.exe --help
// wsl --helpでもOK。以降は.exeを省略。
```

次に、現時点で存在するWSLを確認します。
```
wsl --list --verbose
// wsl --list --allでもインスタンスの一覧は確認可能だが、
// 稼働状態などは--verboseでないと見えない
>   NAME                   STATE           VERSION
* docker-desktop-data    Running         2
  Ubuntu-20.04           Running         2
  docker-desktop         Running         2
```

Ubuntu-20.04をコピーして使いたいので、Ubuntu-20.04をエクスポートします
```
wsl --export Ubuntu-20.04 C:\Users\ming\ExportedWslDistro\Ubuntu-20.04
// 最後の引数はディストリビューションファイルの保存先。
```

Ubuntu-20.04-Javaという名前で複製インポートします
```
wsl --import Ubuntu-20.04-Java C:\Users\ming\ExportedWslDistro\Ubuntu-20.04-Java C:\Users\ming\ExportedWslDistro\Ubuntu-20.04
```

ディストリビューションの複製と同時に新しいインスタンスも生成されます。確認しましょう。
```
wsl --list --verbose
>   NAME                   STATE           VERSION
* docker-desktop-data    Running         2
  Ubuntu-20.04-Java      Stopped         2
  Ubuntu-20.04           Stopped         2
  docker-desktop         Running         2
```

## デフォルトユーザーを調整する
WSLを最初にインストールしたときには流れでデフォルトユーザーを設定していると思いますが、インポートしたインスタンスにはそのデフォルトユーザーが引き継がれません。デフォルトユーザーはVSCodeでも利用されるので確実に設定しておきましょう。

元のインスタンスで作成されたユーザーの情報はコピーされているので、ユーザー自体が存在するかは/etc/passwdを見れば確認できます。

ひとまず、新しいインスタンスにログインしましょう。
```
wsl -d Ubuntu-20.04-Java
```

```
// @WSL Ubuntu-20.04-Java

less /etc/passwd
// 一番後ろに書かれているのが新しく作られたユーザーで、普通WSLではIDが1000:1000
```
※以下、エクスポート元でユーザー設定済みであり、IDが1000:1000のユーザーが存在している前提で話を進めます

/etc/wsl.confを作ります。（既にある場合、追記になります）
```
nano /etc/wsl.conf
```

デフォルトユーザーをmingに変更する場合、以下のような設定内容になります。
```
[user]
default=ming
```

wsl.confを作成したらインスタンスを再起動します。
インスタンスにログイン中のシェルからexitしてしばらくすると止まりますが、サッサと再起動させたい場合は
```
// @PowerShell
wsl --terminate Ubuntu-20.04-Java
// 止まったか確認
wsl --list --verbose
// 再ログイン
wsl -d Ubuntu-20.04-Java
```

ログインユーザーがrootから設定したデフォルトユーザーに変更されているのを確認してください。

## コピー元インスタンスから複製された不要ファイルを削除する
コピー元インスタンスでファイルを作っていた場合、ディストリビューションファイルの複製に伴ってインスタンス内のファイルも複製されています。ディスクを圧迫するするしコピー元と紛らわしくなるので、新しいPlantUML用のインスタンスで使わないファイルは削除しておきましょう。

## PlantUMLの動作環境を整備する
新しいインスタンスの中にPlantUMLの動作環境として必要なソフトウェアをインストールします。
```
sudo apt update
sudo apt -y install default-jre graphviz
// Javaの方は以下のコマンドでインストール確認が可能
java --version
> openjdk 11.0.15 2022-04-19
OpenJDK Runtime Environment (build 11.0.15+10-Ubuntu-0ubuntu0.20.04.1)
OpenJDK 64-Bit Server VM (build 11.0.15+10-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing)
```

## VSCodeでPlantUML用WSL環境にUMLファイルを作成してプレビューする
VSCodeに"Remote WSL"がインストールされていない場合、拡張機能タブから"Remote WSL"または"Remote Development"を検索してインストールします。インストール完了したらコマンドパレットに"new WSL window using distro"と入力して、PlantUML用に作成したインスタンス名（例ではUbuntu-20.04-Java）を選択します。

選択するとPlantUML用インスタンスで作業できる状態になるので、拡張機能で"PlantUML"をインストールします。なぜかインストールが完了しても"build failed"と表示されるのが気になりますが、この状態でも特に問題はなさそうです。

あとは実際にサンプルファイルを作成してプレビューを確認してみましょう。以下のコードはPlantUMLのサイトからシーケンス図のサンプルを拝借しています。

```
@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml
```

ショートカットキーAlt+Dでプレビューウィンドウを開き、AliceとBobがリクエストとレスポンスをやり取りする図が表示されればOKです。

# 終わりに
ひとまずUMLを書くための環境がセットアップされました。環境ができただけなのでUMLの書き方に慣れる必要がありますし、大体の現場では結局「エクセルしか使わん！」とか「パワポで書け！」みたいな話が多いかと思いますが、ちょっと新しいことも取り入れてみようかという人が増えてくれたらよいのではないかと思います。

他業界から来た間隔を率直に言えば、正直IT業界（少なくとも日本の）は決して先進的な業界ではありません。ゆでガエルになるのは怖いですよ。