テスト駆動開発勉強会を開催した話
はじめに
こんにちは。id:takasp です。
この記事は airCloset Advent Calendar 2021 の 13 日目です。
さて、今回は社内で何度か開催しているテスト駆動開発勉強会を久々に開催してみた話です。
社内で新しい人が増え、いろんなスキルセットを持った人が増えてきた中で、下記スライドを見たことでまた開催しようという気持ちが高まってきたので開催することにしました。
今回は上記スライドの開催の流れを参考に 4 回で開催するように設計しました。
勉強会の流れ
勉強会の設計
社内では週 1 回 1 時間、ランチ LT というランチタイムに LT を行う会を実施しています。
本来は LT をする時間ですが、タイムゾーンの違うリモートメンバーがいることもあり、夜に長時間確保する難しさと日中の参加のしやすさからランチ LT の時間を少し拡張して実施しました。
会全体の流れは主に以下のような流れで検討しました。
- TDD のやり方を見て、知ってもらう。
- ペアプログラミング・モブプログラミングのやり方を説明する。
- ペアプログラミング・モブプログラミングで問題に取り組んでもらう。
- 会を通しての感想・改善点をアンケートに回答してもらう。
大きな流れは上記で進めながら会を重ねながら適宜調整する形で進めています。
ペアプログラミングであればペアに発表してもらい、レビューし合うということも検討しましたが時間の都合上、外しています。
問題は以下を参考に選定しました。
今回採用している問題以外にもたくさんの問題があり、TDD のスキルアップにもおすすめです。
1回目
まずは以下の TDDBC の動画を見てやり方をイメージしてもらうことにしました。
TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング
動画の主な流れは以下の通りです。
動画観賞を通して、TDD のやり方を知ってもらえる良いきっかけになりました。
TDD を始めるに当たって、動画を見てから始めると圧倒的に導入が早いので、このような動画を誰でも見やすい形で公開してくださってとても感謝しています。
見たことがない方は 2 時間程度で見られるのでおすすめです。
2回目・3回目
動画を見た後は用意した問題に取り組んでもらいました。
問題は上記スライドでも紹介されている cyber-dojo の「FizzBuzz+」を採用しました。
いきなり動画とは違う問題に挑戦すると最初に問題を理解して解き方を考える要素が発生するため、事前に動画を通して問題の取り組み方がわかっている状態で TDD をやってみて欲しいという狙いです。
また当初ペアプログラミングで実施する予定でしたが、スキルバランスや時間のコントロールのしやすさから急遽モブプログラミングに変更して実施しました。
初めて実施するメンバーも多く、進め方に慣れるに当たって 2 回に分けて実施しています。
問題に取り組む際は下記リポジトリを使って TypeScript + Jest の構成で実施してもらいました。
コード自体はリモートメンバーがいることもあり、Visual Studio Live Share を利用しています。
実際に皆で手を動かしてもらったことで TDD の面白さやモブプログラミングでやる楽しさを感じてもらうことができました。
TDD をやってもらう機会だけでなく、参加したメンバーでワイワイできたのも良かったように思います。
余談ですが、上記リポジトリを作った後に TDDBC で様々な言語の下記リポジトリが用意されていることを知ったので、他の言語でも試してみたい方は以下のリポジトリ群を使うと始めやすいと思います。
4回目
前回、前々回と 2 回に分けて「FizzBuzz+」に取り組んでもらったことで TDD に少し慣れているであろうことを前提に短い時間でも取り組めるような問題を検討しました。
問題としては以下のスライドを参考に「うるう年(Leap Year)」を採用しました。
時間が限られている中で、仕様がそこまで多くないので、ある程度短い時間でも取り組めることを見込んで採用しました。
今回もモブプログラミングで実践しています。
最終回でしたが、別の問題に取り組んだことにより TDD の理解を広げてもらったように思います。
反省点としては、モブプログラミングの進め方やタイムキープなど、モブプログラミングの進め方に課題が残ったので次回以降の機会では改善に努めたいと思います。
さいごに
ここまでに簡単ではありますが、テスト駆動開発勉強会を開催した話をお伝えしました。
会を実施する上での反省はありながらも、TDD を知ってもらう・やってもらうきっかけ作りはできたように思います。
現状においては動画や問題も提供されているので、TDD を始めやすい環境が整っているように感じます。
いろんな人を集めて会を開催するにしても、開催しやすい土壌は整っているので開催してみてはいかがでしょうか。
また、TDD をすれば何もかも解決するということはありませんが、やってみたことがなければ 1 人からでも始められるスキルの 1 つなのでまずはやってみるのもおすすめです。
参考
えっ、まだユニットテスト書いてない現場があるんですか? - ボトムアップでもっといけてるチームになるために、たった一つの大事なこと - / Why don't you write unit tests
テスト駆動開発ハンズオン前編
TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング
TDDBC
cyber-dojo
社内用機種依存文字変換検出ライブラリを作った話
はじめに
こんにちは。id:takasp です。
この記事は airCloset Advent Calendar 2021 の 3 日目です。
さて、他社サービスとの連携において住所情報などを連携すると、連携するサービスによっては機種依存文字の対応を求められる場合があります。
そんなときにどのように対応したかというのが今回のお話です。
下記ツイートは筆者が「こないだやったやつ!」と見たときに思ったツイートです。
このように 1 例としてハイフンに似た文字が混じると他社サービスとの連携に失敗するため、何らかの対策を講じる必要があります。
経緯は知らんが実際混じってくるんだこれが。 https://t.co/W9Jp6V0ofb pic.twitter.com/9QY175hbHu
— inuro (@inuro) 2021年10月18日
背景と対応方針
配送業者を通じてお客様にお洋服をお届け、または、返却をしていただく際にお客様の住所情報を配送業者に連携する必要があります。
しかし、配送業者へ連携する際に対応していない機種依存文字が含まれているとエラーになってしまい、発送・返却できないという事象が発生していました。
そこでお客様が住所情報を入力するタイミングで機種依存文字の対策をしていくことにしました。
ただ複数のサービス、リポジトリごとに機種依存文字の対応をすると同じ実装をすることになってしまうので、ライブラリを作り各サービスはそのライブラリを利用するという形式にしました。
各サービスのフロントエンド・バックエンドは JavaScript で実装されているため、1 つの npm ライブラリを作り各リポジトリがライブラリを呼び出すという方針で進めます。
作成したライブラリは OSS として公開することも検討しましたが、他社サービスの機種依存文字の対応状況に依存しているため社内公開に留めています。
やりたいこと
主にやりたいことは以下のとおりです。
- 配送業者が対応していない機種依存文字を対策したい
- 一般的に機種依存文字となるハイフン、ダッシュ、マイナスなどは 1 つのハイフンに統一したい
- 半角カタカナは全角カタカナにしたい(厳密に機種依存文字という定義から外れるが文字化けする可能性があるため)
- ついでに絵文字も対策したい
- npm ライブラリであること
- 機種依存文字を検知した場合、空白に変換するか、エラー通知するのいずれかが選べること
これらに対応するライブラリの作成を進めます。
意識したこと
ライブラリを作るに当たって以下を意識しました。
- 本番ビルド時には何らかのライブラリに依存しないで作る
- 特にフロントエンドは可能な限り軽くしたいので標準の機能だけを利用した実装を目指す
- テストを書きながら実装を書く
- 要件は明確だが最初から具体的な実装イメージが湧いていなかったため、テストを書きながら実装し、設計を模索する
ハイフンのような文字
記載したツイートのようにハイフン、ダッシュ、マイナスなどの似たような文字はたくさんあります。
以下に一例を記載しますが、目視で見ても差分を判別するのは難しいです。
文字 | Unicode | 名称 |
---|---|---|
- | U+002D | Hyphen-Minus |
﹣ | U+FE63 | Small Hyphen-Minus |
- | U+FF0D | Fullwidth Hyphen-Minus |
‑ | U+2011 | Non-Breaking Hyphen |
‐ | U+2010 | Hyphen |
‒ | U+2012 | Figure Dash |
– | U+2013 | En Dash |
— | U+2014 | Em Dash |
― | U+2015 | Horizontal Bar |
技術選定
npm ライブラリの作り方としては以下のような記事を参考に実装しました。
また型がある嬉しさから TypeScript とユニットテストとしてデファクトスタンダードな Jest を用いてテストを書きながら実装を進めました。
テストを書きながら実装する
テストを書きながらとありますが、いわゆるテスト駆動開発(TDD)で進めました。
テスト駆動開発は以下のようなサイクルで開発をしていく手法です。
- レッド:失敗するテストを書く
- グリーン:できる限り早く、テストに通るような最小限のコードを書く
- リファクタリング:コードの重複を除去する
今回はその流れの 1 例を記載します。
TODO リストを作る
例えばまず以下のような TODO リストを作って実装していきます。
TODO ====================== - [] 機種依存文字のハイフンを小文字のハイフンに変換する - [] 機種依存文字の「–(En Dash)」を小文字の「-(Hyphen-Minus)」に変換する - [] 半角カタカナを全角カタカナに変換する - [] 半角カタカナ「カ」を全角カタカナ「カ」に変換する - [] 機種依存文字を空白に変換する - [] 配送業者の機種依存文字の場合 - [] 機種依存文字「①」を空白に変換する - [] 絵文字の場合 - [] 絵文字「😀」を空白に変換する - [] 機種依存文字をエラーにする - [] 配送業者の機種依存文字の場合 - [] 機種依存文字「①」を指定するとエラーが発生する - [] 絵文字の場合 - [] 絵文字「😀」を指定するとエラーが発生する
テストコードを書く
まずハイフンに対するテストを書くとして、仮に変換するメソッドを convert メソッドとした時、小文字のハイフンに変換されることを期待します。
describe('機種依存文字のハイフンを小文字のハイフンに変換する', () => { it('機種依存文字の「–(En Dash)」を小文字の「-(Hyphen-Minus)」に変換する', () => { expect(convert('–')).toEqual('-'); }) })
テストを実行して失敗することを確認する
この状態で Jest でテストを実行します。
そうすると当たり前ですが、convert メソッドは存在しないためエラーが発生します。
実装を行う
まずは単純に成功になるテストを実装します。
export function convert(text: string): string { return '-'; }
テストを実行して成功することを確認する
この状態で Jest でテストを実行します。 そうすると単純な実装をしたのでテストは成功します。
リファクタリング
ここでリファクタリングをするフェーズになったので、例えば単純な実装であった convert メソッドを正規表現で置き換えるような処理に変更したりします。
export function convert(text: string): string { return text.replace(/[–]/g, '-'); }
この後は三角測量でテストケースを増やしたり、次の TODO リストに取り掛かるなどしてテスト駆動開発のサイクルを回しながら磨き上げていきました。
このようにして進めると仮に誤った実装をしてもテストがあるので気づけるという点と、自身が一番最初の利用者になるため、利用しやすいライブラリは何かを考えながら実装できるという嬉しさがあります。
最終的にテストコードを見れば、ライブラリがどんな機能を提供してくれるのか分かるという利点もあります。
さいごに
ここまで機種依存文字の変換検出ライブラリを作るまでの過程をざっくりとお伝えしました。
作ってみていかにハイフンに似た文字がたくさんあるか分かりましたし、npm ライブラリの作り方を知る良いきっかけになりました。
要件は比較的明確なのでテスト駆動開発のお題にもいかがでしょうか。
参考
ハイフンに似てる文字の文字コード
Unicodeにあるハイフン/マイナス/長音符/波線/チルダのコレクション | hydroculのメモ
テスト駆動開発(TDD)