Slide 1

Slide 1 text

契約による設計 事始め 2020/02/16 Object-Oriented Conference @dnskimox

Slide 2

Slide 2 text

自己紹介 男爵 所属:Alp,Inc. / Scalebase(サブスクリプション管理のSaaS) 開発言語:Scala、TypeScript 好きな話題:OOP、DDD、開発プロセス Twitter:@dnskimox

Slide 3

Slide 3 text

今日は 契約による設計 の話をします https://en.wikipedia.org/wiki/Design_by_contract

Slide 4

Slide 4 text

契約による設計事始め ▸ 契約による設計とはなにか? ▸ 事前条件と事後条件 ▸ クラス不変表明 ▸ 表明と例外の関係 ▸ バリデーションとの違い ▸ 明日から使える実践方法

Slide 5

Slide 5 text

1. 契約による設計とは なにか? どこから来た用語で 何を意味するのか?

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

バートランド・メイ ヤー著『オブジェク ト指向入門 第二 版』 開放/閉鎖の原則、コマン ドとクエリの分離原則、統一 形式アクセスの原則、契約 による設計、単一責任選択 の原則、etc... https://en.wikipedia.org/wiki/Bertrand_Meyer

Slide 8

Slide 8 text

“ キーコンセプトは契約による設計 (Design by Contract)である。クラスと 顧客の間の関係は、お互いの権利と義務 を表した正式な同意と見なすことができ る。すべてのモジ ュールのそのような要 求と責任の詳細な定義があって、はじめ て信頼性の高い大規模システムが実現で きるのである。

Slide 9

Slide 9 text

顧客モジュールと供給者モジュール ● データを利用 ● サービスを利用 要求と責任の詳細な定義 = 契約 が必要

Slide 10

Slide 10 text

“ 顧客モジュールと供給者モジュールの 間の契約は、一方にとっての利益はもう 一方の義務となる。効果的かつ信頼性 の高いソフトウェアを作るということは、 顧客と供給考の間で適切なコミュニケー ションを重ねた末、ベストな妥協案にあ たる契約を作成することである。

Slide 11

Slide 11 text

契約の形を 表明する道具 事前条件、事後条件、クラス不変表明、ループ 不変表明、etc...

Slide 12

Slide 12 text

様々な種類の表明 事前条件 ルーチンを利用する際に求め られる要求 事後条件 ルーチンの終了時に保証さ れる特性 クラス不変表明 クラスインスタンスを特徴付 け、その生存中にずっと保持 される特性 ループ不変表明 説明省略 ループ変化表明 説明省略 check命令 説明省略

Slide 13

Slide 13 text

2. 事前条件と 事後条件 このエラーを 出したのは誰だ!

Slide 14

Slide 14 text

メソッドの コード本体を 表明で挟む 事前条件 コード本体 事後条件

Slide 15

Slide 15 text

ScalaのCase classの特徴 ● 基本的に全てのプロパティが不変 ● 全てのプロパティのgetterを持つ ● プロパティの一部を変更したコピーを返すメソッドがある

Slide 16

Slide 16 text

Statsを持つCharacterを作る

Slide 17

Slide 17 text

供給者側の隠された意図 ● 回復するメソッドでHPを減らせてしまう ● ダメージを与えるはずがHPが増えている? クラスの作者の想定と異なる使われ方

Slide 18

Slide 18 text

メソッドに但し書きをつける?

Slide 19

Slide 19 text

メソッドに事前条件を仕込む

Slide 20

Slide 20 text

供給者の意図に反した呼び出しが できなくなる

Slide 21

Slide 21 text

供給者の意図に則した呼び出しなのに何かが おかしい?

Slide 22

Slide 22 text

メソッドに事後条件を仕込む

Slide 23

Slide 23 text

事後条件に違反していることが判明!

Slide 24

Slide 24 text

事後条件を守るようにコードを修正

Slide 25

Slide 25 text

“ ルーチンの事前条件と事後条件を定義 するということは、とりもなおさず、ルー チンとそれを呼び出すものの間で契約 (contract)を結んだということである。

Slide 26

Slide 26 text

事前条件 顧客は供給者のメソッ ドを呼び出す際、事前 条件を満たす義務を負 う。 契約によって生じる義務 事後条件 供給者は事前条件を 満たして呼び出された メソッドを抜ける際、事 後条件を満たす義務を 負う。

Slide 27

Slide 27 text

事前条件 供給者は想定外の状 況でメソッドを呼び出さ れないことが保証され るという利益を得る。 契約によって生じる利益 事後条件 顧客は事前条件を守っ てメソッドを呼び出す限 り、結果が定義された 特性を満たすという利 益を得る。 どちらのモジュールも想定すべき事項が減る

Slide 28

Slide 28 text

コードがシンプルになる 起こり得ない分岐を書かなくて良い、デッドコードの抑 制、「但し書き」のコメント不要、etc...

Slide 29

Slide 29 text

責任の所在が明らかに 事前条件違反なら顧客側が悪い、事後条件違反なら供 給者側が悪い。修正すべきコードは明白。

Slide 30

Slide 30 text

3. クラス不変表明 オブジェクトにとって 正しい状態とはなにか?

Slide 31

Slide 31 text

“ 事前条件と事後条件は個々のルーチン の特性を記述する。このほかに、全ての ルーチンで維持されなければならない、 クラスに共通する全体的な特性を表す 必要がある。

Slide 32

Slide 32 text

Statsクラスにクラス不変表明を記 述する ● インスタンス化の際にチェックされる ● copyの呼び出し時にも毎回チェックされる ● オブジェクトの生成から破棄まで守られ続ける

Slide 33

Slide 33 text

表明違反は即刻エラーになる Diagram featured by http://slidemodel.com

Slide 34

Slide 34 text

クラス不変表明(不変条件) あるクラスのオブジェクトは、生成されてから破棄さ れるまでクラス不変表明を満たし続ける義務を負 う。 契約によって生じる義務

Slide 35

Slide 35 text

クラス不変表明(不変条件) コードベース全体において、あるクラスのオブジェク トがクラス不変表明に違反するという想定をしなくて 良くなるという利益を得る。 契約によって生じる利益

Slide 36

Slide 36 text

コードがシンプルになる 起こり得ない分岐を書かなくて良い、デッドコードの抑 制、「但し書き」のコメント不要、etc...

Slide 37

Slide 37 text

責任の所在が明らかに クラス不変表明違反はクラス内部のコードに問題があ る。事前条件かメソッドの本体を見直すべし。

Slide 38

Slide 38 text

4. 表明と例外の関係 契約による設計なら 例外は必要なくなる?

Slide 39

Slide 39 text

事前条件 供給者は想定外の状 況でメソッドを呼び出さ れないことが保証され るという利益を得る。 契約によって生じる利益 事後条件 顧客は事前条件を守っ てメソッドを呼び出す限 り、結果が定義された 特性を満たすという利 益を得る。 事後条件を守ることを常に保証できるか?

Slide 40

Slide 40 text

コードの正しさだけでは抑制できな い実行時エラー ファイルアクセスエラー 存在しないパス、パーミッショ ンの不一致、ディスクの物理 的な呼称 メモリエラー メモリ割り当ての失敗、メモリ の物理的な故障 OSからのシグナル 入力デバイスからの割り込 み、中断命令、Kill データベースエラー 接続失敗、コネクション数の 超過、ロック待ち時間の超 過、SQLのシンタックスエラー ネットワークエラー コネクション確立の失敗、コネ クションの中断 外部サービスのエラー 認証失敗、外部サービス側の バリデーション、メンテナンス

Slide 41

Slide 41 text

“ ルーチンが契約を満たす状態で実行を終 えた場合、そのルーチンコールは成功で ある。成功しなければ失敗である。(中略) 何らかの特別なイベントがルーチンの実 行を中断させたときルーチンは失敗する。 そのようなイベントを「例外」という。

Slide 42

Slide 42 text

例外は 契約の放棄を表す データベースエラー、ファイルへのアクセスエ ラー、メモリ確保の失敗、etc...

Slide 43

Slide 43 text

5. バリデーションとの 違い 要するに入力 チェックでは?

Slide 44

Slide 44 text

バリデーションはシステム境界の外から の入力を検証する仕組み

Slide 45

Slide 45 text

表明はシステム境界内のモジュー ル同士のやり取りを定めた規約 常に真

Slide 46

Slide 46 text

外からのいかなる入力に対しても表明違反 を起こさないようプログラミングする 常に真

Slide 47

Slide 47 text

表明とバリデーションは根本的に異 なる道具である バリデーション 表明 誰のためのもの? システムを使う人 コードを書く人 違反が起きた時、 どうする? 入力内容を改める コードを修正する 本番稼働時に必要? 必要 必ずしも必要ではない

Slide 48

Slide 48 text

表明は 動くドキュメント コードの書き手の想定、クラスの責務の範囲、 オブジェクトの「正しい状態」の定義

Slide 49

Slide 49 text

5. 明日からできる実践 方法 で、結局何から 始めればいいの?

Slide 50

Slide 50 text

使っている言語の表明機構を調べる 事前条件 事後条件 クラス不変表明 Scala require ensuring assert PHP assert assert × Ruby raise if/unless raise if/unless × なければ表明を組み込むライブラリを探す

Slide 51

Slide 51 text

事前条件を書く シグネチャで表現しきれない引数の制約はなにか? バグを修正する 発生からの経過時間が短いほど原因調査は簡単 表明違反を通知する 開発環境や本番環境からプログラマへのアラート

Slide 52

Slide 52 text

表明違反は 例外なくバグ オブジェクトの状態が異常、バリデーションの不 足、事前条件が強すぎる、etc...

Slide 53

Slide 53 text

表明違反の修正は簡単 問題のコードのすぐ近くでエラーが起きる、データが破損 する前に処理が停止する、責任の所在が明白

Slide 54

Slide 54 text

表明を使ってシンプルで正 しいコードを! ご清聴ありがとうございました You can find me at @dnskimox & https://dnskimox.hateblo.jp/

Slide 55

Slide 55 text

参考文献 ▸ オブジェクト指向入門 第二版 概念・コンセプト ▹ 11章 契約による設計:信頼性の高いソフトウェアを構築する ▹ 12章 契約が破られるとき:例外処理 ▸ https://en.wikipedia.org/wiki/Design_by_contract ▸ https://speakerdeck.com/twada/php-conference-2016-revised ▸ https://qiita.com/kawachi/items/c3cf53e0602fb53e78e9 ▸ https://stackoverflow.com/questions/147969/is-it-idiomatic-ruby-to-add-an-asse rt-method-to-rubys-kernel-class