「契約プログラミング」の版間の差分
m →概要 タグ: モバイル編集 モバイルウェブ編集 改良版モバイル編集 |
|||
3行目: | 3行目: | ||
'''契約プログラミング'''(けいやくプログラミング、{{lang-en-short|Contract programming}})または'''契約による設計'''(けいやくによるせっけい、{{lang-en-short|Design by Contract; DbC}})は、[[オブジェクト指向]]に基づく[[ソフトウェア設計]]のための方法論である。 |
'''契約プログラミング'''(けいやくプログラミング、{{lang-en-short|Contract programming}})または'''契約による設計'''(けいやくによるせっけい、{{lang-en-short|Design by Contract; DbC}})は、[[オブジェクト指向]]に基づく[[ソフトウェア設計]]のための方法論である。 |
||
ソースコードに、 |
[[ソースコード]]に、入力の検証(validation)と出力への[[表明 (プログラミング)|表明]](assertion)と[[オブジェクト (プログラミング)|オブジェクト]]の不変条件(invariant)などを定義した仕様書式を導入して、各モジュールの特にバグ発生に対する責任の所在を明瞭にし、設計の安全性を高めることを目的にしている。DbC においてソフトウェア設計者は、[[形式仕様記述|形式的仕様]]を定義しつつ、[[抽象データ型]]に準拠した[[ソフトウェアコンポーネント]]を構築することが求められる。その仕様が契約(contract)と称されている。 |
||
DbC においてソフトウェア設計者は、[[形式仕様記述|形式的仕様]]を定義して、主に[[抽象データ型]]に沿った[[ソフトウェアコンポーネント]]を構築することが求められる。仕様とは、クライアント・コンポーネントとサプライヤ・コンポーネントの義務および利益における事前条件・事後条件・不変条件などを定義している[[インタフェース (抽象型)|インターフェース]]書式である。これをビジネスの契約書に見立てている。 |
|||
DbC は[[バートランド・メイヤー]]により提唱された<ref>Meyer, Bertrand: ''Design by Contract'', Technical Report TR-EI-12/CO, Interactive Software Engineering Inc., 1986</ref><ref>Meyer, Bertrand: ''Design by Contract'', in ''Advances in Object-Oriented Software Engineering'', eds. D. Mandrioli and B. Meyer, Prentice Hall, 1991, pp. 1–50</ref><ref>Meyer, Bertrand: ''Applying "Design by Contract"'', in Computer (IEEE), 25, 10, October 1992, pp. 40–51, also available [http://se.ethz.ch/~meyer/publications/computer/contract.pdf online]</ref>。プログラミング言語 [[Eiffel]] は、DbC に基づいた言語機能を備えている。 |
DbC は[[バートランド・メイヤー]]により提唱された<ref>Meyer, Bertrand: ''Design by Contract'', Technical Report TR-EI-12/CO, Interactive Software Engineering Inc., 1986</ref><ref>Meyer, Bertrand: ''Design by Contract'', in ''Advances in Object-Oriented Software Engineering'', eds. D. Mandrioli and B. Meyer, Prentice Hall, 1991, pp. 1–50</ref><ref>Meyer, Bertrand: ''Applying "Design by Contract"'', in Computer (IEEE), 25, 10, October 1992, pp. 40–51, also available [http://se.ethz.ch/~meyer/publications/computer/contract.pdf online]</ref>。プログラミング言語 [[Eiffel]] は、DbC に基づいた言語機能を備えている。 |
||
==概要== |
==概要== |
||
契約による設計(DbC)における中心的な概念は、クライアントとサプライヤ<ref>クライアント(顧客)とサプライヤ(供給者)の用法については例えば {{harvnb|Meyer|1990|pp=30,101}} を参照。邦訳では顧客/供給者が用いられているが本項ではクライアント/サプライヤを用いる。</ref>の'''契約''' ({{en|contract}}) である。DbC における契約とは、[[クラス (コンピュータ)|クラス]]<ref>DbC の文脈における「クラス」の定義は例えば {{harvnb|Meyer|1990|p=85}} を参照。この定義ではクラスは静的な型として表現され、それ自体はオブジェクトと見なされない。また同書ではしばしばクラスを「モジュール」と表現する。[[Smalltalk]] の流れを汲むクラスの扱いに関しては例えば {{harvnb|Meyer|1990|p=138}} を参照。</ref>の[[インスタンス]]<ref>{{harvnb|Meyer|1990}} では基本的に「オブジェクト」の語を用い、あらわにインスタンスとは呼んでいない。DbC の文脈ではクラスのインスタンス以外にオブジェクトは存在しないため ({{harvnb|Meyer|1990|p=139}}) 混用しても問題はないが、一般的な文脈を優先して本項ではインスタンスの語を用いる。</ref>とその[[メソッド (計算機科学)|メソッド]]<ref>{{harvnb|Meyer|1990}} では「メソッド」の代わりに「ルーチン」を用いているが、本項ではより一般的な前者を用いる。「メソッド」は [[Smalltalk]] 由来の同義語として {{harvnb|Meyer|1990|p=589}} に示されている。</ref> を |
契約による設計(DbC)における中心的な概念は、クライアントとサプライヤ<ref>クライアント(顧客)とサプライヤ(供給者)の用法については例えば {{harvnb|Meyer|1990|pp=30,101}} を参照。邦訳では顧客/供給者が用いられているが本項ではクライアント/サプライヤを用いる。</ref>の'''契約''' ({{en|contract}}) である。DbC における契約とは、[[クラス (コンピュータ)|クラス]]<ref>DbC の文脈における「クラス」の定義は例えば {{harvnb|Meyer|1990|p=85}} を参照。この定義ではクラスは静的な型として表現され、それ自体はオブジェクトと見なされない。また同書ではしばしばクラスを「モジュール」と表現する。[[Smalltalk]] の流れを汲むクラスの扱いに関しては例えば {{harvnb|Meyer|1990|p=138}} を参照。</ref>の[[インスタンス]]<ref>{{harvnb|Meyer|1990}} では基本的に「オブジェクト」の語を用い、あらわにインスタンスとは呼んでいない。DbC の文脈ではクラスのインスタンス以外にオブジェクトは存在しないため ({{harvnb|Meyer|1990|p=139}}) 混用しても問題はないが、一般的な文脈を優先して本項ではインスタンスの語を用いる。</ref>とその[[メソッド (計算機科学)|メソッド]]<ref>{{harvnb|Meyer|1990}} では「メソッド」の代わりに「ルーチン」を用いているが、本項ではより一般的な前者を用いる。「メソッド」は [[Smalltalk]] 由来の同義語として {{harvnb|Meyer|1990|p=589}} に示されている。</ref> を制約するための事前条件、事後条件、不変表明などで構成されるものであり、それらはプログラム的にはいわゆる[[表明 (プログラミング)|表明]](assertion)の集合体になるが、コンセプト的にはそれとイコールではないとされる。入力に対する表明を満たすためのプロセスは義務(oblication)と称され、出力に対する表明が満たされた状態遷移は利益(benefit)と称されている。 |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
実行時の表明違反の監視に関連して、[[例外処理|例外]]機構を利用することにより、実行時の表明違反を例外としてクライアントに処理させることができる。 |
|||
⚫ | |||
=== 事前条件 === |
=== 事前条件 === |
||
事前条件 ({{en|precondition}}) は、メソッド開始時に保証されるべき状態の表明である。これはメソッド単位で表明される。具体的には以下になる。 |
|||
# クライアントがメソッドに渡すパラメータ値の有効範囲。 |
|||
⚫ | |||
# そのメソッドに関連したサプライヤ・インスタンスの特定[[フィールド (計算機科学)|フィールド]]の適正範囲。 |
|||
⚫ | |||
=== 事後条件 === |
=== 事後条件 === |
||
事後条件 ({{en|postcondition}}) は、メソッド正常終了時に保証されるべき状態の表明である。これはメソッド単位で表明される。正常終了とは例外スロー終了やエラー発生終了ではない終了を指す。具体的には以下になる。 |
|||
# 渡されたパラメータ値に関連したサプライヤ・インスタンスの特定[[フィールド (計算機科学)|フィールド]]の適正範囲。 |
|||
# クライアントに渡すリターン値の有効範囲。 |
|||
事後条件を満たすことは、呼び出された側であるサプライヤの責任となる。そうすることで、クライアントは呼び出したメソッドの実装部分(本体)で事後条件に違反している状況を考慮する必要がなくなる。 |
|||
=== 不変表明 === |
=== 不変表明 === |
||
クラス不変表明 ({{en|class invariant}}) は、各メソッドの開始時と正常終了時に共通して保証されるべき状態の表明である。これはクラス単位で表明される。不変表明は、creation用メソッド([[コンストラクタ]]と同義)の開始時には照会されない{{sfn|Meyer|1990|pp=168–172}}。具体的には以下になる。 |
|||
クラス不変表明は次の状況で満たされなければならない{{sfn|Meyer|1990|pp=168–172}}: |
|||
# サプライヤ・インスタンスの各フィールドの適正範囲。 |
|||
* [[コンストラクタ]]の実行完了時 |
|||
<code>事前条件 AND 不変表明</code>が真であった後に、<code>事後条件 AND 不変表明</code>も真であったならば、メソッド呼び出しによる契約は全うされたことになる。 |
|||
* メソッドの呼び出し時 |
|||
* メソッドの実行完了時 |
|||
=== 義務と利益 === |
|||
すなわちクラス不変表明は、コンストラクタを除くすべてのメソッドの事前条件、およびコンストラクタを含むすべてのメソッドの事後条件として暗黙に適用される(クラスの属性に関する)表明である。 |
|||
契約でのクライアントとサプライヤの、プロセス(process)およびステート(state)は、それぞれの義務と利益に例えられている。 |
|||
不変表明は、事前条件としても事後条件としても働くため、クライアントとサプライヤの両者を束縛する。 |
|||
* クライアントの義務:サプライヤ・インスタンスのフィールド値の審査と、有効なパラメータ値を渡すこと。これは事前条件を満たすプロセスとされる。 |
|||
不変条件は好ましくない状態遷移を防止して、バグ責任特定とプログラムテストの助けになる。<code>事前条件 AND 不変条件</code>が真であった後に、<code>事後条件 AND 不変条件</code>も真であったならば、メソッド呼出しによる契約は全うされたことになる。不変条件は、[[ホーア論理|ホーアトリプル]]の<code>P</code>から<code>Q</code>への遷移が[[オブジェクト指向]]では[[宣言型プログラミング|宣言的]]ではないことへの対応策でもある。総じて契約項目は、プログラムの[[形式的検証]](verification)に深く関連している。 |
|||
* サプライヤの義務 :メソッドの決められた働きと、正常終了時に決められた状態遷移を果たすこと。これは仮想メソッド向けであり、後述の契約の派生でのサプライヤ・サブクラスの実装メソッド向けと考えると分かりやすい。これは事後条件を満たすプロセスとされる。 |
|||
<!-- |
|||
* クライアントの利益:メソッド正常終了時の決められた状態遷移と、あるならばリターン値を受け取ること。これは事後条件からのステートとされる。 |
|||
'''その他''' |
|||
* サプライヤの利益 :必要なサプライヤ・インスタンスのフィールド値が不適正か、渡されるパラメータ値が無効ならば、メソッドを実行しなくてよいこと。これは事前条件からのステートとされる。 |
|||
:例外型、エラー型、パラメータ型、リターン型、[[副作用 (プログラム)|副作用]]などは、契約の注釈として扱われることがある。 |
|||
--> |
|||
=== 例外 === |
|||
⚫ | |||
⚫ | |||
⚫ | |||
=== 契約の派生 === |
=== 契約の派生 === |
2021年11月19日 (金) 06:41時点における版
契約プログラミング(けいやくプログラミング、英: Contract programming)または契約による設計(けいやくによるせっけい、英: Design by Contract; DbC)は、オブジェクト指向に基づくソフトウェア設計のための方法論である。
ソースコードに、入力の検証(validation)と出力への表明(assertion)とオブジェクトの不変条件(invariant)などを定義した仕様書式を導入して、各モジュールの特にバグ発生に対する責任の所在を明瞭にし、設計の安全性を高めることを目的にしている。DbC においてソフトウェア設計者は、形式的仕様を定義しつつ、抽象データ型に準拠したソフトウェアコンポーネントを構築することが求められる。その仕様が契約(contract)と称されている。
DbC はバートランド・メイヤーにより提唱された[1][2][3]。プログラミング言語 Eiffel は、DbC に基づいた言語機能を備えている。
概要
契約による設計(DbC)における中心的な概念は、クライアントとサプライヤ[4]の契約 (contract) である。DbC における契約とは、クラス[5]のインスタンス[6]とそのメソッド[7] を制約するための事前条件、事後条件、不変表明などで構成されるものであり、それらはプログラム的にはいわゆる表明(assertion)の集合体になるが、コンセプト的にはそれとイコールではないとされる。入力に対する表明を満たすためのプロセスは義務(oblication)と称され、出力に対する表明が満たされた状態遷移は利益(benefit)と称されている。
表明を予め記述しておくことで、実装者はその表明に従ってプログラムを記述することができる。また、プログラム実行時に表明を違反していないか監視することができる[8]。実行時の表明違反の監視に関連して、例外機構を利用することにより、実行時の表明違反を例外としてクライアントに処理させることができる。
Aインスタンスが、Bインスタンスのメソッドを呼び出す場合、Aはクライアントになり、Bはサプライヤになる。クライアントとサプライヤは同一インスタンスであってもよく、例えば暗黙のThisメソッド呼び出しではそれになる。クライアントが任意のサプライヤのメソッドを呼び出した時に契約が照会される。契約は以下の項目からなる。
事前条件
事前条件 (precondition) は、メソッド開始時に保証されるべき状態の表明である。これはメソッド単位で表明される。具体的には以下になる。
- クライアントがメソッドに渡すパラメータ値の有効範囲。
- そのメソッドに関連したサプライヤ・インスタンスの特定フィールドの適正範囲。
事前条件を満たすことは、呼び出し側であるクライアントの責任となる。そうすることで、サプライヤはメソッドの実装部分(本体)で事前条件に違反している状況を考慮する必要がなくなる[9]。
事後条件
事後条件 (postcondition) は、メソッド正常終了時に保証されるべき状態の表明である。これはメソッド単位で表明される。正常終了とは例外スロー終了やエラー発生終了ではない終了を指す。具体的には以下になる。
- 渡されたパラメータ値に関連したサプライヤ・インスタンスの特定フィールドの適正範囲。
- クライアントに渡すリターン値の有効範囲。
事後条件を満たすことは、呼び出された側であるサプライヤの責任となる。そうすることで、クライアントは呼び出したメソッドの実装部分(本体)で事後条件に違反している状況を考慮する必要がなくなる。
不変表明
クラス不変表明 (class invariant) は、各メソッドの開始時と正常終了時に共通して保証されるべき状態の表明である。これはクラス単位で表明される。不変表明は、creation用メソッド(コンストラクタと同義)の開始時には照会されない[10]。具体的には以下になる。
- サプライヤ・インスタンスの各フィールドの適正範囲。
事前条件 AND 不変表明
が真であった後に、事後条件 AND 不変表明
も真であったならば、メソッド呼び出しによる契約は全うされたことになる。
義務と利益
契約でのクライアントとサプライヤの、プロセス(process)およびステート(state)は、それぞれの義務と利益に例えられている。
- クライアントの義務:サプライヤ・インスタンスのフィールド値の審査と、有効なパラメータ値を渡すこと。これは事前条件を満たすプロセスとされる。
- サプライヤの義務 :メソッドの決められた働きと、正常終了時に決められた状態遷移を果たすこと。これは仮想メソッド向けであり、後述の契約の派生でのサプライヤ・サブクラスの実装メソッド向けと考えると分かりやすい。これは事後条件を満たすプロセスとされる。
- クライアントの利益:メソッド正常終了時の決められた状態遷移と、あるならばリターン値を受け取ること。これは事後条件からのステートとされる。
- サプライヤの利益 :必要なサプライヤ・インスタンスのフィールド値が不適正か、渡されるパラメータ値が無効ならば、メソッドを実行しなくてよいこと。これは事前条件からのステートとされる。
例外
契約の主要な目的は、各メソッドの実行(例外可能性)実行中止(例外未発生)正常終了(例外可能性)異常終了(例外スローとエラー発生)を特定して、バグ責任の所在を明らかにすることである。そこでは例外(exception)の操作が重視されている。正常終了には、途中の例外発生とその解決継続も含まれていることに注意する。無効なパラメータ値やフィールド値の不適正によるメソッドの実行中止は、同時に例外も未発生と解釈されることに注意する。 やや分かり難いサプライヤの利益の「メソッド未実行=その時その範囲での例外未発生」は有効な責任特定材料になる。例外が解決できなかったら異常終了になる。異常終了は最も容易な責任特定材料になる。正常終了には例外発生の解決継続も含まれるのでやや複雑になる。例えば契約の入れ子で、内側契約の例外が外側契約で解決されていた場合などは見落とされがちなので要注意になる。
契約の派生
契約による設計ではクラスの継承がフォローされている。適切な継承は、スーパークラスの契約を保持しながら、そのサブクラスによる柔軟なパフォーマンスをもたらせる。スーパークラスの契約に対するそのサブクラスの適用は、動的バインディングと同義になる。これは開放閉鎖の原則に沿っている。
スーパークラスの契約と、そのサブクラスの契約の間には明確な整合性が要求される。サブクラスの契約の改変許容範囲は、以下のように定められており、この法則はbehavioral subtypingとも言われる。それに沿って派生された契約下のサブクラス・インスタンスは、スーパークラスの契約下でも安全に用いることが出来るとされる。
- 事前条件は、サブクラスで弱める(weaken)ことはできるが、強めることはできない。
- 事後条件は、サブクラスで強める(strengthen)ことはできるが、弱めることはできない。
- 不変条件は、サブクラスでもそのまま維持されなければならない。
- スーパークラスの例外から派生した例外を除いては、サブクラスで独自の例外を投げてはならない。
事前条件の弱めるは様々な意味を持つが、一例としてはパラメータ型の汎化である。事後条件の強めるも様々な意味を持つが、一例としてはリターン型の特化である。
メイヤーのオブジェクト指向入門
1988年第1版と1997年第2版の『Object-Oriented Software Construction- OOSC』は『オブジェクト指向入門』の邦題で知られているが、直訳すれば「オブジェクト指向ソフトウェア構築」である。入門というのはおそらく販売促進用の題名と考えた方が無難である。
OOSCのオブジェクト指向は、継承が有望視されていた古き良き時代のオブジェクト指向であることにも留意する必要がある。OOSCの継承は、実装継承による改訂モジュールの情報隠蔽と動的束縛を要点にしている。これは後年のSOLIDなどの界面継承による機能抽象インターフェースの動的ポリモーフィズムを要点にしたものとは異なっている。OOSCの開放/閉鎖原則と、2000年代に聞かれる開放/閉鎖原則の性格も異なるものである。
契約による設計の思想は、リファクタリング、テスト駆動開発、アジャイルソフトウェア開発などの対極的な位置にあることもそうである。
契約による設計のサポート言語
出典
- ^ Meyer, Bertrand: Design by Contract, Technical Report TR-EI-12/CO, Interactive Software Engineering Inc., 1986
- ^ Meyer, Bertrand: Design by Contract, in Advances in Object-Oriented Software Engineering, eds. D. Mandrioli and B. Meyer, Prentice Hall, 1991, pp. 1–50
- ^ Meyer, Bertrand: Applying "Design by Contract", in Computer (IEEE), 25, 10, October 1992, pp. 40–51, also available online
- ^ クライアント(顧客)とサプライヤ(供給者)の用法については例えば Meyer 1990, pp. 30, 101 を参照。邦訳では顧客/供給者が用いられているが本項ではクライアント/サプライヤを用いる。
- ^ DbC の文脈における「クラス」の定義は例えば Meyer 1990, p. 85 を参照。この定義ではクラスは静的な型として表現され、それ自体はオブジェクトと見なされない。また同書ではしばしばクラスを「モジュール」と表現する。Smalltalk の流れを汲むクラスの扱いに関しては例えば Meyer 1990, p. 138 を参照。
- ^ Meyer 1990 では基本的に「オブジェクト」の語を用い、あらわにインスタンスとは呼んでいない。DbC の文脈ではクラスのインスタンス以外にオブジェクトは存在しないため (Meyer 1990, p. 139) 混用しても問題はないが、一般的な文脈を優先して本項ではインスタンスの語を用いる。
- ^ Meyer 1990 では「メソッド」の代わりに「ルーチン」を用いているが、本項ではより一般的な前者を用いる。「メソッド」は Smalltalk 由来の同義語として Meyer 1990, p. 589 に示されている。
- ^ Meyer 1990, pp. 196–199.
- ^ Meyer 1990, pp. 159–160, 163–164.
- ^ Meyer 1990, pp. 168–172.
参考文献
- Meyer, Bertrand『オブジェクト指向入門』酒匂, 寛(訳); 酒匂, 順子(訳); 二木, 厚吉(監訳)、アスキー出版局、1990年11月21日(原著1988年)。ISBN 4-7561-0050-3。