MetadataComponentDependencyAPIとPlantUMLでクラス図を作成しよう！

# はじめに
　クラス図書いてますか？私はSalesforceの導入に携わるようになってあまり書いたことがありません。（笑）
　作成しなくなった理由は、個人的な考えですが、Platformを利用しているため、ビジネスロジック部分の実装のみで、基本的な処理パターンの図を一度作成してしまえば、名前や形を少し直すだけで再利用できてしまうためだと考えています。もし、作成する必要がある場合は、他システム連携や、何か特別な実装をしている時ではないでしょうか？
　ただし、お客様によっては共通アプリケーションアーキテクチャに従って実装している機能でもクラス図を納品対象にするお客様は少なくありません。目的としては、ドキュメントをひと目見るだけで共通アプリケーションアーキテクチャに従っていない機能を検出できる以外に、プログラムの構造を把握していない人に情報を共有し、仕様変更や追加要望、障害対応時の影響調査で漏れなく確認部分を把握したいという目的があります。
　しかし、手動で作成したUMLは、詳細設計で初版を作成した後に、仕様変更や追加要望、障害対応でプログラムに修正が入る度にメンテナンスが必要で、複数のチームがシステムをリリースするために様々な作業を並行して実施している中で、精度の高いドキュメント修正に十分な工数や期間が確保できない場合が多々あり、複数の作業を掛け持ちしている開発担当者や引継ぎ担当者が修正作業すると漏れやミスが発生しやすく、いつの間にか品質が低下し納品のためだけのドキュメントとして、納品前に一人の担当者がまとめて作成することもたびたび見てきました。
　そうした中で、タイムリーにその時の組織の状態をボタン一つでUMLが生成できるようになれば、オブジェクト提議書とともに強力なツールになると考えています。ああ、前の会社でも同じことを言ってたような・・・
　今回は、Winter’19でベータ版としてリリースされた、MetadataComponentDependencyAPIとPlantUMLを使ってタイムリーに簡単にクラス図を作成します。
　実行すると下のクラス図が作成できます。（※クラス名を削除しています。）
<img width="629" alt="dependency.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/dcc2c32d-878e-2a06-c01b-7d41cc06e801.png">


# Dependency APIとは
　メタデータ間の依存関係を取得できるAPIで、Summer'18でpilot版、現在[Winter'20](https://releasenotes.docs.salesforce.com/ja-jp/winter20/release-notes/rn_api_metadatacomponentdependency_beta.htm)でベータ版になりました。
　現在、[Sandboxのみ利用できる状態](https://salesforce.stackexchange.com/questions/281806/soql-query-of-metadatacomponentdependency-dependency-api-is-not-enabled)になっており、次回のリリースで運用組織（DE組織を含む？）に拡張されるとのことです。楽しみですね。
　私が初めて知ったのは、去年の[Dreamforce'18のセッション](https://www.youtube.com/watch?v=6sIRJSdoCqo)でMetadataComponentDependencyAPIのデモが紹介されていました。
<img width="1440" alt="Dependency API" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/2c122d7b-24a1-08ae-0e1a-7157fd48cc00.png">
　そのデモでは、SFDXコマンドでMetadataComponentDependencyAPIからメタデータの依存情報を取得してDot言語に変換し、Dotコマンドでモデルを生成するデモを紹介されていました。
　見ていて「おおー！」と驚いたのが記憶に残っています。
<img width="400" alt="クラス図" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/304402c5-297d-2932-9eef-ad4f2bcd76e3.png">
　サポートされているメタデータは、Dreamforce'18の資料で古いですがのせておきます。
<img width="1440" alt="スクリーンショット 2019-12-22 18.42.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/7f2da5a7-ec6f-b88b-101c-4cf415bd5e62.png">


**参考資料**
[ToolingAPI](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_metadatacomponentdependency.htm)

# PlantUMLとは
　目で見て理解できるPlantUML用の形式で書かれたテキストファイルを読み込ませるとUMLが生成できるオープンソースのJavaのツールで、Graphviz (Graph Visualization Software) を利用しています。
[リファレンス](https://plantuml.com/ja/)

# 考慮事項
　RESTやSOAP APIを利用してクエリで情報を取得するため、検索結果の[最大取得件数：２０００件](https://developer.salesforce.com/docs/atlas.ja-jp.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_apicalls.htm)の制限があります。表示するメタデータの件数が多い場合には、MetadataComponentId項目やRefMetadataComponentId項目でクラス図で出力したいメタデータのID指定するのが有効だと考えています。
以下の条件は、ヘルプでサポートされてないとのことです。

- ORDER BY
- count()関数
- queryMore()
- WHERE句でMetadataComponentNameの利用
- WHERE句でRefMetadataComponentNameの利用
- WHERE句で=, !=, AND, or OR以外の利用
- WHERE句でRefMetadataComponentType = ‘StandardEntity’条件利用
- WHERE句でMetadataComponentType項目またはRefMetadataComponentType項目でLIKEの利用
- OFFSET

# それでは試してみましょう！
　今回は、POST MANを使用して、REST APIでMetadataComponentDependencyAPIにアクセスし依存情報を取得します。取得された情報をPlantUML用の形式に変換してクラス図を作成します。

## MetadataComponentDependencyAPIをPOSTMANから実行
　ToolingAPIを使ってMetadataComponentDependencyAPI用のクエリを実行します。

```
{Instance_URL}/services/data/v47.0/tooling/query?q=SELECT+MetadataComponentId,+MetadataComponentName,+ MetadataComponentNamespace,+MetadataComponentType,+RefMetadataComponentId,+ RefMetadataComponentName,+RefMetadataComponentNamespace,+RefMetadataComponentType+
FROM+MetadataComponentDependency+
WHERE+RefMetadataComponentType+=+'ApexClass'
```

　POSTMANで、クエリを実行すると下記のような状態になります。Body部分のJSONをコピーして[dependency.json]（任意）を作成します。
<img width="962" alt="POSTMAN" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/188883eb-e66b-d615-5f54-2d81f294222d.png">


## PlantUMLでクラス図を生成
　作業用フォルダを作成し、PlantUMLページからダウンロードしたjarと先ほどPOSTMANの取得結果から作成した[dependency.json]を配置します。そのほかの、[change.py]と[config.txt]は下記の手順で作成できます。
<img width="257" alt="スクリーンショット 2019-12-22 18.58.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/6d44de59-7e5e-8eb4-1190-66c8632c6844.png">

　Macでプリインストールされている言語の一つPython言語で、JSONからPlantUML用の形式に変換するプログラムファイルを作成します。Windowsの場合、PowerShellで書いてもイイですね！

``` change.py
import sys
import json

# Load Json File from ComandLine argument
with open(sys.argv[1], 'r') as f:
    data = json.load(f)
# Output
markuplist = ["@startuml\n\n"]
for member in data['records']:
    comp_name = member['MetadataComponentName']
    ref_name = member['RefMetadataComponentName']
    ref_type = member['RefMetadataComponentType']
    markuplist.append(comp_name + " --|> " + ref_name + " : " + ref_type + "\n")
markuplist.append("\n@enduml")
with open(sys.argv[2], mode='w') as of:
    of.writelines(markuplist)
```
　PantUML実行時の設定ファイルを作成します。

``` config.txt
skinparam backgroundColor #EEEBDC
skinparam classAttributeIconSize 0
skinparam componentStyle uml2
```

　PlatUMLは、Graphvizを利用しているため実行前にインストールします。

```
brew install graphviz
```

　PlantUML形式変換用のプログラムを実行して、読み込み用のテキストファイルを作成します。

```
python change.py ./dependency.json ./dependency.txt    
```

　PlantUML読み込み用のテキストファイルが作成されました。
<img width="1130" alt="スクリーンショット 2019-12-22 12.16.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/e345ddbe-64c2-3ae8-c3b1-55fe1fca508d.png">

　PlantUMLを実行して、クラス図を作成します。

```   
java -jar plantuml.jar -config ./config.txt dependency.txt
```

　読み込みファイルと同じファイル名のクラス図の画像ファイルが作成されました。

<img width="629" alt="dependency.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76270/dcc2c32d-878e-2a06-c01b-7d41cc06e801.png">



# 最後に
　いかがだったでしょうか？
　DependencyAPIから依存情報を取得して、PlantUMLでグラフを生成しました。
　実際に操作してみると、タイムリーに簡単にクラス図が作成できる事が実感できました。
　PlantUMLはクラス図意外にもシーケンス図などいろいろなUML図を作成できるので試してみてください。では、