Slide 1

Slide 1 text

僕と契約して、メソッドになってよ! 僕と契約して、メソッドになってよ! 僕と契約して、メソッドになってよ! 僕と契約して、メソッドになってよ! 僕と契約して、メソッドになってよ! 僕と契約して、メソッドになってよ! 契約による設計から考えるメソッドの作り方 契約による設計から考えるメソッドの作り方 契約による設計から考えるメソッドの作り方 契約による設計から考えるメソッドの作り方 契約による設計から考えるメソッドの作り方 契約による設計から考えるメソッドの作り方 1 / 22

Slide 2

Slide 2 text

@zaru @zaru @zaru @zaru @zaru @zaru 2 / 22

Slide 3

Slide 3 text

メソッドを作ってください メソッドを作ってください メソッドを作ってください メソッドを作ってください メソッドを作ってください メソッドを作ってください 2 つの引数を使って、割り算をした結果を返してください 2 つの引数を使って、割り算をした結果を返してください 2 つの引数を使って、割り算をした結果を返してください 2 つの引数を使って、割り算をした結果を返してください 2 つの引数を使って、割り算をした結果を返してください 2 つの引数を使って、割り算をした結果を返してください       3 / 22

Slide 4

Slide 4 text

こんな感じ? こんな感じ? こんな感じ? こんな感じ? こんな感じ? こんな感じ? def def div a div a, , b b a a / / b b end end div div 10 10, , 3 3 #=> 3 #=> 3 4 / 22

Slide 5

Slide 5 text

コードレビューしましょう コードレビューしましょう コードレビューしましょう コードレビューしましょう コードレビューしましょう コードレビューしましょう 5 / 22

Slide 6

Slide 6 text

0 が入ってきたらどうしよう 0 が入ってきたらどうしよう 0 が入ってきたらどうしよう 0 が入ってきたらどうしよう 0 が入ってきたらどうしよう 0 が入ってきたらどうしよう Numeric 以外の値が入ってきたどうしよう Numeric 以外の値が入ってきたどうしよう Numeric 以外の値が入ってきたどうしよう Numeric 以外の値が入ってきたどうしよう Numeric 以外の値が入ってきたどうしよう Numeric 以外の値が入ってきたどうしよう 小数点はどうなってるの 小数点はどうなってるの 小数点はどうなってるの 小数点はどうなってるの 小数点はどうなってるの 小数点はどうなってるの                   6 / 22

Slide 7

Slide 7 text

書き換えてみる 書き換えてみる 書き換えてみる 書き換えてみる 書き換えてみる 書き換えてみる 例えば、0 チェックやタイプチェックをしてあげる? 例えば、0 チェックやタイプチェックをしてあげる? 例えば、0 チェックやタイプチェックをしてあげる? 例えば、0 チェックやタイプチェックをしてあげる? 例えば、0 チェックやタイプチェックをしてあげる? 例えば、0 チェックやタイプチェックをしてあげる? def def div a div a, , b b return return false false if if b b == == 0 0 return return false false unless unless [ [a a, , b b] ]. .all all? ?{ {| |v v| | v v. .is_a is_a? ? Numeric Numeric } } a a / / b b end end div div 10 10, , 0 0 #=> false #=> false div div '10' '10', , 3 3 #=> false #=> false 7 / 22

Slide 8

Slide 8 text

例えば、数値以外の値が入った時、よしなに変換をしてあげる? 例えば、数値以外の値が入った時、よしなに変換をしてあげる? 例えば、数値以外の値が入った時、よしなに変換をしてあげる? 例えば、数値以外の値が入った時、よしなに変換をしてあげる? 例えば、数値以外の値が入った時、よしなに変換をしてあげる? 例えば、数値以外の値が入った時、よしなに変換をしてあげる? def def div a div a, , b b a a, , b b = = [ [a a, , b b] ]. .map map( (& &method method( (:Float :Float) )) ) a a / / b b rescue rescue false false end end div div '10' '10', , 3 3 #=> 3.3333333333333335 #=> 3.3333333333333335 8 / 22

Slide 9

Slide 9 text

例えば、返す値の精度や丸めを調整してあげる? 例えば、返す値の精度や丸めを調整してあげる? 例えば、返す値の精度や丸めを調整してあげる? 例えば、返す値の精度や丸めを調整してあげる? 例えば、返す値の精度や丸めを調整してあげる? 例えば、返す値の精度や丸めを調整してあげる? def def div a div a, , b b a a, , b b = = [ [a a, , b b] ]. .map map( (& &method method( (:Float :Float) )) ) ( (a a / / b b) ). .round round( (3 3) ) end end div div 10 10, , 3 3 #=> 3.333 #=> 3.333 9 / 22

Slide 10

Slide 10 text

まとめてみる まとめてみる まとめてみる まとめてみる まとめてみる まとめてみる def def div a div a, , b b a a, , b b = = [ [a a, , b b] ]. .map map( (& &method method( (:Float :Float) )) ) return return false false if if b b == == 0 0 return return false false unless unless [ [a a, , b b] ]. .all all? ?{ {| |v v| | v v. .is_a is_a? ? Numeric Numeric } } ( (a a / / b b) ). .round round( (3 3) ) rescue rescue false false end end 10 / 22

Slide 11

Slide 11 text

くらべてみる くらべてみる くらべてみる くらべてみる くらべてみる くらべてみる def def div a div a, , b b a a / / b b end end def def div a div a, , b b a a, , b b = = [ [a a, , b b] ]. .map map( (& &method method( (:Float :Float) )) ) return return false false if if b b == == 0 0 return return false false unless unless [ [a a, , b b] ]. .all all? ?{ {| |v v| | v v. .is_a is_a? ? Numeric Numeric } } ( (a a / / b b) ). .round round( (3 3) ) rescue rescue false false end end 11 / 22

Slide 12

Slide 12 text

12 / 22

Slide 13

Slide 13 text

何が問題か 何が問題か 何が問題か 何が問題か 何が問題か 何が問題か メソッドの メソッドの メソッドの メソッドの メソッドの メソッドの作り手 作り手 作り手 作り手 作り手 作り手はどこまで はどこまで はどこまで はどこまで はどこまで はどこまで 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? メソッドを メソッドを メソッドを メソッドを メソッドを メソッドを使う側 使う側 使う側 使う側 使う側 使う側はどこまで はどこまで はどこまで はどこまで はどこまで はどこまで 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか? 考慮すれば良いんだろうか?             13 / 22

Slide 14

Slide 14 text

契約による設計 契約による設計 契約による設計 契約による設計 契約による設計 契約による設計 14 / 22

Slide 15

Slide 15 text

契約による設計 契約による設計 契約による設計 契約による設計 契約による設計 契約による設計 {P} A {Q} {P} A {Q} {P} A {Q} {P} A {Q} {P} A {Q} {P} A {Q} 任意の A の実行は、P の状態になったときに始まり、 任意の A の実行は、P の状態になったときに始まり、 任意の A の実行は、P の状態になったときに始まり、 任意の A の実行は、P の状態になったときに始まり、 任意の A の実行は、P の状態になったときに始まり、 任意の A の実行は、P の状態になったときに始まり、 Q の状態になったときに終了する。 Q の状態になったときに終了する。 Q の状態になったときに終了する。 Q の状態になったときに終了する。 Q の状態になったときに終了する。 Q の状態になったときに終了する。 by バートランド・メイヤー さん by バートランド・メイヤー さん by バートランド・メイヤー さん by バートランド・メイヤー さん by バートランド・メイヤー さん by バートランド・メイヤー さん 15 / 22

Slide 16

Slide 16 text

事前条件 事前条件 事前条件 事前条件 事前条件 事前条件 呼ぶ側で保証すべき性質 呼ぶ側で保証すべき性質 呼ぶ側で保証すべき性質 呼ぶ側で保証すべき性質 呼ぶ側で保証すべき性質 呼ぶ側で保証すべき性質 事後条件 事後条件 事後条件 事後条件 事後条件 事後条件 終了時に呼ばれる側が保証すべき性質 終了時に呼ばれる側が保証すべき性質 終了時に呼ばれる側が保証すべき性質 終了時に呼ばれる側が保証すべき性質 終了時に呼ばれる側が保証すべき性質 終了時に呼ばれる側が保証すべき性質 不変条件 不変条件 不変条件 不変条件 不変条件 不変条件 すべての操作の開始時と終了時に保証されるべき、共通した性質 すべての操作の開始時と終了時に保証されるべき、共通した性質 すべての操作の開始時と終了時に保証されるべき、共通した性質 すべての操作の開始時と終了時に保証されるべき、共通した性質 すべての操作の開始時と終了時に保証されるべき、共通した性質 すべての操作の開始時と終了時に保証されるべき、共通した性質 16 / 22

Slide 17

Slide 17 text

Eiffel で事前条件と事後条件 Eiffel で事前条件と事後条件 Eiffel で事前条件と事後条件 Eiffel で事前条件と事後条件 Eiffel で事前条件と事後条件 Eiffel で事前条件と事後条件 class class STACK STACK [ [T T] ] feature feature is_empty is_empty : : BOOLEAN BOOLEAN; ; pop pop : : T T is is require require -- 事前条件 -- 事前条件 non_empty_stack non_empty_stack : : not not is_empty is_empty; ; do do -- 配列から1 個取り出す処理 -- 配列から1 個取り出す処理 ensure ensure -- 事後条件 -- 事後条件 one_less_count one_less_count : : count count = = old old count count - - 1 1 end end --pop --pop end end --STACK --STACK 17 / 22

Slide 18

Slide 18 text

いいこと いいこと いいこと いいこと いいこと いいこと 明示的な条件を付けることで、作る側も使う側も安心できる 明示的な条件を付けることで、作る側も使う側も安心できる 明示的な条件を付けることで、作る側も使う側も安心できる 明示的な条件を付けることで、作る側も使う側も安心できる 明示的な条件を付けることで、作る側も使う側も安心できる 明示的な条件を付けることで、作る側も使う側も安心できる 本来の責務に集中できるのでコードの見通しが良くなる 本来の責務に集中できるのでコードの見通しが良くなる 本来の責務に集中できるのでコードの見通しが良くなる 本来の責務に集中できるのでコードの見通しが良くなる 本来の責務に集中できるのでコードの見通しが良くなる 本来の責務に集中できるのでコードの見通しが良くなる 微妙な所 微妙な所 微妙な所 微妙な所 微妙な所 微妙な所 言語レベルでサポートしているのは Eiffel と D くらい 言語レベルでサポートしているのは Eiffel と D くらい 言語レベルでサポートしているのは Eiffel と D くらい 言語レベルでサポートしているのは Eiffel と D くらい 言語レベルでサポートしているのは Eiffel と D くらい 言語レベルでサポートしているのは Eiffel と D くらい Ruby の gem もあるけど実行時チェックなので… Ruby の gem もあるけど実行時チェックなので… Ruby の gem もあるけど実行時チェックなので… Ruby の gem もあるけど実行時チェックなので… Ruby の gem もあるけど実行時チェックなので… Ruby の gem もあるけど実行時チェックなので… https://github.com/egonSchiele/contracts.ruby https://github.com/egonSchiele/contracts.ruby https://github.com/egonSchiele/contracts.ruby https://github.com/egonSchiele/contracts.ruby https://github.com/egonSchiele/contracts.ruby https://github.com/egonSchiele/contracts.ruby                               18 / 22

Slide 19

Slide 19 text

require require 'contracts' 'contracts' class class Example Example include include Contracts Contracts: :: :Core Core include include Contracts Contracts: :: :Builtin Builtin Contract Contract Num Num = => > Num Num def def double double( (x x) ) x x * * 2 2 end end end end puts puts Example Example. .new new. .double double( ("oops" "oops") ) 19 / 22

Slide 20

Slide 20 text

ParamContractError ParamContractError: : Contract Contract violation violation for for argument argument 1 1 of of 1 1: : Expected Expected: : Num Num, , Actual Actual: : "oops" "oops" Value Value guarded guarded in in: : Example Example: :: :double double With With Contract Contract: : Num Num = => > Num Num At At: : ( (pry pry) ): :7 7 20 / 22

Slide 21

Slide 21 text

Ruby に活かせる考え Ruby に活かせる考え Ruby に活かせる考え Ruby に活かせる考え Ruby に活かせる考え Ruby に活かせる考え YARD で引数の型や例外処理など挙動をちゃんと書こう YARD で引数の型や例外処理など挙動をちゃんと書こう YARD で引数の型や例外処理など挙動をちゃんと書こう YARD で引数の型や例外処理など挙動をちゃんと書こう YARD で引数の型や例外処理など挙動をちゃんと書こう YARD で引数の型や例外処理など挙動をちゃんと書こう IntelliJ なら YARD を読み取ってサジェストしてくれる IntelliJ なら YARD を読み取ってサジェストしてくれる IntelliJ なら YARD を読み取ってサジェストしてくれる IntelliJ なら YARD を読み取ってサジェストしてくれる IntelliJ なら YARD を読み取ってサジェストしてくれる IntelliJ なら YARD を読み取ってサジェストしてくれる メソッド内部で受け取った引数を メソッド内部で受け取った引数を メソッド内部で受け取った引数を メソッド内部で受け取った引数を メソッド内部で受け取った引数を メソッド内部で受け取った引数をよしなに よしなに よしなに よしなに よしなに よしなにするのは止めよう するのは止めよう するのは止めよう するのは止めよう するのは止めよう するのは止めよう 例外を投げるか false / nil を返すかは自由 例外を投げるか false / nil を返すかは自由 例外を投げるか false / nil を返すかは自由 例外を投げるか false / nil を返すかは自由 例外を投げるか false / nil を返すかは自由 例外を投げるか false / nil を返すかは自由 ただし、例外を内部で握りつぶすのはやめよう ただし、例外を内部で握りつぶすのはやめよう ただし、例外を内部で握りつぶすのはやめよう ただし、例外を内部で握りつぶすのはやめよう ただし、例外を内部で握りつぶすのはやめよう ただし、例外を内部で握りつぶすのはやめよう                               21 / 22

Slide 22

Slide 22 text

thanks thanks thanks thanks thanks thanks 22 / 22