はじめに
変更しやすいコードが書けないのにソフトウェア開発とか舐めているのですか
天使様1ごめんなさい〜、nikkieです
「かわいい」と技術書が夢の合体を果たした、ちょうぜつ本(『ちょうぜつソフトウェア設計入門』)!🤗
読書会と絡めて読み進めており、今回は第6章「テスト駆動開発」の6.6を写経しつつ読みました。
目次
- はじめに
- 目次
- 前回のちょうぜつ本!
- 仕様変更を考慮したFizzBuzz
- TDDでジェネリックFizzBuzz
- シンプルさ
- 終わりに
- P.S. 9/22(金) 第6章「テスト駆動開発」後半のちょうぜつ本_読書py!
前回のちょうぜつ本!
いわしまんさんの書評エントリがきっかけで、手に取りました。
6.5まで読み進め、BDDを体験。
次の読書会の予習の一環で、今回は6.6に取り組みます
仕様変更を考慮したFizzBuzz
5章のOCP(開放閉鎖原則)で、仕様変更を考慮したFizzBuzz(a.k.a. ジェネリックFizzBuzz)の実装例が登場します2。
このFizzBuzzがどうできたのか、それが6.6で明かされるのです!
DDD の「深いモデル」という用語、なんか、言葉がロマンチックすぎて拡大解釈されがちなんじゃないかな。意図してはいなかったけど、ちょうど #ちょうぜつ本 で「FizzBuss というのは、突き詰めると畳み込み演算のことだったのか」とTDDで発見した、あれでいいんじゃないのかな
— 田中ひさてる (@tanakahisateru) 2023年8月17日
6.5からつなぐ言葉は設計手法としてのTDDでした。
テスト駆動開発を設計に使って、5章で見たFizzBuzzが実装されていきます!
TDDでジェネリックFizzBuzz
ポイントは、モックを使って仮説検証していくことだと思いました。
- 抽象についての仮説(初案)
- ReplaceRuleInterface(抽象)をモックして具象を用意し、FizzBuzzのロジックのテストを書く
- replaceメソッドが引数1で呼ばれたら、
"hoge"
を返すのようにモックを設定 - 具象のルールが実装されていなくても、テストではモックを具象として動作検証できる
- FizzBuzzのロジックはできた!
- replaceメソッドが引数1で呼ばれたら、
- ReplaceRuleInterface(抽象)を実装した具象4
- 倍数のreplaceを扱う具象
- 数字を文字列にreplaceする具象
- できたー!! BDD的なテストで動作確認するぞー
「Fizz3だと!?」(Kindle版 p.258)
初案をもとに、テストファーストでFizzBuzzを実装していきますが、最後BDDで予期せぬ動きとなります。
このエラーを分析し、抽象についての仮説の2案目に至ります。
- 抽象についての仮説(第2案)
- ReplaceRuleInterfaceは(replaceの代わりに)applyメソッドとmatchメソッドを定義
- FizzBuzzのロジックの実装を、ruleにmatchしたらapplyと変える
- applyは累積する(畳み込み演算!)
- インターフェースを変えたのでテストは落ちる。1つ1つ直していく
- 直し切ると、BDD的なテストも通る!!🙌
写経したコードはこちら:
ここで紹介されたモックの使い方(抽象をモック)を、私はほとんどしてきませんでした。
写経してやってみたときにハッとしたのはこの一節です。
仕様を頭の中で考えているうちは、どれだけ知恵をしぼろうと、完全な設計を得ることはできません。(Kindle版 p.262)
たしかに、仕様を頭の中でしか考えていなかったな〜、と。
「開発完了!テストも通ってる!動かすぞ〜」となって、実データに対して動かない経験をしてきました。
これって抽象をモックして検証できておらず5、手を動かして仮説検証が足りなかったから、完全な設計に至ってなかったってことじゃないかと思います。
抽象をモックすると、「実データに対して動かない!」の検出タイミングが前倒しになると理解しました(具象を作るより前に気づける!)。
シンプルさ
設計手法としてのTDDで至ったFizzBuzzはシンプルだと思います。
これはRich Hickeyが語る意味でのシンプル6、イメージはレゴブロックです。
Pythonで表すと以下のようになるのですが、
fizz_buzz = NumberConverter( [ CyclicNumberRule(3, "Fizz"), CyclicNumberRule(5, "Buzz"), PassThroughRule(), ] )
1つ1つは小さなRuleを組合せてFizzBuzzを実現しているという点がシンプルだと思うのです。
Ruleがレゴブロックの1つ1つで、Ruleを組合せてFizzBuzzができあがります。
そして作ったものの作り直しも簡単です!
ここに至るには、TDDのTODOリスト7からして違うのではないかと思うのです。
FizzBuzzの仕様からTODOを書き起こしたのではなく、長生きすると分かっていて(もしくは確度高くそう信じられて)変更容易な=シンプルなFizzBuzzの仕様として書き起こしたのではないでしょうか。
そして実装中も抽象についての仮説をモックで検証していき、仮説検証のフィードバックを元にTODOリストを更新しているように思えます。
終わりに
ちょうぜつ本 6.6で、設計手法としてのTDDを体験しました。
モックを使って抽象(仮説)を検証し、シンプルなFizzBuzzに到達します。
6章の扉には「変更に対して安全なアーキテクチャの設計を、確かに動くものとして作っていく方法」とあり、6章までできれいに示されたなと感服です👏
ここで紹介された方法は私はあまり経験がないのですが、「変更容易な設計にするには、こういう抽象がいいんじゃないかな」という仮説を早期に検証できるのがよさそうなので、自分のプロジェクトなどで練習していきたいですね。
P.S. 9/22(金) 第6章「テスト駆動開発」後半のちょうぜつ本_読書py!
次回ちょうぜつ本_読書py(Python使い視点でちょうぜつ本を読む、みんなのアウトプット中心の読書会)は9/22(金)です!
常連さんも、お久しぶりの方も、はじめましての方もテスト駆動開発に興味ある方、大歓迎です!
ぜひぜひお気軽にお越しください〜
- ちょうぜつ本読書ログシリーズではおなじみのこちらの書き出し。元は『お隣の天使様にいつの間にか駄目人間にされていた件』の「家事ができないのに一人暮らしとか舐めているのですか」です↩
- 「本質を抜き出して変更に対して閉ざし、仕様は拡張に対して開きます。」読書ログ | #ちょうぜつ本 第5章 〜SOLID原則、この章までの積み重ねと豊富なサンプルコードでこれまでで一番分かりやすかった解説!〜 - nikkie-ftnextの日記↩
- ソースコードにおいて、抽象はcoreに置かれています↩
- ソースコードにおいて、具象はspecに置かれています↩
- 実力不足で、そもそも抽象が浮かばなかったこともありました↩
- 直近ではこちらで取り上げました ↩
- 直近書いた おーい、t-wadaさん、ペアプロしようぜ!TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング 視聴ログ🦁 - nikkie-ftnextの日記 をどうぞ↩