何某日和

「カメラ」のち「ハンダゴテ」ところにより「プログラミング」 ── そんな私“かめきち”のウェブサイト

プログラムの性質とその計測

目次

「プログラム」の古今

 プログラムの歴史について簡単にまとめておきます。 どのような背景があって今のプログラミング技術に至ったのか、どうしてスパゲッティプログラムが発生したのかなどに注目しつつ、時代を追ってゆきます。 文献[1]を参考にしました。

職人技の時代からスパゲッティプログラムの発生まで

 それまで事務方が手で行なっていた冗長な作業を自動化すべく、急速にコンピュータが導入されたのは、ちょうど高度経済成長の頃合い。 当時の貧弱な環境の中で、如何に資源効率と計算効率を向上させるかが重要視される時代でした。 機械語に近いものを書いて処理の高速化を図ったり、同じ処理が必要になった場合にgoto文で該当行に飛ばしたり。とかく職人にしか為し得ない作業だったのです。

 しかし、コンピュータシステムの普及やシステム規模の拡大が進み、職人だけでは手が足りず、さほどに熟練していない人間にもプログラムを書くことが求められました。 さらに複雑さを増すに連れて職人技にも限界が訪れ、手のつけようのない「スパゲッティプログラム」が発生します。 保守(メンテンナンス)などできたものではありません。

構造化プログラミングの恩恵?

  • 順次・連接(Concatenation)
  • 分岐(Selection)
  • 反復・繰り返し(Repetition)

 エドガー・ダイクストラによって提唱された「構造化プログラミング」における「基本3構造」と呼ばれるものです。 「1つの入り口と1つの出口を持つようなプログラム」は、順次・分岐・反復の3構造で実現できるということと、 プログラムの機能をトップダウンに分割してゆく「段階的詳細化」の考え方を利用することで、 保守性の高い(スパゲッティではない)プログラムを作ることができるようになったのです。 かくしてシステムの肥大化に拍車がかかったと言えるかもしれません。

銀の弾丸を求めて

 やがてGUIによるドラッグ&ドロップでアプリケーション開発ができるようになったり、 プログラミングの素養がなくても作れてしまうウェブページで、HTML・JavaScript、さらにサーバーサイドのスクリプトまでも、 コピー&ペーストで開発されるようになってしまいました。 構造化プログラミングのイロハもわきまえないままオブジェクト指向へ走り、かと思えばLL(Lightweight Language)に走り...。

 かつて議論されたはずの様々な知見も蔑ろにされ、「もっと楽に、もっと簡単に開発できる方法はなんだ」と、銀の弾丸への信仰が行なわれ、 それでも決定的な打開策もないまま現在に至ります。


[1] WEB+DB PRESS Vol.33 p.9-18 構造化プログラミング入門 第1章 羽生章洋 技術評論社 2006

[2] "Go To Statement Considered Harmful" Edsger W. Dijkstra  Communications of the ACM Vol.11 No.3 p.147-148

プログラムの良し悪し

「良いプログラム」とは何か

 一言に「良いプログラム」と表現する事は容易いのですが、その言葉の意味するものは、具体的にどのようなプログラムなのでしょうか。 文献[3]を調べてみたところ、「良いプログラム」という言葉そのものの説明は少なく、 代わりに以下のようなフレーズがよく現れました。

  • 実行効率の良いプログラム
  • 移植性(ポータビリティ)の良いプログラム
  • 見通しの良いプログラム
  • 使い勝手の良いプログラム
  • 反応の良いプログラム
  • 依存性が少なく良いプログラム
  • 可読性の良いプログラム
  • 保守性の高い良いプログラム
  • 気持ちの良いプログラム
  • ...

 プログラミングに従事する人間であれば、多くは「良いプログラムを書きたい」と思うはずです。 ところが、その「良い」の定義を具体的に考えてみると、実は非常に多様で、立場や場面が異なればその定義は変わってしまいます。 つまり、一概に「プログラムの良し悪し」について議論することができないのです。

 ただ、逆に立場や場面が決まれば「良いプログラム」が定義できるということでもあります。 現場のプログラマなら、保守性の高いプログラムを「良いプログラム」と呼ぶでしょうし、 その上司なら、生産性の高いプログラムを「良いプログラム」と呼ぶでしょう。 はたまたクライアントなら、要求どおりに動いてくれるプログラムを「良いプログラム」と呼ぶはずです。 (そもそもクライアントは、プログラムについて議論しないかもしれませんが。。。)

 もし、メトリクスツールで「良いプログラム」を示そうとするのであれば、上のような色々な立場を網羅すべく、あらゆる指標値を表示することになりましょう。 あるいは、特定の立場に特化したメトリクスツールを拵えることになりましょう。 むむ、「使いやすい(Usable)」と「役に立つ(Useful)」の狭間に立っているようですね。 その両立を実現できないものでしょうか。。。 (特別研究II 座学 [2012.07.11] - 使い心地がよいを参照)

本研究おける定義

 結論から述べると、本研究では「プログラムの良し悪し」について、一般的かつ一義的に定義することは避けようと考えています。 何が「良いプログラム」で、何が「悪いプログラム」なのかは、メトリクスツールを用いるユーザ自身(あるいはその分野の専門家)が一番よく知るはずですから、 敢えて私自身が無理なこじつけで「良し悪し」を定めることもないでしょう。 研究にしては非常にラフな捉え方ではありますが、このように捉えることで、 本研究で提供するメトリクスツールの柔軟性(ユーザによる指標選択・写像方法選択の自由)を実現できるのです。

 しかし、本研究の第一義は、可食化というアプローチによって有効な情報提示ができるかどうかを検討すること。 これを果たすには、やはり適切な指標設定をしなければ実験・検討もできませんので、非常に限定的な範囲における「プログラムの良し悪し」の定義を定めた上で、 必要な実験及び検討を行います。なお、用いる指標に関する具体的な説明は、別項「スパゲッティへの写像」をご覧下さい。


[3] 雑誌「Software Design」および「WEB+DB PRESS」

既存のメトリクスツール

 既に存在するソフトウェアメトリクスツールがどのようなものかを調べるべく、実際にツールを二種類ほど使ってみました。 いかにして情報を提示しているのか、またどのような工夫が施されているのか、といった点を重点的にまとめておきます。

Source Monitor

 まず、Source Monitor[4]というメトリクスツールです。 C++、C、C#、VB.NET、Java、Delphi、Visual Basic(VB6)、HTMLといった言語について計測が可能で、今回は試しにJavaのプログラムを解析してみました。

メトリクス結果1(Source Monitor) メトリクス結果2(Source Monitor) メトリクス結果3(Source Monitor)
メトリクス結果4(Source Monitor)

十数種類の指標値を表示するとともに、クラスごとにグラフによる可視化が施されています。

Eclipse Metrics Plugin (by Frank Sauer)

 次に試用したのは、Eclipse Metrics Plugin[5]です。 これは、Eclipseと呼ばれる開発環境で用いることのできるメトリクスのプラグインで、ある記事[6]を参考に導入・試用を行いました。 計測対象は、先のSource Monitorと同じようにJavaのプログラムとしました。

メトリクス結果1(Eclipse Metrics plugin) メトリクス結果2(Eclipse Metrics plugin) メトリクス結果3(Eclipse Metrics plugin)

 プラグインを導入して設定を済ませると、ウィンドウ下部にメトリクス結果を表示するエリアが出現します。 ビルド可能な状態にある場合は、その場ですぐに解析を行なってくれるようで、問題のあるクラスを赤字で表示しています。 計測結果も扱いやすいようにまとめられており、また開発環境に統合されていることもあり、非常に使い勝手の良いメトリクスツールだと感じました。
 3つ目の画像は、パッケージ間の依存関係を図で示しているものです。今回の解析対象があまりに単純だったため効果は薄いですが、 より複雑になれば、この図示は有意義だと思います。パッケージをドラッグアンドドロップで移動させることもできるので、 パッケージ間の依存関係を簡単に把握することができそうです。
 また、解析結果をHTML形式で保存することも可能です。

二つの例を踏まえて

 たった二つの例を見ただけで言えることは高が知れているかもしれませんが、どちらもやはり「数値の提示」や「グラフの提示」を冗長に行なっているに過ぎません。 結局このプログラムはどうなの??と問われても、このような結果提示の方法ではとても容易には答えられません。あまり直感的でないのです。

 前節の「プログラムの良し悪し」で触れた通り、プログラムの評価というのは、様々な立場の人が様々な側面で行うもの。 ある立場の人は、ある指標を見て、そのプログラムの良し悪しを判断します。また別の立場の人は、別の指標を見て、その良し悪しを判断します。 つまり、こうした様々な立場に対応すべく、ありとあらゆる指標値を提示するのでしょう。

 しかしながら、「役に立つ」こと(つまり機能追加)に注力しており、使いやすさは後回しにされているようにも感じられます。 Eclipse Metrics Pluginは、パッケージの依存関係を図示してくれる点で、随分良いと思いますが、 まず指標値の一覧を前に出している部分がいただけないと感じるのです。ユーザに対して「操作・見方の熟練」を強いていることに他なりませんので。 (指標値が表すプログラムの性質を理解しているのであれば、つまり指標値の見方に長けておれば、問題ないのですが、そうでないユーザにとっては錯乱の原因にもなりかねません。)


[4] SourceMonitor V3.3 - http://www.campwoodsw.com/sourcemonitor.html

[5] Metrics 1.3.6 (Eclipse Metrics plugin (by Frank Sauer)) - http://metrics.sourceforge.net/

[6] Eclipseで使えるメトリクス計測ツール:豊富にメトリクスを計測:Eclipse Metrics Plugin(Frank Sauer)- @IT - http://www.atmarkit.co.jp/fjava/rensai3/eclipsetst03/eclipsetst03_2.html

プログラムの指標(既存の指標)

 前節で取り扱ったメトリクスツールや、その他文献に記載されている「プログラムの指標」をここにまとめます。 ただし、それぞれの指標値は計測システムの違いによって規則の異なる場合があるようです。

メトリクスツール「Resource Standard Metrics (RSM)」における指標

 メトリクスツール「Resource Standard Metrics」のウェブサイトに掲載されている指標の一覧から引用しています。(説明文に誤訳がある場合があります。)

指標名説明
LOCLines of Code。コードの行数。SLOC(Source LOC)とも。計測の規則も様々で、以下にはその例を幾つか掲載する。関数毎・クラス毎・パッケージ毎で計測する。
Effective LOCeLOCとも。空行・コメント行・括弧だけの行を除いてカウントした数値。
Physical LOC物理LOC。ソースファイルに記載されいているプログラムの行数をそのまま計測した数値。
Logical LOC論理LOC。lLOCとも。プログラムにおける文(statement)の数を表す数値。1行に複数文書かれている場合も文の数だけカウントする。
Comments Linesコメントの行数。
Blank Lines空行の行数。
FP (LOC由来)LOCの値から算出したFP(Function Point:ファンクションポイント)値。機能数とその複雑さによって算出した数値。
Number of Input Parameters引数の数。
Number of Return Points関数が戻る場所(return)の数。
Interface ComplexityInput Parameters + Return Points。インタフェースの複雑さ。
Cyclomatic Complexity循環的複雑度。線形独立な経路の数。循環の数 + 1。
{Functional, Class, Namespace/Package} ComplexityInterface + Cyclomatic。
Average, Maximum, Minimum関数ごとのLOCについて算出する平均値・最大値・最小値。
Number of Data attributes属性(フィールド)の数。アクセス修飾子(public, private, protected)毎に数え分ける。
Number of Methods操作(メソッド)の数。アクセス修飾子(public, private, protected)毎に数え分ける。
Number of Functions関数(メソッド?)の数。クラス毎・パッケージ毎で計測する。
Depth of Inheritance Tree継承の階層数。
Number of Classesクラス数。
Number of Base Classes基底クラス(親クラス)の数。
Number of Derived classes派生クラス(子クラス)の数。
Derived/Base Class Ratio派生クラス数と基底クラス数の比率。派生クラス数÷基底クラス数で求める。
{Maximun, Average} Inheritance Depth継承の階層数の最大値・平均値。
{Maximun, Average} Number of Child Classes子クラス数の最大値・平均値
Average functions per classクラス毎の関数(メソッド)数。
Comment and White space percentagesプログラム中のコメントや空白が占める割合。
Average Character line length1行の文字数の平均値。
Memory Allocation and De-allocation metricsメモリの動的確保及び解放を行なっている箇所の数。
Language Keyword use利用している予約語(キーワード)の数。
Language Construct use利用している言語構造の数。(PHPのprintやexitのようなもの。)
Extract Comments per file for understandability rating and spell checkingコメントの理解しやすさとスペルチェック。
Extract Strings per file for spell checking文字列のスペルチェック。
Metrics differentials between two file version2バージョンのファイルについてメトリクス結果の比較を行う。
Total C, C++ and Header FilesC, C++のソースファイル及びヘッダファイルの総数。
Total Java FilesJavaのソースファイルの総数。
Total Number of Files総ファイル数。

指標のリストはウェブページ[7]を、 指標の説明はウェブページ[8]を参照しました。

メトリクスツール「Source Monitor」における指標

 以下の指標群は、Javaのプログラムを解析にかけた場合のものです。指標名と実測値からその意味を類推しているので、誤記が存在するかもしれません。

指標名説明
Lines空行を除いた行数を表す数値。
Statementsセミコロンで終わる文と、クラスやメソッドの定義文の合計を表す数値。
% Branchesおそらく、Statements中に存在するif文の割合を表す数値。
Callsメソッド呼び出しの回数を表す数値。
% Commentsコメントが占める割合。
Classesプログラム中のクラス定義数(内部クラス数を含む)を表す数値。
Methods/Classメソッド数とクラス数の比率。メソッド数÷クラス数で算出する。
Avg Stmts/Method1メソッドあたりの平均Statements数。
Max Complexityおそらく、各メソッドのCyclomatic Complexityのうち、その最大のものを表す数値。
Max Depthおそらく、{ }(ブロック)の最大ネスト数。
Avg Depthおそらく、{ }(ブロック)の平均ネスト数。
Avg Complexityおそらく、各メソッドのCyclomatic Complexityの平均値。

メトリクスプラグイン「Eclipse Metrics Plugin」における指標

指標名説明
NORMNumber of Overridden Methods。オーバーライドしているメソッドの数。
NOFNumber of Attributes (Field)。属性(フィールド)数。
NSCNumber of Children。子クラス数。
NOCNumber of Classes。総クラス数。
MLOCMethod Lines of Code。メソッドのLOC。
NOMNumber of Methods。メソッド数。
NBDNested Block Depth。ブロックのネスト数。
DITDepth of Inheritance Tree。継承の階層数。
NOPNumber of Packages。パッケージ数。
CAAfferent Coupling。依存しているパッケージ外のクラス数。
NOINumber of Interfaces。インタフェースの数。
VGMaCabe Cyclomatic Complexity。循環的複雑度。
TLOCTotal Lines of Code。コードの行数。
RMIInstability。(パッケージの)不安定性。Ce / (Ca + Ce)で算出する。
PARNumber of Parameters。引数の数。
LCOMLack of Cohesion of Methods。あるクラスの凝集性の欠如を表す。小さいほど凝集度は大きく、メソッドの強度が高いことを表す。
CEEfferent Coupling。依存しているパッケージ内のクラス数。
NSMNumber of Static Methods。スタティックメソッド(クラスメソッド)の数。
RMDNormalized Distance。
RMAAbstractness。パッケージの抽象度。全クラス及びインタフェース中の抽象クラス及び抽象インタフェースの割合。
SIXSpecialization Index。クラスの特殊化指標の平均値。NORM * DIT / NOMで算出する。
WMCWeighted methods per Class。あるクラスに定義されているメソッドのCyclomatic Complexityの総和。大きいほど複雑であり、メンテナンスのコストがかかることを示唆する。
NSFNumber of Static Attributes。スタティックフィールド(クラスフィールド)の数。

指標の説明は、ウェブページ[9][19]を参考にしました。

その他の指標

指標名説明
NOANumber of Attribute。NOFに同じ。
NCVNumber of Class Variables。クラス変数の数を表す。NSFに同じ。
NIVNumber of Instance Variables。インスタンス変数の数を表す。
NCMNumber of Class Methods。クラスメソッドの数を表す。NSMに同じ。
NIMNumber of Instance Methods。インスタンスメソッドの数を表す。
NOCNumber of Children。サブクラスの数を表す。NSCに同じ。大きいほどサブクラスへの影響力が強く、メンテナンスに注意が必要であることを示唆する。
CBOCoupling between Objects。あるクラスに関係しているクラスの数を表す。大きいほど他のクラスに依存していることを表し、複雑でメンテナンスコストがかかることを示唆する。
RFCResponse for a Class。あるクラスに関係しているメッセージの数を表す。大きいほど発信しなければならないメッセージが多いことを表し、複雑なクラスであることを示唆する。
HFHierarchy Factor。あるクラスの抽象性(具体性)を計測した値。0の場合は、そのクラスがインヘリタンス(クラス階層)の一番上に位置することを意味し、階層を下がるにしたがって1に近づく。0に近いほどクラスの抽象性が高く、再利用性が良好であることを示唆する。
RFReference Factor。あるクラスの全体性(部分性)を計測した値。クラスの相互参照関係(半順序)のどのあたりに位置するのかを表す。他のクラスを参照する割合が大きいほど1に近づき、0に近いほどクラスの独立性が高く部品として使われる可能性が高いことを示唆する。
PFPolymorphism Factor。あるクラスの多相性(一義性)を計測した値。クラスが所有するメッセージが、他のクラスの所有するメッセージとどのくらい重なっているのかを表す。1に近づくほどメッセージが重なっていることを示し、ポリモーフィズムが有効に働いている可能性を示唆する。0に近づくほどメッセージが統一されていないことを示唆する。
CPClass Popularity。あるクラスの人気度を計測した値。人気の高いクラスほど、他のクラスから利用されていることを表す。人気の高いクラスが集中しているほど、依存しているクラスが統一されていることを表し、良好なプログラムであることを示唆する。
MPMessage Popularity。あるメッセージの人気度を計測した値。CPと同様で、人気の高いメッセージが集中しているほど、発信されているメッセージが統一されていることを表し、良好なプログラムであることを示唆する。
走行時間プログラムの走行時間。ベンチマークテストにも。

文献[11][12][13]を参考にしています。

 「プログラム」ひとつに、これだけ多くの切り口があるのだということを垣間見ることができました。 ただ、指標値の種類がこれほどあると「このうちのどれを見て何がわかるのか、どれを見るのが最適化」といったことが、なかなか見えて来ません。 一つのメトリクスツールで、一度にたくさんの指標値を提示すれば便利かもしれませんが、ユーザ(メトリクスを行う人)はその全ての数値を参考にするわけではありません。 ゆえに、必要のない指標値は(視覚情報のノイズでしかありませんから)表示すべきではないと思うのです。


[7] Source Code Metrics (RSM Metrics) - http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics.htm

[8] Metrics Definitions (RSM Metrics Narration) - http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm

[9] Metrics 1.3.6 - http://metrics.sourceforge.net/

[10] Eclipseで使えるメトリクス計測ツール - @IT - http://www.atmarkit.co.jp/fjava/rensai3/eclipsetst03/eclipsetst03_2.html

[11] Shyam R. Chidamber and Chris F. Kemerer, "A Metrics Suite for Object Oriented Design," IEEE Transactions on Software Engineering, Vol.20, No.6, pp.476-493, 1994.

[12] Shyam R. Chidamber and Chris F. Kemerer, "Towards a Metrics Suite for Object Oriented Design," OOPSLA'91 Proceedings, pp.197-211, 1991.

[13] 「オブジェクト指向システム分析設計入門」 青木 淳 - ソフト・リサーチ・センター 1993

新しい指標の検討

 前節に記載した既存の指標を踏まえ、他に考え得る新しい指標を検討します。 (特にスパゲッティへの写像に使えそうなアイデアがあれば尚良し...)

  • 絡み具合・縺れ具合
    • 大域変数の「単純な出現数」or「参照(get)数」or「変更(set)数」 など...
  • 玄人っぽさ・素人っぽさ
  • 継承したメソッドの数・属性の数(つまりスーパークラス(祖先)たちのメソッド数・属性数)
  • 変数名・関数名・ファイル名などの各種名称(その人気度や命名規則)
  • スペースやインデントの空け方
  • 括弧の位置取り(GNU形式、Apache形式など)
  • 書き方の統一感
  • コメントの書き方
  • 変数を使いまわすか否か