Slide 1

Slide 1 text

TDD with RDD Clojure/Lisp のREPL で変わる開発体験 #NextbeatTechBar 1

Slide 2

Slide 2 text

のシニアエンジニア スタートアップの起業家と投資家のための業務効 率化/ 連携プラットフォームを開発している 主要技術スタック: & TypeScript の運営企業 , などの関数型言語と関数型プログ ラミングの実践が好き Java, , Clojure, Kotlin とJVM 言語での開発実務 に長く取り組んできた lagénorhynque 🐬カマイルカ 株式会社スマートラウンド Kotlin Server-Side Kotlin Meetup Clojure Haskell Scala 2

Slide 3

Slide 3 text

Clojure でRDD とTDD のハイブリッドな開発スタイル を実践しよう 3

Slide 4

Slide 4 text

1. TDD とRDD 2. TDD with RDD 3. Clojure での実践例 4

Slide 5

Slide 5 text

1. TDD とRDD 5

Slide 6

Slide 6 text

[IMO] プログラミングで体感的に大きな割合を占める 対話的プロセス 言語 対話の相手 ( 高度な型システムを持つ) 静的 型付き言語 コンパイラ ( 高度なREPL 開発環境と動的性質 を持つ) Lisp 系言語 REPL その他の多くの言語 ユニットテスト or/and ( ログ付 きの実行を含む) デバッガー 6

Slide 7

Slide 7 text

対話の延長上にある3 種類の開発スタイル コンパイラとの対話 → 型駆動開発(type-driven development) REPL との対話 → REPL 駆動開発(REPL-driven development, RDD) ユニットテストとの対話 → テスト駆動開発(test- driven development, TDD) 7

Slide 8

Slide 8 text

試行錯誤の探索的なプロセス ツールに助けられたり惑わされたりしながら進む 高速で高頻度なフィードバックループ 反応を見て、書き換えて、反応を見る繰り返し 設計の漸進的改善の機会でもある ユニットテストによるフィードバックと一定の動作 保証は高度なコンパイラやREPL を補完しうる 複数を組み合わせて実践しよう💡 8

Slide 9

Slide 9 text

2. TDD with RDD 9

Slide 10

Slide 10 text

テスト駆動開発(TDD) 0. 満たすべき仕様を整理する 1. 🟥 Red: 仕様に対応するテストコードを書いて( 想定 通り) テストをパスしないことを確かめる 2. 🟩 Green: テストをパスする最小限の実装を与えて テストをパスすることを確かめる 3. 🟦 Refactor: 内部実装( コード設計) を改善して引き 続きテストをパスすることを確かめる → 再び1. へ 10

Slide 11

Slide 11 text

コードを読み取り、評価し、出力する繰り返し REPL (read-eval-print loop) ;; [Clojure] REPL 内で素朴なrepl 関数を定義し実行してみる user=> (defn repl [] (loop [] (-> (read) ; 入力の読み取り (eval) ; 評価 (prn)) ; 出力 (recur))) ; 再帰(= ループ) #'user/repl ; 関数定義式の評価結果 user=> (repl) (+ 1 2) ; 入力 3 ; 出力 (map inc [1 2 3]) ; 入力 (2 3 4) ; 出力 11

Slide 12

Slide 12 text

REPL 駆動開発(RDD) 1. ✍️ Write: 小さなコード( 任意の式) を書く 2. 🔍 Eval: 式を評価し結果を確かめる → 再び 1. へ 12

Slide 13

Slide 13 text

TDD with RDD 1. ✍🔍️ テスト対象の式を書いて評価する 2. ✍🔍 テスト用の式を書いて評価し結果を確かめる 🟥 意図通りでない → 再び 1. へ 🟩 意図通り → ( 適宜) テストケースに記録する 3. 🟦 内部実装を改善して評価結果が意図通りである (or テストをパスする) ことを確かめる → 再び 1. へ 13

Slide 14

Slide 14 text

3. Clojure での実践例 14

Slide 15

Slide 15 text

事前準備: プロダクトコード用ファイル (ns clj-tdd-with-rdd.core) ; 名前空間( モジュール) の宣言 (defn fizzbuzz [n]) ; 関数の定義( ※ボディはまだ空) 15

Slide 16

Slide 16 text

事前準備: テストコード用ファイル (ns clj-tdd-with-rdd.core-test (:require [clj-tdd-with-rdd.core :as sut] ; テスト対象 [clojure.test :as t])) ; 標準のテストライブラリ (t/deftest test-fizzbuzz ; テスト関数の定義 (t/testing "3 の倍数ならFizz") ; テストケースの説明 (t/testing "5 の倍数ならBuzz") (t/testing "3 の倍数かつ5 の倍数ならFizz Buzz") (t/testing "3 の倍数でも5 の倍数でもなければ整数の文字列")) 16

Slide 17

Slide 17 text

エディタでファイルを開き、REPL に接続する 17

Slide 18

Slide 18 text

関数の定義と適用の式を評価してみる 18

Slide 19

Slide 19 text

関数定義を書き換えてそれぞれ評価してみる 19

Slide 20

Slide 20 text

テストケースに書き換えて評価してみる 20

Slide 21

Slide 21 text

類似のケースを追加してテスト全体を実行してみる 21

Slide 22

Slide 22 text

さらに続けて…… 22

Slide 23

Slide 23 text

プロダクトコードとテストコードを書き上げた 23

Slide 24

Slide 24 text

リファクタしてみた 24

Slide 25

Slide 25 text

リファクタリング後もテストをパスする😌 25

Slide 26

Slide 26 text

リッチなREPL は探索的な開発フローを加速する♾️ Lisp 系言語のREPL はいいぞ😈 ( 他言語でも同じような開発体験がしたい) 26

Slide 27

Slide 27 text

Further Reading cf. Clojure/ClojureScript 関連リンク集 > REPL 駆動開 発 『テスト駆動開発』 Type-Driven Development with Idris Idris: A Language for Type-Driven Development 型駆動開発|プログラング言語Idris に入門させた い(v0.9 ) 27