筆者:金田一
10年以上前の話になりますが、お付き合いください。
私が、大阪の事務所に出張していて、夜の10時に仕事を終えホテルに帰ろうとした時に
A君が「先輩助けてください」と泣きそうな顔で言ってきました。事情を聴くと...
・ 実績あるプログラムでお客さんの都合で仕様を変更したところバグが発生した
・ バグというのはプログラムのデータが破壊される
・ あるアクションをすると必ず現象が発生する
というものでした。A君が泣きそうだったのは、明日お客さんに納品するのに、バグの原因が分からないからなようです。プログラムはVCで開発したアプリケーションでした。あるアクションをすると現象が必ず発生するということで、私は「1時間半で原因を突き止めてやる」と宣言しました。
まずは、きっかけのアクションをしてもらい、現象を確認することから始めます。A君には、そのアクションとデータ破壊される領域との関係を聞きました。私が、VCを使ってソースデバッグしている間、A君は一生懸命プログラムのソースを調査していました。
私は、「いまさらソースを見ても、思い込みがあるから無駄」「こういう場合は、現象を把握することが問題解決への近道」と言いました。
データ破壊される領域を特定し、VCのハードブレーク機能を使い、破壊するタイミングを特定しました。破壊していたのは関数memcpyでした。関数memcpyを抜けた(関数memcpyを呼び出した)個所のソースを見て、A君は「あっ!」と大きな声で言いました。
聞くと、仕様の変更というのは、それまで512バイトであった領域を256バイトに変更するというものでした。先ほどのソースは、その領域を別の領域にまさにコピーする個所でした。なぜそのような事が起きたかを調べると、512バイトの領域を管理する構造体があり、その領域として
char area[512];
と記述されていました。
私はそれを見た時に、A君のお尻をキックしていました。「これはプロが作るプログラムではない!」
私は、A君にいろいろ説教しましたが「今回の君のいいところは、恥を忍んで先輩に素直に頼ったところだ」と慰めました。
ソースを修正し現象が発生しない事を確認すると共に、同じような個所がないかを確認させました。それが終わり、事務所を出たのが1時半でした(ちょいと宣言時間をオーバーしました)。
プログラムのソースに含まれる(仕様が分からない人に)意味不明な数値を“マジックナンバー”といいます。マジックナンバーを使うと、仕様が変わった場合の手間が多くかかってしまいます。
マジックナンバーにしないように、数値はdefineで定義するようにしましょう。