Javaパッケージ間の循環依存を検出する
※以下では結局のところ所望の結果は得られなかった。中途半端な調査なのでその旨ご了承を。
以下を記述したずっと後でJDKバンドルのjdepsを知った。これを使用した循環依存検出については/tag/depDetectを参照されたい
適当にJavaプログラムを記述していると、パッケージ間の依存が循環してしまっていることが良くあるのだが、Javaコンパイラはこれを警告してくれない。後から一部をライブラリ化しよう等と考えても、もつれあった糸をほどくのが大変になる。何かしらのツールなどは無いものか、と思って調べてみると、StackOverflowに以下の投稿があった。
Java package cycle detection: how do I find the specific classes involved?
以下、この投稿に沿って解決策を考えてみる。というよりも、ここで紹介されているツールは役にたつのだろうか?
問題点
Javaパッケージの循環依存を検出するためのツールは何が良いだろう?
classcycleやJDependは知っているのだが、両者とも循環パッケージ依存を起こしているクラスはリストしてくれない。Metricsは、循環依存の素敵なGUI表示をしてくれるが、これもまたパッケージに限られるし、非常に読みにくことがある。
もう僕は以下のメッセージがイヤになってるんだ(何のメッセージか不明)
” you have a package cycle dependency between those 3 packages
you have xxx classes in each
good luck finding the right classes and break this cycle ”
何か、実際に説明してくれるツールをしらないだろうか?つまり、関わってるクラスを指摘してくれるものだ。
FindBugs
FindBugsは循環クラス依存を検出してくれるよ。Eclipseのプラグインもある。
http://findbugs.sourceforge.net/
※Eclipse Marketplaceから簡単にインストールできる。ただし現在はSpotBugsという名前になっている。日本語マニュアルがある。
※SpotBugsの使い方についてはEclipseでSpotBugs(FindBugs)を使ってみる、その1に記述した。
Class Dependency Analyzer
Dependency Finderを試してみたが、単純な依存は素早くて役に立つが、しかし、多数のクラスにはスケールしないようだ。
実際の答えとしては、Class Dependency Analyzerだね。
これは高速で更新されており、完全に使え、クラスのGUI表現によって循環依存が表示される。夢が実現されたようだよ。
やることは、.classファイルのディレクトリを指定することだ(すべてのクラスパスを指定する必要はない)。
「Detect circular dependencies (Alt+C)」を使ってアドバイスを得ることができるが、468のクラスを分析するのに、CPUを100%も使うことはなかった(?)。
ワークスペースをリフレッシュするには、再度オープンする必要がある、クラスの新規スキャンをさせるためにね。
※使用してみたが、10分で使えないものとわかった。
Sonar
僕たちは、パッケージ循環の検出にSonarを使ってる。これは素敵な依存グラフを描画し、それが間違った方向になっているかがわかる。そこから、ソースコードにナビゲーションすることもできるよ。
https://blog.sonarsource.com/fight-back-design-erosion-by-breaking-cycles-with-sonar/を見てほしい。
※実際にはSonarQubeという名前のソフトで、それなりに巨大なソフトと思われる。CommunityEditionは無料だが、上位バージョンはかなり高価。
Structure101
https://structure101.com/はこの作業をしてくれるよ。
※有料ソフト。30日間のトライアルがある。
Highwheel
Highwheelはクラスとパッケージの循環を検出し、依存の元を報告してくれる。クラス、メソッド、フィールドレベルでの関係性だ(継承、コンポジション、メソッドシグニチャの中でなど)。
そして、大きな循環を分割し、より理解しやすく取り組み易いようにしてくれる。この出力は埋め込みSVG入のHTMLなので、最近のブラウザが必要だ。
※マニュアルが不十分で使い方は全くわからず。
CAP
※ここで紹介されたCAPはリンク切れ。
Dependency Finder
Dependency Finderを使ってみてくれ。
※どうにも使い方がわからない。