挨拶
こんにちは。2023年04月に入社した、minne事業部エンジニアの@kazuです。
この度、弊社GMO ペパボ(以下、ペパボ)では2022年に引き続き、今年も日本のTest-Driven Development(TDD) の第一人者である @t_wada さんをお招きしてTDDワークショップを開催しました。前回:『t_wadaさんによるTDDワークショップを開催しました』
なぜTDDワークショップを開催しているのかについては、こちらの記事『ふつうの開発と TDD ワークショップ』で詳しく説明していますのでご覧ください。
さて、それでは今回のTDDワークショップで何をしたのか、どんな気づきがあったのかなどについて、参加パートナーからそれぞれお話ししてまいります。
具体的な研修内容
概要
ワークショップは、事前に各参加パートナーが基調講演/ライブコーディングの動画を予習し、動画内でのライブコーディングの続きからスタートして、動画には収まりきらなかった応用的な内容とそれをベースにした議論から始まりました。また、実際に参加パートナーがコーディングする際には、整数の閉区間についての実装課題に取り組みました。
スケジュール
- 10:00 〜 12:35 講演 + ライブコーディングによるデモ + 質疑応答
- 12:35 〜 13:35 昼休み
- 13:35 〜 16:30 ワークショップ + 1on1コードレビュー
- 16:30 〜 17:00 全体レビュー + 質疑応答 + クロージング
ライブコーディング
自己紹介
4月に入社した @kromiii です。
博士新卒という珍しいキャリア出身ですが、ペパボの個性あふれる社員の中で日々楽しく働いています。
私からは講義前半をまとめます。
事前教材
ワークショップの前日に @t_wada さんから事前教材(動画)が配布され、そこでTDDについての基礎的な事項の説明がありました。
そこではFizzBazzという世界のナベアツみたいなプログラムを例にとって、実際にTDDでコードを書くということがどういうことなのか、映像で学習する流れになっていました。
事前の印象では、「簡単なプログラムでもTDDだと毎回大量のテストを書かないといけないので大変だなぁ」くらいのざっくりとした理解でした。
当日の講義スタイル
そんなわけでTDDへの理解がおぼろげなまま当日を迎えたのですが、最初に@t_wadaさんから指示があったのは 「みんなSlackでどんどんワイワイしてほしい」 ということでした。
オンラインでの講義は気を抜くとただ存在するだけの場になってしまいがちです。
そうではなくて、Slackでの双方向のやり取りを通して 「みんなで講義を作り上げていく」 というところに注力されていたのが非常に印象的でした。
そのため、講義の最初は各々が今朝食べたものをSlackに書き込むというアイスブレイクから始まりました。
ちなみに私は黒糖クロワッサンとかだったと思います(意識高い)。
講義の要点
ここからは講義の内容についてですが、まずは事前課題として渡されたTDDに関する基礎的な事項についての振り返りから始まりました。例えば
テスト駆動開発とは何か? → 「動作するきれいなコード」をキープすること
だったり
良いテストとは何か? → テストがそのままドキュメントとして理解できるようなテスト
とか具体例をまじえてわかりやすく教えてくださいました。
また講義の後半には私を含めた受講者からの質問に答える形で
- リファクタリング失敗した場合は立て札を立てること
- テストコードへのロジックの漏れ出しに注意すること
など実践的で実務で役立つ知識を伝授していただきました。
参考図書
講義中に @t_wada さんが紹介してくれた参考図書を共有します。テスト駆動開発についてより深く知りたい方におすすめです。
- 『テスト駆動開発』
- 『Clean Architecture 達人に学ぶソフトウェアの構造と設計』
- 『LeanとDevOpsの科学[Accelerate] テクノロジーの戦略的活用が組織変革を加速する』
ワークショップ&1on1レビュー
今年新卒入社した@yumuです!最近はゼルダの伝説 ティアーズ オブ ザ キングダムを一生やっています。
ここからは、ワークショップのお題&1on1レビューについてお話ししていきます。
ワークショップのお題
ワークショップでは、指定されたお題をTDDで実装していきました。
使用する言語は何でも良いとのことだったので、私は馴染みのあるRubyで参加しました。
お題は「問題文の長さ」×「自力でTODOを分解するかどうか」で4パターンに分けられており、自分が解けそうな問題からチャレンジできました。
今回のお題は「整数の閉区間を示すクラスを作る」で、4つの問題文は以下の通りです。
- 整数の閉区間(短めの問題文)
- 整数の閉区間(長めの問題文)
TDDを身につけるためにも、できるだけ自力でTODO分解版に取り組んだほうがいいとのことだったので、私は「長めの問題文」×「自力でTODO分解」版に挑戦しました。
まずは、午前中の講義を思い出しながら、以下のようにTODOに分解しました。
# 問題文
整数閉区間を示すクラス(あるいは構造体)をつくりたい。
整数閉区間オブジェクトは下端点と上端点を持ち、文字列表現も返せる(例: 下端点 3, 上端点 8 の整数閉区間の文字列表記は "[3,8]")。
ただし、上端点より下端点が大きい閉区間を作ることはできない。
整数の閉区間は指定した整数を含むかどうかを判定できる。
また、別の閉区間と等価かどうかや、完全に含むかどうかも判定できる。
# TODO
- [] 下端点を持つ
- [] 上端点を持つ
- [] 上端点 < 下端点の閉区間を作ろうとすると例外を発生させる
- [] 文字列表現を返すことができる
- [] 指定した整数を含むかどうかを判定できる
- [] 指定した整数が下端点より一つ小さい場合、falseを返す
- [] 指定した整数が下端点と等しい場合、trueを返す
- [] 指定した整数が上端点と等しい場合、trueを返す
- [] 指定した整数が上端点より一つ大きい場合、falseを返す
- [] 指定した別の整数閉区間オブジェクトと等価かどうかを判定できる
- [] 指定した整数閉区間オブジェクトと等価な場合、trueを返す
- [] 指定した整数閉区間オブジェクトと重なるが等価でない場合、falseを返す
- [] 指定した整数閉区間オブジェクトと全く重ならない場合、falseを返す
- [] 指定した別の整数閉区間オブジェクトを完全に含むかどうかを判定できる
- [] 指定した整数閉区間オブジェクトと等価な場合、trueを返す
- [] 指定した整数閉区間オブジェクトと重なるが等価でない場合、falseを返す
- [] 指定した整数閉区間オブジェクトと全く重ならない場合、falseを返す
仕様を場合分けする際は、「〜〜な場合、〜〜を返す」という形式で文章を統一し、実装時に条件間の差異がわかりやすくなるように工夫しました。
また、仕様に書かれている以外の事象(例えば小数点が入力された場合など)は極力考慮せず、仕様に書いてある最低限の内容を確実にTDDで実装することに集中しました。
さらに、実装はChatGPTやGitHub Copilotを使いながら行いました。
ペパボでは以前からAIの活用が盛んで、GitHub Copilotも最近全社的に導入されました。
テストでは、it '下端点を持つこと'
のように、最初にこれから書くコードの内容を書く形が多いため、Copilotとの相性が良く、スムーズに実装を進めることができました。
今回私はテストの読みやすさを重視し、it
やcontext
の内容を日本語で書いたのですが、AIを活用する際は英語で書いた方がより良い結果が得られる可能性があると感じました。
この点について、@t_wadaさんもどちらが良いかは状況次第だとおっしゃっていました。
1on1レビュー
実装中には2度@t_wadaさんと1on1の時間が設けられ、悩んでいる箇所を相談したり、コードを見てもらった上でアドバイスを受けることができました。
私の場合は、itを書いておくことでテストをpending状態に保つ方法や、必要十分なテストを書くための場合分けの仕方についてのアドバイスを受けました。
1on1は参加者全員がjoinしたmeetで行われたので、他の人が受けたフィードバックも聞くことができ、自分の実装に活かすことができました。
他の参加者の中には、RustやGoでテストを書いたり、私とは異なるアプローチでTODOリストを作成したりしている人もいて、とても勉強になりました。
成果物のシェア会
昨年10月にminneのWebエンジニアとして入社した @inoway です!テストでRedからGreenに変わった瞬間の気持ちよさが好きです!ここからはワークショップで作成した成果物のシェア会についてお話していきます。
趣旨
みんなの前で成果物をシェアすることで、@t_wadaさんや他の参加者からのフィードバックを受けることで、発表者はもちろん、みんなの学びにするためのものでした。
挙手&投票制で発表者を決める
まずは、@t_wadaさんとの1on1を通して作成した課題について発表したい人を決めました。挙手すれば発表者になれるとのことで、恥をかいてこそなんぼの精神で挙手してみました。クオリティに自信はなかったですが、だからこそフィードバックをいただいて改善していきたいという気持ちでした。
次に投票により発表者が決まり、@n01e0と@kromiiiが発表することになりました。@n01e0は講義中に鋭い指摘をたくさんしていて、@kromiiは講義中のコメントで議論を活発化させていたのが印象的でした。
発表タイム
内容は、課題を解く上で工夫したこと・苦戦したことをそれぞれ発表しました。
@t_wadaさんより「発表中はテンション高めに実況していきましょう」という声かけがあり、それぞれの発表タイムで参加者たちがSlack上でわいわいコメントしました。「自分もそこで迷った」「この観点おもしろいですね」などの気づきや学びを後から振り返ることができるので、コメントをたくさん残すことって大事だなと改めて実感しました。
以下、3名の発表のハイライトです。それぞれ本人コメントになります。
@inoway
自分はRubyで書きました。ある仕様を実現するために、メソッドの中身をdef true end
と書いてGreenにし、そこからGreenにしたままリファクタリングを重ねていくステップを踏むことで、期待通りのロジックを組むことができ、とても楽しい経験になったことを話しました。質問タイムでは、@donokunから「describeとcontextの使い分けって何ですか?」という質問をいただいて、そういえば曖昧な理解だったなということに気づくことができました。@t_wadaさんから補足があり、「両者はエイリアスのため挙動は同じだが、意味としては異なっている。describeは機能について、contextは状況について書く」ということを知りました。今までdescribe -> contextという包含関係のみで書いていましたが、context -> describeと書くべき場合もあることを知り、次にテストコードを書く時は意識しようと思いました。
@n01e0
自分はRustで実装しました。「仕様からToDoリストを作成し、それに基づいたテストを書いた上で、それらを満たすような型を実装する」という流れで作業を行い、型システムの強力さとテストの書きやすさからTDDとの相性が良いと感じたことを共有しました。
また、「リファクタリングできなかった部分をコメントで記述する」という方法が、Rustにおいては「この機能がまだstableではないので冗長な書き方になっています」というような使い方ができ、便利でした。
@kromiii
私はRubyで書きました。実装にあたって気をつけたことは 1. TODOリストの作成を念入りに行うこと、2. Red > Green > Refactoringの順番を厳密に守ることです。コードを書くフェーズではGitHub Copilotを使いました。Copilotのメリットとしてはテスト名やプロパティ名を良い感じにしてくれるところです。デメリットとしては補完がききすぎるため、不要なテスト関数が生成されてしまうことです。RSpecを使うのは初めてでしたがCopilotのおかげで完走できたのは良かったです。
TDDワークショップに参加した各パートナーからの感想
@kromiii
TDDに触れるのは初めてだったので、最初の講義の部分ではUnit Testの概念やテストの偽陽性の話など理解が追いつかない部分もありました。しかし後半のハンズオンで実際に手を動かしながらテストを実装することによって TDD への理解が深まったような気がします。
特に1on1で、@t_wadaさんからTODOリストの書き方を褒められたのは自信につながりました。また最近GitHub Copilotが導入されたこともあり、TODOリストからテストの実装に関してはスムーズに行うことができました。テスト駆動開発に関する書籍なども今後読んでみたいです。
@yumu
これまでもTDDについて学習したことはありますが、自身のスキルセットに組み込まれているとは言えず、実際の業務で使った経験もありませんでした。今回、TDDの各ステップ(Red、Green、Refactor)について詳細な説明を受け、それに従ってテストを実際に書いてみたことで、業務内でTDDを適用するイメージができました。
今回は比較的シンプルなお題でテストを書いたため、より複雑な機能に取り組む際は難易度が上がると思いますが、今回学んだことを忘れず、問題を細分化しTODOリストを作成するところから始めようと思います。
@donokun
これから何を実装すれば良いか、既存の実装は何をするかをテストで表現する考え方を知りました。
Humble ObjectパターンやTest Doubleのようなテクニックはテストを小さく安定したものにするテクニックで、上手にテストを書くためのイディオムみたいなものだと解釈するようになりました。上手に開発をするために、今回の学びを活かしていこうと思います。
@kosuke
今回の講義では1on1をする機会をいただけて非常に有意義でした。ワークショップ後に追加で行ったレビュー会を通じてさらに知識を深めることができ、改めて自身の知識の不足点を見つけるきっかけとなりました。
これからはワークショップで学んだことを実務に活かし、TDDのプロセスを適用しながら、継続的に学びを深めていきたいと思います。
@n01e0
私はRustを使ってTDDに取り組みました。TODOリストを書き、型を定義するとCopilotが大活躍するので、TDDとCopilotの相性の良さを感じました。
また、Testでカバーすべき範囲とFuzzingで検知すべき部分の違いまで考えることができ、非常に楽しい講義でした。
以下ChatGPTによるいい感じのまとめ
先日、まことに興味深く気鋭な@t_wada氏のTDDワークショップに潜入し、驚くべきRust言語を使用してTDDの冒険に乗り出しました。我々の旅は、わずかな要件から一連のTODOリストを生み出すことから始まりました。続いてテストを筆記し、型定義を施すと、Copilotの驚くべき技芸により、たちまちコーディングが極めて効率的なものと化すのであります。
TDDの利発さにただただ驚嘆することはもちろん、Copilotが如何に相性抜群かも認識せざるを得ませんでした。長らく強靭な型システムを擁する言語におけるテストの真髄については、あまり鑑みることなく過ごしてまいりましたが、今回の体験から、この信念がCopilotと型システムの効果を最大限発揮する遠因となることに気づくことができたのです。
世にも奇跡のような出会いに恵まれ、有益な知見を得ることができたこの度のTDDワークショップ。Rust、TDD、そしてCopilotが見事な調和を奏でる中、未知の世界への扉が開かれるのを感じずに はいられません。さあ、この目から鱗のワークショップに触れるや否や、伝説の冒険者になるための旅が始まるのです!
tsurup
TDDについて学習する機会がありましたが、実際の業務では出来上がっているコードを参考にして実装することが多く、実際に自分がTDDの考え方に沿って開発できていなかったと思います。
ワークショップを通して、信頼性の高い自動テストを備えることの重要性を改めて認識することが出来ました。また、講義全体を通して知識不足もあり、理解するのが難しいことが多々ありましたが、Unit TestのUnitについて実際のコードを通して説明をしていただき、理解を深めることが出来ました。
とても学びのある時間を過ごすことが出来たと同時に、知識不足も痛感いたしました。今回の学びを実際の業務に活かしていけるように、継続して学習していきたいと思います。
@harukin
これまでTDDという概念には馴染みがなかったのですが、実務ではテストコードを書く機会がありました。ただ、既存のテストコードを見て、なんとなく書いていたため、TDDのRed、Green、Refactoringのサイクルには意識が及んでいませんでした。
今回の研修でGo言語を選択しましたが、Go言語におけるテストコードの書き方についてのアドバイスやサンプルコードを教えていただき、研修前よりもテストに対する理解が深まったと感じています。実務でも学んだことを実践していきたいと思います。
@inoway
@t_wadaさんの講義をYouTubeやポッドキャストなどで度々お聞きしていて、今回のTDDワークショップに参加できることをとても楽しみにしていました。TDDに取り組んでみたいという気持ちはありつつも、実務ではいつもの書き方に甘んじていたので、こうした研修の機会をいただけたのがありがたかったです。
また、Unit Testのsociableとsolitaryの違いの理解が至らず「コード例を見てみたい」と軽い気持ちでリクエストすると、昼休みの間にコードサンプルを用意していただいていてとても驚きました。おかげさまで理解が進み、感謝しております。
ワークショップ後にRubyで書いた人同士でレビュー会を行い、さらに理解を深めることができました。実務でもconventional commitsを使用し、Red→Green→Refactoringのサイクルを回すことにチャレンジしていきたいと思います。そしてチームにTDDの文化を広げていきたいです。
@horiyu
研修の感想を端的に表すと「手が動いて、コードが綺麗になって楽しい!」でした。
TODOリストの作成をすることで、これからすべき実装が明瞭になり、Red、Green、Refactorの流れで作業を進めるとコードがどんどん綺麗になっていきました。
特に印象に残っている点はTODOリストを修正していく中で、本当に実装すべきものが何か明確になっていくことです。例えば、仕様書に「値を返す」とあったときに、それは文字列なのか、数値なのか思い込みで実装してはなりません。実務で置き換えれば、しっかりとどのような仕様なのか確認するという作業がそこで挟まります。最初にTODOリストを作り、徐々に修正していくことは本当に求められているものを実装する上で大切な作業だと感じました。
@kazu
ワークショップを通して感じたことは以下の2点でした。
- TDDを実践することで、実際に実装を進める前に、仕様理解における曖昧さを明確にし、解消することができる
- Red→Green→Refactorの順で進めることで、安心感を持ってコードを書くことができる
まず1について、実際に実装を進める前にTODOリストを書きながら、「この場合はどうすればいいのだろう」と様々なケースをイメージして、それぞれのケースにどう対応するかを考えることができました。そのようにして、仕様理解における曖昧さが明確になり、考慮の漏れについての不安が限りなく少なくなった状態で実装を進めることができました。
次に2について、まずテストが落ちるであろうテストコードを書いて確かに落ちることを確認し、次にそのテストコードが通るように実装をしてみて、確かにテストが通った時には自分の実装が正しいという安心感を得ることができるので、安心して楽しく実装を進めることができました。また、リファクタリングをする際にはテストが通っているうちは、「より読みやすく綺麗なコードを書くこと」に集中できることが嬉しいことでした。
@t_wadaさんからのコメント
昨年の研修に続き、予習できるものは事前に動画で予習いただく反転学習の要素を取り入れた研修を設計し、応用的な内容の講義から始めることができました。 また、当日は研修用の Slack チャネルを作成いただき、リアルタイムに質疑応答したり、研修の進み具合を各自実況したりと、オンラインならではの研修を進めました。
今年特に印象に残ったのは GitHub Copilot 等のコーディング支援 AI を多くの参加者が活用していることでした。研修最後の全体コードレビューの時間も開発フローの質とスピードに大きな影響を与える変革の年を象徴する内容になり、テスト駆動開発の世界も大きく変わるだろうと再度認識しました。皆様、ご参加誠にありがとうございました。
終わりに
今回、私を含め、TDDワークショップに参加したパートナーは、新卒で入社した方や、まだ入社して間もない方もおり、全員が実際に業務でTDDを実践しているわけではありませんでした。しかし、TDDの考え方を学び、実際に手を動かしてみることで、TDDの重要性・有効性を再認識することができました。今後は、参加パートナーそれぞれが、業務においてTDDを実践することで、より壊れにくいコードを書き、より早くプロダクトの改善を進めてまいります。
@t_wadaさん、ありがとうございました!