読者です 読者をやめる 読者になる 読者になる

インターフェイス志向設計を読んだメモ

積読消化したい

インターフェイス指向設計 ―アジャイル手法によるオブジェクト指向設計の実践

インターフェイス指向設計 ―アジャイル手法によるオブジェクト指向設計の実践

契約しようよ!

契約とは、

  • インターフェイスを実装するモジュールが守らなければならない(守るべき)約束
  • インターフェイスのユーザーと実装の間に成立する約束事
インターフェイスの三原則

1. インターフェイス実装は、そのメソッド名が示す通りの処理をしなければならない

  • メソッド名から実装が行う処理が想像できるか
  • メソッドの目的と意味合いがその名前と実装場所だけでは明確に連想できない場合、しっかりと文書化されてないといけない(テストにも言及した方がよい)
  • 「インターフェイスの文書化はとても大切だ。しかし、文書化しなければならないということは、メソッド名に改善の余地があるということでもある。」

2. インターフェイス実装は他に危害を加えてはならない

  • 「実装は、インターフェイスによって提供されたリソースだけを使うべきである。」
  • EX) 画面への書き込みを目的とするインターフェイスは、データベースへの接続を要求するべきではない

3. インターフェイス実装は、責務を果たせない場合にそれを呼び出し元に伝えねばならない

  • インターフェイスが報告するエラーもインターフェイス契約の一部
契約による設計
  • メソッドが満たすべき条件についてのガイドラインを示すもの
  • 事前条件・・・メソッド呼び出し時に満たされていることで動作を保証する特定の条件
  • 事後条件・・・インターフェイス内の各メソッドが、呼び出しが適切に実行された場合に真となる保証がある条件
  • 契約(事前条件)のチェックをどうやって行うか: 各メソッドにチェックコード or アスペクト or Proxy or nContracts(C#限定)
  • 事前条件または事後条件が満たされない場合、処理の失敗を通知する
インターフェイスのプロトコル
  • "実行可能なメソッドコールの組み合わせ、つまりメソッドシーケンスのまとまりのことです" わからん・・・
  • インターフェイス内のメソッドを呼び出す順番の規則でいいのかな
  • EX) インターフェイスFileではopen()→read()→close()する必要があるよ!
  • UMLシーケンスで表現しておくのがおすすめらしい
インターフェイスのテスト
  • ブラックボックステスト
  • 対象のインターフェイス実装が契約が満たされているかどうか確認するために行われるべきこと
  • インタフェイス実装の少なくとも1つが契約に対するテストをすべて成功するまでは、インターフェイスの定義は完了したとは言えない
  • 「実装ではなく、インターフェイスをテストせよ」
  • インターフェイスのテストを作成することは、インターフェイスの問題点の検出にもつながる(契約内容、メソッド定義、プロトコルが曖昧とか)
  • インターフェイスのテストが困難→そのインターフェイスはとても使いづらい
  • そういう場合はインターフェイスを設計し直すべき
  • インターフェイスは一度決定すると変更しづらいから早めにテスト書かないと死ねるよ
データインターフェイスとサービスインターフェイス
  • データインターフェイス・・・クラス属性を処理対象とするインターフェイス(DTOとか)
  • サービスインターフェイス・・・渡されたパラメータに対する処理を行うメソッドを中心に構成されているモジュール
  • データインターフェイスとサービスインターフェイスに明確な区別はなく、段階的に分類される
インターフェイス作成時に長所と短所を考慮すべきこと
  • シーケンシャルアクセス or ランダムアクセス
  • プッシュ or プル
  • ステートフル or ステートレス
  • 複数メソッド or 単一メソッド
複雑性保存の法則
  • APIを単純にすることはできるが、そうすると実装が果たすべき責務が複雑化する(特にエラー処理とか)
  • 実装を単純にすることができるが、そうするとインターフェイスが複雑になってしまう
設計
  • 凝集度の高いインターフェイスを設計することが大事
  • ただし、何をもって凝集度の高いインターフェイスとするかの検討は難しい
  • インターフェイスを使うことで、疎結合を実現しやすくなる
  • 最小 or 完全
  • 単純 or 複雑
継承とインターフェイス
  • インターフェイス・・・振る舞いの共通点
  • 継承・・・振る舞いの共通点 + 実装の共通点
  • インターフェイスは継承より柔軟だが、共通処理を重複させないためにはヘルパークラスに委譲する必要がある
  • 継承は基底クラスと共通するコードを簡単に共有できるが、派生クラスと基底クラスとを密結合させてしまう