Upgrade to Pro — share decks privately, control downloads, hide ads and more …

フロントエンド開発で自動テストをしてElmという言語に流れ着いた話

 フロントエンド開発で自動テストをしてElmという言語に流れ着いた話

D3 ワーストプラクティス

ababup1192

June 01, 2018
Tweet

More Decks by ababup1192

Other Decks in Programming

Transcript

  1. 自己紹介 - Twitter: ababupdownba - GitHub: ababup1192 - 2018年3月にBizReachに入社 -

    半学生、半社会人 - Elmとドラクエを布教しに 2
  2. 例 - デジタル・アナログ時計 5 デジタル時計 <-> アナログ時計 2つの言語からなるネットワーク デジタル時計の数字を変えると、変 更がアナログ時計に伝わる

    アナログ時計の針を動かすと、 変更がデジタル時計に伝わる 時間経過でも時計は動く 初等教育での利用を想定
  3. 例 - 数式・グラフ, 座標 6 数式 <- グラフ 2つの言語からなるネットワーク 数式の値を変更するとグラフへ変更

    が伝わる グラフの傾きや切片を変更すると数 式へ変更が伝わる 教育での利用を想定
  4. ScalaFX 9 利点 - Scalaが使用可能 懸念点 - Javaが入った環境が必要 - JavaFXがベースなのでミュータブル

    要素が強い - テストが難しい - JavaFXが Oracle JDKから削除 JavaFXをScalaでラッパーしたGUIフレームワーク
  5. Scala.js 10 利点 - Scalaの多くの資産が利用可能 - サポートが厚い 懸念点 - 複雑

    - 環境構築が複雑 - フレームワークのデファクトスタンダー ドが決まっていない - 結果テストに対する知見が薄くなる ScalaからコンパイルするAltJS
  6. TypeScript + React(Redux) 12 利点 - サポートが厚い(Microsoft) - 開発者(知見)が多い 懸念点

    - JavaScriptがベースなので、言語そのもののテスタビリ ティが低い - テスタビリティを補うには、フレームワーク依存のテスト フレームワークを利用する AltJS JavaScriptに型を付与した言語
  7. 各環境所感 13 言語 UIに対するテスト ロジックに対するテスト マルチプラット フォーム 開発コスト ScalaFX X

    O △ サポート X Scala.JS X O O X TypeScript + React △(フレームワーク・ ライブラリに依存) △(フレームワーク・ライブラ リ選定) O △
  8. 各環境所感 16 言語 UIに対するテスト ロジックに対するテスト マルチプラット フォーム 開発コスト ScalaFX X

    O △ サポート X Scala.JS X O O X TypeScript + React △(フレームワーク・ ライブラリに依存) △(フレームワーク・ライブラ リ選定) O △ Elm O O O △(O?)
  9. Elm 17 利点 - 言語自体がフレームワークを内包している (選択コストが無い) - ビルド環境がシンプル - 型安全

    - テスタビリティが高い (純粋関数型言語) - 学習コストが低い(初期コストは高いが途中から平坦 ) 懸念点 - 情報が少ない(がHaskellの知識をほぼそのまま転用可能 ) - JSのライブラリをフルに使うような場合には向かない (Elmを捨てよ) Haskellライクな AltJS
  10. Elm 19 Model - アプリケーションの全体の状態 View - UIを表現した関数呼び出し Update -

    Modelの更新 Msg - 変更の種類を通知 すべての項目に対して言語レベルでテスト可能 (言語レベルでテスト項目を制限 )
  11. Elm 20 Model - 数値、文字列、リスト、レコード View - Html型の値と言う単なるデータ Update -

    Modelを戻り値とする関数 Msg - 網羅性を保証した自己定義型 すべての項目に対して言語レベルでテスト可能 (言語レベルでテスト項目を制限 )
  12. 自動テスト - 値の比較(言語レベル) 21 TypeScript Elm [1, 2, 3] ===

    [1, 2, 3] // false [1, 2, 3] === [1, 2, 3] // True { a: 1, b: “abc” } === { a: 1, b: “abc” } // false { a = 1, b = “abc” } === { a = 1, b = “abc” } // True
  13. 自動テスト - 更新した値の比較 22 TypeScript Elm record = { a

    = 1, b = “abc” } { record | b = “def” } == { a = 1, b = “def” } // True record == { a = 1, b = “abc” } // True var obj = { a: 1, b: “abc” } obj.b = “def” obj === { a: 1, b: “def” } // false 値の更新は、新しい値を作るため 他の関数(処理)に値を渡しても不変であることが保証される
  14. 自動テスト - 分岐した値の比較 23 TypeScript Elm var x = 10

    if(x > 10) { x *= 2 } else { x += 2 } x === 12 x = 10 (if x > 10 then x * 10 else x + 2) == 12 aが前後で 書き換わる ifは式なので そのまま比較可能 xは不変(== 10)
  15. 自動テスト - 分岐した値の比較 24 TypeScript Elm var x = 10

    if(x > 10) { x *= 2 } x === 12 // false // テストがなければ気 づかない x = 10 (if x > 10 then x * 10) == 12 // コンパイルエラー // テストが無くても防げる! elseを書き忘れてし まった!
  16. 自動テスト - オプション値 25 TypeScript Elm function evenDouble(num) { if(num

    % 2 == 0) return num * 2; else return undefind; } var doubled = evenDouble(10) if(doubled === undefined) { return “odd number”; } return “num: ${num}”; evenDouble num = if num % 2 == 0 then Just num * 2 else Nothing case (evenDouble 10) of Just num -> “num: ” ++ toString num Nothing -> “odd number”
  17. 自動テスト - エラー値 26 TypeScript Elm function evenDouble(num) { if(num

    % 2 == 0) return { status: “OK”, value: num * 2 }; else return { status: “NG”, value: “odd number” }; } var { staus, value } = evenDouble(10) if(status === “OK”) { return “num: ${value}”; } else if(status === “NG”) { “error: ${value}”; } evenDouble num = if num % 2 == 0 then Ok num * 2 else Err “odd number” case (evenDouble 10) of Ok num -> “num: ” ++ toString num Err msg -> “error: ” ++ msg
  18. 自動テスト - UIテストと分岐 27 39 37 38 40 39 打たれたキー

    TypeScript function toKeyCode(key) { if(key === UP) { return 38; } else if(key === DOWN) { return 40; } … else { console.log(“なんかのキー”) } } 分岐漏れが怖い else 節は何・・・?
  19. 自動テスト - UIテストと分岐 28 39 37 38 40 39 打たれたキー

    Elm type Key = Up | Down | Left | Right toKeyCode key = case key of UP -> 38 DOWN -> 40 Left -> 37 Right -> 39 case が値を返す パターン漏れはコンパイラが検知、不思議なケー スはカバーする必要がない
  20. 自動テスト - 実際の想定されるテスト 29 TypeScript 状態1 状態2 状態3 状態4 状態5

    状態6 各状態をデバッガ等で確認、人間が網羅的に確認していく。
  21. 自動テスト - 実際の想定されるテスト 30 Elm ケース1 ケース2 ケース3 ケース4 ケース5

    ケース6 Model, Update, Msg, View 自己定義したケースの漏れ (網羅性)、 不正な型の値を返していないかは、コンパイラがチェック 各ケースが正しい値を返しているかはテストで保証 UI(見た目)もテストで保証
  22. Property Based Testing (Fuzz) 31 randomlyGeneratedStringの生成データ例 str: "" str: "k1C#dcn-2=v`xI,q.NmwRDk5wY9QE{IR|z~h

    G6V1dO[Jl]*/f=)C^Z=<i=V+<{ ]le@Cpy{KD*47[gX7(-g?}f2" str: " \t\n\n\n\n" str: "\n" str: "e"
  23. Property Based Testing - 例 32 now > [2018] [5]

    [30] [19] [00] [30] == Expired 0, 1000000000000000, -1, -1000000000000, 10, ...
  24. Elm 39 “[(1, 2), (3, 4), (5, 6)]” |. は捨てる

    |= は値として使う elm-tools/parser 座標の列のパーサコンビネータ