未来のためにクラス図作成作業の半自動化をした話(PlantUML, PlantUML Dependency, plantuml-parser + html)

## はじめに
クラス図を書いていますか？

担当範囲のクラス数が10や20であれば、特にクラス図を書くこともなく脳内で設計を済ませて実装をすることも多いのではないでしょうか。熟練のエンジニアであればあるほど、いちいち大仰な図を書かなくても設計ができることでしょう。

ここで、プロジェクトやプロダクトのライフサイクルに視野を広げてみましょう。
仮に担当者が10人いるプロジェクトならば、一人が10や20のクラスを作成すればプロジェクト全体では100や200のクラスが存在することになるでしょう。
100や200のクラスの中には似て非なるクラスも量産されているかもしれないし、そうでないかもしれません。
**シュレディンガーの猫のようなソースコード**で、ソースを隅々まで読まない限りはまったく無用なコードがあるのかどうか分からなそうです。

神プログラマーが丹念にコードレビューを行う事で品質の均質化を図れるかもしれませんが、神プログラマーへの負荷の集中しボトルネックと化してしまうのは想像に難しくありません。場合によってはプロジェクト半ばに神プログラマーが離脱してしまうこともあるかもしれません。

このシュレディンガーのソースコードは、リリースを迎えた後に保守フェーズに移行し、製品寿命がつきるまでは破棄されずにメンテナンスされる宿命をおいます。脳内に設計図を持つ初期開発メンバーの大半は保守フェーズ移行時に解散していて **『なんとなく誰も触りたくない状態』** のまま保管されることとなります。

パッケージ製品ではなく、基幹業務のシステムやWebサービスであればリリース後も機能追加や改修がなされることが往々にしてあります。
新たな要求仕様を満たそうにも、初期開発チームは解散しています。その様なケースでは、SES（など）で傭兵の様に新たなエンジニアがランダムに招集されます。
ここで招集されたエンジニアが目の当たりにするのは、**いろいろな人間の設計思想が入り混じった100や200のクラス** です。
これを一切の事前情報もない状態で間違いなく読み取り、新たな要求仕様を満たすべく修正するには初期開発チーム以上の技術と時間が必要になります。

ただ、**『本当に必要になるかどうか分からない未来に発生する莫大なコスト』** に対して、ギリギリの予算やスケジュールの中で『必ずしも今必要ない』ドキュメントを書くことは大変難しいとは思います。

ということで(?)、今回は『クラス図はなくて本当にいいのか問題[^1]』について解決策を模索した話を書こうと思います。


## クラス図とPlantUML

クラス図を知らない方のために、以下に、PlantUML で記述したクラス図の例を示しておきます。

![2022-03-12_14h31_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/078c179c-ceeb-38b7-ca8b-838ccbd5b797.png)
(参考)[PlantUML使い方メモ](https://qiita.com/opengl-8080/items/98c510b8ca060bdd2ea3)

クラスの関係性を示した図で、**『視覚的に』** プログラムの構成を理解できる設計工程における重要な図です。
熟練の開発者であれば当然名前を聞いたこともあるでしょうし、設計の際に脳内でクラス図を描くこともしているでしょう。
実際に図を描くのにはコストがかかり、また、実装が更新されてもメンテナンスされないことも多く、**「開発現場ではあまり見かけない図面」** になっているように感じています。

結果として、初学者の職業プログラマは業務上でクラス図を見ることもなく、業務で必要な図と認知することもできない状況になっており、業務をこなしているだけではクラス設計ができるようにならないことが懸念されます。

この問題を解決するためには作図のコストの問題を解決しなければなりません。Excel方眼紙、[diagrams.net(旧draw.io)](https://www.diagrams.net/)や [AmaterasUML](https://qiita.com/takatea/items/bd1015df17a439614048)など様々なツールがありますが、図を描くのはやはりコストがかかります。
[PlantUML](https://plantuml.com/ja/)であれば、コードベースでクラスとクラスの関係性の定義のみを行えば自動でクラス図が生成されるので、大幅に作図のコストを落とせますが、以下の問題が残ります。

1. 実装に合わせてメンテナンスするのはやはり大変
2. 微妙にいい感じの図にならない
3. 『図』は ctrl + f で検索できない

よって、これらの問題の解決方法を考えていくことにしました。


## 実装に合わせてメンテナンスするのはやはり大変

実装から PlantUML ファイルを生成できれば、実装に合わせてメンテナンスを行う必要がなくなりそうです。

コマンドラインツール [PlantUML Dependency](http://plantuml-depend.sourceforge.net/command_line/command_line.html) を用いれば、ソースを解析し PlantUML ファイル(.puml) を生成できるようで、リリース時などにこのツールを実行することで、メンテナンスの問題は解決できました。

```
Examples:
	java -jar plantuml-dependency-cli-1.4.0.jar -h
	java -jar plantuml-dependency-cli-1.4.0.jar -o /home/test/plantuml.txt -b . -dp ^(?!net.sourceforge.plantumldependency)(.+)$ -v
	java -jar plantuml-dependency-cli-1.4.0.jar -o /home/test/plantuml.txt -b . -i **/*.java -e **/*Test*.java -dn .*Test.* -v
	java -jar plantuml-dependency-cli-1.4.0.jar -o /home/test/plantuml.txt -b . -i **/*.java -e **/*Test*.java -dt implementations,interfaces,extensions,imports,static_imports
	java -jar plantuml-dependency-cli-1.4.0.jar -o myoutput.txt -b "C:\Users\PlantUML test" -i **/*Test.java
	java -jar plantuml-dependency-cli-1.4.0.jar -version -v
```


## 微妙にいい感じの図にならない

長年の悩みでした。
AI()でいい感じに配置できればいいのですが、それは難しそうだったので別のアプローチを取ることにしました。

PlantUML が出力する図の不満点を考えてみると、以下２点が思いつきました。

- 設計者が脳内に描いている制約をつけられない
- 横や縦に無限に大きくなる図面が出力される

設計者の脳内は、AI()ではなく別途設定ファイルで書いてもらうとして、あとは横や縦に無限に大きくならない簡単なルールを決めればよさそうです。

実装コストも考慮して、flexbox で可能な範囲の配置ルールと簡単な設定を行える様にすることにしました。

```
配置の考え方
- flexbox で配置
- 1行に最大4パッケージ配置
- 1パッケージ内の1行に最大4クラス
    - max-width: 25%;
    - min-width: max-content;

設定の考え方
- 何段目にどのパッケージを置くかを設定
- justify-content の値も設定(省略時は center)
```

ここまで方針が決まれば後は簡単です。
[plantuml-parser](https://github.com/Enteee/plantuml-parser)を用いて、puml -> json 変換を行います。
変換した json ファイルを読み込んで js で html 上に配置すれば、後は css が勝手に見やすく並べてくれます。

html で配置までは簡単でしたが、関係性を示す線は html では多少面倒です。
業務ではあまり利用することのない svg を利用して、配置後のクラスの座標を元に線を引く様な実装とすれば比較的容易に引けました。

``` sample.js
// jQuery で svg.append({svg element}) のように直接 append 操作しても svg要素として認識されないので、
// svg タグを作る時に文字列として svg要素も一緒に作る。

const svgElements = []

...
svgElements.push(`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" class="${cls}" data-left="${leftId}" data-right="${rightId}" />`)

...
const svg = $(`<svg width="${width}" height="${height}">${svgElements.join('')}</svg>`)
container.append(svg)

```


## 『図』は ctrl + f で検索できない

前述の通り、html で作成する方針としましたので、ctrl + f で検索も可能となりました。
[DataTables](https://datatables.net/) も併用して、クラス一覧なども併記するようにしたり、`Element.scrollIntoView()` も利用して一覧で選択したクラスをクラス図上で表示するようにしたりして、だいぶ快適なクラス図が完成しました。


## おわりに

随分昔に『よりよい設計をしたい』と思いクラス図を学んだものですが、皆様はいかがでしょうか？
前述の通り描かなくなって久しかったのですが、未来を見据えると必要かなと考えさせられたのでツール作成にいたりました。

IT業界で仕事をしていると、よい設計が何かも知らないししたいとも思っていない方が大多数なのかなと感じます。
これは、よい設計を見る機会もないし、よい設計が給料に反映されているかを知る方法もないというIT業界の構造的な問題にも原因があるように思えます。

その様な状況下で、さほどコストをかけずに「よい設計」も「よくない設計」も見える化することで、自然とよい設計に近づいていける仕組みを作れたらよいなと思いました。

[^1]: クラス図のタグをつけようと思ったら、クラス図のタグがついた記事が30件しかなかった(2022/03/12時点)ことからもクラス図への関心の低さが伺えました。