web-dev-qa-db-ja.com

Javaコードをクラスタリング手法を使用してパッケージに配布する

理論的には、お互いを強く認識して使用するクラスは、(packageを使用して、他のクラスで使用されていない関数の可視性を同じパッケージに含める必要がありますしたがって、簡潔で理解しやすいインターフェースを形成します。 [よく知られているクラス(ロガーなど、ほとんどどこからでもアクセスできる)は、独自のパッケージに移動し、utilsと呼ぶ必要があります。]

コードベース 数百のJavaファイル、約6ダース以上のパッケージをかなり自由に配布し、ほとんどのメソッドがpublicと宣言されている(一部のprivate ones)、そしてクラス間の関係は不明瞭です(重要な場合、メソッドはJSFインフラストラクチャから呼び出されるため、明確なエントリポイントもありません。いくつかのmain()メソッドがあるかもしれませんが、通常未使用

このような大規模なJavaクラスのセットをパッケージにグループ化するためにクラスタリングアプローチを適用することについて誰かが考えたことはありますか?クラス間の関係の強さを次のように概説することは、これが可能かどうか、またどのようにして可能になるのでしょうか。手動でのクリーンアップ、またはコードを何らかの方法で自動的に再編成するのに役立ちます。

距離の測定には、publicの宣言に必要な関数の数、およびコードに必要なパッケージimportステートメント(.*で終わるステートメント)の数が含まれる場合があります。コンパイルする。その質問に対するアルゴリズム的に「最良の」答えは、すべてのクラスを1つのパッケージに含めることです(anyパブリックメソッドを必要としないか、これ以上インポートしません)。私が望むものではありません)、階層的クラスタリングアプローチが最良であるように思われますが(パッケージの最終的な粒度を人間の決定として残します)、おそらく私が知らないより良いアプローチがあるでしょう。

そのトピックに関する情報を見つけようとしましたが、「Java」と「クラスタリング」を検索すると、Javaでのクラスタリング実装の方法を説明するページにたどり着きましたが、これは私が探しているものではありません。 (もちろん、イントロスペクションを使用して実現できるため、Javaでもアプローチを実装できます。しかし、それは私の質問にとって重要ではありません。)

5
Matthias Ronge

このような大量のJavaクラスのセットをパッケージにグループ化するために、クラスタリングアプローチを適用することについて誰かが考えたことはありますか?

はい、それは数年前のソフトウェア(リ)エンジニアリング(より具体的にはソフトウェアの再構築)の研究でホットなトピックであり、フローネットワークカッティングアルゴリズム(構造的観点と行動的観点の両方)と他のいくつかのアプローチがあります。

いくつかの参考文献、実際にはこのトピックに関する多くの研究論文があります:

距離/類似性の他の概念も考慮されています。たとえば、同じコミットで頻繁に変更されるモジュール(クラスなど)は、時間とともに共進化する傾向があるため、互いに「近い」と見なすことができます。したがって、これらの「類似した」モジュールのクラスターを決定すると、忘れられた共進化のニーズを回避し(クラスを変更し、その関連クラスを変更するのを忘れた)、モジュール間の暗黙的な(そしておそらく望ましくない)関係を強調できます。

4
mgoeminne

私は実際にこの正確なトピックについて考えました。私が蹴ったアイデアは:

  1. プロジェクトのコードベースをグラフとして表します。
  2. 各クラスはグラフの頂点になります。
  3. Parametersで宣言された各メソッドは、Directed Edgeになります。クラスAにクラスBのタイプの入力パラメーターを必要とするメソッドがある場合、クラスAからクラスBへの有向エッジがグラフに追加されます。たとえば、メソッド(ClassA内で宣言)public void doWorkWith(ClassB b, ClassC c)を使用すると、2つの有向エッジがグラフに追加されます。
  4. 実装で使用されているがAPIレベルでは公開されていないメソッドの戻り値の型とクラスを検討しました。私がこれらをどのように処理するつもりだったかを忘れました
  5. プログラムでグラフを作成するには、Javaリフレクションを使用します。
  6. 結果のグラフで、ある種のクラスターやコミュニティー検出を実行します

また、オンラインでざっと目を通したときに、このトピックに関する情報はほとんど見つかりませんでした。とはいえ、本 Robert Martinによるアジャイルソフトウェア開発 はこのトピックについて説明しています。

これを実装しなかったのは、次の理由によります。(1)多くの作業が必要であり、(2)この方法で分析する必要のあるプロジェクトでは、グラフを「完全に分離」するのが難しい、ひどく混ざり合ったグラフになることに、多額の資金を投じます。その結果、より多くの依存性注入を使用するようにプロジェクトをリファクタリングすることに集中しました。

編集用に追加:すばやく簡単なことの1つは、インポート文の数を数えることです。大まかに言えば、何億ものインポートステートメントで始まるクラスは、改善努力の主要なターゲットです。残念ながら、これらはおそらく最も危険なクラスです。

3
Ivan

私は、パッケージ間の依存関係を最小限に抑えるためにクラスをパッケージに分離することが最善であるという基本的な仮定に同意しません。その極端なヒューリスティックに続いて、すべてのクラスが同じパッケージに含まれることになり、これは明らかにメンテナンスの悪夢です。しかし、そのような不条理な議論を使用しなくても、クラスがどこにあるべきかを決定する上で最も重要な要素は、それがチームのプログラマーがどこにあるべきかを推測できるように、パッケージに論理的に適合することです。あります。

依存関係を最小限に抑えることは良いことですが、ファサードや依存関係の逆転などの手法を、クライアントとサーバーが一緒になるようにコードを移動するのではなく、これを実現する主要な方法として使用する必要があります。

1
Jules

私はこの答えを提案しますが、実際には、これらの関係を視覚化し、リファクタリングの開始点を提供し、リファクタリングの効果を明らかにするための優れたディスカッションとツールへのポインタです。

Edmund Kirwanはこのトピックに取りつかれており、彼のサイトにはコードの構造に関する興味深い発見がぎっしり詰まっています。彼の分析ツールであるSpoiklin Soiceは彼のサイトで入手できます。

エドムンドのサイト

記事

0
WillD