テスト界の第一人者、高橋寿一さんに実践的、かつ効率的な開発者テストに関してご解説いただくこのコラム。前回は、上流工程でバグを見つける「シフトレフトの本質」を教えていただきました。どんなポジションであってもミスなく仕事をすること、自分のミスは自分で修正する意識を持つこと。その大切さを改めて痛感しましたよね。さて今回は、そのシフトレフトの品質について。どのようなバグが出て、どう防ぐか。アジャイル開発における「テスト手法」を学びましょう。
この記事でわかること
・要求仕様やユーザーストーリを書く難しさ。そこで常に考えておきたいこと
・80%以上のバグを潰せるかもしれない「境界値テスト」について
シフトレフトでの品質の落とし穴はどこ?:人は間違える。どんなソフトウェアを作りたいかを文章で書けますか?コードをちゃんと書けますか?
さて、前回お読みいただいた方は、「ブルシット・ジョブ」について理解していただけたかと思います。アジャイル開発が主流となる「アジャイル時代」では、テスト担当者が主なテスト実行の役割ではなく、開発者がソースコードを書いた先からテストしていくことを期待されています。これぞシフトレフト。
シフトレフトするための「要求品質」。完璧ではないことを前提に。そのとき必要な考え方とは?
「ブルシット・ジョブ」をなくすためには、まずはバグを下流工程までもっていかないことです。上流で入り込んだバグは、上流で。要求仕様フェーズのバグは、要求仕様でちゃんとみつけましょう!コーディングのバグはコーディングフェーズで……。なんて、知ったかぶりでみなさん言ったりしていませんか?
でもほとんどの組織でそれができてないのはなぜでしょうか?また、もしも市場不具合があり、それが要求仕様におけるバグが起因だったとしても、その再発防止では「ちゃんと要求仕様を書こうね!」で終わっている組織がほとんどなのではないでしょうか。
アジャイル時代になり、要求仕様という言い方より「ユーザーストーリー」という言い方に最近は変化してきました。本質は同じなので些末な差異に関してはここでは述べませんが、要求仕様やユーザーストーリの不備によるバグは、アジャイル時代になってもなくなりません。
要求仕様・ユーザーストーリを書く難しさは、人間の考えること、もしくは、希求することをソフトウェアの世界に落とすことの難しさです。しかしまずは、人間の希求していることを自然言語で書く必要があります。でもそれがまた難しい…。
例えば、エスカレーターがあり、その横に以下のような標識が立っているとしましょう。
別段問題のない記述だと、普通の人はそう思います。離散数学的に書くと(はい、もちろん数学が得意な人以外は理解する必要はないです)、
になります。論理的には、十分ソフトウェアに変換できそうです。しかし、品質のプロ(というより偏屈な人)は、以下のように考えます。
・エスカレーターに乗るときは必ず犬を抱いて乗らねばならぬのか?
・エスカレーターに乗るときに犬は必須条件なのか?
・靴を買ってきて紙袋に入っている場合はどうであろうか?
これを離散数学的に書くと……、もう十分だという声が聞こえそうなのでやめておきます。
現実世界というのは、事象やパラメータやデータが凄まじいほど存在し、その組み合わせは無限大です。ソフトウェアのすべてをテストすることができないのと同様に、ソフトウェアのすべての期待する振る舞いを要求仕様として記述することもできません。
なので、要求が完璧ではないこと(要求に関するバグがあらゆるところで発生する)を前提に、プロジェクトを進めることが大切です。常に、こういう例外の場合はどうであろうか?ここの要求が変わったけど、他の要求仕様には影響はないか?などを考え続ける必要があります。
アジャイルは複数のイテレーション
で開発されます。イテレーションごとに要求仕様・ユーザーストーリが定義されると思いますが、常に要求やユーザーストーリは、開発ライフサイクル全体の視点で見ないと思わぬ抜けが生じたりするわけです。シフトレフトするための「ソースコード品質」。境界値テストは、80%以上のバグを潰せる?
さて次は、ソースコード品質を見ていきましょう。実際このフェーズからほとんどのバグが出てきます。まずソースコードってなんでしょうか?なぜそこに、バンバンと間違い(バグ)が挿入されるのでしょうか?例えば以下のように18より小さい数の場合を
if (a < 18)
間違えて18以下と書いてしまう。
if(a <=18)
本当は日本語の文書をそのまま要求仕様に書けば間違いは少ないのだろうけれども、自然言語からソースコードへの自動変換はもう少し技術の進化が必要でしょう。そのため人間が自然言語から論理言語(プログラム言語)へと変換する必要があります。
ここで、プログラムというのはどういう論理でなりたっているかを少し解説。簡単に言うと「四角(実行文)」と「ひし形(分岐)」でなりたっている、いわゆるフローチャートです。(違うと異論を唱える人はちょっと昔の本だけど、この本を読んでほしい:Richard Linger, Harlan Mills, and Bernard Witt, Structured Programming: Theory and Practice, Addison-Wesley Publishing, 1979.)
While文やfor文がありますが、それらは「分岐」と「実行」を組み合わせたもの。そう、ソフトウェア開発というのは要求仕様を書く、そしてそれを四角とひし形に変換する。その2つのアクティビティを膨大に行う作業なのです(まあ、開発者がアーキテクチャーとかなんとか難しいことを言っているけど、本質はそんな難しいことをやっているわけではない)。
膨大なジグソーパズルを組むぐらいの面倒くささはあるが、難しい作業ではないと思っています。ただただ、メンドクサイ。
例えば1行の要求仕様の文書を100個の四角と70個のひし形に変換しなきゃならないので、そりゃー間違えるよねーという話です。テストはというと、その変換が正しく行われているか(人間が変換するので、ある一定の確率で間違いを起こす)を確認する作業のこと。
ここで重要になってくるのがテスト手法の一つ「境界値テスト」です。境界値テストとは、文字通り、要求仕様の「境界」をテストします。ひし形への変換がちゃんとテストされているかをチェックするということです。期待する結果を四角の振る舞い、もしくはデータでチェック。このテストさえちゃんとしていれば、80%以上のバグは潰せるかもしれません。
ただここで一つだけ気をつけなければならないのが、そもそもの要求仕様の抜け。要求仕様の間違いは、上記の境界値テストで見つけることができます。しかし、要求そっくりそのまま書き忘れただとか、それを考慮にいれなかっただとかは、残念ながらテストしようがありません(当然プログラムにも入れ込まれない)。
ただ単にテストされずに出荷されるため、多くの市場バグはここから生まれます。エラー処理がいい例で、ネットワークからの返答がなくタイムアウトしてしまった場合の多くは、要求仕様の抜けから生じたバグになります。
さて今回は、シフトレフトするとどのようなバグが出て、そしてそれをどう防ぐかを説明しました。人は間違えるものなので(仕事に限らず)、完璧はありえません。それでも、例外の場合はどうするのか、抜け漏れはないか、常に考え続けることが重要です。次回は最終回。シフトレフトが当然の「アジャイルの世界」では、どのように品質担保していくかを説明していきます。
▼これまでのソフトウェア品質を高めるために知りたい開発者テストの最前線
【第1回】なぜテストは必要なの?
【第2回】シフトレフトの本質とは