モダンアジャイルについて

2021年7月1日に「モダンアジャイル 再考 2021」というイベントが分散アジャイルチームについて考える会の主催でありました。

distributed-agile-team.connpass.com

このイベントのきっかけは、私のFacebookでのつぶやき?でした。

f:id:yach:20210712083608p:plain

これへのコメントできょんさん、鬼木さん、川口さんらに反応していただけ、さっそくオンラインイベントとして開催されたのでした。

以下では、イベントでいろいろな方から出た話、意見、考え方を踏まえながら、私自身の解釈や思っていることを書いてみます。最初に議論したいと思っていた内容もあれば、イベントでのやりとりから感じたこともあるし、後から思い出しつつ考えが変わってきた部分もあります。内容や文章について責任は私にあります。

モダンアジャイルとは

モダンアジャイル(Modern Agile)はJoshua Kerievskyが2016年頃に発表しました。Agile 2016の基調講演や、Agile Japan 2017の基調講演では来日したJoshuaがモダンアジャイルを紹介しました。Joshua自身はXP(エクストリームプログラミング)の初期からの実践者で、「Kent Beckから教わった」(川口さん談)そうです。1996年にIndustrial Logic社を創立していて、同社が作ったXPカードゲームは今でも持っています。

f:id:yach:20210712083846p:plain

さて、モダンアジャイルは以下の図にある4つのGuiding Principlesで説明されています。日本語で理解するには「導いてくれる原則」とでも訳すといいでしょうか。4つの項目は、今給黎さん、角さん、伊藤さん、平鍋さんらが日本語にしてくれたそうです。

f:id:yach:20210712084010p:plain

私は自分の研修など(「アジャイル入門」的なやつ)で、4つの項目をざっくり以下のように紹介しています。

f:id:yach:20210712084059p:plain

  • 工場などで物理的安全を確保するのは、作業者がパフォーマンスを発揮できるようにするため。おっかなびっくりではいい仕事はできない。
  • 心理的安全は、対人関係の中にあるリスクについて、安全を確保する=言いたいこと、言うべきことを誰でも誰にでも言えるという観点の安全性の話。
  • 安全ニアリング(=Anzeneering。Joshuaの造語)は心理的安全を含む(たぶん)が、それ以外にも、急にデータが消えるとか、ちょっとしたミスが重大な損害につながるとか、ユーザーが食い物にされるとか、そういう危険がなく安全であることまで含む。

f:id:yach:20210712084141p:plain

  • 現状維持を目指すのではなく、新しい発見とそこから起きる変化をはやくたくさん起こそうというアプローチ。
  • 実験には失敗がつきものなので、失敗していなかったらちゃんと実験できていないことになる。失敗しても問題ないような安全性が前提となる。安全性なくては実験はできず、実験なくして学習はできない。
  • いわゆるプロセスの改善だけでなく、プロダクトの改善も含む(これは「継続的に価値を届ける」との合わせ技になる)。

f:id:yach:20210712084217p:plain

  • なんの仕事をしているのであれ、アウトカム、提供価値、結果が大事。誰のための仕事かを理解した上で、その誰かまで価値を継続的に届ける。
  • 自分の仕事をやり遂げるところから、誰かの価値になる成果に意識をうつし、そのために自分の仕事に集中する。意識をうつすのにも、自分の仕事に集中するのにも、安全は欠かせない。
  • 価値が届いたかどうか確認するところまでが「価値を届ける」こと。届けたつもりだけど、本当に使ってもらえているのか、想定した価値が出せているのか、喜ばれているのか。知りたいと思い、実際に知るべく、フィードバックを獲得する。

f:id:yach:20210712084309p:plain

  • 最高の結果は、人々を最高に輝かせるところから得られる(awesomeは「メチャクチャすごい」とか、ものすごさや凄まじさを感じる意味合いという気がしてます)。受け手を輝かせることも、作り手が輝くことも同じく大切。価値の提供はそのために必須。
  • その輝くべき人々を考えるとき、誰のための仕事なのか、そしてその仕事をしているのは誰かを見渡したとき、見つかるすべての「誰」が対象となる。ユーザーだけでもダメだし、開発者だけでもダメ。
  • 輝く人々は新たな価値を生み出していくし、より良いあり方を求めて学習もする。逆に、価値を提供せずに輝かせることもできないし、学習せずに輝くこともできない。

以上4つのGuiding Principlesは、人々が集まって有意義な活動をしている場面であればどこでも適用できます。2001年のアジャイルソフトウェア開発宣言は、ソフトウェア開発に限定した内容になっていました。現在ではアジャイルという言葉や考え方はもっと幅広く、プロダクト開発全体、サービス提供、組織づくりなど、様々な業種、場面で使われるようになっており、それらを包摂した上でアジャイルという言葉に新たな意味づけをしたのがモダンアジャイルとも言えます。

(そしてうがった見方をするならば、アジャイルを冠するコンサルタントやコーチが支援できる業種が増え、マーケットが広がり、仕事の幅を多様にする再定義とも考えられます。)

Guiding Principlesの使い方

モダンアジャイルを学び、4つのGuiding Principlesを活用するためにはなにをしたらいいのでしょうか。ここでは主に、Joshuaの記事にあることと、鬼木さんにうかがった話とを書いていきます。私自身はいままで、モダンアジャイルを紹介しているだけで、直接的に使ったことはありません。

f:id:yach:20210712091102p:plain

モダンアジャイルは"principle driven and framework free"であると定義されています。やるべきこと(フレームワーク、プラクティス)が決まっておらず、4つのGuiding Principlesによって導かれ、自分たちのPrinciplesを軸にして推進されるものです。そこでまず活用に向けて、それぞれのGuiding Principlesを理解した上で、自分たちにとってのPrinciplesを定義していきます。以下のような疑問について考えながら、自分たちの状況、ビジネス、とりまく環境などを考慮に入れつつ、独自のPrinciplesを作ります。

  • 誰を「最高に輝かせる」のだろうか?
  • その人が「最高に輝いて」いるとはどういうことか?
  • どうしたらそんなふうに輝くのか?
  • 届ける価値とは何か?
  • 継続的に届けるとはどういうことなのか?
  • いま実験したいことは何か? していない理由は?
  • どんな危険が身の回りにあるか?

ここで言うPrinciplesは、日本語で言えば「行動原理」が近そうです。行動、やることそのもの(Practice)ではなく、行動する理由だったり行動が結果を生み出すメカニズムを説明するものになります。

こうした自分たちのPrinciplesを定義し、共有し、みんなが理解したら、モダンアジャイルのスタートラインを踏み出したことになります。ここからはPrinciplesを実体ある実際の行動に移していくことになります。

行動の中でもGuiding Principlesを使えます。ここは私の想像になりますが、ひとつのアクションを取り上げて4つの項目に照らして評価したり、日々の行動全体を見直したり、組織全体の方向性をそろえ直して局所最適を防いだりする際にも役立ちそうです。ふりかえりで使うのも良さそうです。

モダンアジャイルはいわゆるプラクティス、具体的なやり方やルールを提示していません。すべて自分たちで考えつつ、自分たちで作りつつ、自分たちでより良くしていく、「補助輪なし」という方法を提言しています。ルールやプラクティスが与えられると、ついつい「それをやること」に気が向かってしまい、そもそもの目標から逸れてしまいがちです。モダンアジャイルは、常に目標に向きながら自分たちの頭で考えるよう促しているように思います。

(そしてまたうがった見方をしてみると、決まったやり方がないぶんアジャイルコーチの支援の重要性が増すのかな……という気もします。まあ、ルールが多いほうがコーチが必要になる気もするので、どっちもどっちかもしれません。)

この4つは何なのか

さてこのへんから、私自身がモダンアジャイルを独自解釈したうえで疑問に感じている点に触れていきます。モダンアジャイルのGuiding Principlesとは何なのか、という話です。

"(Guiding) Principles"という名前は、アジャイルソフトウェア開発宣言のprinciples=「背後にある12の原則」を想起させます。12の原則のほうは、たとえば「顧客満足を最優先し、価値のあるソフトウェアを早く継続的に提供します。」という行動原理が書いてあります(ここでも、principlesは「原理」のほうが近いかなと個人的に思っています)。この一文は「顧客満足」を「価値のあるソフトウェアを早く継続的に提供する」ことで実現するという、目標と達成方法を含んだものです。

(なお和訳だとその構造はちょっとわかりにくいかもしれません。原文は"Our highest priority is to satisfy the customer through early and continuous delivery of valuable software."です。)

アジャイルソフトウェア開発宣言では4つの価値(Values)と12の原則(Principles)を述べています。XP(エクストリームプログラミング)では、価値・原則・プラクティス(Values / Principles / Practices)という構成で全体を記述しています。価値とは目指すもの、究極のゴール、目標です。プラクティスは価値に到達するための手段です。ただし、やみくもにプラクティスをやるだけでいい、やれば自動的に価値に近づくというわけではありません。そこをつなぐのが原則です。プラクティスがなぜ役に立つのか、どうしたら価値の到達に近づくのか、そこを説明し、機序(メカニズム)を明らかにし、プラクティスの効果的なあり方を示すのが原則です。

f:id:yach:20210712085024p:plain

あらためて4つのGuiding Principlesを見てみると、「○○する」としか書いていない。あるいは「○○を実現する」と言っているだけです。きょんさんが「動詞だから(価値ではなく)原則では」とコメントしていましたが、「○○」の名詞を取り上げればそこが価値のようにも思えます。

モダンアジャイルの使い方として、Guiding Principlesを使って自分たちのPrinciplesを見つけるという話がありました。そう考えると、「自分たちのPrinciples(とValueとPractice)」を見つけるときに使うGuiding Principles=「導いてくれる原則」なのであって、それ以上でも以下でもなさそうだ、そういう理解に落ち着いてきました。結局これ自体が補助輪だったのかと言える気もします。

Joshua自身、Agile 2017のキーノート中で"These four, I call them principles, you can call them values. You can call them thingies. They are the four things that I focus on."と言っていたりする(リンク先にtranscriptがあります)ので、Value / Principles / Practices という構造をモダンアジャイルでは採用していないか、単にこだわっていなさそうです。

さて、さらにめんどくさい話に少しだけいってみると、XPはパターンランゲージである(少なくとも志向している)。スクラムパターンランゲージである(と考えている人々がいる)。パターンランゲージがとらえるのは全体性であって、(うまく説明できないから拙劣なメタファを使うと)一本の美しい木があって、木が育つ土地があって、土地を取り巻く山々と水源と動植物相があって、気候は……とひと続きの壮大な連なりとして考える。それに比べると、モダンアジャイルの4つに分ける整理の仕方は安直で、即物的で、あたかも木を掘り起こして根と幹と枝と葉に切断して語っているような印象ですらある。

たぶんこれがモダンアジャイルのいいところで、わかりやすい。間口が広く、入りやすいし、やってみようかという気になる。アジャイルの濃い人たちの話ってめんどくさ……いい話なんだけど、今それを聞かされてもわからないし困るんですがという人たちはたくさんいて、そんなときはモダンアジャイルに導かれて自分たち自身のことを捉え直すところから始めるアプローチがうまくいく、かもしれない。

まあだからこそ、濃い人から見ると疑問もあって、こんなふうに絡んでしまってごめんなさいという話にもなるのかなと思います。

モダンアジャイルは何を価値とするのか

Ron Jeffries著 "The Nature of Software Development"では、価値(Value)をピラミッドの最上位に置いたうえで「価値とはほしいものだ」あるいは「価値とはあなたがほしいものだ」と定義しています。

f:id:yach:20210712085300p:plain

モダンアジャイルの価値は何なのでしょうか。2001年のアジャイルソフトウェア開発宣言では、4つの価値を明言していました。モダンアジャイルを導入するあなたは何がほしいのでしょうか? 何がほしいとき、モダンアジャイルを考えればいいのでしょうか?

私自身は「最高に輝く人々」がモダンアジャイルの価値なのではないかと考えています。2001年のほうの「個人と対話」と直接対応するためです。もっともモダンアジャイルでは「人々」の中で受け手と作り手を等しく扱っているためか、上でも紹介したJoshuaの記事では"Make People Awesome"を”Customer collaboration over contract negotiation"と紐付けています。

7月1日のイベント(本質的には雑談会)でも、最高に輝く人々に特別な価値を置いていると考えてもいいんじゃないかと、そういう雰囲気になりました。論が尽くされたわけではないとも思いますが。

もしそうでなかったら、「人々を最高に輝かせる」のはあくまで手段であり目標(価値)は別なのだったらと考えると、気持ち悪さが出てきます。人々が輝くとビジネスにいいとか儲かるとかいった理由づけは、幸福な人は生産性が12%高いから従業員を幸福にすれば会社が儲かるみたいな考え方と同じく、人間性を見失いかねない危険なものだと思います。

最高に輝く人々について

ここからは完全に私の妄想というか連想として出てきた話になります。人々を最高に輝かせたとき、最高に輝いている人々とはどんなものなのだろうか。そこで思い出した、というか根拠なく連想したのが『民芸とは何か』(柳宗悦)で述べられている民衆です。(ちなみに著作権切れのためKindle版が無料で読めます。)

「あの無学と云われ凡庸と云われる民衆も、無限に美しい作を生み得るのであると。…民衆ならでは、あの民藝品の美を産むことはできないのだと。…民衆の作に誤謬はあり得ない。自然に従順だからであると。私は最後にこう云いたいのです。民衆は天才より、なお驚くべき作を造り得るのだと。」

この本は民芸について、民芸運動の中心人物である柳宗悦が書いたものです。民芸運動は20世紀前半に始まっており、「日常的な暮らしの中で使われてきた手仕事の日用品の中に「用の美」を見出し、活用する」運動です(Wikipediaより)。同書の中で柳は、「民藝とは民衆が日々用いる工藝品」と定義して、機械で工業的に作ったものや、人が意図的に美しく作ろうとしたものより、民衆が無心で「用途のために」作った民芸のほうが美しいと断じています。こうした工芸品は雑器とも呼ばれる、安価で多産に作られてきたものです。

この論の是非はここでは置いておきます。いったん前提を受け入れ、無学で凡庸な民衆が、自然に従順に、手作業で安価なものを多産する仕事の中で、無心に生み出した品が著しく美しくなり得ると考えたとき、この人は「最高に輝いている」と言えるのではないだろうか? それが私の疑問です。

この製作者であるところの民衆は、無心なのですから、もっといいものを作ろうとか、高く売れるよう作ろうとか、実験しようとか改善しようとか、考えていないはずです。ユーザーを喜ばせようという意識もないでしょう。自分の仕事に大してモチベーションがあるわけでもなく、一連の作業の繰り返しに無心で集中しているフロー状態のような状況はあるかもしれませんし、作ったものは確かに誰かの役に直接たつものですが、仕事への充実感はあまりなさそうです。決して収入が高いわけではなく、社会的地位もなく、文字通り無名の民衆のひとりでしょう。

こうした人々こそが美しい、価値のある品を作り出せる。ただし、そうした美は見過ごされたり、軽視されたりしがちである。そのように目立たないが優れた仕事をしている人々は、輝いていると言うべきだと思います。際立っておらず、壮大なビジョンがあるわけではなく、さして情熱的でもない、最高に輝く人々です。受け手と作り手を取り巻くエコシステムがこんなふうに自然に従順に成立するとしたら、そうした人々についてモダンアジャイルはどう考えるのか、あるいは「個人と対話を価値とする」広義のアジャイルからどう見えるのか、そして私はいったいいどうしたいのか。迷走する連想からたどりついた、これが私の疑問です。

スクラムマスターの資格って必要?本当に答えます

スクラムマスターに資格(職務に就くための必須の条件)はありませんが、認定(スクラムマスターとして有能である、十分である)はいくつかあります。

ですので、タイトルに直接答えれば「資格は必要ありません(そんなものはありません)」となります。

いっぽうで、スクラムマスターの認定はいくつかの組織から提供されています。こちらは勉強する目標としても、就任する上での判断材料のひとつとしても、有用ではないかと思います。

Certified Scrum Master® / CSM® / 認定スクラムマスター

非営利組織Scrum Allianceが提供しています。認定トレーナーの研修を受けた上で受験します。日本ではOdd-e Japanアギレルゴコンサルティングアトラクタなどが提供しています。

Licensed Scrum Master / LSM

Scrum, Inc.が提供、日本ではScrum, Inc. Japanが提供しています。研修を受けた上で受験します。

なお、Scrum, Inc.(米国)では現在 Licensed Scrum Master という名称を使わず、 Scrum Master by Scrum Inc.™となっているようです。Scrum, Inc. JapanでもLSMという表記が目立たなくなっており、名称の変更がされるのかもしれません。(2021年5月現在)

Professional Scrum Master™ / PSM

Scrum.orgが提供しています。試験だけ合格すれば認定を取得できます。対応する研修もあり、日本ではITプレナーズなどが提供しています。

スクラムマスター以外

それぞれ、より上位の認定や、スクラムマスター以外のプロダクトオーナーや開発者の認定も提供しています。より広く・深く学ぶうえで有用だと思います。

参考にした資料:

なお本記事はCC-BY 4.0で提供します。ご自分のブログ、メディア、サイトなででそのまま掲載いただいて構いません。

こちらの講演時にいただいた質問への回答です。

「テスト自動化とテスト駆動開発」講演資料 - やっとむでぽん

質問10. 仕様変更時、テストが壊れるケースがあると思います。どのようにプログラム修正するのが良いでしょうか?リファクタリングとは異なり、新規開発のように先にテストを書くのでしょうか?

スライド88で、機能追加のプロセスを説明しました。仕様変更も機能追加と、手順は変わりません。

f:id:yach:20210409141139p:plain

仕様変更は「動作を変える」ことなので、リファクタリングとは違うものです。リファクタリングは動作を変えないままで、内部構造を変更します。余談ですが、リファクタリングを単なる「ソフトウェアの変更」という意味で使う場面を見るのですが、本来の意味とは違います。

この図の「自動テストがある場合」では、実装を終えてから、変更後の仕様に合わせてテストをまとめて変更します。すべてのテストが成功したら、仕様変更は完了です(もちろん見落としがなければです)。 同様に「テスト駆動開発の場合」では、まず変更後の仕様に合わせてテストを直します。ただし、TDDのサイクルは小さいので(数分~数十分)、すべての仕様変更を一気に盛り込めません。どうするかというと、仕様変更をブレークダウンして、テストと実装がすぐ終えられるように小さくしていきます。そのうえで、ひとつずつをテスト駆動開発で進めていきます。

たとえば、ユーザーがデータを操作する画面(ブラウザ)があって、そこに項目を1個増やすような仕様変更を考えてみます。ブレークダウンした結果は、たとえば次のようになります(あくまで一例です)。

  • 入力画面に項目を増やす
  • テーブルに入力項目に対応するカラムを増やす
  • 保存処理で新しい項目を保存する
  • 表示画面に項目を増やす
  • 入力画面のバリデーションを直す
  • 入力内容確認画面に項目を増やす

このようにすると、ソフトウェアは「動作するきれいなコード」を保ちながら、機能としては中途半端な状態を経由して、少しずつ完成に近づいていきます。入力はできるけど保存されない、保存されてるけど表示できない…それぞれのステップでテストを書き足して(書き換えて)、実装し、リファクタリングまでします。

このように進めるのは、ふわっとした言い方ですが「安全」のため、ないしは不安が小さいままで進めるためです。一気にテストを直すと、大量にテストが失敗する状態になります。すべてテストが成功するのは、入力し、保存し、表示ができて、バリデーションまで…それまでの間、テストが成功しているから壊れていない、という状態がおあずけになります。壊れていない保証がないまま直すのは、不安です。途中で思うようにいかなくなって、あれこれ試行錯誤すれば、不安はさらに増大していきます。

テストが成功している状態は、「動作するきれいなコード」なので、安全エリアです。不安になったり、先に進むやり方がわからなくなったら、いったん安全エリアまで戻り、何も壊していない状態を確認してから、あらためて次の一歩の作戦を考えます。この安全エリアにいつでもすぐ戻れるように、仕様を少しずつテストにして、実装していくのです。

不安の程度、安全エリアからの距離というのは、多分に心理的なものです。とりわけ、担当者の理解度、自信、体調、疲労度、言語の練度などによって大きく変わります。スキルのある人が元気で頭がフル回転している月曜日であれば、もしかしたら一気にすべて書き上げてしまえるかもしれません。自信を持って「大きな一歩」で飛び越えられるなら、それに越したことはありません。しかしそこまでスキルのない人、このコードを初めて見るメンバー、疲れ果ててる金曜日、今夜の試合が楽しみで気もそぞろ……というような場合は、もっと小さな一歩ずつにブレークダウンしたほうが安全になります。

和田卓人さんは、こうしたスキルや状況に応じて一歩の大きさを変えることを「間合いを調整する」と表現しています。自信があるなら間合いを広くとって、一発で決める。自信がなければ間合いを狭くして、細かく密接に追随する。テスト駆動開発のメリットとは、そうした間合いを自由自在に調整して最適な仕事の進め方を選べるように、開発者がなる、そういう能力を獲得する、と言うこともできます。

質問11. カバレッジを上げようとすると費用対効果が悪くなっていくという理解です。どこまでテストすべきか指針となるものはありますか? 例.業務ロジックのみテストコードを書く…など

前の質問への回答と関連しますが、和田卓人さんはテスト駆動開発においては「不安を手がかりにしてテストを書きます」と言っています。プログラマーは自分の心の声を聞いて、自分が対象のコードをどのくらい自信を持って理解しているか把握します。その心の声が「ちょっとヤバイかも」と囁くなら、テストを書いて確認する。というのが、とても曖昧に聞こえますが、現場の方へのアドバイスになります。

自明ではありますが、大事なところは丁寧にテストします。お金を扱う、SoRで保存すべきデータを保存する、個人に紐付く情報(個人情報に限らず)、複雑なビジネスロジック、などは仕様の検証、設計のレビューなども含めて手厚くテストをします。テストを自動化する場合でも、どういうテスト設計をしたのか、それぞれのテストケースにどんな根拠があるのか、あとからわかるようにしておいたほうがいいでしょう。

自分たちのコードでない部分も、場合によってはテストを厚くします。外部からデータを取り込む場合(外部にどんなバグがあるかわからない)、ライブラリを使う場合(ライブラリを作った人をどれだけ信用するか、ライブラリのバージョンアップで急に挙動が変わったら気づけるか)。

こうしたアプローチは、リスクベースドテストの一種とも言えます。危険そうなのはどこか、問題があったとき損害が大きくなるのはどこか、自分たちが把握しきっていないのはどこか、そうした観点を用います。リスクベースドテストについて、秋山浩一さんのブログを引用して紹介しておきます。(秋山さんは、スライド内で紹介した『ソフトウェアテスト技法ドリル』の著者。)

リスクベースドテストとは

『ISTQBテスト技術者資格制度 Foundation Level シラバス 日本語版 Version 2018.J03』では、「リスクベースドテスト」をテスト戦略のひとつ(分析的テスト戦略)に位置付けています。該当部分を引用します。

テスト戦略は、通常、プロダクトまたは組織のレベルでの、テストプロセスに関する汎用的な考え方を提供する。テスト戦略の一般的な種類は以下の通りである。

・ 分析的:いくつかの要因(要件やリスクなど)の分析に基づく。分析的アプローチの例としては、リスクのレベルに基づいてテストを設計し優先度付けするリスクベースドテストがある。

さらに「5.5.3 リスクベースドテストとプロダクト品質」の項で詳細な説明があります。こちらは、ちょっと長いので要約しています。(オリジナルが気になる方は、JSTQB FLシラバスの71-72ページをご一読ください。)

リスクを使用して「テストの内容・優先順位・実施順番を決めること」ができる。また、テストを「プロダクトリスクを減らし残存リスクを明らかにすることを目的とした活動」と位置付けることができる。
識別されたリスクに対して、(期待しない事象が)「発生する可能性」と「発生した場合の影響」を評価する。

(残存リスクに対して)リスクマネジメントで実施することは下記の通り。
・ リスクを分析する(定期的に再評価する)。
・ コンティンジェンシープラン(緊急対応計画)を作る。

note.com

コードカバレッジの数値は、手を入れるべき場所を見つけるために使うとよいです。達成目標にすると、機能不全を起こします。全体が80%だからOKとかNGとかいうのではなく、特にカバレッジの低いところがないか、ドリルダウンしていってテストが足りていないところを見つけるという使い方がよいです。

仕様に対するカバレッジも、テストの不足を見つけるのに使えます。コードカバレッジのように自動で測定するのは難しいかもしれませんが、仕様ドキュメントに対するテストのカバレッジや、仕様としてのビジネスロジックの場合分けに対するカバレッジ、画面上の操作に対するカバレッジなどを調べます。

そういう意味で、どういうテストを書くべきかという基準はあったほうがよいでしょう。詳細な定義やルールではなく、プログラマーを導けるようなものにするとよいと思います。これは思いつきですが、

  • ユーザーのやりそうな操作はすべてカバーする
  • 外部データ入力は創意工夫して変なパターンをテストする(もちろん普通のケースはちゃんとやる)
  • 異常なパラメータだったら異常な結果になるかテストする
  • 境界値、同値クラスを意識した上で、変なパラメータを選ぶ

のようなものです。○×を付けるようなものではなく、「どうしてこのテストがいる/いらないと思ったのか?」と議論できるようなものだとよいのではないでしょうか。(すみません、この部分は本当に思いつきなので、あまり信用されないでください。面白そうだったら試してみてください。)

10年前くらいのJavaの経験だと、コードカバレッジ(C0)は80~90%くらいが良い感じで、それより低かったら、なにか抜けていそうなので調べるというふうにしていました。95%以上にするには、テストが大変になったり、無駄に設計を変えないといけなかったり、現実には絶対起きない例外をおこしたりしないといけないので、やらないようにしていました。

コードカバレッジでは検出できない抜け漏れもあります。数字だけ意識していると、こうした部分のテストを見落とします。

こちらの講演時にいただいた質問への回答です。

「テスト自動化とテスト駆動開発」講演資料 - やっとむでぽん

質問9. DBアクセスを含む処理をテストする場合、どのように環境を整えるのが良いと思いますか? 例.開発環境DBにつなぐ/クライアント端末にDBを建てる/メモリ内で完結させる

挙げていただいた例は、いずれも有用で、使い分けるとよいです。使い道を分類すると、どれも使うことになるのではないかと思います。使い道、目的に合わせどれを選ぶか、どう運用するか、私の経験から考えてみます。

まずテストの実行時間です。テスト駆動開発のサイクルで使うテストは一瞬(1秒以内)に結果が見たいので、本物のDBは避ける傾向にあります。DBアクセスする部分をモックで置き換えてやれば、実行時間は本当に一瞬(0.1秒以内)になります。これがCI/CD環境で実行するテストであればもっと遅くても構わないので、テスト用のDBに接続して実際のDBアクセスをします。もっとも今どきの環境は、クライアント端末にローカルのオンメモリDBを立てても、実行速度には遜色ないでしょう。フレームワークがそういうテスト用機能を提供している場合もあります。モックの濫用はテストの保守性を下げるので、カジュアルにDBを使うのも選択肢になると思います。

テスト対象も大事です。DBアクセスを含む処理の、なにをテストしたいのか。SQLそのものなら、DB接続は必須です。複雑なクエリを組み立てる部分のテストなら、クライアント端末にオンメモリDBを立てて実行できます。本番準拠のデータからクエリでデータが正しく取得できるか確認するようなテストなら、テスト用DBにデータを準備するほうが経済的かもしれません。

いっぽう取得したデータに対して実行するロジックがテスト対象なら、DB接続はせず、取得したのと同じデータをテストケース内で作って、それを渡してやればすみます。こうした細かな部分を個別にテストを書いていると、ソフトウェアの設計が自然と細粒度になり、依存関係も分離できた状態になります。テストデータのバリエーションも、テストケース内のほうが細かく大量に作りやすいかもしれません。

テスト対象がエンドツーエンド、ユーザーが操作する画面や、バッチの入力ファイルと出力ファイルを対象とするテストならば、当然DB接続は必要です。パフォーマンスを見るなら本番同等のDB環境を使います。

以上のように、テストの種類によって接続するDBも変わってきます。どの環境でどの種類のテストを実行するか考えてみると、一例として以下のようになります。

  • 開発中(テスト駆動開発) ― 速いテストだけ、ユニットテストだけ実行する。DB接続しないか、ローカルDBを使う。
  • 開発の区切り(コミット時、プッシュ時、マージ時、など) ― 手元で実行できるテストをすべて実行し、壊していないか確認する。適当なデータがあるDBに接続するか、ローカルにそういうDBを(テスト時だけ)起動する。
  • CI/CD ― ビルド環境上ですべてのテストを(システムテストや受け入れテストも)実行する。テスト用に用意した、本番同等のRDBMSに接続する。
  • 手動テスト ― 開発中に動かして動作確認したりするときには、手動テスト環境を使う(専用環境でもいいし、ローカル環境も使える)。適当なデータが入っていないと使いにくい。開発中のプログラムから使うので、データが壊れたり異常になったりするのを想定して、運用する。テスト担当者も触るという場合は、さらに別の安定した環境が必要になることもある。

テストデータの問題も大きいです。以下のような作戦があります。

  • テストデータを詰め込んだ「テストDB」を用意し、そこに接続する。手動テストでは、使えるデータを見つけたり作ったりしてテストを実施できる。自動テストの場合、テスト内で変更したデータを再度テストに使うと、テストの事前条件が異なるので結果が変わってしまう。そのため、自動テストを実行するたびに初期テストデータをロードする必要がある。初期テストデータは、テストの内容や機能によって変わっていくので、ソースコードと同じくバージョン管理対象になる。開発中に手動で動作確認することもあるので、それ用の「開発DB」と、自動テスト用の「テストDB」は、別々に用意する。複数人が同時並行してテストを実行することを考えると、開発者1人にテストDBを1つ用意するほうが安全(DBMSとしては1つで、ユーザーや名前空間で分離してもよい)。
  • テストデータが「全テーブルの全レコード」で構成されていると、いろいろな条件でテストしたいときにバリエーションが足らなくなる。そのため、個々のテストケースについて、そのテストのためのテストデータを構築する。テストケース内でプログラムでデータを生成してもよいし、ExcelCSVで別ファイルとして用意しておく方法もある。プログラム内で生成すると、「どんなデータにどんなテストをするか」が一緒に書いてあって読みやすくなり、変更もしやすい。いっぽう、複数のテーブルに渡る複雑なデータ構造を組み立てるのに、プログラムでは煩雑になり過ぎることも多く、データを外出し(別ファイル)にするのもよい。
  • プログラムをテストコードから呼び出してデータを生成したい、しかし煩雑になる、という場合に、テストデータを構築するためのヘルパーライブラリを作るという方法もある。またRuby on Railsのfactory_botやLaravelのSeederのように、フレームワークサードパーティのライブラリとして、そうした機能が提供されているものもある。
  • 別の観点として、アジャイルではデータスキーマも頻繁に変更するため、DDLもバージョン管理対象とし、テスト実行時にバージョンを確認したり合わせたりしないといけない。フレームワークマイグレーションスキーマバージョン管理の機能を提供していることがある。

プロジェクトのテスト戦略として、どういう部分をどういうテストでカバーするか計画し、漏れがないようにしましょう。たとえばDAO(Data Access Object)を、ユニットテストでは「統合テストで確認するから」とモックで置き換え、統合テストでは「ユニットテストで確認してるから」と網羅しなかったりすると、テスト漏れになってしまいます。逆に、システムテストで「絶対確実だからここで全条件網羅する」などと考えると、テスト量も実行時感も膨大になり、費用対効果が悪くなります。

いろいろ書いて、整理ができておらずすみません。私がいいなと思う一例は、こんな感じです。あんまりちゃんと考えられてないので、おかしなところがあると思いますが……DBを青く塗っています。ここは私も学びたいので、ツッコミやコメントをお待ちしています。

f:id:yach:20210409105449p:plain

こちらの講演時にいただいた質問への回答です。

「テスト自動化とテスト駆動開発」講演資料 - やっとむでぽん

質問8. リモートでペアプロするときのメリット、デメリットはありますか?

リモートペアプロは、ツールやデバイスを上手く使えば十分に有効です。現在多くのチームがリモートペアプロ(リモートモブプロも)を実践しています。

f:id:yach:20210409135636p:plain

オンサイトのペアプログラミングは、人間がもっとも得意な、全チャンネルを用いたコミュニケーションを活用するものです。目の動き、ちょっとした表情、呼吸の変化、指先や姿勢の動き、仕草、声色、そうした表現をフルに双方向でやり取りすることで、お互いの様子もつかめるし問題もあぶり出せるし、共同で意気込む空気も生まれます。ドライバーがふと眉をひそめたのを見て、ナビゲータが「何か気になる?」と聞いたのをきっかけにして、隠れたバグが見つかったりします。リモートではチャンネルの内ごく一部しか使えず、自然に伝わる力に頼れなくなります。

そのためリモートペアプロでは意識的に、使えるチャンネルを最大限に使います。

  • カメラは常時ONで顔出し
  • マイクも常時ONで、つぶやきや息づかいも聞こえるよう高級なマイクを使う
  • ドライバーが自分の画面を共有する
  • 両者が大きなモニタを使用した上で画面全体を共有する(ウインドウだけではなくて)
  • 常時声を出すよう意識する

などです。頭の中を声に出したり、大げさに表情を作ったり、感情も含めて音声で表現したりしていくと効果が高まります。仕事の話だけだと感情が乗らないので、わざと雑談や無駄話を入れたりもします。

リモートでも身体性を生かせるよう「やったー!」と言おう

うまくいったらすぐ、2人一緒に「やったー!」と声に出して、両腕を上げてバンザイもする(身体も使って表現すると、人間の身体内部は驚くほど反応するので、ぜひやってみてください)。オンサイトだと拍手することも多いのですが、ZoomやTeamsなどのノイズキャンセリング機能で拍手の音が消えてしまいがちなので、声を出してやってください。

問題に関するコミュニケーション(仕事の話)もリモートでは不利になります。オンサイトでは画面を指さしながら「そこ間違い」「これをこっちにして」「それが先、次がそれ」など指示語を使いながら、同じものを見て、同じところに視線を当てて、認識を合わせていきます。リモートではこういう指さしが弱まります。ツールによっては人の画面共有に介入する機能もあり、擬似的な指さしができます(Zoom)。機能がない場合は、行番号を言ったり、テキストを読み上げるなどして伝えなければならなくなります。これも意識的にやらないといけないので、リモートペアプロのほうが疲れやすい感じが、個人的にはしています。

リモート特有のメリットもあります。スペースの問題がなく、手元のPC・環境のまま参加でき、キーボードやエディタの違いが問題なることもないので、オンサイトのときより気軽にペアプログラミングのセッションを開始できます。「ちょっといいですか」くらいの声かけでペアプロに入れるし、普段なら距離が遠くてペアが組みづらい人でもハードルがありません。パッと始めてさっと終われるので、短時間のスポットセッションもやりやすいです。ソースコードの共有だけは問題になりますが、gitなどリポジトリを経由する、クラウド上に共有の開発環境を準備する、などで対応できます。

リモートで今のところ代替できていないのが、ホワイトボードや大学ノートや裏紙のような、一緒に書き込みながら議論する媒体です。オンラインのホワイトボードは色々ありますが(Google Drive、JamBoard、Miro、MURAL)、雑にハコや丸を2人で描き込みながら設計やUIの議論検討をするようなツールは、まだないようです。(個人的には、ペンタブレットを使って、同時に描画できるようなツールが有用ではないかなと考えています。Windows であればMicrosoft Whiteboardはいいかもしれません)

リモートペアプロに限らず、リモートワークの懸念点ですが、ツール、デバイス、環境が些細な点も含め影響してきます。ネットがたまに不安定になる、声が聞こえづらい、背景ノイズがある、画面が小さい・狭い、ツールに制限がある、VPNが遅い、シンクライアント、PC内蔵マイク、カメラがない、などすべて、パフォーマンスに直結します。

ちょっと不便、ちょっと遅い、ちょっと聞こえにくいくらいだと、ついついそのままにしてしまいがちですが、それを1日中、何ヶ月も続けていると、フラストレーションも溜まるし、コミュニケーションそのものを減らす・避ける方向に働くおそれもあります。目にした範囲でも、以下のような例があります。

  • ネットが細いのでカメラOFFで(表情も大事なのに)
  • セキュリティ制限で使えない機能がある(該当機能だけでなく、いろいろ工夫するモチベーションを阻害する)
  • 外で工事してるので、話すときだけマイクONにします(発話する量が絶対に減る。ノイキャンマイク付ヘッドセットを支給すべき)
  • PCのスペックが低く、開発環境とコミュニケーションツールを同時に使うと仕事にならない(社内ルールで事務用PCとごっちゃにしている。自家用車と工事用特殊車両を同じルールで購買するような、現場を見ていない感)
  • セキュリティルールで、オンラインのサービスを制限・禁止する(ホワイトボードが使えなかったり、環境の共有ができなかったり、技術調査ができなかったりと、致命的)

こちらの講演時にいただいた質問への回答です。

「テスト自動化とテスト駆動開発」講演資料 - やっとむでぽん

質問7. TDD導入に関する質問です。 実際にテスト駆動の場合は、最初のリリース時は以前に比べると工数、費用はかかり、運用保守まで考えて効果がでてくるはず。最初のリリース時の費用はどうしても上がりそうです。 それを顧客に説明するときの考え方、作戦、政治、などが気になります。他社導入時の工夫など事例はありますか?

f:id:yach:20210407143822p:plain:w350

難しい質問ですね…ご質問ありがとうございます。前提とするプロダクトの状況によって、考え方が変わってくると思いました。1.初期開発なら、テスト駆動開発工数が増えることはありません。2.既存システムの再開発や、保守運用では、先行投資が必要になります。いずれにしても、3.一人前に作業できないなら、それは仕事でやって大丈夫?という話になります。もう少し詳しく説明します。

新規開発ならシンプル

新たなソフトウェアを新規開発する(1.)という幸運な状況では、最初からテスト駆動開発を導入するのがベストです。単にテストが自動化できるだけでなく、目の前の仕事をより品質よく実装していけるので、進みは速くなりますし、デバッグや再テストで取られる工数も減ります。スライドではこちらのデータを紹介しました(スライド81)。

f:id:yach:20210407143646p:plain

そもそも、テスト駆動開発を使いこなせる人であれば、それを「まったく使わない」という選択肢はありません。「ぜんぶテスト駆動で書く」「部分的にテスト駆動で書く」といった選択肢がありますし、実装する部分(フロントかバックエンドか、ビジネスロジックかボイラープレートか、フレームワークを利用するかどうか、など)でも最適なアプローチが違いますし、さらにレッド・グリーン・リファクタリングのサイクルを守る度合いも調節できます。ルール化するなら、「プロダクトコードにはテストコードを書く。タスク完了時(コミット、プルリクエスト、コードレビュー依頼など)には、必ず両方揃っていてテストはグリーンであること」というくらいがいいかもしれません。熟練者であれば状況によって選択肢を選べるので、必ずしも厳密にテストを先に書かなくても、サイクルを大きく1日1回くらい回すのでも、ちゃんとした結果を出せます(これは初級者は真似しないほうがよいです)。

和田卓人氏(タワーズエスト)の講演「質とスピード」では、コードに対しテストを書いてきれいな状態を維持することが、開発スピードの向上につながるという話が繰り返しされています。またMartin Fowlerの言葉として、「品質の低いコードは、数週間でスピードを大幅に遅くしてしまう」(“Developers find poor quality code significantly slows them down within a few weeks.”)と紹介しています。こちらのスライドは、開発スピードに関する重要な知見を含んでおり、読んでみるのをお勧めします。

f:id:yach:20210407143722p:plain

speakerdeck.com

再開発や保守運用は工夫が必要

さて、新規開発ではなく、既存システムや保守運用の場合(2.)は話が変わってきます。いまからテストを自動化するというかなり重大な先行投資が必要になるためです。この負担をまるごと一括で顧客に求めるのは、かなり難しいと思います。

ひとつのアプローチは、細く長くテスト自動化を内部で進めていき、徐々に内部の工数が減っていく効果をねらうというものです。細く長く工数を確保しないといけない話ではあるので、厳しい面もあるとは思います。いっぽう、現場のメンバーが何名かいて、TDDやテスト自動化をやってみたいというモチベーションがあって、仕事の中で時間を捻出して自主的に進めるというのは、よく見る姿です(工数を確保してあげられないのはブラック風味ではあります)。組織の共通予算のようなところから、戦略的にどこかのチームに投資するという選択肢も、あるかもしれません。予算(工数)確保であったり、スキルあるメンバーがやって来てパートタイムで手伝ってくれるなどです。

そもそも投資である

3番目の論点は、テスト駆動開発や自動化が初めてです、という人にお客様の仕事をさせるのでしょうか?という話です(3.)。これは開発サイドから見ると投資です。開発機材を最新化したり、未知の言語を勉強したり、新しいクラウドアーキテクチャを試してみるというのと、同じ意味で投資です。そうした投資の話をお客様とできる関係性なのであれば、ぜひ説明していただければと思います(コンサル的役割で説明のお手伝いもできるかもしれません)。

投資をお客様に求められる状況にないのであれば、初めてのテスト自動化をプロジェクトの予算でやるわけにはいかないでしょう。勉強、練習の工数は別途確保して、ちゃんと仕事で使えるようになってから仕事で使うという流れになります。スクラムを導入して、ちゃんと改善をまわせているチームであれば、改善をするという時間を確保しているはずなので、その中で勉強・練習をすることになります。

勉強と練習をするのはそんなに長い時間ではなくて大丈夫でしょう。勉強だけの時間が1週間(40時間)あったら素晴らしいですが、そこまでやらなくても、いったんできるようにはなると思います。そこからは仕事の中でやっていくことになりますが、書くテストの種類や、フレームワークの取り扱い、データベースの扱いなど、自分たちのプロダクトの環境で必要になるやり方を調べたり、編み出したりしていく必要もあります。最初の勉強から、プロダクトでテストを書くやり方があるていど安定するまでは、経験者や外部のメンターなどがいるほうが安心です。

勉強と練習をするのは、実際のところ自分たちはどのくらいのスピードで進めるのか、それを見極めるためにも必要です。納期とスコープが決まっていて、それに間に合わせないといけないのなら、実際の仕事の環境でスピードを計測するのはリスク対策としても必須です。やってみて、明らかに間に合わないなら、いまは諦めるという選択肢が採れます。テスト駆動開発でやると決定してから、それでは間に合わないとわかるのでは、手遅れになってしまうかもしれません。現実問題としては、練習してできるようになったうえで、その前提で見積もるはずです。

回答が長くなって恐縮ですが、懸念となる点を図で整理するとこうなるのかなと思いました。

f:id:yach:20210407143822p:plain

(字が読めなかったらごめんなさい。「現在の生産性とそれを基準とした見積り」「TDD勉強中~試行サクゴ中の生産性」「TDD上達後の生産性」です)

  • Bの生産性は本当にAより高くなるのか、どのくらいなるのか?
  • 勉強や試行錯誤で生産性が下がるCの期間はどのくらいかかるのか?
  • Cの期間中の仕事はどう見積もるのか?
  • Dの投資をどう捻出するのか?

こうした疑問には、申し訳ないですが私には回答できません。現状によるというところもあるし、結局は人次第の面もあります。Cを圧縮するためDを深くする、あるいは逆にCを引き延ばしてDを薄くするというような作戦もありそうに思えます。

私自身の、何年か前にアジャイルコーチとして支援したチームで、まず普通に作ったシステム(テストなし)に対し、エンハンス(保守)の中でテスト自動化とテスト駆動開発導入に取り組みました。なので既存システムのシナリオ、ただし初期メンバー(けっこう優秀)がそのまま追加開発をしている体制です。そこではかなり感覚的ですがBはAの1.2~1.3倍、Cは半年くらい、Dは主にメンバーのモチベーションで捻出した(ただし内製なので政治的な話にはならない。開発チームがビジネス側を説得した)、という感じです。

TDDではなくテスト自動化で考えると、プロジェクト全体で見て、手動でテストする方法と、テストを自動化する方法、どちらが工数面で有利かは、状況によると思います。すみませんが私には、そのへんのノウハウがありません。「自動化するだけで安くなる」はまやかしですが、手動と自動をうまく使い分ければトータルのコストを下げられる可能性はあるのではないか、少なくとも選択肢として俎上に載せられるのではないかとは思います。

こちらの講演時にいただいた質問への回答です。

「テスト自動化とテスト駆動開発」講演資料 - やっとむでぽん

質問6. テストコード部分の品質はどのように維持するのでしょうか?テストコードのテストコードを作るのではないと思いますが……

ひとつは、プロダクトコードと同様のレビューとリファクタリング。もうひとつは、テスト駆動開発に特有ですが、プロダクトコードとテストコードがお互いに支え合うような関係にする考え方です。

テストのレビュー

まずはレビューですが、これは普通のやり方です。テストコードの書き方、テストの内容、他のテストと見比べた上で全体を把握しやすく書けているかなどを見ます。特に、テストコードや実行結果から、テスト一覧を出力したり、失敗時の表示などを見て、どんなテストをしているか把握できると、テストドキュメントをある程度代替できるので、そうした観点で読めるか・伝わるかも見ます。

プロダクトコードのレビュー時に、TDDで書いたテストコードも一緒にレビューするのも一般的です。急いでいるときはテストだけレビューすれば、何が動いているか、どこまで進んでいるかわかるというメリットもあります。

極端に品質の低いテストコードには、以下のようなものもあります。

  • テストの実体がない(ガワだけ。書き忘れ、時間不足)
  • テストが実行されていない(タイプミスなどで、けっこうやりがち)
  • なにも検証していない(assertがない。テストを理解できていない。コードカバレッジを増やすためにやってる場合もあるが、無意味)
  • テスト対象のプロダクトコードが、なぜかテストコードにコピーしてある(テストへの理解不足。「このコードをテストしたいんだ」という気持ちはわからなくもない。コピペ開発のやりすぎかも)
  • 書いた人の環境、PCでないと実行できないテストになっている(ファイルアクセスが必要、特殊なテストデータが必要などで、全員が実行できるようなテスト環境を整えられていない場合に見られる。開発ができる人ほど、できちゃうので、やりがち)

メンバーの理解不足、スキル不足が原因の場合もありますが、時間がなくてつい…ということもあります。人の目によるレビューは、だいたいいつも有用です。ペアプログラミングをしていれば、レビューは減らしても大丈夫かもしれません。ペアプロでも、コードレビューをまったくゼロにするチームは少ないようです。

テストコードもリファクタリング

レビューからのフィードバックを取り込むのは、テストコードのリファクタリングです。もっとも、レビューがなくても、リファクタリングではいつでもテストコードを対象にします。ここでは「コードとしてのリファクタリング」と「テストとしてのリファクタリング」を両方とも意識する必要があります。

テストコードもコードなので、プロダクトコードと同様、読みやすく、重複なく、変更しやすいようにリファクタリングをします。基本的にはプロダクトコードのリファクタリングと同様です。ただしテストコードの場合は、「どんなテストケースなのか」を読み取れるのが最優先となります。プロダクトコードは、コードを書く人しか通常読みませんが、テストコードを読む人はテストの内容を知るために読む場合が多くなります。そうするとロジック(How)を把握するより、何をしているのか(What)を把握するのが早いほうが、嬉しい。

私は、読む人は以下の順にテストコードを把握したいだろうと想定して、できるだけ早く必要な情報がわかるように意識しています。

  1. どんなテストか(What) - テスト名(メソッド名など)を見ればわかるように
  2. 確認している内容は何か - assert部分を1行だけ見ればわかるように
  3. どうやってテストしているか(How) - テストメソッド全体(だけ)、特にassertまでの準備部分を見ればわかるように
  4. テストを書き足すにはどうするのか - 共通化されたセットアップ、フィクスチャやヘルパーを含めたテストコード全体を見る

また、少しずつ異なる複数テスト内容が、少しずつ異なる複数のテストメソッドで実装されます。この「少しずつ」の差異は、テストコードの中に埋もれてしまって読み取りづらくなりがちです。「あれ、このテストとこっちのテスト何が違うんだろう…(5分後)あー、ここが123546789か123465789かの違いかー」みたいになります。この間違い探しはツラいし時間を食いますし、さらに違いを見落とす場合もあります(実はさらに"あああああああああ"と"ああああああああああ"の違いがあった、ということもある。なお、こんなテストを書いた人は呪われてしまえと思う)。

こういう差分が素早く確実に読み取れるような工夫も、テストコードには大事です(特有なわけではなく、プロダクトコードでも役に立ちますけれど)。定数を使う、インデントを揃える、コメントを入れる、名前付きパラメータやデフォルト値を活用する、フィクスチャなどで再利用する、前準備をテストのネストで構造化する、ヘルパー関数を作る、カスタムアサーションを作るなどのテクニックがあります。

テストとしてのリファクタリングも、ここで考えるべきです。テスト駆動開発で書くテストは、開発を進める順番に書いていくので、後から見ると「なにをテストしてるのか」「なんでテストしてるのか」わからなくなりがちです。ひとまとまりの機能が完成して、その機能をテストがだいたいカバーしているタイミングで、今までに書いたテストを見渡します。一貫性があるか? 仕様、なにをする機能か(What)がテストから読み取れるか? テストどうしの見分けがつくか? 全体としてどんなテストをしているか把握できるか? 他の機能のテストと並べてみて、意味があるか? テストの重複はないか? 足しておきたいテストは?

作業が一区切りついたとすると、次にこの部分をさわるのは、もしかしたら半年後かもしれません。この部分をまったく知らない別の人(ペア)が、また新しい仕様変更に対応するかもしれません。そのとき、テストが作りっぱなし、書きっぱなし、半年前に作業したペアにしかわからない状態だと、ひどく苦労することになります(そして元々のペアも半年前のことはもちろん覚えていません)。「テストが整理されていない」状態では、テストを適切に変えることもできなければ、テストを命綱として安全に変更することもできなくなります。

テストコードを他の人が読むことを想定し、またテストの内容や網羅性、観点やテスト全体での位置づけを伝えるのが大事だという認識で、テストコードをリファクタリングします。テスト名を仕様の言葉で表現し、正常系なのか異常系なのか、境界値をテストしてるのか、組み合わせをテストしているのか、見分けがつくようにします。テストをネストして分類したり、同種のテストをグルーピングしたりします。パラメタ化テストも便利です。こうしてリファクタリングされたテストは、QAテストでも役に立ちます。

テストのリファクタリングでもっとも難易度が高いのは、テストの削除です。すでにあるテストが、重複しているように見えるのだけど本当に消していいのかわからない…ここで消してしまう勇気はなかなか出ません。実際問題として、自信を持ってテストを消せるのは、テストを書いた当人だけ、テスト書いた直後だけです。書いたばかりのテストをリファクタリングするタイミングであれば、これはこういう事情で書いたけど、もういらないという判断ができます。不要なコードを後に残すのは、メンテナス性を下げるだけです。不要なテストの削除も含めて、テストのリファクタリングを忘れないでください。

コードとテストが支え合う

もうひとつ、テスト駆動開発ではプロダクトコードとテストコードを使ってお互いに動作確認をしあうことがあります。テスト駆動開発の技法として仮実装(Fake It)というものがあります。これは、テストコードを書いた段階で、確実にテストを成功させる(Greenにする)ため、プロダクトコードに偽物(Fake)の簡易な実装をします。実際の計算をする代わりに固定の値を返すなどです。もしもこの時点でテストが成功しなかったら、問題があるのは(固定値を返すだけの)プロダクトコードではなく、テストコードです。こうして、テストコードが正しく動作するかを確認します。テストのための初期化が足りていなかったり、呼び出す対象が間違っていたり、結果の確認方法が違うなどの問題を検出できます。

同じアプローチは、書き始め以外でも使います。コードのこの部分を変えると、このテストがこういうふうに失敗するはずだと考えて、実際に変えてテストを実行します。ここでテストが失敗しなかったり、失敗しても想定と違うメッセージを出していたりすると、テストが間違っている(あるいは自分の理解が違う)とわかります。

TDDのレッド・グリーン・リファクタリングのサイクルは、数分くらいとごく短いですが、このアプローチを使っているときは

  1. 試しに1文字変えて実行→
  2. 期待通りRed→
  3. 正しいつもりで数文字直して実行→
  4. 期待通りRed→
  5. さらに数文字直して実行→
  6. 期待と違うRed→
  7. いったんコードを戻してGreen→
  8. テストを直してRed→
  9. 正しく直してGreen

というように、1分以内、秒単位のサイクルで、コードとテストの挙動を細かく確認しながら進める場合もあります。こうして、テストが機能していなかったり、想定と違うテストをしてしまっているような状況を防ぎます。