契約による設計事始め

88ad4f75d7c84fcf560bb6205c52e8c1?s=47 dnskimo
February 16, 2020

 契約による設計事始め

Object-Oriented Conferenceの発表資料です。
カンファレンスの感想はこちら。
https://dnskimox.hateblo.jp/entry/2020/02/22/104342

88ad4f75d7c84fcf560bb6205c52e8c1?s=128

dnskimo

February 16, 2020
Tweet

Transcript

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

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

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

  4. 契約による設計事始め ▸ 契約による設計とはなにか? ▸ 事前条件と事後条件 ▸ クラス不変表明 ▸ 表明と例外の関係 ▸

    バリデーションとの違い ▸ 明日から使える実践方法
  5. 1. 契約による設計とは なにか? どこから来た用語で 何を意味するのか?

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

    https://en.wikipedia.org/wiki/Bertrand_Meyer
  8. “ キーコンセプトは契約による設計 (Design by Contract)である。クラスと 顧客の間の関係は、お互いの権利と義務 を表した正式な同意と見なすことができ る。すべてのモジ ュールのそのような要 求と責任の詳細な定義があって、はじめ

    て信頼性の高い大規模システムが実現で きるのである。
  9. 顧客モジュールと供給者モジュール • データを利用 • サービスを利用 要求と責任の詳細な定義 = 契約 が必要

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

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

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

    される特性 ループ不変表明 説明省略 ループ変化表明 説明省略 check命令 説明省略
  13. 2. 事前条件と 事後条件 このエラーを 出したのは誰だ!

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

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

  16. Statsを持つCharacterを作る

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

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

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

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

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

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

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

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

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

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

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

    特性を満たすという利 益を得る。 どちらのモジュールも想定すべき事項が減る
  28. コードがシンプルになる 起こり得ない分岐を書かなくて良い、デッドコードの抑 制、「但し書き」のコメント不要、etc...

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

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

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

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

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

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

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

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

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

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

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

    特性を満たすという利 益を得る。 事後条件を守ることを常に保証できるか?
  40. コードの正しさだけでは抑制できな い実行時エラー ファイルアクセスエラー 存在しないパス、パーミッショ ンの不一致、ディスクの物理 的な呼称 メモリエラー メモリ割り当ての失敗、メモリ の物理的な故障 OSからのシグナル

    入力デバイスからの割り込 み、中断命令、Kill データベースエラー 接続失敗、コネクション数の 超過、ロック待ち時間の超 過、SQLのシンタックスエラー ネットワークエラー コネクション確立の失敗、コネ クションの中断 外部サービスのエラー 認証失敗、外部サービス側の バリデーション、メンテナンス
  41. “ ルーチンが契約を満たす状態で実行を終 えた場合、そのルーチンコールは成功で ある。成功しなければ失敗である。(中略) 何らかの特別なイベントがルーチンの実 行を中断させたときルーチンは失敗する。 そのようなイベントを「例外」という。

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

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

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

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

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

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

    コードを修正する 本番稼働時に必要? 必要 必ずしも必要ではない
  48. 表明は 動くドキュメント コードの書き手の想定、クラスの責務の範囲、 オブジェクトの「正しい状態」の定義

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

  50. 使っている言語の表明機構を調べる 事前条件 事後条件 クラス不変表明 Scala require ensuring assert PHP assert

    assert × Ruby raise if/unless raise if/unless × なければ表明を組み込むライブラリを探す
  51. 事前条件を書く シグネチャで表現しきれない引数の制約はなにか? バグを修正する 発生からの経過時間が短いほど原因調査は簡単 表明違反を通知する 開発環境や本番環境からプログラマへのアラート

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

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

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

    https://dnskimox.hateblo.jp/
  55. 参考文献 ▸ オブジェクト指向入門 第二版 概念・コンセプト ▹ 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