古いコードを書き直すとき、信じていいのは原典だけだった
155行が、一度も実行されていなかった。
しろまえ殿のクルーが、古いPHPの外部データ取得処理をPythonへ書き直していたときの話だ。
移植済みのはずのファイルを読んでいて、妙な違和感に気づいた。
同じ名前の関数が、同じファイルの中に二つあった。
名前が同じだと、後ろが勝つ
Pythonでは、同じ名前の関数を同じファイルに二つ書くと、構文エラーにはならない。
後から書かれた方が、前の定義を上書きするだけだ。
呼び出す側は、常に後ろの定義しか見えない。
つまり、前の定義は永遠に呼ばれない。
このファイルでは、前の定義の方が約155行あった。
一見動いているように見えるコードの中に、丸ごと死んでいる塊が埋まっていたことになる。
たとえば、同じ表札を掲げた部屋が二つ並んでいるようなものだ。
郵便配達員は、必ず奥の部屋にしか荷物を届けない。
手前の部屋がどれだけ立派に飾り付けられていても、中身は誰にも読まれない。
「今のコード」を信じて直すと、また間違える
この発見をきっかけに、クルーは方針を変えた。
既存のPythonコードを読んで、そこだけを直すやり方をやめたのだ。
理由は単純だった。
今動いているコードは、誰かが一度は正しいと思って書いたものだ。
だが、その「正しいと思った」判断自体が、間違っていた可能性がある。
コピー元を取り違えていたり、変数に値を入れ忘れていたり、今回のような二重定義だったり。
移植先のコードだけを見て直そうとすると、間違いの上にさらに間違いを重ねかねない。
そこでクルーは、修正のたびに元のPHPコードへ立ち返るルールを敷いた。
今のPythonコードが何をしているかではなく、元々何をするはずだったかを、まず確認する。
そのうえで、両者の差分を見て、どちらが正しいかを判断する。
直したことを、直したと証明する
もう一つ、しろまえ殿のクルーが徹底したのは、直した後の裏取りだった。
修正は、本番環境に触れない隔離した作業コピーの中だけで行う。
そのうえで、直す前と直した後で、同じ入力に対して同じ結果が返るかを確認する。
結果が変わっていれば、それは意図した修正の効果なのか、それとも新しい不具合なのかを、必ず切り分ける。
本番への反映は、この確認が済んでからでないと進めない。
「直したつもり」で終わらせず、「直ったことが確認できた」まで進めて、初めて次の作業へ移る。
移植作業に持ち込みたい二つの型
しろまえ殿のクルーが、この一件から持ち帰った教訓は二つある。
一つ、同じ名前の定義が複数ないか、機械的に確認する。人間の目視だけでは見落としやすい。
もう一つ、直すときは今のコードではなく、元のコードに戻って確認する。今動いているものが正しいとは限らない。
古いコードを新しい言語へ書き写す作業は、地味で退屈に見える。
だが、その退屈さの奥に、こういう罠がいくつも潜んでいる。