Robert C. Martinは、興味深い 記事 を執筆しました。その内容は、設計内のサブシステム間の相互依存という観点から、オブジェクト指向設計の品質を測定するために使用できる一連のメトリクスに関するものです。
モジュール間の相互依存について、彼は記事の中で次のように述べています:
What is it that makes a design rigid, fragile and difficult to reuse. It is the interdependence of the subsystems within that design. A design is rigid if it cannot be easily changed. Such rigidity is due to the fact that a single change to heavily interdependent software begins a cascade of changes in dependent modules. When the extent of that cascade of change cannot be predicted by the designers or maintainers the impact of the change cannot be estimated. This makes the cost of the change impossible to estimate. Managers, faced with such unpredictability, become reluctant to authorize changes. Thus the design becomes rigid.
そして硬直性に対抗するために、求心性結合、遠心性結合、抽象度、不安定度といったメトリクスを紹介しています。
求心性結合(Afferent Coupling): このプロジェクト外の型のうち、このプロジェクト内の型に依存している型の数。
遠心性結合(Efferent Coupling) このプロジェクトの型によって使用されている、このプロジェクト外の型の数。
遠心性結合と求心性結合は、名前空間や型にも適用できます。たとえば、特定の型の遠心性結合は、その型が直接依存している型の数です。TypeCeが非常に高い型は、多すぎる他の型に依存しています。そのような型は複雑で、一般的に複数の責務を持っています。
抽象度
内部の抽象型(つまり抽象クラスとインターフェース)の数を、内部の型の総数で割った比率。このメトリクスの範囲は0から1で、A=0は完全に具象的なプロジェクト、A=1は完全に抽象的なプロジェクトを示します。
A = Na / Nc
Where:
A = abstractness of a module
Zero is a completely concrete module. One is a completely abstract module.
Na = number of abstract classes in the module.
Nc = number of concrete classes in the module.不安定度
遠心性結合(Ce)を結合の総数で割った比率。I = Ce / (Ce + Ca)。このメトリクスは、変更に対するプロジェクトの耐性を示す指標です。範囲は0から1で、I=0は完全に安定したプロジェクト、I=1は完全に不安定なプロジェクトを示します。
I = Ce/(Ce + Ca)
I represent the degree of instability associated with a project.
Ca represents the afferent coupling, or incoming dependencies, and
Ce represents the efferent coupling, or outgoing dependencies抽象度対不安定度グラフと「苦痛の領域」
例として、C++ POCOライブラリの抽象度対不安定度グラフを示します。

このグラフの背後にある考え方は、プログラム内で広く使用されているコード要素ほど、より抽象であるべきだというものです。言い換えると、具象実装に過度に依存するのではなく、抽象に依存してください。ここで言う人気のあるコード要素とは、プログラム内の他のプロジェクトから大規模に使用されるプロジェクトのことです(この考え方はパッケージや型にも適用できます)。
コードベース全体で広く使用される具象型を持つのは良い考えではありません。これによりプログラム内に「苦痛の領域」が生まれ、実装を変更するとプログラムの大部分に影響する可能性があります。そして実装は抽象よりも頻繁に進化することが知られています。
上図の主系列線(点線)は、抽象度と不安定度をどのようにバランスさせるべきかを示しています。安定したコンポーネントは左側に配置されます。主系列を確認すると、そのようなコンポーネントは望ましい線の近くに位置するために非常に抽象的であるべきだと分かります。一方、抽象度が低い場合、「苦痛の領域」と呼ばれる領域に配置されます。
OOPアプローチを使用する場合、硬直性にどう対抗するか?
Robert C. Martinが記事に書いているように、プロジェクトの柔軟性を高め、コード要素間の強い結合を減らすためには、抽象クラスとインターフェースを使用する必要があります。
OOPで結合が生じる原因は次のとおりです:
- 継承:OOPパラダイムを採用する際に過剰に使われることが多く、残念ながら多くの場合、コードをより硬直化させます。継承によって生じる硬直性を解決するには、いくつかのデザインパターンが有用です。たとえばAdapterパターンは、継承によって生じる硬直性を最小化します。
- 具象実装の直接使用:この場合もコードは硬直化します。何らかの理由で別のライブラリやフレームワークを使用する必要が生じたときに、変更が困難になるからです。継承と同様に、硬直性を最小化するためのデザインパターンがあり、BridgeやProxyなどがあります。
OOPアプローチを使用する場合は、GoFの構造パターンを習得することが推奨されます。これらは、結合によって生じる硬直性を減らすのに役立ちます。
