NBM2

natural born minority

CircleCIとPlantUMLで「リバースしたClass図を常時生成」する

おそらくですが「もっと苦労しなくともできるものがある」…とは思うので、教えて欲しいのですよね。

経緯っぽいの

DDDが関係する勉強会に行ってる時に、ふと思ってつぶやいたんです。

とか言うと、関西におけるDDD実践者で著名な @haljik さんから…

と来まして、 なんだかんだあって

みたいになったので「20秒くらいで出来へんかな?」と思って、やってみました。

説明

コンセプト

最初から「こうしたい」って決めてたのは…

  • タダであること
  • 真似すりゃ簡単にできること

です。(だってそうでないと俺自身が出来ないんだものw)

もちろん目指すのは、タイトルどおり、

  • CIするたびにリバース・エンジニアリングして依存性を示したClass図が常時吐き出される

です。

前提

こんなJavaプロジェクトがあるとします。

CircleCIの設定ファイル circle.yml は、

machine:
  java:
    version: openjdk8

程度で、ほぼ何も仕込んでないです。

これを例に「リバースしたClass図を常時生成」できないか、をやって来ます。

やったこと

使う道具

要件は

  • (Linixの)コンソールから出力命令を実行できること
  • 出力された図は特殊なビューアを必要としないこと

と(自分に)課します。

昔はなんかあった気がするのですが、今は「有料の統合ツールを買う」か、以下の

くらいしかググっても出てきません。

上記ツールだけでは「テキスト(DSL)を書けばpngのクラス図が出せる」だけなのですが、別途「JavaからPlantUMLのテキストファイルを生成できるツール、

を組み合わせれば「コンソールからテキストをリバース -> 画像化」できます。

お試し

まず、 plantuml-dependency-cli ですが、こちらから tgz をダウンロードして、解凍します。

その後出てきたJarを使って、目的のディレクトリと出力ファイルを指定、実行してみます。

java -jar plantuml-dependency-cli-1.4.0-jar-with-dependencies.jar \
  --basedir './src/main/java//com/github/kazuhito_m/odf_edit_sample/domain' \
  -o test.pu

すると…s test.pu にそれっぽいのが出てきます。

@startuml
annotation java.lang.Override
class com.github.kazuhito_m.odf_edit_sample.domain.user.User
class com.github.kazuhito_m.odf_edit_sample.domain.workresult.WorkResultDay
class com.github.kazuhito_m.odf_edit_sample.domain.workresult.WorkResultRow
class com.github.kazuhito_m.odf_edit_sample.domain.workresult.WorkResults
class com.github.kazuhito_m.odf_edit_sample.domain.workresult.report.WorkResultReportMaker
class com.github.kazuhito_m.odf_edit_sample.infrastructure.fw.util.DateUtils
class com.github.kazuhito_m.odf_edit_sample.infrastructure.fw.util.OdsUtils
class java.io.File
class java.io.IOException
...

この出力されたファイルを plantuml を使って画像出力させてみます。

こちら から、Jarをダウンロードし、実行します。

java -jar plantuml.1.2017.13.jar test.pu

すると、対になる test.png という画像ファイルが生成されます。

画像を出してみた結果

馬鹿でかいのでわかりにくいかもしれませんが、「JavaのAPI」や「フレームワークのクラス」まで依存が描かれてるのは邪魔ですね。

テキスト加工してjava.org.削除してみましょう。

ちょっとアレンジ

おお、これならいい感じかも。

設計

  1. CIでテストが成功したらクラス図生成をする
  2. 出力したクラス図はCircleCIへビルドごとに「成果物」として保存
  3. ツールはWebから常時落とす
  4. どのパッケージをリバースするかは設定ファイルで指定出来る
  5. 除外するものを(文字一部一致で)設定ファイルで指定できる
  6. 上記を邪魔に成らない程度にスクリプトでプロジェクトに置いとく

くらいにしといたら、使いやすいでしょうかね。

作ったもの

スクリプトやらもろもろ

プロジェクト直下に .purc なディレクトリをつくり、そこにスクリプトなりを一式置いてみました。

.purcとは

plantuml-reverce-class-diaglam.sh がメインのスクリプトで、

#!/bin/bash

# どこから呼ばれても同じ挙動をする様に
scriptDir=$(cd $(dirname $0);pwd)
cd ${scriptDir}

# 共通関数読込、設定ファイル読みこみ
source ./functions.sh
source ./setting.conf

# 作業ディレクトリ作成
outDir=./class-diagrams
workDir=./work
clearDir ${outDir}
clearDir ${workDir}

cd ${workDir}

# plantuml-dependency-cli をダウンロード
wget https://sourceforge.net/projects/plantuml-depend/files/1.4.0/plantuml-dependency-cli-1.4.0-archive-with-bundled-dependencies.tar.gz
tar xzf plantuml-dependency-cli*.tar.gz
mv ./plantuml-dependency-cli*/plantuml-dependency-cli-*.jar ./plantuml-dependency-cli.jar

# plantuml 自体をダウンロード
wget https://sourceforge.net/projects/plantuml/files/1.2017.13/plantuml.1.2017.13.jar
mv plantuml.*.jar plantuml.jar

cd ${scriptDir}

for targetPackage in $(cat ./target-package.list) ; do
  targetDir=`echo ${targetPackage} | sed 's/\./\//g'`
  lastPackageName=`basename ${targetDir}`
  targetFile=${outDir}/${lastPackageName}.pu

  # PlantUMLのクラス図ファイルへリバース
  java -jar ${workDir}/plantuml-dependency-cli.jar --basedir ../${SRC_DIR}/${targetDir} -o ${targetFile}

  # 作成されたファイルを加工
  for ignoreWord in $(cat ./ignore-words.list) ; do
    rowDelete ${targetFile}  ${ignoreWord}
  done

  # クラス図テキストファイルから、画像へ。
  java -jar ${workDir}/plantuml.jar ${targetFile}

done

makeHtml './target-package.list' ${outDir}

てな感じで、ダウンロード->テキストリバース->画像化してます。

サービスで画像を一覧出来るHTMLなども吐いてみました。

target-package.list は「対象指定ファイル」で、

com.github.kazuhito_m.odf_edit_sample.domain
com.github.kazuhito_m.odf_edit_sample.application

のようにパッケージ指定で除外、

ignore-words.list は除外設定ファイルで、

java.
org.

のように「除外したいクラス・パッケージの一部」を書けば除外出来るようにしています。

CircleCIの設定

circle.yml は以下のようなカタチにしています。

machine:
  java:
    version: openjdk8
test:
  post: # PlantUMLのクラス図の画像を生成・保存
    - sudo apt-get install -y graphviz
    - ./.purc/plantuml-reverce-class-diaglam.sh
    - cp -r ./.purc/class-diagrams $CIRCLE_TEST_REPORTS/

テストが成功した後に、スクリプトを実行し、CircleCIの「成果物(Artifacts)」に成果フォルダごとコピーします。

PlantUMLの実行には、本体Jar以外に graphviz が必要なので、直前にインストールしています。

(CircleCIのコンテナのデフォルトはUbuntuっぽい何からしいです)

実行すると…

テスト成功、CI完了後に、画面中 Artifacts をクリックすると、クリックすると、成果物が保存されています。

CircleCIのArtifacts

index.html をクリックすると、こんな感じ。

CircleCIのArtifacts

でもですね…

やった! …のですが、いろいろアカン感じがありまして…

  • 同一パッケージ内のクラス依存は線を引いてくれない
  • パッケージ階層のネストは考慮してくれない
  • フィールド・メソッドは考慮してくれない

というのが見て取れます。

例えば、今回解析した domain パッケージは、

今回の例

という構成で、 PlantUML 的に頑張れば、

本来のカタチ

と言うような表現が出来るのですが…こうなってはくれません。

これは plantuml-dependency-cli のリバース能力の限界だと思います。

(多分、javaファイルのimport部からしかテキスト的に拾ってきてるだけなのでしょう。 * 指定とかすると拾えなくなりますし。)

ここはもう こういうの を使って自力でツール作ったらエエかな、と考え始めてます。

インストール?

使いたい方が居ましたら、 ここ から

.purc/
circle.yml

だけコピーし、 .purc/ の中の設定ファイルを変更してください。

小並感

ちょっと故あって CircleCI で行いましたが、もちろん我らがJenkinsでも同じことが出来ます。

また、「CircleCIの成果物」というとこは、常時何かで通知するor意識しないと観に行くことが少ないと思われるので、現場で使う際は「ポータルサイト」や「Wiki」などにアップしたらよい感じかなぁと。

でも、やっぱり「もっと簡単に出来る手段」がある気がするので、なんかあれば教えてくださいませ。

blog comments powered by Disqus