はじめに
本記事はテスト駆動開発 Advent Calendar 2021の3日目の記事です。8月に書いた記事であり、新作ではありませんが、アドベントカレンダーがスカスカなので穴埋めします。
アドベントカレンダーへのご参加をお待ちしております!
この記事を書いた目的、読んでもらいたい対象
書籍『テスト駆動開発』には下記のように書かれています。
テスト駆動開発の良さ、強みは手を動かせば分かります。
結果ではなく過程に本質があります。
テスト駆動開発とは練習によって獲得できる技術です。
ですが、その練習の題材として何があるのか、知らない人も多いかもしれません。
そこで本記事では、テスト駆動開発(以下、TDD)の練習題材になりそうなものを紹介していきます。また、私なりの題材のポイントも合わせて紹介します。
「FizzBuzzの次に何をしよう…?」と悩んでいる人に参考にしてもらえればと思います。
目次
- はじめに
- この記事を書いた目的、読んでもらいたい対象
- 目次
- 題材を紹介する前に 〜題材の使い方〜
- 基本問題
- 設計まで踏み込む問題
- ボトムアップで取り組む問題
- トップダウンで取り組む問題
- レガシーコードのリファクタリングの問題
- さいごに 〜参考文献など〜
題材を紹介する前に 〜題材の使い方〜
TDDで題材を選ぶポイントは以下の2つがあります。
- プログラミング言語やTDDに対する慣れ(少ないor多い)
- 題材の難易度(低いor高い)
TDDを練習するには、この2つのバランスを考えた方が良いです。
例えば、新しく学ぶプログラミング言語のTDDを練習しようと思ったら、簡単な題材を選びましょう。
一方、ある程度業務でも使っているプログラミング言語のTDDを練習しようと思ったら、少し応用の題材でも良いかもしれません。
基本問題
ここからは、題材になるようなものをどんどん紹介していきます。
まずは基本問題です。新しいプログラミング言語を使ったり、初めてTDDを練習してみる時は、この基本問題に書いている題材から始めると良いでしょう。
題材1. FizzBuzz
みんな大好きFizzBuzzです。
この題材を用いて、t_wadaさんがライブコーディングしている講演が既にYoutubeに上がってます。この動画を見ながら、写経してみるのも良いかもしれません。
題材2. ローマ数字変換
ローマ数字を数値に変換するプログラムです。
例えば、下記のようになります。
◆入力値
MCMXLIV
◆出力値
1944
毎回FizzBuzzばかりで飽きた人向けです。
ただし、単純作業が多く発生するため、途中で飽きる可能性があります。
題材3. ボウリング
ボウリングの点数を算出するプログラムです。
例えば、下記のようになります。
◆入力値 X 12 9/ 12 ※「X」がストライク、「/」がスペア ◆出力値 30
最初は単純な足し算をやった後に、ストライクやスペアの計算についての仕様を追加していく形になるでしょう。
題材4. 格子点
x座標とy座標からなる格子点についての問題です。
入試数学のように導かれるような順番で出題されているので、ステップバイステップでTDDを練習することができます。
この題材を用いた、いのうえさんととーますさんのペアプロ動画が既にYoutubeに上がってます。この動画も参考にしてください。
設計まで踏み込む問題
基本問題から少し発展した問題です。言語、TDDに少し慣れてきた人が解いてみると良いでしょう。
題材5. 火星探索機
初期位置(x,y)とステージの広さを定義した後、「90°右回転」「90°左回転」「前進」「後進」の指示を元に、現在位置(x',y')を求める問題です。「題材4. 格子点」の応用のような位置付けです。
火星は球体なので、ステージの広さが(5,5)の広さの時、初期位置(1,1)の北向きで90°左回転して前進すると、現在位置は(5,1)になるのがポイントです。
例えば、下記のようになります。
◆入力値 初期位置(1,3)、ステージの広さ(5,5)、北向き 「90°左回転」「前進」「90°右回転」「前進」 ◆出力値 現在位置(5,4)、北向き
題材6. ポーカー
ポーカーの手札の役判定などを行う問題。
上記のTDDBC Sendaiの出題がステップバイステップで分かりやすいので、入出力例についてはそちらを見てください。
題材にも馴染みがあるので、取り組みやすいかもしれません。
ボトムアップで取り組む問題
一定のルールに基づいているので、まずは小さい範囲で考えて、だんだんとその範囲を広げて解いていく形式の問題です。
題材7. ラングトンのアリ
正方形が敷き詰められた地面にアリがいて、下記のルールに従ってアリが進む問題です。
- 現在位置が白マスだったら黒マスに変更して右に進む
- 現在位置が黒マスだったら白マスに変更して左に進む
シンプルなルールですが、下記画像のように面白い動きになります。
プログラム入出力例は下記のようになります。
◆入力値 ステージの広さ(3,3)、初期位置(2,2) ◆出力値(※「-」が白マス、「*」が黒マス) 0 --- -a- --- 1 -a- -*- --- 2 -*a -*- --- 3 -** -*a --- 4 -** -a* --- 5 -** --* -a-
題材8. ライフゲーム
正方形に敷き詰めた地面に対して、条件によってセルが生きたり死んだりします。 条件は下記の通りです。ここでいう「隣接するセル」とは、自身のセルの上下左右斜めの8つが対象です。
- 死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代が誕生する。(誕生)
- 生きているセルに隣接する生きたセルが2つか3つならば、次の世代でも生存する。(生存)
- 生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。(過疎)
- 生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。(過密)
この題材も面白い動きになります。
プログラム入出力例は下記のようになります。
◆入力値 ステージの広さ(5,5)、初期生存セル(2,3)(3,3)(4,3) ◆出力値(※「-」が死滅セル、「*」が生存セル) 0 ----- ----- -***- ----- ----- 1 ----- --*-- --*-- --*-- ----- 2 ----- ----- -***- ----- -----
トップダウンで取り組む問題
途中で仕様が追加されていく問題です。問題を進めるに従ってコードが変化していくはずです。
題材9. Potter
ルールに従って、同じシリーズまとめ買いによる値段の割引が行われる時、その最安値を求める問題です。
ルールは下記の通りです。
- 1冊1000円
- 同じシリーズの別の巻を2冊買うと、それぞれ5%引き
- 同じシリーズの別の巻を3冊買うと、それぞれ10%引き
- 同じシリーズの別の巻を4冊買うと、それぞれ15%引き
- 同じシリーズの別の巻を5冊買うと、それぞれ20%引き
例えば、下記のようになります。
◆入力値 第1巻を1冊、第2巻を1冊 ◆出力値 (1000*2)*0.95=1900円 ◆入力値 第1巻を2冊 ◆出力値 1000 * 2 = 2000円 ※同じ巻なので割引なし ◆入力値 第1巻を2冊、第2巻を1冊 ◆出力値 (1000*2)*0.95+1000=2900円 ◆入力値 第1巻を2冊、第2巻を1冊、第3巻を1冊 ◆出力値 (1000*2)*0.95+(1000*2)*0.95=3800円 (1000*3)*0.9+1000=3700円 ※(第1巻+第2巻)の5%引き+(第1巻+第3巻)の5%引きのパターンと、 (第1巻+第2巻+第3巻)の10%引き+第1巻のパターンが存在する
題材10.LCD表示
数値を与えられると、それに対するLCD表示(デジタル表示)を求める問題です。
例えば、下記のようになります。
◆入力値 2 ◆出力値 _ _| |_
問題が進むと、途中で仕様変更が発生し…というのがミソ。ネタバレ防止のために、ここには記載しません。
題材11.自動販売機
自動販売機の動きをプログラミングする問題です。
題材: プログラミングのお題: 自動販売機 (設計進化重視バージョン) · GitHub
仕様が提示されている形式なので、単なるTDDではなく、cucumberなどを用いたATDDで解くのもオススメです。
またこの題材を元に、TODOリストの整理の仕方について説明した発表を以前に行いました。
レガシーコードのリファクタリングの問題
ここからは既存のコード(テストコード無し)に対して、リファクタリングをしていく問題です。
題材12. テニスゲーム
テニスの点数表示を題材とした問題です。詳しくは、リンク先参照。
同じ仕様に対して3パターンの実装があるので、1つの言語に対してリファクタリングを3回練習できます。
テニスの計算方法を知っていれば、仕様の読み込みを行う必要がなく、すぐに問題に取り組めるので便利な題材です。
ソースにはテストコードが既にありますが、既存のテストコードを消して、レガシーコードのリファクタリングの練習として使うのがオススメです。
先日公開した書籍『テストコードの注入から始めるレガシーコードのリファクタリング』では、この題材のリファクタリング過程を載せて解説しています。
題材13. GildedRose
仕様もあって面白い問題です。詳しくは、リンク先参照。
今年のJaSST Tokyoでも題材にして、実際にリファクタリングする様子をライブコーディングしました。
また、先日公開した書籍『テストコードの注入から始めるレガシーコードのリファクタリング』では、この題材のリファクタリング過程を載せて解説しています。
題材14. trivia
クイズゲームを題材とした問題です。詳しくはリンク先参照。
この題材をリファクタリングしている動画が既にYoutube上にあったりします。
さいごに 〜参考文献など〜
TDDの題材になりそうなものをざっと紹介してみました。
ご自身のプログラミング言語のスキルレベル、TDDのスキルレベルに合わせて、適切な難易度かつ楽しそうな問題を選んで取り組んでみてください!
もしも「他の題材も探したい!」という人は、下記のサイトがオススメです。
TDD Boot Camp(TDDBC)
おそらくTDDに関して日本で一番充実しているサイト、コミュニティです。
年に数回、ワークショップ形式のイベントも開催しています。
本文中に紹介した、t_wadaさんのライブコーディング動画や、いのうえさんととーますさんのペアプロ動画はこのコミュニティのイベントによるものです。
All Kata
今回紹介した題材の多くが載っているサイトです。
Kataの用途ごとにTopicが分かれているので、行いたい内容を元に題材を探すにも最適です。
Coding Dojo
今回紹介した題材の多くが載っているサイトその2です。
All Kataに比べると、目的にあった題材を探すのは少し難しいです。
Cyber Dojo
オンライン上でTDDを練習できるサイトです。
現時点で58種類の問題が用意されています。
ただし一覧になっているので、難易度や目的に沿ったお題なのかは分かりづらいかも。
Philippe Bourgau's XP Coaching Blog - A coding dojo exercises plan towards refactoring legacy code
題材集ではないですが、今回のブログを書くにあたって大いに参考にしたサイトです。
題材を区切った種別の仕方(ボトムアップ、トップダウンなど)は、このサイトを参考にしました。
最後に、書籍『テスト駆動開発』の文章をもう一度載せます。
テスト駆動開発の良さ、強みは手を動かせば分かります。
結果ではなく過程に本質があります。
テスト駆動開発とは練習によって獲得できる技術です。
ぜひ、たくさん練習して、TDDを身に付けてくださいね!