見出し画像

『オブジェクト指向入門』ガイド(2) 顧客と供給者

前回、オブジェクト指向プログラミングの主な目的はソフトウェアの内的品質要因であるモジュール性を向上させることであると述べました。では「モジュール」とはいったい何のことでしょうか? おそらくその答えは、コンテキストによって異なると思います。この記事では、「モジュールとは、あるコードの塊である」として話を進めます。例えば一つの関数、一つクラス、一つのパッケージなどがモジュールに当たります。

依存関係とは顧客と供給者の関係である

バートランド・メイヤー博士の『オブジェクト指向入門』ではモジュールの関係性について語る際、「顧客」と「供給者」という言葉が頻繁に出てきます。供給者とはある機能や知識を提供する側のモジュールのこと。顧客とは供給者が提供する機能や知識を利用する側のモジュールのことです。例えば「給与計算」モジュールと「算術演算」モジュールがあった場合、給与計算は算術演算を利用するはずなので、以下の関係が成り立ちます。

画像1

破線の矢印については後ほど説明します。

「顧客」と「供給者」は排他的な属性ではありません。ある供給者モジュールが別の供給者モジュールの顧客になっている、あるいは顧客モジュールが別のモジュールの供給者になっていることもありえます。

画像2

さらにはモジュール同士が互いに顧客であり、供給者であることもあります。ギブアンドテイクの関係ですね。

画像3

これらの用語を確認したところで、モジュールの依存関係について考えてみましょう。あるモジュールAが別のモジュールBの顧客であるとき、「モジュールAはモジュールBに依存している」と言えます。

画像4

さきほどから描かれていた破線の矢印は、モジュールからモジュールへの依存の方向を表していたわけです。

依存関係と聞くといい印象は持たないかもしれません。ですが前回も述べた通り、オブジェクト指向プログラミングとは小さく単純な部品を組み合わせて複雑なソフトウェアを作る技法です。部品同士が協力して複雑な仕事をこなすためには、依存関係は必要不可欠なものなのです。独立した小さなモジュールだけでは大した仕事はできません。

依存関係は変更の伝播をもたらす

ただし、依存関係を扱うには注意が必要です。何かに依存するということは、それが変化した際に影響を受ける可能性があるということです。言い換えると、顧客モジュールは供給者モジュールへの変更の影響を受けるのです。

ある架空のプロジェクトで開発中のソフトウェアのモジュール群が、以下のような顧客・供給者関係を持っていると想像してみてください。

画像5

このとき、モジュールEに変更を加えてモジュールE’にしたいとします。すると、モジュールEの顧客モジュールは正常に動作しなくなる可能性があります。

画像6

それらを修正し終わったら、今度は「修正したモジュールの顧客モジュール」が正常に動作しなくなる可能性があります。

画像7

互いに顧客であり供給者である(相互依存している)モジュールがある場合、問題はさらに深刻です。依存関係が以下のようになっていた場合、どのモジュールに変更を加えるとどのモジュールに影響が出るか考えてみてください。

画像8

このように変更の影響が伝播して次々と修正が必要になるのは、眼の前の機能の実装だけを考えてコードを増やし続けたソフトウェアにありがちな現象です。重要なのは、秩序ある依存関係を構築することです。モジュール間の依存関係を可能な限り少なく、できれば単方向にすることで変更に強いソフトウェアを構築できるようになります。

画像9

オブジェクト指向はソフトウェアのモジュール性を向上させる(再度)

依存関係の数を減らすことは重要ですが、これにも限界があります。モジュールを小さく単純にすることと、依存関係の数を減らすことは相反する目標です。全ての要求を一手に引き受ける巨大な泥団子のようなモジュールを作れば依存関係の数は0になりますが、複雑度が極度に高まったモジュールはもはや拡張も再利用も不可能になるでしょう。

実はオブジェクト指向が力を発揮するのはここからです。オブジェクト指向の持つ抽象化の力を使うことで、単純な顧客と供給者の依存関係から抽象への依存という新たなステージに上がることができるようになります。「オブジェクト指向プログラミングがモジュール性を高める」というのは、つまり抽象化の力で顧客と供給者の関係をアップグレードし、モジュールの分解しやすさ・組み合わせやすさを促進するという意味なのです。このアプローチをとることで、変更の伝播を最小限に抑えることも可能になります。詳しくはまたいずれ、お話したいと思います。

余談:レイヤードアーキテクチャ

ソフトウェア設計の世界には「アーキテクチャパターン」と呼ばれるものがあります。その正確な意味を説明するのは難しいのですが、アプリケーション全体の設計に関する雛形のようなものと考えて差し支えないと思います。さきほどモジュール間の依存関係を可能な限り少なく、できれば単方向にするという指針をあげたのですが、まさにそれを実践するためのアーキテクチャパターンが「レイヤードアーキテクチャ」です。

レイヤードアーキテクチャでは構築するアプリケーション全体をいくつかの層(レイヤー)に分割し、各層の間の依存関係に厳格なルールを設けます。そのルールとは、「各層のモジュールは、自分と同じ層または自分より下の層のモジュールにしか依存できない」というもの。

画像10

どのような層を作るかは自由に考えれば良いのですが、上の例で言うとプレゼンテーション層はどこからも依存されず、ドメイン層はプレゼンテーション層からのみ依存されるようになっています。顧客と供給者の関係を思い出すと、プレゼンテーション層への変更は他のどの層にも影響を与えず、ドメイン層への変更もデータ層へは影響を与えないことが保証されますね。

これにより、変化しやすい上層の変更から、下層のコードを守ることができるようになります。また安定した層の上にコードを重ねていけるため、安全かつ高速に開発できるというメリットもあります。大規模なプログラムは巨大なジェンガのようなものだと想像してもらうとわかりやすいかもしれません。

レイヤードアーキテクチャの話題はドメイン駆動設計の文脈でもよく出てくるので、そのときは顧客と供給者の関係について思い出してみてください。近年流行りのクリーンアーキテクチャについても、顧客と供給者の関係からその意図を読み解くことができると思います。


この記事が気に入ったらサポートをしてみませんか?