見出し画像

『オブジェクト指向入門』ガイド(3) 再利用可能なモジュール

前回はモジュール同士の依存関係、すなわち「顧客と供給者」の関係性について書きました。今回はオブジェクト指向プログラミングが促進するという「モジュール性」について、もう少し詳しく見ていきたいと思います。第一回で述べたとおり、モジュール性とはソフトウェアの内的品質要因の一つであり、拡張性と再利用性を総合したものです。モジュールの依存関係の話は、主に拡張性に関連の深い話でした。今回は再利用性について考えていきます。

バートランド・メイヤー博士の『オブジェクト指向入門』ではモジュール性を測る基準として、「分解しやすさ」「組み合わせやすさ」「分かりやすさ」「連続性」「保護性」の5つが提示されています。今回着目するのは、このうち最初の二つです。

モジュール分解の二つの手法

大きく複雑なソフトウェアを小さく単純なモジュールで表現する方法について、本の中では二つの手法が示されています。ひとつはソフトウェアの機能をトップダウンで分解する方法です。例としてシミュレーションRPGのバトルシステムを取り上げてみます。ユニットが別のユニットにダメージを与える処理を書いていると想像してください。この処理をトップダウンで分解するなら、以下のようなツリー状になるでしょう。

画像1

それぞれのモジュールはサブルーチンであり、それらとは別に「ユニットデータ」や「装備品データ」のようなオブジェクトがあるかもしれません。

もう一つの手法はモジュールをボトムアップで積み上げるやり方です。こちらはまずバトルシステムを構成するのに必要な要素(概念)を考えて、それらの要素同士のネットワークによって機能を実現していきます。

画像2

それぞれのモジュールはオブジェクトであり、ロジックはオブジェクト自身に内包されます。「ユニットにダメージを与える」というのも、ユニットの持つ振る舞いの一つになるでしょう。

どちらも「分解しやすさ」の点では理にかなった手法であるように思われます。しかし『オブジェクト指向入門』では、モジュール性を高めるためにはトップダウンの機能分解は不適切であるとされています。それは、この手法が「組み合わせやすさ」の基準の達成に寄与しないためです。

コンテキストを超えた組み合わせ

一度分解したモジュールを再度組み合わせられるのは当然のように思えますが、より「組み合わせやすい」とはどういうことでしょうか? 以下、メイヤー博士の定義を抜粋します。

ある手法が、もともと開発されたのとは全く異なる環境においても、互いを自由に組み合わせることにより、新しいシステムを製作できるようなソフトウェア要素の生産を助けるならば。その手法は「モジュールの組み合わせやすさ」を満たす。

ここでいう「環境」というのは、いわゆるプログラムの実行環境のことではなく、機能の文脈(コンテキスト)と捉えて良いでしょう。つまり、最初に分解した機能の文脈においてだけでなく、別の文脈において、既存のモジュールを組み合わせることで新たな機能を構築できる可能性がある場合、そのモジュールは「組み合わせやすい」と言えるわけです。

この性質を持たせるためにはモジュールを出来る限りもとのコンテキストから独立させる必要があるのですが、メイヤー博士はトップダウンの機能分解ではこの目標の達成が困難であると主張します。

この手法は、即座に必要とされる以上にモジュールを一般的なものにするヒントを提供しないばかりでなく、そうする気を起こさせることすらない。階層構造のさまざまな部分に存在するモジュール間の共通性や冗長さの回避を促さないだけでなく、それらの検出も助けない。

常に上位のモジュールの存在を前提として下位のモジュールを設計するため、どうしてもコンテキストに依存したものが出来上がってしまうということでしょう。逆に言えば、ボトムアップの設計手法はモジュールを一般なものにするヒントを提供し、モジュール間の共通性や冗長さの回避を促し、それらの検出を助けるというのがこの本の主張であると言えそうです。

ボトムアップにモジュールを創造し、組み上げるためには、ある種の発想の転換が必要になります。「ユニットにダメージを与えるにはどういう処理を書けばいいのか?」ではなく、まず「ユニットとは何か?」「ダメージとは?」という思考をする必要があるのです。言い換えると、大きな機能を起点にした連続的な思考ではなく、一度機能のことは忘れて、そこに存在する概念について思いを馳せるということです。その本質的な答えが見つかったなら、別の機能において再び同じ問いが生まれた際、既に答えは手中にあるはずです。これが再利用可能なモジュールが生まれるメカニズムです。

オブジェクト指向はまず概念、モノ、オブジェクトを考えることを促すアプローチです。この性質がボトムアップの設計を自然に導くことになるのではないでしょうか。一方で、オブジェクト指向言語を使っていても、機能からのトップダウンで設計を考えている限り、オブジェクト指向らしいコードにはなかなか辿り着きません。

再利用性と拡張性の関係

再利用性の高いモジュールは拡張性にも寄与します。同じロジックが各所に点在している場合、一つの変更理由で広範囲のコードを書き換える必要が出てきます。単に手間が増えるというだけでなく、変更後の動作に意図せぬ差が生まれたりしてバグの温床になるのは言うまでもないでしょう。低コストで安全にコードを拡張できる状態を維持するためにも、再利用可能なモジュールを設計するチャンスを見逃さないよう普段から心がけておくことが大切です。

ただし、「コードが一致している」というだけの理由で同一のモジュールにまとめてしまうのは、ちょっと待ったほうがいいかもしれません。その一致が果たして同一の概念を表す本質的なものなのか、それとも今現在偶然にも一致しているだけなのかは考える余地があるでしょう。後者だった場合、闇雲にコードを統合してしまうと、かえって拡張性を下げてしまう結果にもなりかねません。

顧客と供給者の再利用

ボトムアップに設計すればいつでも再利用性の高いモジュールが手に入るかというと、実はそうでもありません。単に「一般的なものを目指し、共通性や冗長さを排した」だけでは、再利用可能な供給者モジュールが生まれるに留まります。では顧客モジュールを様々なケースで使いたい場合、どのように再利用性を高めれば良いのでしょうか?

画像3

ここでも鍵となるのは「抽象への依存」というアプローチです。このアプローチは複雑な依存関係がもたらす変更の伝播を軽減するだけでなく、モジュールの再利用性を高めることにも繋がるのです。次回はいよいよ、その話を書きたいと思います。


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