色々なテストコードを作成してみようの講座を受けてくれてありがとう。
ウサギだ
講座の最後に、なぜテストコードを書く必要があるかを語っておく
軽い気持ちで聞いてくれればいい
まだ講座を受けてないやつも聞いていいからな。むしろ聞いてって
テストコードを書くと時間がかかる?
正直はじめてテストコードを書いた奴にとっては、なぜこんな面倒なことをやる必要があるのだろうと思ったかもしれない。
いいんだ。正直に言ってくれ。
ここを読んだ輩の中で、
テストコード、やっぱりよくわからねーな。
俺たちは早くプロダクトコードを書きたいし、納期はキツキツだし、PMのクソやろうはうるさいし、こんなところで時間をかけてる暇ないんだよ。
って思ってるやつがいる。
絶対にいる。
いいんだ。そこについては批判しない。
しかし断言しよう。テストを書くから時間がかかるんじゃない。
テストを書かないから時間がかかるんだ。
これからいくつかエピソードトークをし、お前らをテストしたくてしょうがない状態に持って行こうと思う。
まあ気張らずに聞いてくれ。
バグ修正が楽
テストを書くと生産性が上がる。と言われているが、本当だろうか。
むろん、本当だ。
これはバグ修正時にもっとも効果を体感できる。
例えば本番環境で、ユーザーからバグ報告が上がってきたとする。
解析の結果、バグの原因は分かった。
どうやら特定のDB条件だと、とある関数でnullアクセスが起きるようだ。
聡明なるお前は1行パパッと修正して、テストをしようとする。
さてここからが問題だ。
テストコードがないんだとしたら、下記のような手順を取ることだろう。
- プロダクション環境のDBをダンプして、ローカル環境に入れ込み同じ条件を作り出す
- もしくはプロダクション環境のDBを注意深く読み解き、ローカルのDBを同じ状態にする
- そのあと、ユーザーの手順を再現し。。。いやいや、そういえばローカル環境では決済ができないぞ? 手順の中に決済があってどうしても必要なのに。ああどうしよう
- ていうかプロダクション環境のDB入れたらレコードが多すぎてマシンが動かない。え、会員一覧が表示されないぞ???
- ああ。もう。しょうがない。PLに状況を説明して、ぶっつけステージング環境でテストするか
- (PLとゴチャゴチャ不毛な話をする)
- この関数を修正したことでの影響範囲だって?? 知るかよ! 退職したやつが作った機能だぞ!
- しょうがない、単体テスト仕様書から関係がありそうなのをいくつかピックアップして〜
- って、280項目もあるじゃん!!!
- ひとまず、俺の長年の経験でピックアップするしかないか。。。
- でもこれ、どうやってテストしたんだ?? テストの手順は? 証跡は残ってないか??
- お、単体テスト、とかいうフォルダが残ってるぞ。しめしめ。
- 謎のスクリーンショットが一枚貼ってあるだけだった
- やっぱ無理だって。こんなのテストできるわけないじゃん。何日かかるんだよ。。。やっぱPLと。。。
- (PMとPLと3者でゴチャゴチャ意味のない話をする)「1行修正ですし。。。」「決済絡みは怖いから。。。」「夜間対応も。。。」などと無意味な単語が飛び交う
- PMが勇気を持って決断。
- よし! 本番デプロイするぞ!!!(ここまで3.5日)
これが、テストコードのないチームの一般的なバグ修正フローだ。
バカみたいだろ?
ここでのポイントは、修正が他の仕様を壊していないことを誰も証明できないことだ。
証明できないからこそ、議論に議論を尽くしたていを装い、最終的にはPMの漢気でデプロイするという決断しかできない。
単なる賭け事の話だ。
オレの偏見によると、実のところ、一般的な古き良き会社は80%の企業がこのレベルだ。
残りの10%がQAチームの人海戦術と金の力で280項目を本当に手動でやる会社だ。
一方、残りの10%がテストコードを書く会社だ。
そう、10%だけだ。
これを読んでいるお前は希少種だ。絶滅危惧種だ。
(重ねて言うが、この数値はすべてオレの偏見であり妄想だ)(2021年現在)
一方、テストコードを書く会社のバグ修正フローは下記となる。
- nullアクセスが起きる時の関数のテストコードを書く
- テストを通す
- 単体テストが網羅されているテストを流す。全テストOKが確認できる=仕様を壊していないことが確認できる
- ステージング環境で修正確認
- 本番デプロイする
随分楽だと思わないだろうか。
おまけに、今回追加されたバグのテストコードは半永久的に記録される。
手動テストの会社が次に同じような箇所に手を入れた場合。
280項目+1項目の手動テストが必要になる。
来年はバグが増えて280項目+50項目になっている可能性もある。
その度にあちこちから人を掻き集め、5人で3日ぐらいかけてテストをしなければならない。
おまけに途中でNGがあればやり直しだ。
地獄のようなコストがかかる。
そして、そのうち。
暗黙の了解でテストが省略され、この前うまく言ったから今回も多分うまくいくだろうの精神。
未テストのままデプロイがかかる。
結果、死ぬ。
担当が失踪する。
PMがうつ病になる。
他のベテランエンジニアも次々と辞めていく。
テストコードのない大規模開発は想像を絶する地獄である。
一方、テストコードのある会社は、どれだけバグが増えようがテストはプログラムがやる。
正確で速く、確実にバグを拾い上げる。
手順を確認するみたいなバカな時間もない。
ワンコマンドで仕様を壊していないことを確実に担保してくれる。
積極的なリファクタリングによる品質向上
こんな経験はないだろうか。
既存プロジェクトの保守にまわったとき。
あまりのコードの汚さに辟易するお前。
イケてるお前はガッツリとリファクタリングをやってみた。
随分イケてるコードになったはず。
さあ、デプロイするぞ!
その夜中、大量のエラー報告がSlackに通知され、お前は夜中、会社に呼び出されることになった。。。
あるよね?こういうこと。
ここまで露骨なやつじゃないとしても、書き方がおかしかったのをちょっとだけ直して、テストせず本番デプロイしたやつ。
先生怒らないから手を挙げろ。よしよし、正直に手を挙げたな。
泣いて詫びろ。
お前の愚行は、規模の大小にかかわらず、動いているコードを壊し、未テストのままデプロイしたことだ。
保守的で伝統を重んじるSIer上がりのエンジニアだったらこう言うだろう。
「動いているコードをいじるな!!!!」
これは半分正しくて半分アホだ。
当然ながら、負債をみかけたらできうる限りリファクタリングすべきだ。
ただし、きちんとテストで担保できる場合の話だ。
ろくに仕様も知らないお前が局所的なコードの綺麗さだけを求めて未テストで好き勝手リファクタするのはテロ行為ですらある。
じゃあこのカオスなコード、カオスな現場において、リファクタリングをするのは不可能なのだろうか。
ここでメンテされた単体テストのテストコードがあった場合。
リファクタリングはめちゃくちゃ簡単になる。
なぜなら、単体テストを流せば、仕様を壊していないことが担保されるからだ。
INとOUTが明確に示された単体テストがあり、外部仕様に基づいたディシジョンテーブルが自動テストにすべて反映されているプロジェクトは、積極的なコード改善がギャンギャンできる。
仕様的なバグがあれば必ず自動テストが拾い上げるからだ。
いっぽう、1行なおす度に全テストを手動で実施するような責め苦を受けるのであれば、
誰もリファクタリングなんかやりゃしない。
そんな状況では「動いているコードをいじるな!」という名言が生まれても仕方がない。
無論、テストコードがあったとて。
修正には細心の注意を払う必要はある。
が、少なくとも。
前述のテロリストが無謀なリファクタを行おうとしても即座にテストエラーとなる。
そのコードが本番環境に流れる可能性は極めて低い。
CIで自動テストを回していればなおさらだ。
テストコードがあるから、リファクタが頻繁に行えるようになるのだ。
動く仕様書
今までアサインされたプロジェクトで、メンテされ続けている仕様書が存在した経験は?
先輩エンジニアから手取り足取り、時折ペアプロを交えながら仕様を教えてもらえたことがある?
設計書をそのまま実装すれば機能が出来上がる現場はあった?
リーダブルなコードで、コードを見れば仕様が即座にわかる現場はあった?
そんなものは、ない。
あるかもしれないが、限りなく少ない、ということが訓練されたエンジニア諸君だったらわかると思う。
なぜなら、世界中のほとんどのプロダクトは、職業訓練学校を卒業したばかりのエンジニアがリードしているチームだとか、コードが書けないからマネジメントで勝負するぜと息巻くPLに率いられた、プルリクエストでのレビューという概念が存在しない、駆け出しエンジニアの集団によって作られる。
勘違いしないでほしい。これはお前のイケイケ職場の話をしているのではない。
世間一般に溢れる有象無象のソフトウェア会社の一般的な状況を説明しているだけだ。
決してお前のチャラチャラ職場の話をしていないことを念頭においてくれ。
お前は天才だし最高だ。
その上で。
世間一般の開発に携わっているソフトウェア開発者全員が、プログラミングを好きでやっているわけではないし、小難しいメソトロジーを試すほどの好奇心も根気もない。
業務時間外にプログラミングの勉強をすべきか否かと言う質問がTwitterを賑わすぐらいの世の中だ。
わたしは技術が好きですという風を装っていながら、家では1行もプログラミングをしない輩で溢れている。(これは人生における優先度の問題で、だからと言って悪いわけじゃないよ! でも技術好きってのは嘘じゃない? って話)
そんな状況の中。名前も知らない全世界の会社の99%を占める中小企業のうちの70%ぐらいの企業は、ひとまずプログラミングができはします、みたいな輩を集めて、そのうちの50%ぐらいが失敗して倒産し、残りの45%ぐらいがひとまず動きはしました、みたいなプロダクトを量産する。(やたら混み入った言い方をするのはこの決めつけが決してあなたの職場のことを言っているわけではないという意図だ。つまり、ケムに巻こうとしているのだ)
そういう会社のプロジェクトは、高尚なメソトロジーが適用されるわけもなく、ろくな仕組み化がされないまま残業でカバーする対策が取られがちになる。
ただし。
それ自体に問題はない。
なぜなら上述のようなアプローチをとっても、なんだかんだ見た目上は製品ができるからだ。
想定よりお金がかかったり、バグが大量にあったり、CSSやJavaScriptはぐちゃぐちゃかもしれないが、それでも製品はできる。
そもそもそういう会社は単価が安いので、コストに見合った成果だとすら言える。
問題はそういうアプローチをしているプロジェクトのほとんどに、仕様書が存在していないという点だ。
もしかしたら、要求定義すらない。
客の思いつき、社長の思いつき、PL・POの思いつきは口伝による一子相伝で伝えられ、現場エンジニアがそれを五月雨で実現する。どこにも記録することなく。
何が言いたいかと言うと、なんとかリリースまでこぎつけ、動いているものがあるにはあるが、実のところその要求や仕様がよくわからない、なんてことは世界中で起きているありふれた日常であると言うことだ。
それはリリースして数ヶ月〜数年で必ず起こる。
例えばあるプロダクトがリリースされた2年後。
当時の担当者が全員退職した後、お前がこのプロジェクトの保守を任された。
お前は思う。今あるコードが何を解決しようとしているのか全く分からない。
いつもいつも、Slackに通知される謎のエラー通知に怯え、もし今致命的なバグが発見されたら、どうやって対応すればいいのだろうか。と胃をキリキリさせていた。
そんなある日。
クライアントから1通のメールが来る。
「〇〇がXXになるんですが、どういうことでしょうか??」
お前の感想はこうだ。
え〜っと。〇〇がXXになるのが何がいけないんでしょう???
当然だ。仕様がわからないので、〇〇がどうあるべきかの正解がわからない。
営業からはとにかく何か回答せよとせっつかれる。
資料を探すも、本番環境に入るためのSSH接続の情報しかない。
(注. 本当にやばい会社はこれすらない)
あるのはソースコードだけ。
さあどうする。〇〇は一体何が正解なのだろうか。
そこで万が一。
テストコードがあった場合。
「〇〇が▲▲になることを確認する」とコメントが書かれたテストコードがあった場合。
少なくとも〇〇は▲▲であることが正解、と言う情報が得られる。
この後、顧客に
「〇〇は▲▲であることが仕様の認識ですが、どのようなパターンでXXになるのでしょうか。情報をいただければ幸いです」
と、本当は深く仕様を知らないにも関わらず、ジャブを打って情報を集めることができる。
つまり、テストコードが動く仕様書になるのだ。
もちろん、テストコードがリーダブルでないと意味がない。
しかし、仕様書や設計書と違って、テストコードがCIで回されてさえいれば、高確率でそのテストは陳腐化していない。
情報がソースコードしかない、みたいなXX(ものすごい卑語)なプロジェクトにおいて、テストコードを指針に仕様を読み解いていくことができるのだ。
まとめ
テストを書くことでリファクタを容易にし、担当者の失踪、外注先から納品されたスパゲッティコード(設計書なし)、仕組みや体制を作らないPM、技術力の低いプログラマー、などなどの理由により失われたドメイン知識が後世に残される。
バグ修正も死ぬほど楽できる。
以上の理由から、テストコードを書かない理由が全くない。
特にDjangoはテストフレームワークが死ぬほど優秀なので、テストを書くハードルがさらに下がる。
下記に、ウサギが知りうる限りのテスト手法を「すべて」講座に盛り込んでおいた。
ぜひ繰り返し読むことでマスターし、お前らの現場を少しでもマシなものに変えれるよう、頑張ってくれ。
健闘を祈る。
\ 講座で学んだことを即アウトプットしよう /
テストコードにさらに興味を持ったら
下記の書籍を読むと、より良いテストコードの書き方がわかるはずだ。
試してみてくれ。
コメント