ドキュメントとコードが違うとき何を信じるか
一言でいうと
顧客企業のコードで最も危険な欠陥は、例外を投げるコードではなく、もっともらしい値を黙って返すコードです。
なぜ必要なのか
壊れるバグは簡単です。トレースバックがどこに問題があるかを教えてくれ、モニタリングがアラートを鳴らし、誰もその結果を信用しません。
怖いのは、200を返すバグです。/sum?a=2&b=3が-1を返すAPIは、ステータスコードが正常なのでダッシュボードでは緑色のままで、ログにもエラーがなく、数か月後に経理担当者が数字が合わないと言い出したときに初めて見つかります。そのころには、誤った値がすでに下流システムの何か所にも複製されています。
FDEが顧客企業から引き継ぐコードは、たいていこのような状態です。もともと作った人は退職し、テストはなく、ドキュメントはあってもコードと食い違っています。
どう動くのか
ドキュメントとコードが食い違うとき、何を信じればよいでしょうか。答えは、どちらも信じず、観測された動作を信じることです。ただし、ドキュメントは捨てません。ドキュメントは「本来の意図」を知る唯一の手がかりであり、コードとドキュメントが食い違う箇所がそのままバグ候補の一覧になるからです。
実務の手順は次のとおりです。
1. 仕様を入出力表に書き写す。ドキュメントに書かれていることを、「この入力ならこの出力」という形で数行にまとめます。ドキュメントになければ顧客に尋ねます。この表がなければ、何がバグなのかを判定する基準がありません。
2. 境界値を入れてみる。0、負数、要素が1つ、空の値、必須パラメーターの欠落です。欠陥の多くは、平均的な入力ではなく境界で表に出ます。avgが要素3つでは合っていて1つでは間違っているなら、割る数を誤って書いています。
3. 失敗の種類を区別する。不正なリクエストに500を返すのと400を返すのは、まったく別の問題です。400は「あなたの送り方が間違っている」、500は「こちらで処理中に壊れた」という意味です。この区別が崩れると、下流のリトライロジックが誤動作します。クライアントは5xxをリトライの対象と見なすため、永遠に失敗するリクエストを無限にリトライしてしまいます。
4. データが関わる箇所を疑う。コードは正しいのに、入力データに壊れた行が1行混ざっているせいで全体が落ちることが非常によくあります。仕様には「有効でない行は読み飛ばす」と書いてあるのに、コードにはその分岐がない、といった具合です。
現場での姿
引き継いだバッチスクリプトが、「データが増えて遅くなったようだ」という顧客の推測とともに届くことがよくあります。開けてみると、遅いのではなくそもそも落ちていて、原因はデータが増えたことではなく、新しく入ったデータに初めて見る形の行が混ざっていたことです。
ここでFDEの判断が分かれます。その行を消して先に進めば、来週同じことが繰り返されます。仕様どおりに読み飛ばすよう直し、読み飛ばした行をログに残すようにすれば、次回は原因が1分で出てきます。
顧客の推測を正面から否定する必要はありません。検証リストに入れて一緒に確認すれば済みます。顧客の仮説を門前払いにすると、次の障害でその人は観察したことを話してくれなくなります。
直したあとにすること
欠陥を見つけて直しただけでは、仕事は終わりません。引き継いだコードでバグを1つ直したということは、同じ種類のバグがほかにもある可能性が高いというサインだからです。もともと作った人が、そのミスを1回しかしなかったとは考えにくいでしょう。
そこで、直した直後に次の3つを実施します。
1. 同じパターンをすべて探す。割る数を誤っている箇所を1つ見つけたなら、同じファイルのほかの集計関数もすべて開いて確認します。例外を握りつぶすexcept: passを1つ見つけたなら、リポジトリ全体でその形を検索します。この作業はたいてい数分で終わり、2つ目、3つ目がほぼ必ず見つかります。
2. そのバグを捕まえるテストを残す。直したコードが正しいことを示すテストではなく、直す前であれば失敗していたテストを残します。この区別が重要です。前者は現在の状態を記録するだけで、後者だけが元に戻ることを防ぎます。テストを先に書き、それが失敗するのを目で確認してから直せば、この区別は自然に守られます。
3. なぜ今まで誰も気づかなかったのかを書き留める。この問いの答えが、次に直すべきものを教えてくれます。ステータスコードが200でダッシュボードが緑色だったなら、それはコードの欠陥ではなく観測の欠陥です。計算結果が間違っていても気づく手段がまったくなかったということであり、それなら値の範囲を検査するアサーションや、下流での照合手順が必要です。
顧客に報告するときにも順序があります。何が間違っていたのか、いつからなのか、影響範囲はどこまでか、何を直したのか、再発しないよう何を入れたのかの順に伝えます。このうち、人々が最も知りたがり、FDEが最もよく書き漏らすのが3つ目です。誤った値がすでにほかのシステムへ流れていたなら、それを元に戻す作業はコードの修正よりはるかに大きく、その判断は顧客が下すべきです。影響範囲がわからなければ、わからないと書いたうえで確認方法を提案するほうが、黙って済ませて後から発見されるよりも常に良い結果になります。
次のラボですること
引き継ぎのないまま受け取った計算APIを相手に、ドキュメントに書かれた仕様と実際の動作を突き合わせて4つの欠陥を見つけて直し、不正なリクエストに正しいステータスコードが返るようにします。