進化するアーキテクチャーと新方式の設計

メトリックによる新方式の設計

コードのなかに隠れている設計を見つけて改善するために、メトリックと視覚化を利用する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: 進化するアーキテクチャーと新方式の設計

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:進化するアーキテクチャーと新方式の設計

このシリーズの続きに乞うご期待。

新方式の設計における難問の 1 つは、コードのなかに潜んでいるイディオムのようなパターンや他の設計要素を見つけ出すことにあります。そこで役立つのが、メトリックと視覚化です。メトリックと視覚化を利用することで、コードの重要な部分を特定し、これらの部分をファーストクラスの設計要素として抽出できるようになります。この記事で注目するメトリックは、循環的複雑度 (CC: Cyclomatic Complexity) と求心性結合の 2 つです。循環的複雑度は、あるメソッドの別のメソッドに対する相対複雑度を測る手段であり、もう一方の求心性結合は、対象とするクラスを使用している他のクラスの数を表します。この記事を読んで、両方のメトリックを視覚化し、理解するために使用できるツールについて学び、メトリックを組み合わせることによって設計特性を明らかにする方法を覚えてください。

循環的複雑度については「Test-driven design, Part 2」で取り上げましたが、このメトリックにはその記事では説明しなかった多少の考慮が必要な部分があります。Java™ ツールによる循環的複雑度の測定を複雑にしている要因のひとつに、作業単位があります。循環的複雑度はメソッド・レベルの測定値ですが、Java プログラミングでの作業単位はクラスです。そのため、循環的複雑度の測定値は一般に、クラスに含まれるすべてのメソッドの複雑度の合計値あるいは平均値として出されます。どちらの測定値にも、興味深い意味があります。

この両方の測定値に関するシナリオとして、以下のような例が考えられます。例えば、あるクラスのなかに 1 つの極めて複雑なメソッド (CC = 40) があるだけでなく、その他にも多数のごく小さなメソッド (Java コードに共通の get/set メソッドのペアなど) があるとします。このメトリックをすべてのメソッドの合計としてレポートする JavaNCSS (「参考文献」を参照) などのツールで循環的複雑度を測定すると、その結果はクラス全体の合計値として非常に高い数値になります。一方、循環的複雑度をクラスの平均値としてレポートする Cobertura などのツールを使用すると、このクラスの測定値はそれほど高くなりません。多数の単純なメソッドによって、極めて複雑なメソッドの分の値が償却されるためです。この作業単位の不一致から考えると、循環的複雑度の測定値については、合計値と平均値の両方を調べるのが妥当と言えます。それぞれを別個のものとして考えてしまうと正しい結果として得られなくなる可能性がありますが、両方の数値を使用することで、その可能性は軽減されます。

設計に関係するもう一方のメトリックは、遠心性結合と求心性結合という 2 つの結合についての数値です。遠心性結合では、対象とするクラスが参照する別のクラスの数を測定します。これは単純な検査によって簡単に判断することができます。つまり、当該クラスを開き、そのクラスが (フィールドおよびパラメーターで) 他のクラスを参照している数を数えればよいだけのことです。遠心性結合に比べ、求心性結合は判断するのが難しい一方で、極めて有用な情報を提供します。求心性結合で測定するのは、対象とするクラスを使用している他のクラスの数です。この数を判断するには、コマンドライン fu を使用することも、あるいはこのメトリックを認識するツールのいずれかを使用することもできます。そのようなツールの一例は ckjm で、これは、Chidamber/Kemerer オブジェクト指向のメトリック一式を実行するオープンソースのツールです (「参考文献」を参照)。稼働させるまでの作業は少し複雑ですが、このツールは循環的複雑度 (クラスに含まれるすべてのメソッドの循環的複雑度の合計としてレポート) と、遠心性結合および求心性結合の数値の両方を提供します。

これらの数値をすべて取得したら、その結果が、特に設計の観点で何を意味するのかを考えてみてください。メトリックとして生成された数値が提供するのは、コードについて 1 つの側面だけからとらえた情報です。大抵の場合、数値自体はそれほど意味を持ちません。メトリックから有益な情報を引き出すには 2 つの方法があります。その 1 つは、特定の値が時間とともにどのように変化するかを調べ、傾向を特定することです。あるいはもう 1 つの方法として、メトリックを組み合わせることで、情報密度を充実させます。それが、この記事でこれから説明する方法です。

メトリックと設計

このシリーズでは、いくつもの記事で Struts コード・ベースを責め立ててきましたが、それは私が Struts に対して反感を抱いているからではなく、これがよく知られたオープンソース・プロジェクトだからです。まじめな話、Struts の世界のコードを見てください。そのほとんどから、魅力に欠けた設計特性を見つけられるはずです。Struts を話題に出したところで、今回も引き続き Struts を使用して私の考えのポイントを説明することにします。

ckjm の出力はテキストです。テキストは、XML に変換することができます (さらに、XSLT による各種の変換により、XML から他のフォーマットに変換することもできます)。図 1 に、複数の ckjm メトリックの組み合わせを示します。この図に示されている WMC (Weight Methods per Class) が、クラス内メソッドの循環的複雑度の合計で、Ca が求心性結合です。

図 1. 表形式での ckjm メトリックの結果
ckjm メトリックの結果を示す表
ckjm メトリックの結果を示す表

図 2 に、上記と同じ表を WMC (Weight Methods per Class) でソートした場合を示します。

図 2. WMC でソートされた ckjm メトリックの結果
WMC でソートされた ckjm メトリックの結果
WMC でソートされた ckjm メトリックの結果

この結果だけで判断すれば、DoubleListUIBean が Struts コード・ベースで最も複雑なクラスであるということになります。これが意味することは、リファクタリングによって複雑さを軽減し、抽象化可能な繰り返しのパターンをクラスの中に見つけられるかどうかを調べるには、このクラスが有力候補であるということです。ただし WMC 値からは、設計の改善を目的にこのクラスのリファクタリングに時間をかけることが有効であるかどうかはわかりません。このクラスの Ca を見てみると、このクラスを使用する他のクラスは 3 つしかありません。これはつまり、このクラスの設計を改善するために多くの時間を費やす価値はないことを示しています。

図 3 に、同じ ckjm の結果を今度は Ca でソートした場合の表を示します。

図 3. 求心性結合でソートされた ckjm メトリックの結果
Ca でソートされた ckjm メトリックの結果
Ca でソートされた ckjm メトリックの結果

このようにソートされた表からは、Struts のクラスのうち、他のクラスに最も使用されているのは Component であることがわかります (Struts が Web フレームワークであることを考えれば、これは当然です)。Component は DoubleListUIBean ほどには複雑でないものの、このクラスは 177 の他のクラスによって使用されるため、設計を改善するには有力な候補です。Component の設計を改善すれば、他の多数のクラスに波及効果がもたらされます。

WMC と Ca の組み合わせは、図 3 に提供された情報の意味を読み取る方法として最適です。この2 つを組み合わせることによって、コード・ベースのなかでどのコードが重要なのか、そしてどのコードが複雑なのかを 1 つの表で同時に確認することができます。コード・ベースについて予備知識が何もないとしても、この表を見れば、どのコードを作業の対象にすれば最善の結果をもたらす可能性があるかを判断することができます。その判断は絶対確実であるとは言えないものの、大量のコードをただ見るだけで引き出すことのできる情報よりも、この表から得られるコード・ベースに関する情報のほうが遥かに充実しています。

数値によるメトリックはコードを理解する上での手掛かりとなりますが、その数値はかなり下位レベルのものであるため、特定のクラスに関する情報は提供しても、コード・ベースの全体像についての情報はほとんど提供しません。現在は、視覚化という方法によって、メトリックを次のレベルに引き上げるための多数のツールが用意されています。

メトリックの視覚化

メトリックを視覚化することにより、特定の側面を個別に検討することも、まとめて検討することもできるようになります。Smalltalk コミュニティーは、これまでかなりの数のメトリックの視覚化ツールを作成してきました (このような視覚化を可能にするための Moose というプラットフォームまで作成したほどです。「参考文献」を参照してください)。Smalltalk コミュニティーが開発したメトリック手法の多くは、Java プログラミングにマイグレーションされています。

iPlasma と業界標準

循環的複雑度に関してよくある質問には、「自分が作成したコードを他のコードと比較するにはどうすればよいのか?」、「ある特定のクラスに望ましい数値は何か?」というものがあります。これらの質問に答えるのが、iPlasma プロジェクトです (「参考文献」を参照)。iPlasma プロジェクトは、オブジェクト指向設計の品質評価を目的に、ルーマニアの大学プロジェクトとして作成されたプラットフォームです。iPlasma が生成するピラミッドには、プロジェクトの重要なメトリックと、これらの数値に対する業界の標準範囲との比較が併せて表示されます。

iPlasma を実行するときには、ソース・コードのディレクトリーを指定します。すると iPlasma が処理して、図 4 に示すようなメトリックのピラミッドを生成します。この図には、Struts 2.0.11 のコード・ベースを基に生成されたピラミッドが示されています。

図 4. iPlasma によるメトリックのピラミッド
iPlasma によるメトリックのピラミッド
iPlasma によるメトリックのピラミッド

このピラミッドをどのように解釈するのかをいったん理解すれば、ここには豊富な情報が詰め込まれていることがわかります。各行に示されている色分けされたパーセントの値は、その行の数値と、その下の行の数値の比率から算出されます。表 1 に、図に示されている数値が何を表しているのかを図の上から順に説明します。

表 1. iPlasma ピラミッドの内容
コード説明
NDD直接の子孫の数
HIT継承ツリーの深さ
NOPパッケージの数
NOCクラスの数
NOMメソッドの数
LOCコードの行数
CYCLO循環的複雑度
CALLメソッドあたりの呼び出し数
FOUTファン・アウト (ある特定のメソッドが呼び出す他のメソッドの数)

数値は比率を示し、色は、その比率が業界の標準範囲 (多数のオープンソース・プロジェクトを基に算出された範囲) のどのあたりに収まるかを示します。各比率の色は、緑 (範囲内)、青 (範囲未満)、赤 (範囲超過) のいずれかとなります。Struts コード・ベースの場合、NDD と CYCLO が、これらの数値に対する業界の標準範囲を上回っており、LOC と NOM が範囲を下回っています。ここで使用されている範囲を表 2 に記載します。

表 2. iPlasma のメトリックに対する業界の標準範囲
CYCLO / 行0.160.200.24
LOC / メソッド71013
NOM / クラス4710
NOC / パッケージ61726
CALLS / メソッド2.012.623.20
FANOUT / 呼び出し0.560.62 0.68

iPlasma はまた、生成したピラミッドに基づくアドバイスも生成します。iPlasma の表示では、このアドバイスはピラミッドのすぐ下に示されます。Struts の場合のアドバイスは、図 5 のとおりです。

図 5. iPlasma のアドバイス
iPlasma のアドバイス
iPlasma のアドバイス

iPlasma が生成する数値は、いくつかの目的に役立ちます。第一に、これらの数値を使用すれば、コード・ベースを複数の側面で他のコード・ベースと比較することができます。そして第二に、これらの数値から、コードの簡潔さと設計の改善に労力を費やしても良さそうな場所がわかります。例えば Struts の場合、iPlasma は継承ツリーがかなり深くなっていること、そしてメソッドが複雑になり過ぎている傾向があることを示しています。ただし、これらの数値は背景を踏まえて理解しなければなりません。Struts のような Web フレームワークは、かなり複雑な階層になりがちです。したがって、NDD の数値は、おそらく懸念するにはあたらないでしょう。その一方、CYCLO (循環的複雑度: CC) の数値は背景とは全く関係なく、極めて高い値になっており、メソッド・レベルで設計に問題がある可能性を示しています。

比較のために、図 6 に Vuze プロジェクトの場合の iPlasma ピラミッドを示します。Vuze は、Java 言語で作成されたオープンソースの BitTorrent クライアントです (「参考文献」を参照)。

図 6. Vuze の場合の iPlasma ピラミッド
Vuze の場合の iPlasma ピラミッド
Vuze の場合の iPlasma ピラミッド

Vuze は大規模なプロジェクトであることから (500,000 行を超えるコード)、継承ツリーの深さ、各クラスのメソッド数、メソッドあたりのコードの行数、メソッドあたりの呼び出し数に関して設計に問題がある可能性があります。

依存関係

新方式の設計には、コード内での相互関係やコード全体の抽象的な概要を見通せることが必要となっています。このようなコード全体にわたる概念をソース・コードから理解しようとするのは、目隠しされた人が手で触れるだけで、今触っているものが象であることを理解しようとしている、かの有名な姿を思い起こさせます。象の各部はそれぞれ別の何かのように思えるにもかかわらず、手で触るだけではあまりにも局所的で、全体像をとらえることはできません。

クラスやオブジェクト間の依存関係を判断する際にも、これと同じような局所性の問題が障害となります。iPlasma などのツールを使用すれば、コードの全体的な特性の要約を理解することができますが、これらのツールは、調査すべき特定の場所を示してくれません。幸い、他のツールを使用すれば、さまざまな光を当てるなかでそれが象であることを理解できるようになります。

Smalltalk コミュニティーが Moose プラットフォームをベースに作成した CodeCrawler というツール (「参考文献」を参照) は、クラスのサイズやメソッドの長さなどの複数のメトリックを使ってコードをグラフィカルに表現します。CodeCrawler に Java コードを処理させるようにすることは可能ですが、それにはかなり厄介な作業が伴います。幸い、その作業に挑戦する必要はありません。X-Ray プロジェクトがその作業をすでに終わらせているからです (「参考文献」を参照)。

X-Ray は、コードの全体的な構造を理解できるようにコードを視覚化し、数種類のグラフを生成する Eclipse プラグインです。生成されるグラフには、クラス間の依存関係を示す円グラフもあります。図 7 は、Struts の場合の円グラフです。

図 7. X-Ray によるクラス依存関係の視覚化
X-Ray によるクラス依存関係のビュー
X-Ray によるクラス依存関係のビュー

円周上にある各要素がクラスで、2 つのクラスを結ぶ線によって、そのクラス間の依存関係が示されています。線の太さは、依存関係の強さを表しています。クラスをクリックすると、そのクラスに関する情報が表示され、ダブルクリックすると Eclipse エディターにそのクラスが開きます。もちろんこのビューには、役に立つと言うにはあまりにも多くの情報が溢れているのは確かです。しかしありがたいことに、個々の線が見えるように、ズームインすることもできます。太い線は、クラス間の依存関係 (遠心性結合) が強いことを示しています。つまり、2 つのクラスがあまりにも密接に関連しているとしたら、それは設計上の欠陥を意味する可能性があります。

X-Ray には、パッケージ依存関係についても同じようなビューが組み込まれています (図 8 を参照)。

図 8. X-Ray のパッケージ依存関係のビュー
X-Ray のパッケージ依存関係のビュー
X-Ray のパッケージ依存関係のビュー

全体的な構造

X-Ray には、同じく CodeCrawler をベースに有益なコードの視覚化を行うもう 1 つのビューがあります。それは、システム複雑度のビューです。このビューにはコード・ベースがグラフとして表示されます。このグラフでは、継承階層がトップ・ダウン型ツリーとして表示され、そのボックスのサイズがクラスに含まれるコードの行数、ボックスの幅がメソッドの数を表します。図 9 に、このビューでのシステム複雑度を視覚化したものを示します。

図 9. X-Ray のシステム複雑度のビュー
X-Ray のシステム複雑度のビュー
X-Ray のシステム複雑度のビュー

このビューはまた、他のクラスに対する呼び出し (遠心性結合) をピンクの線で、他のクラスからの呼び出し (求心性結合) を赤の線で示します。クラス依存関係やパッケージ依存関係のビューと同じく、いずれかのボックスをクリックすると、該当するクラスが Eclipse に表示されます。このビューでは、コードを読むだけでは理解するのが難しい、独特の視点からの見方が示されます。このビューで、ある側面を基準にフィルタリングして、詳しい調査が必要なコードの部分を絞り込むことができるようになれば、その特定の側面に関する設計上の欠陥を発見するのは容易な作業となるはずです。

まとめ

X-Ray と iPlasma は、Java コードに使用できる視覚化ツールのほんの一例にすぎません。これらのツールを賢く使用することで、プロジェクトのコードに埋もれて隠れている設計の側面に、素早く焦点を絞り込めるようになります。新方式の設計を可能にする鍵の 1 つは、イディオムのようなパターンを見つけ出すことです。コードのパターン (優れているものも、あまり適切でないものも) を見つけやすくするツールによって、調査の作業を大幅に省き、その分、より多くの時間をコード改善のためのリファクタリングに費やせるようになります。


ダウンロード可能なリソース


関連トピック

  • プロダクティブ・プログラマ ――プログラマのための生産性向上術』(Neal Ford 著、オライリー・ジャパン、2009年): この本で、このシリーズで取り上げるいくつもの話題を詳細に解説しています。
  • Chidamber & Kemerer object-oriented metrics suite: ckjm ツールで利用しているこのメトリック一式について、詳しく学んでください。
  • CodeCrawler: これは、Smalltalk のメトリック視覚化を提供するプロジェクトです。X-Ray ツールでは、このプロジェクトを Java メトリック用に実装しています。
  • Moose: Moose は Smalltalk メトリックおよび可視化のための環境で、CodeCrawler のベースとなっています。
  • Object-Oriented Metrics in Practice』(Michele Lanza、Radu Marinescu 共著、Springer、2006年): CodeCrawler の作成者 (Lanza) が共著者として書いたこの本で、オブジェクト指向メトリックを詳しく調べてください。
  • Vuze: この記事では、Vuze BitTorrent クライアントのコード・ベースも例として使用しました。
  • developerWorks Java technology ゾーン: Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。
  • JavaNCSS: このコマンドライン・ユーティリティーは、Java 言語のソース・コード・メトリックを測定します。
  • ckjm: ckjm は、Java コードを対象とした Chidamber/Kemerer オブジェクト指向のメトリック一式の結果を生成するオープンソースのツールです。
  • iPlasma, An Integrated Platform for Quality Assessment of Object-Oriented Design: iPlasma をダウンロードしてください。
  • X-Ray: CodeCrawler のオープンソース Java バージョンをダウンロードしてください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=477860
ArticleTitle=進化するアーキテクチャーと新方式の設計: メトリックによる新方式の設計
publish-date=03042010