どんな本なのか
インターフェイスを用いてどのようにアプリケーションを設計するか詳しく解説された本です。
インターフェイスとは何かから始まり、原則や契約、インターフェイスの評価基準、継承とインターフェイスとの対比について、ピザ屋さんを例にして説明しています。
2008年に出版された本なので古い情報について書かれている部分はありますが、現代のアプリケーション設計でも活かせる内容が書かれていると思います。
以下、目次になります。
- 1章 インターフェイスとは何か
- 2章 インターフェイスと契約
- 3章 インターフェイスと材料
- 4章 何をインターフェイスに持たせるべきか?
- 5章 継承とインターフェイス
- 6章 リモートインターフェイス
- 7章 開発プロセスの開始
- 8章 リンクチェッカー
- 9章 Web自動集約ツール
- 10章 サービレポジトリ
- 11章 パターン
目的
ソフトウェア設計について学ぶことで、テストしやすく・変更しやすい、実装の意図が把握しやすい等、継続的な開発を容易に行える設計を今よりもできるようになりたいからです。
知識や経験がないと開発の際に考えられる幅が小さくなりがちなので、そこは継続的に改善していきたいところです。
感想
具象クラスではなくインターフェイスに依存させて実装してテストの際は差し替えられるようにしたりと設計・実装してきましたが、インターフェイスの原則だったり契約や評価基準というものは知らなかったので、なるほどと思いながら読んでいました。
無意識にしていたことがこの本を読んで言語化されたこともあるので、この本を読んで良かったなと思います。
読書ノート
- ここでの契約は、インターフェイスのユーザーと実装の間に成立する約束事を指す
- 3つの原則
- 原則1: インターフェイス実装は、そのメソッド名が示す通りの処理をしなければならない
- 実装はインターフェイスの作成社が意図した通りの処理を実行できなくてはいけない
- 実装は、戻り値を適切に処理できなくてはいけない
- 原則1は、「サブタイプの古い米はその継承元と異なってはならない」というリスコフの置換原則(Liskov Substitution Principle: LSP)に対応している
- 原則2: インターフェイス実装は他に危害を加えてはならない
- ここでいう危害とは、実装がプログラム内の他モジュールや、別のプログラムの正常な動作を妨害してしまうような場合のことを指す
- 実装は、リソースをやたらに消費してしまうようなものであってはいけない
- 原則3: インターフェイス実装は、責務を果たせない場合にそれを呼び出し元に伝えねばならない
- 実装は、問題に遭遇し、それを自ら修正できない場合は、その問題についての呼び出し側に報告をしなければならない
- 報告の方法(エラーシグナル)は、リターンコードでも、例外でも構わない
- インターフェイスが報告するエラーも、インターフェイス契約の一部
- 実装は、問題に遭遇し、それを自ら修正できない場合は、その問題についての呼び出し側に報告をしなければならない
- 原則1: インターフェイス実装は、そのメソッド名が示す通りの処理をしなければならない
- インターフェイスを効果的に使うためには、呼び出し側と実装側がそれぞれ契約を理解していなければならない
- 実装が呼び出し側のどのような要求に応えるべきであるか、ということについて双方の同意が必要
- 契約の3つの側面
- 事前条件(precondition)
- インターフェイスのユーザーは、メソッド呼び出し時に特定の条件が満たされていることを確認しなければならない
- 事後条件(postcondition)
- インターフェイス内の各メソッドは、呼び出しが適切に実行された場合に真となる条件を持つ。この保証のこと。
- クラス不変表明(class invariant)
- すべてのオブジェクトインスタンスが満たすべき条件を示す
- インターフェイスにおいては、クラス不変表明は通常、特定の実装のプロパティでありメソッドではない
- 事前条件(precondition)
例)
メソッド | 事前条件 | 事後条件 |
---|---|---|
set_size() | なし | サイズを設定 |
set_toppings() | サイズが設定されている | トッピングを設定 |
set_address | サイズとトッピングが設定されている | 住所を設定 |
get_time_till_delivered | サイズ、トッピング、住所が設定されている | なし |
- インターフェイスのプロトコルを知ることが大切
- プロトコルとは、実行可能なメソッドコールの組み合わせ、つまりメソッドシーケンスのまとまりのこと
- プロトコルには、インターフェイスが作成したコールバック、生成されたイベント、呼び出されたオブザーバも示される
- インターフェイスの機能を分離させることによって、1つのインターフェイスが持つ状態遷移の数を減らすことができ、エラーの発生率を低く抑えることができる
- インターフェイスのテストとは、対象のインターフェイ実装が契約を満たしていることを確認するために行われるべきものだと言える
- Christine MinginsとJean-Marc Jezequelは、契約には複数のレベルがあることを提唱している
- 型を持つプログラミング言語における、基本となる型の契約
- 事前条件と事後条件を含む意味的な契約
- リアルタイムシステムにおける、パフォーマンスの契約
- 定量化の難しい、サービスの質についての契約
- ※テストは、こうした異なるレベルの契約それぞれに対して行う必要がある
- データインターフェイス
- 本書では、たくさんの属性をもつクラスに対応するメソッドで構成されるインターフェイスのこと
- データインターフェイスのメソッドは、属性に値を設定したり、属性から値を取得したりするためのメソッド
- 状態を持つ
- 状態には、クラスの全属性の値が含まれる
- サービスインターフェイス
- 本書では、渡されたパラメータに対する処理を行うメソッドを中心に構成されているモジュールのこと
- 渡されたパラメータを処理の対象とし、実装の属性は対象にはならない
- Ivar Jacobsonは、オブジェクトのステレオタイプを3つ定義
- エンティティオブジェクト
- オブジェクトの永続的な状態を示す
- バウンダリオブジェクト
- システムやアクター(ユーザーおよび外部システム)とのやりとりを司る
- コントロールオブジェクト
- 特定の仕様に対する振る舞いを表し、バウンダリオブジェクトとエンティティオブジェクトとの間をやりとりして処理を実行する
- エンティティオブジェクト
- インターフェイス実装は、ステートフル/ステートレスにできる
- ステートフルインターフェイス
- メソッドは現在の状態によって異なった動作をする
- 状態は、メソッド呼び出しの順序によって変化する
- 長所
- パラメータリストが短くて済む
- 短所
- メソッドコールの順序が重要になる
- ステートレスインターフェイス
- 振る舞いがメソッド呼び出しの順序によって変わることはない
- 長所
- メソッドコールの順序にこだわらなくてもよい
- 短所
- パラメータ数が多くなる
- ステートフルインターフェイス
- インターフェイスの書くメソッドは互いに高い凝集度を持たねばならない
- 各メソッドが提供する機能は共通するコンセプトに基づかねばならないということ
- いくつかの処理をまとめて行うようであれば、それらは同じインターフェイスで扱うべき
- 結合度(coupling)は、あるモジュールが他のモジュールにどれだけ依存しているうかを示す
- 実装ではなくインターフェイスに依存しているのであれば、あるメソッドが別の実装に強く結合することは稀になる
- 疎結合とは、呼び出される側のインターフェイスの実装を変更した際に、呼び出し側のコードを変更する必要がないということ
- 密結合になっていると、コードを変更しなければならない
- インターフェイスの評価基準
- 最小
- Pros: メソッド数が少ないので、実装とテストが簡単
- Cons: 特定の機能を実現するためにコードを書く必要があり、コードの重複を招くこともある
- 完全
- Pros: すべてのメソッドを利用できる
- Cons: メソッド数が多いため、インターフェイスの理解が難しくなる
- 単純
- Pros: 共通する機能を簡単に使える
- Cons: 変化が必要なときに、新しいメソッドのコーディングが必要になる
- 複雑
- Pros: 「好みの方法」を柔軟に選択できる
- Cons: インターフェイスを理解することが難しい
- 最小
- インターフェイスは完全性が高まれば高まるほど、メソッドの数は増え、実装は難しくなる
- 凝集度の高いインターフェイスを設計することが大切
- ただし、何をもって凝集度が高いと判断するのか
- 疎結合を目指す
- ポリモーフィズムとは、あるメソッドの実装を複数のクラスが提供することで実現されるものを指す
- 実現方法は2つ
- 継承
- インターフェイスを用いる方法
- 実現方法は2つ
- 複数インターフェイスの難しい点は、各実装のメソッドに共通化できるコードがでてしまうこと
- 避ける方法は2つ
- 方法1
- ヘルパークラスによる処理の委譲
- 方法2
- インターフェイスを実装したクラスを作成
- このクラスはメソッドの多くの実装を提供
- インターフェイスを実装する代わりに、この作成クラスを継承する
- インターフェイスを実装したクラスを作成
- 方法1
- 避ける方法は2つ
- インターフェイス
- 長所
- クラス階層を構成する経験が不十分な場合にそれを避けることができる
- 軽装を横断できる
- 使い方の共通性によってまとめられる
- 改装を横断するロールを表しやすい
- どのメソッドを実装すべきかが明白になる
- 別の軽装改装にあるクラスがインターフェイスのサービスを提供できる
- 短所
- 共通機能を提供するために、ヘルパークラスがないとコードが重複する
- ヘルパークラスを多く作成しなければならない
- 長所
- 継承
- 長所
- 共通の処理の委譲が少なくて済む
- 共通の属性を取得できる
- 実装する処理の共通性によってまとめられる
- 基底クラスを通じて共通の実装を提供できる
- 継承と実装が簡単
- 短所
- 状況の変化に柔軟に対応できない場合がある
- ロールの変更が難しい場合はがる
- 長所
- インターフェイスは、振る舞いの共通点を表す
- 継承は、振る舞いの共通点に加えて、実装の共通点を表す
- ソフトウェアプロジェクトには、ビジョンが必要
- ビジョンとはソフトウェアの使用目的を1文か2文で簡潔に言い表したもの
- ビジョンを明確にしたら、次はソフトウェアの要件を定義する
- 要件を表す形式には、正式の要求仕様書や、ユーザーストーリー(誰々は何々ができる)、ユースケースなど様々なものがある
- ユースケースには、システムに対して要求を行う人と、システムから利益を受けるエンドユーザーを記述する
- ユースケースの定義
- ビジネスゴールを達成するために、アクターとシステムとの相互作用を定義したもの
- アクターとは、システムの外部にいて、システムとやり取りする主体のこと
- ユーザーを表現するクラスやユーザーが担うロール、他システムなどがアクターとなりうる存在
- アクターの特定は、ユーザーが行う具体的な作業やユーザーの組織内での役職だどではなく、システムにおいてユーザーが担うロールに基づいて行う