開発現場でこんなやり取り、一度は経験したことがありませんか?
先輩: 「あ、この処理ちょっとイマイチだから修正しておいて〜」
自分: 「わかりました!(良し、サクッと直して成果を見せるぞ!)」
……知識や経験が浅い時期、悲劇は静かに訪れます。
軽い気持ちで修正したコードが、思わぬ「副作用」を引き起こし、他の画面を破壊したりパフォーマンスを悪化させたり……。
今回は、私が過去にやらかした「修正依頼の言葉足らず」から発生した悲劇と、そこから学んだコードの影響範囲(副作用)およびコミュニケーションの捉え方についての考察をまとめます。
事故現場1:共通メソッドを直したら、他の画面が巻き添えで崩壊した
状況
Javaで記述されたバックエンド処理で、「入力値のフォーマットを整える処理」を修正するよう指示を受けました。
// 修正前の共通ユーティリティメソッド
public class StringUtil {
public static String formatCode(String input) {
if (input == null) return "";
return input.trim();
}
}
指示は**「コードの頭振りにゼロ埋め(Padding)をしてほしい」**というもの。「よし、このユーティリティメソッドを直せば一発だな!」と思い、以下のように修正しました。
// 軽い気持ちで修正したコード
public class StringUtil {
public static String formatCode(String input) {
if (input == null) return "";
// 8桁にゼロ埋めする処理を追加
return String.format("%8s", input.trim()).replace(' ', '0');
}
}
発生した悲劇
自分の担当画面ではバッチリ動くことを確認し、PR(プルリクエスト)をマージ。
しかし翌日、全く関係のない「商品検索画面」と「ユーザー設定画面」でエラーが多発していると連絡が届きます。
実はこの formatCode、システム全体で100箇所以上から呼び出されている共通メソッドだったのです。他画面では「ゼロ埋めされていない生のコード」を前提としたロジックが組まれており、全滅しました。
考察と反省
- 「共通処理」は牙をむく: 共通化されているコードを変更する際は、単体テストを通すだけでなく「影響範囲(どこから呼ばれているか)」の検索が必須。
- 安易な共通メソッドの改修より、個別ロジック化・別メソッド化: 「直しておいて」の真意は、「その画面で必要な処理を行って」であって「共通処理そのものを書き換えて」ではなかった。
事故現場2:SQLのパフォーマンス改善のつもりが、更新処理を殺した
状況
「この検索画面、表示が遅いからSQLのパフォーマンス改善しておいて」と言われ、実行計画(EXPLAIN)を確認。テーブルスキャンが発生していたため、インデックス(Index)を追加することにしました。
-- 検索速度向上のために複合インデックスを追加
CREATE INDEX idx_orders_status_date ON orders (status, created_at);
「よし、インデックス貼ったら検索が爆速になった!解決!」と達成感に浸っていました。
発生した悲劇
検索は速くなったものの、別機能である**「夜間注文データの一括インポート(INSERT/UPDATE)」が通常の3倍以上の時間を要するようになり、タイムアウトで落ちる**という事態が発生。
考察と反省
- トレードオフの意識不足: インデックスは「READ(検索)」を速くする反面、「WRITE(挿入・更新・削除)」のたびにインデックスの再構築が発生するため、書き込みコストが増加する。
- 単一の指標にとらわれる恐怖: 「検索を速くする」という目的に集中するあまり、データベース全体への副作用(書き込み性能の低下)に目が向いていなかった。
なぜこの悲劇は繰り返されるのか?(全体の考察)
今回の失敗を通じて、「言葉足らずな指示」と「それを受け取る自分」の間に存在する 2つの課題 に気づきました。
1. コミュニケーションにおける「文脈の非対称性」
指示を出す側(先輩・リーダー)は、頭の中にシステム全体の構造や背景文脈を持っています。そのため、「ここ直しといて」という短文の中に以下のような暗黙の前提が含まれています。
- (他の機能に影響を与えない形で) ここ直しといて
- (全体的なパフォーマンスのバランスを考慮して) ここ直しといて
一方、受ける側(特に経験の浅い段階)は指示された言葉通りの「点」でタスクを捉えてしまいがちです。言葉の行間にある「前提」をすり合わせないまま手を動かすと、事故に繋がります。
2. 「コードの影響範囲(副作用)」に対する解像度
プログラミングを始めたばかりの頃は、「動くコードを書くこと」に全神経を注ぎます。
しかし実務で求められるのは、「その1行を変えたとき、どこに波及するか」を予測する力です。
【視点の変化】
初心者:自分が書いたコードが期待通りに動くか?
中級者:自分が書いたコードが「他の既存コード」を壊していないか?
この失敗から得た「明日から使えるアクションプラン」
同じ悲劇を繰り返さないために、私は以下のルールを自分に課すようにしました。
-
修正前に「影響範囲」をGrep(全検索)する
- 共通クラスや共通メソッドを触る際は、呼び出し元(呼び出し階層)を必ず確認する。
- 影響範囲が大きい場合は、既存メソッドを修正するのではなく、新しくメソッドを生やす(または呼び出し側で処理する)ことを検討する。
-
「〇〇というやり方で修正します」と宣言してから手を動かす
- 「ここ直しといて」と言われたら、実装に入る前に「影響範囲を踏まえてA案で直そうと思いますがよろしいですか?」と一言チャットを入れる。これだけで手戻りは9割防げる。
-
トレードオフを意識する
- 特にSQLやメモリ空間、非同期処理などを扱う際は、「何かを良くすると、別の何かが犠牲にならないか?」を一度立ち止まって考える。
おわりに
「ここ修正しておいて」という短い言葉の裏には、実は数多くの罠が潜んでいます。
言葉足らずな指示を責めるのは簡単ですが、「影響範囲を察知し、確認を取れるエンジニア」へ成長するための良い経験だったと今では感じています。
皆さんも「軽い修正のはずが事故になった」思い出があれば、ぜひコメントで教えてください!