2021-03-07

『オブジェクト指向入門 第2版』の11章を読んだ

第11章 契約による設計

10章の総称性は省略.

契約による設計は,すべてのモジュールの要求と責任を詳細に定義する.要求はモジュールに与えられる値の条件であり,責任はモジュールが返す値が満たす条件である.モジュールは,要求となる条件を満たす限り,責任となる条件を満たす.

何らかの処理Aの正しさの公理は以下のように書ける.

{P}A{Q}

正しさの公式の意味

任意のAの実行は、Pの状態になったときに始ま、Qの状態になったときに終了する。

Pは事前条件,Qは事後条件である.

  • 事前条件が弱い
    要求が大きく,処理が難しい
  • 事後条件が強い
    満たさなければならない条件が厳しく,処理が難しい

事前条件,事後条件は,それぞれ抽象データ型のPRECONDITIONSとAXIOMSを表す.

とある塾講師になるための条件として,「小学3, 4年生に算数を教えられる」よりも,「小学生から高校生の算数(数学),理科,英語を教えられる」の方が満たすのが難しい.

時間の指定がある配達において,「9時から17時の間」よりも「12時から13時の間」の方が,条件を満たすのが難しい.

非冗長生の原則

どんな事情があっても、ルーチンの事前条件に当たるテストを、ルーチンの本体で行ってはならない。

この原則と逆のことを主張するのが「防衛的プログラミング」である.防衛的プログラミングは,できるだけ自己防衛するようにコンポーネントを設計する(供給か顧客かを問わず,条件を確認する).規模が大きいプロジェクトでは,事前条件を検証するコードの重複によって,コードの読みやすさが失われる可能性がある.契約による設計では,供給側か顧客側のどちらに責任があるか,一貫性を持たせる必要がある.

供給側に責任を持たせたとき,事前条件の確認はルーチンに含まれる.顧客側に責任を持たせたとき,事前条件を確認してからルーチンを呼び出すことが要求される.再利用性が重要であるソフトウェアでは,後者の方法を用いる.

事前条件を満たさなかったときの処理をルーチンに入れてしまうと,顧客はその部分を変更できなくなる.事前条件を満たさなかったときに,例外を投げるのか,デフォルト値を返すのか,リトライするのかを顧客が選択できた方が好ましい.

ソフトウェアの災いを表す用語

  • エラー
    ソフトウェアシステムの開発中になされた誤った決定.
  • 欠陥
    意図した振る舞いからシステムが逸れてしまう原因となるソフトウェアシステムの特性.
  • フォルト
    意図した振る舞いから逸れてしまうソフトウェアシステムのイベント.

「絶対パスではなく,相対パスを用いていたというのがエラーだった.相対パスを用いると正しくファイルを指定できずnullが返ってしまう.この関数にはnullチェックがないという欠陥があり,ソフトウェアの実行中にフォルトが発生し,実行が止まってしまった.」

クラス不変表明

すべてのルーチンで維持されていなければならない,クラスインスタンスに共通する全体的な特性をクラス不変表明という.

例えば,配列,要素数,配列の大きさを持つスタッククラスがあるとする.このとき,要素数は必ず0以上,配列の大きさ以下でなければいけない.要素を追加して要素数が配列の大きさを超えたり,要素を取り出して要素数が-1になったりしてはいけない.

表明の使い道

  • 正しいソフトウェアを書くのを助けるため。
  • 文書化支援のため。
  • テスト、デバッグ、品質保証をサポートするため。
  • ソフトウェアの対障害性(fault tolerance)をサポートするため。

最後の2つだけは、実行時に表明を監視することができることが前提である。