別のバッチを参考に処理を書いたら動いた。でもレビューで「失敗したら、どこから再実行される?」と聞かれて答えられない。コピー元にも同じ処理があるから大丈夫だと思っていた。
この記事は、既存コードを参考に改修できるようになったものの、採用理由や失敗時の動きを説明できない人向けです。コピー自体を禁止する話ではありません。コピー元で成立していた前提が、今回も成立するかを確かめます。
全部を読む前に、結果が変わる条件を一つ選ぶ。
入力・失敗・再実行の三つを問い、動く理由を予想してから試します。説明できない条件は、調べる場所か確認相手が分かる問いに変えてください。
一回成功しただけでは分からないことがある
例えば、CSVから請求対象を取り込み、外部サービスへ登録する処理をコピーしたとします。一回の正常終了は確認できても、次のことはまだ分かりません。
- 途中まで登録した後に失敗すると、どこから再開するか。
- 同じファイルをもう一度渡すと、同じ対象を二重に登録しないか。
- 通信がタイムアウトしたとき、相手では登録が終わっている可能性をどう扱うか。
外部サービスへ書き込む処理と、画面の表示データを読み取る処理では、同じリトライの書き方を使ってよいとは限りません。コードの形が似ていても、失敗したときに困ることが違います。
これは説明用の例です。本番へ同じ請求を流して試すのではなく、外部接続を置き換えた検証用の処理で確かめます。
コピー元と今回の条件を、横に並べる
関数の各行を日本語に訳す前に、「何をしてよいコードなのか」を書きます。
| 確認すること | コピー元について調べること | 今回決めること |
|---|---|---|
| 入力の前提 | 重複した対象が来ない保証はどこにあるか | 同じファイルの再投入を許すか |
| 失敗時の扱い | 保存済みと未処理を何で区別するか | 部分的に成功したとき何を残すか |
| 再実行の範囲 | 一件の再試行か、全件のやり直しか | 自動で再実行してよい範囲はどこか |
「コピー元は毎回新規データだけを受け取るが、今回は再投入を許す」と分かれば、そのまま使えない理由を説明できます。文法を何度読み直しても、入力元の契約が分からなければこの違いは見えません。
予想を書いてから、失敗を一つ差し込む
三件のデータを処理する小さな検証を考えます。外部サービスの代わりに、二件目だけ失敗させる受け口を用意します。
実行前に、次のように予想します。
一件目は処理済みとして記録される。二件目で止まり、三件目は未処理になる。再実行では一件目を飛ばし、二件目から進むはず。
次に、実際の記録と呼び出しを確認します。一件目が再び呼ばれたら、想定した重複防止がどこにもないのか、処理済み情報の保存時点が違うのかを追えます。
大切なのは、予想が外れた瞬間に動くよう書き換えないことです。期待する動きが仕様と一致しているかを先に確認します。間違った予想にコードを合わせても、正しい改修にはなりません。
一行ずつの説明より、「この実装を選ぶ理由」を言う
レビューで使える説明は、「for文で回してtryで囲みました」だけでは足りません。
同じ入力が再投入されるため、対象ごとに処理済みかを確認します。ただし、外部で成功してからこちらの記録前に失敗する場合は未解決です。相手側の重複防止キーが利用できるか確認しています。
この説明なら、分かっている範囲と設計上の穴が見えます。「完全に理解しました」と言うより、何が未解決かを示す方がレビューを進められます。
質問も同じです。「この処理が分かりません」ではなく、「相手で登録済みか分からないタイムアウトを、現行処理ではどう扱いますか」と聞けば、調査対象を絞れます。
読むのを止めてよい境界を決める
ライブラリ内部まで毎回理解する必要はありません。今回の担当として、少なくとも次の三点を説明できるかを区切りにします。
- どんな入力を受け、何を変えるか。
- どんな失敗があり、途中まで変わった状態をどう扱うか。
- なぜコピー元の方法を今回も使えると判断したか。
契約や仕様が分からないなら、コードを読む時間を延ばすより、その決定記録や担当者を探します。実装を知っていることと、採用してよいことは別だからです。
次にコードをコピーしたら、成功する入力だけでなく、もう一度同じことをしたらどうなるかを予想してみてください。その一問で、今回引き継いだ前提を具体的に調べ始められます。
