【ノンプログラマ向け】プログラマの仕事内容を理解する ~「テスト」という工程が必要な理由

前書き

「一緒に働いている以上、プログラマのことを理解して仕事をしたい」そう考えている企画・ディレクションの方は経験則的に少なくない。
ノンプログラマから見て、プログラマの仕事はイメージが湧きづらく、何故その工程にそこまでのコストをかける必要があるのかわからない事が多い。
プログラマは作業の必要性を説明してくれるかもしれないけれど、専門用語も多いしイマイチピンとこなかったりする。

ここで重要なのはまさに「イメージ」だと思う。すなわちイメージを提供するための良質なメタファーだと思う。メタファーが良質であれば より直感的に理解できる
実際メタファーの力はバカにならない。「Chef」も「Jenkins」も それぞれ 統一的な世界観が学習者の直感的な理解を後押ししてくれる。

というわけで、今回から数回に分けて なるべく「技術的な話」をせずに イメージを想起しやすいストーリーを導入することで プログラマの具体的な仕事の内容についての説明を試みる。

対象読者

・企画、ディレクター等 プログラマと直接コミュニケーションを取る機会の多い人達
・プログラミング初学者

現時点での執筆予定

< 具体的な作業工程 >
・「テスト」について (今回)
・「アジャイル開発」について
・「TDD(テスト駆動開発)」について
・「バージョン管理(Git / SVN)」について
・「CI(継続的インテグレーション)」について
< スタンス・文化 >
・「プログラマのスタンス/経営者のスタンス」の重要な違い、ハッカー文化について
・「プログラマがよく使用する用語」について
・「自社で採用するべき言語」について(人事向け)
・「炎上」について

※ ニーズにより目次は前後・変更する可能性があります。
また、若干 宗教論争になりそうな所は テーマ・対象を厳密に熟考した上で できるだけ主観が入らないよう注意します。
※ 最近は企画の方もGitをいじられるそうなので、そのうちGit詳解編もつくる予定です。
(11/16 21:50 追記) ※ ↑ブコメにて「いわゆる”ハッカー文化”を語るのはWeb系に多く、他分野ではそうではない」という重要なコメントを頂きました。確かにWeb系を中心に考えすぎており他分野に対して盲目的でした。申し訳ございません。文化的な部分を語る際は 認識の誤りが無いよう、対象を限定するように注意いたします。
(2015.04/09 追記) ※ 私都合により少々執筆の目処が立たないため シリーズとのたまったものの一時休止させていただいております、申し訳ございません。

長くなりましたが、それではこれからテストをめぐるAくんのストーリーを見ていくことにします。

——————————

オープニング

20XX年――― ある小さな町に A君 という若者がいました。
A君は 自宅で自作のロボットを設計しては組み立てて売ることで 生計を立てていました。

robo1

最初は友達に小さなロボットを見せたりして、細々とロボットをつくっていたA君でしたが、
次第にA君のつくったロボットの評判は町中に広がり、ロボットを買いに来てくれる人が多くなりました。

ロボットを買ってくれる人が多くなるにつれて、買ってくれる人から色々な意見を貰うようになりました。

手足が動くようになればもっといいね」
装飾としてアンテナをつけた方が格好良いと思う」

できるだけ多くの人を満足させたいA君は、貰った意見を基に ロボットに対して色々な機能をつけながらロボットの改善を重ねていきました。

robo2

こうして、最初はシンプルだった ロボットには色んな機能がつきました。
それでも買ってくれる人からの要求は絶えません。A君にとっては常に改善の日々です。

そんなある日、A君は あるお客さんからいただいたアドバイスを基に部品の追加をしようとした所…。
部品を追加したい場所に、結構前につけた別の部品がくっついています。
この部品がクセモノで、他の沢山の部品と接続されているため なかなか取り外しづらそうです…。

「困ったなあ・・・。でもお客さんの要望にこたえなきゃいけないしなあ」

暫く悩んだA君は、元々くっついていた部品を改造した上で 新しい部品をつけてみました。

robo3

「うん、何とか動きそう」

部品が動く事を確認したA君は さっそく追加した機能をお客さんに見せます。
お客さんは非常に満足して、ロボットを買って帰っていきました。

数日後、A君のもとにぽつりぽつりとクレームが届き始めます。

「なんかアンテナのランプが光らなくなったんだけど・・・」

何ということでしょう。
今回A君が追加した部品とは違う部分で問題が起きていました。

robo4

A君は 追加した部品が動くかどうかだけに気ををとられてアンテナのランプが光らなくなっていた事を見落としていたのです。
(これは余談ですが、人間別の事に集中していると 他の事に対する注意力が落ちるものです。例えば「何回パスが渡されたか数えて下さい」と指示があり、バスケットの試合が映し出される動画(こちら)があるのですが、皆パスの回数を数えるのに夢中になるあまり、途中でゴリラが乱入しても全く気が付きません。是非友達に試してみて下さい)

アンテナは 今回追加した部品と直接繋がってはいないものの 間接的に別の部品を経由して動いている部分でした。
大切なお客さんに対して 不具合のあるロボットを渡してしまったことで A君はひどく落ち込んでしまいました。

——————————

そこで「テスト」の工程を導入

これだけ複雑なロボットになってしまったわけなので、そろそろ 目視や何となく動くかチェックするだけでは先ほどのような抜け落ちが出てきてしまうことに気がついたA君は、ロボットをお客さんに出す前に「この部分の機能がちゃんと動いているかどうか」という項目を上げて かならずテスト作業をすることにしました。項目は以下のようなものです。

「ボタンを押した時に 手足が正常に動くか」
「胸元のランプを押した時に 胸元のランプが光るか」
「ロボットの電源を起動した時に アンテナのランプが光るか」

毎回 部品を追加した後にテスト工程を含めることで お客さんに新しいロボットを提供するスピードは以前より落ちてしまいましたが、これで 大きな不具合を出して沢山のお客さんを困らせてしまうことはなくなりました。

——————————

解説

・ロボット
Webアプリケーションやソフトウェアなどの「システム」そのものです。
一般的に規模が大きくなるにつれて、お客さんの要求によってどんどん色んな機能がついていって構造が複雑になります(一見サービスとしてはシンプルなシステムに見えてもです)。

・お客さん
企画の方や、顧客のことです。
内部構造がいかに複雑で 機能の変更が難しいかは彼らには関係ありません。
彼らは色んな要求をしてきますが、本当は何が欲しいのかを自分たち自身が気づいていないケースもあるため あらゆる要求を飲む事はせず しっかりとコミュニケーションをとることが大切です。

・アンテナのランプが光らなくなった
開発現場ではこのように「既存機能に変更を加えた結果として 元々の部分に予期しない変更が起きる」ことを「デグレ(デグレード・デグレーション)」と言います。
(例) 「●●の部分デグレってる」

(11.17 追記) 「デグレーション」という言葉も一応存在するみたいですが、正しくは デグレード、またはデグラデーション(degradation) のようで、こちらの言葉が一般に使用されるみたいです。ブコメにてご指摘下さった方、ありがとうございます )

——————————

以上です。テストを導入することで確かにロボットを提供するスピードは少し落ちてしまいますが( とはいえ、実はテストを書いた方が 導入時こそ大変なものの後からスピードが速くなるのですが )、「テスト」という作業がどれだけ大切な作業かご理解いただけたら幸いです。

「テスト作業」について

ここからは ちょっと踏み込んだ部分になりますので、より詳細に技術者の仕事を理解したい!という有志のみご覧下さい。

概要

「●●をした時、●●という結果が返ってくるか」という形でテスト項目をつくっておき、機能の追加・修正が発生した段階で項目にしたがってテストを行います。

種類

単体テスト・ユニットテスト
プログラマの作成したシステムの断片的な機能を、テスト用のコードを書いてテストします。
部品を組み合わせる前に、その部品が本当に正常に動いているかを見るわけです。
例) square関数(二乗のための関数) のテスト
「数字 4 を渡した時に 16 という結果を返すか」
「数字 0 を渡した時に 0 という結果を返すか」
「数字 -5 を渡した時に 25 という結果を返すか」
「文字列 を渡した時に エラー “数字を入力して下さい” を返すか」

統合テスト(インテグレーションテスト)
システムについて、複数の機能をそれぞれ何人かで分けて開発している場合、どこかの時点で「部品を組み合わせる作業」が必要です。
その際、個々の部品が不具合無くしっかり動いていたとしても、組み合わせた時点で不具合が発生しないとは限りません。
そのため、部品がしっかり組み合わせられているかを保証するために 部品を組み合わせた状態でのテスト作業を行います。

エンドツーエンドテスト(E2Eテスト/受け入れテスト)
単体テスト・ユニットテスト・統合テストは主に不具合が無いかを保証するための「プログラマ」寄りのテストでしたが、こちらのテストは技術的な話を抜きにして「追加・変更した仕様がしっかりと要望通りに動くか」をテストするためのものです。
こちらのテストは 実際に要望を出す 企画・ディレクション の方がつくるのが一般的です(認識のずれによって間違った物を開発してしまわないためにも、企画の方は どんな要望なのかを間違いなくプログラマに伝える必要があります)。

例) ECサイトの購入確認ページ かごの中の商品を表示するようにシステムを変更した場合のテスト例(飽くまで一例。実際はもっとテスト項目が多いので注意)
テスト1・単数条件
「1. テスト用のURLに遷移し、『テスト本』を買い物かごに入れる
 2. “購入”ボタンを押し、確認ページに遷移する
 期待する結果: 確認ページに『テスト本』の情報が表示されている」

テスト2・複数条件
「1. テスト用のURLに遷移し、『テスト本』『テスト本2』をそれぞれ買い物かごに入れる
 2. “購入”ボタンを押し、確認ページに遷移する
 期待する結果: 確認ページに『テスト本』『テスト本2』の情報がそれぞれ表示されている」

テスト3・購入する商品がない場合
「1. テスト用のURLに遷移し、”購入”ボタンを押し、確認ページに遷移する
 期待する結果: “かごの中に何も入っていません”と表示されている」

そもそもテスト項目の結果が変わるような変更が起きた時は?

テスト項目自体を変更します。
これが「ユニットテストでどこまでの範囲をテストするのか」という問いにも繋がってきます。
( 100%全てのシステムを網羅してテストコードを書いても、仕様変更の度にテストコードを沢山書き換えなければいけないようであれば コストがかかりますから )
なので、ソースコード全体のうちどれくらいの範囲のテストを書くのか(「カバレッジ」ともいいます)は そのサービスの規模によって変化させるべきです。
ただし、システムの規模が小規模であれ大規模であれ、コアな機能(その機能に不具合があればサービスが成り立たないような機能)に関しては必ずテストを行うべきです。
スピードを大事にしすぎるあまり本当にテストが必要なコア機能すらしっかりテストしないとかそれサバンナでも同じ事言えんの?

テストの方法

単体テスト、ユニットテスト、統合テスト の場合
テスト用の便利なフレームワークが世の中には沢山存在します( xUnit と呼ばれるものが有名です )。
このフレームワークの規則に沿ってテスト用のコードを書くのが一般的です。
元々テストを導入してこなかった場合: 急にテストを全て書くのは至難の業なので長い年月が必要になりますが、そのあたりは僕よりもテストに詳しい方が 昔からよく議論されている部分なのでそちらを参考に。

エンドツーエンドテストの場合
意見が分かれる所だと思います。
最近の技術体系だと E2Eテストですらソースコードで導入できるようになってきてはいますが、
まだまだ Excelが多い印象です。
理由としては、企画・ディレクション職のノンプログラマに E2Eテスト用のコードを書くための若干の学習コストを強いることになる点、部署をまたいだ組織的な取り決めのプロセスにコストがかかる点等が挙げられると思います。

テストを導入することの難しさ

(11/16 21:50 追記) ブコメにて貴重なコメントを頂きました。ありがとうございます。
ここまでを見ると、「ああ、じゃあテストを導入すれば品質が上がるんだな」となりますが、テストの工数に関しても触れないわけにはいきません。
テストは導入してしまえば終わりではなく、追加・変更にもそれなりのコストがかかります( 特に開発初期に関しては 導入にかなりの時間を要します )。そのコストは実際にテストを設計し、落とし込む作業が入るため、開発作業と同等のコスト・もしくはそれ以上の工数が発生する可能性を考慮しておく必要があります
( とはいえテストを導入しない場合は導入しない場合で、どのみち開発工程の多くの時間を 正体不明のバグの対応で埋めることになりますので、長期的に品質、不具合の規模・頻度、不具合対応の速さを考慮するのであれば テストの導入は不可欠となります )

——————————

以上です。
ここまで読んで下さりありがとうございました。
僕もまだまだひよっこなので、「ここ間違ってるよ」という部分がございましたら是非ご指摘・アドバイスいただければ幸いです!

Written by Nisei Kimura ( 木村 仁星 )

- Sponsored Links -

<<

Top

>>