新卒で入社した企業では20年物のソースコードが現役で動いていたりしました。しかも協力会社に丸投げした部分やインドにオフショアした部分などが入り混じってカオスとなっていました。エンジニアも玉石混在で、カオスに練度の低いエンジニアが保守拡張したりしてカオスがさらにカオスに。そんなソースコードには発狂しそうになるレガシーコード(一部ではウンコードと呼ぶ人もいる)が豊富に眠っていました。今回はレガシーコードの反面教師としてその具体例を挙げてみます。
レガシーコードの具体例
意図が分からない
if ( path != null ) { str = Path.Combine(path, fileName); } else { str = path + fileName; }
たぶんpathがnullでPath.Combineでクラッシュする不具合があったんでしょうね。それを修正した結果が上のコードになったのでしょう。pathがnullのときクラッシュすることはこれで回避できた(できてるこれ?)かもしれませんが、nullのときstrは本当に問題ないんですかね…。この不具合修正で新たな不具合を作っていそうです。
無駄なファイル生成
File.Copy("A.txt", "./Files/B.txt"); ... File.Delete("./Files/B.txt"); File.Copy("C.txt", "./Files/B.txt");
A.txtをB.txtにコピーしていたのですが、A.txtもB.txtも一切操作せずにB.txtを削除する処理が実行されていました。何のためにコピーしたのか意図が分かりません。意図が分からないので削除して良いのか判断するのが難しいです。
謎のコメントと気遣い
if(...) { // ここが実行されることはないが、一応残しておく ... }
消してください。古いソースコードはGitやSVNなどのバージョンコントロールツールがない時代から作られているので、コメントアウトでソースコードの変化を記述して残そうとしている場合があります。Visual Studioを画面一杯に表示して縦に100行くらいは表示できるのに、コメントアウトでプログラムが数行しか表示できないなんてケースも遭遇したことがあります。
コメントアウト失敗
if(False) // NotImportantMethod(); VeryImportantMethod();
if文の中身をコメントアウトしたつもりが、{}を省略していたため次のステップが実行されなくなってしまった例です。不具合を追っていたらここにたどり着きました。このような不具合を引き起こす可能性があるので、Microsoftのコーディング規約では{}の省略を禁止しています。
レガシーコードの特徴
意図が分からない
レガシーコードって遭遇してみないと分からないのですが、本当に酷いケースだと意図が分からないコードがたくさんになってきます。依存関係や変数の持ち方、DBのテーブル設計による機能拡張コストの増大なんていうのはまだかわいいレベルです。本物のレガシーコードは意図が分からないので、機能拡張しようにもどの変数が何を現わしていて、何を変更して良くだ何を変更したらダメなのか分からないのです。
可読性が極めて悪い
新卒で入社した企業のソースコードには1万行のメソッドがありました。他にも、
- メソッドの引数が30個弱
- プロパティのgetterが数百行
などありました。本当に読むのが大変です。
変数名やメソッド名が嘘
レガシーコードでは変数名やメソッド名は信用してはいけません。意味が真逆になってしまっていたり、哲学的な意味を内包した名前になってしまっていることがあります。また、メソッド名以外の機能を有しているメソッドばかりなので、名前だけで利用を決めてはいけません。
var firstValue = 1; var secoundValue = 4; int result; if (Add(firstValue, secoundValue, out result)) { MethodA(result); } else { MethodB(result); }
Addという名前のメソッドですが、bool型の返り値があるようです。この返り値は何なのでしょうか?Addの成功可否でしょうか?それにしては分岐後の処理に違和感があります。もはやメソッド名では振る舞いが想像できません。
- 作者: マイケル・C・フェザーズ
- 出版社/メーカー: 翔泳社
- 発売日: 2016/01/15
- メディア: Kindle版
- この商品を含むブログ (3件) を見る