※2011.3.30追記
11個目の判断項目を追加しました。
また、「昔はね...」の補足説明を各項目に追加しました。
レガシープログラマ = モダンな言語のおいしい機能をうまく使いこなせていないプログラマ
おいらは時々社内システムのコードレビューなんかをやっているのですが、「なんかちょっと前時代的だな〜」とか「ちょっと修正したらC言語でもコンパイルできそうだな〜」って思うことがよくあります。
おいらがレビューする言語は主にC#です。C#やJavaのような比較的モダンな言語のおいしい機能をうまく使いこなせていないプログラマを、ここでは「レガシープログラマ」と呼ぶことにします*1。
そこで、おいらがこれまでに見てきたコードの中から「これはレガシープログラマっぽい」と思った典型的な症例を10個11個挙げてみます。
レガシープログラマの判断項目
- 使われるローカル変数をすべてメソッドの最初に宣言する。
- ローカル変数の宣言時に空文字("")や新しいオブジェクト(new Xxx())で初期化する。その後にすぐ別の値をセットする。
- メソッドの戻り値がすべて成功・失敗を表す 0 か -1 になっている。
- 複数のデータをまとめて扱う際は毎回配列を使う。配列の上限数はありえなさそうな数を指定する(1000とか)。
- 基本データ型(stringやint)と配列だけでデータ構造を表現しようとする。
- 変数の命名規則にハンガリアン記法*2を使う。
- クラスのフィールド変数をグローバル変数のように利用する。
- 配列やリストを毎回forループで処理する(例: for (int i = 0; i < array.Length; i++))。
- クラスやクラスメンバの可視性を意識していない(privateメソッドがpublicになっている等)。
- 変更履歴をコード中にコメントとして残す (ADDやDELみたいなコメントがたくさん付いている)。
- 変数名やメソッド名を何かと略したがる。
判断項目に従って採点してみる
いかがでしょうか?自分の書いたプログラムを見て採点してみてください。
すべて当てはまるようであれば、あなたは立派な「レガシープログラマ」です。
残念ですがJavaやC#を使えているつもりでも、実はほとんど使いこなせていません。
今すぐ中級者〜上級者向けの本を読んで勉強しましょう。
また、該当項目が少なかったといって安心しないでください。
1つでも該当しているようなら、あなたのどこかにレガシープログラマの血が流れています・・・。
下の解説を読んでこの先自分が書くコードを改善していって下さい。
2015.10.26追記:この記事を書いた頃の自分の職場について
この記事を読むと人によっては「xxxみたいな環境だったら今でもこう書く」とか「こういう制約があったらレガシーとは限らない」みたいな異論が出てくると思います。
もちろんそういった異論が出てくるのは理解できるのですが、この記事を書いた時の職場には特に制約はなく、自由にC#のコードが書ける環境でした。
レガシープログラマの処方箋
1. 使われるローカル変数をすべてメソッドの最初に宣言する。
- 問題点
- 変数の寿命が長くなり、可読性が低下する。
- 改善方法
- 変数は必要になったタイミングで宣言する*3。できるだけ変数の寿命が短くなるようにする。
- 昔はね...
- C言語では変数は関数の最初に宣言しなくてはいけなかった。VBも変数の宣言と代入が同時にできなかったので、最初にまとめて宣言されることが多かった。
2. ローカル変数の宣言時に空文字("")や新しいオブジェクト(new Xxx())で初期化する。その後にすぐ別の値をセットする。
- 問題点
- 無駄なオブジェクトが作成され、メモリを無駄遣いする。そのコードを書いたプログラマはオブジェクト参照の概念を理解できていない可能性が高い。
- 改善方法
- 変数は宣言と同時に必要な値をセットする。オブジェクト参照の概念を理解する。
- 昔はね...
- C言語では変数の初期値が決まっていなかったので、必ず初期化する必要があった。
3. メソッドの戻り値がすべて成功・失敗を表す 0 か -1 になっている。
- 問題点
- 戻り値が無視され、予期せぬ不具合を生む。処理結果が引数やフィールド変数に格納され、可読性が低下する。
- 改善方法
- エラー処理のベストプラクティスを導入する*4。
- 昔はね...
- C言語では例外機構がなかったので、処理の成功と失敗を戻り値で返すことが多かった。
4. 複数のデータをまとめて扱う際は毎回配列を使う。配列の上限数はありえなさそうな数を指定する(1000とか)。
- 問題点
- 上限が決まってしまうためにプログラムの柔軟性がなくなる。
- 改善方法
- Listクラスなど、大きさを動的に変更できるコレクションクラスを利用する。
- 昔はね...
- C言語やVBでは配列の大きさを簡単に変更する方法がなかった。
5. 基本データ型(stringやint)と配列だけでデータ構造を表現しようとする。
- 問題点
- 複雑なデータ構造を表現するのが困難になる。無理矢理表現しようとすると複雑怪奇なデータ構造ができあがる。
- 改善方法
- 注文クラスや社員クラスのようなデータをまとめて保持するクラスを作成する。
- 昔はね...
- この問題についてはC言語でも構造体を使えば同じようなことができたはずだが。。。(構造体がネストしたり、構造体に配列を組み込んだりするとポインタの処理がややこしくなったとか??)
6. 変数の命名規則にハンガリアン記法を使う。
7. クラスのフィールド変数をグローバル変数のように利用する。
- 問題点
- 処理の前後にコンテキスト(前提条件)が発生し、可読性が低下する。また予期せぬ不具合が発生しやすくなる。
- 改善方法
- 必要なデータのやりとりは引数と戻り値だけで完結するようにメソッドを設計する。データの数が多い場合は、データをまとめて保持するクラス*7を作成する。
- 昔はね...
- 項目3で説明した通り、戻り値が成功・失敗を表すことが多かったので、戻り値以外の方法(たとえばグローバル変数)でデータをやりとりしていた。
8. 配列やリストを毎回forループで処理する(例: for (int i = 0; i < array.Length; i++))。
- 問題点
- 終了条件を間違えることによって、予期せぬ不具合が発生する可能性がある。
- 改善方法
- イテレータやforeach文など、ループカウンタを使わない処理方法に変更する(「foreach (string val in array)」等)。
- 昔はね...
- C言語ではループ処理を実現する構文と言えばforループとwhileループぐらいしかなかった。
9. クラスやクラスメンバの可視性を意識していない(privateメソッドがpublicになっている等)。
- 問題点
- カプセル化が不完全になり、コードの変更に弱くなる。また、使われていないクラスメンバを見つけにくくなる。
- 改善方法
- 可視性を正しく設定する。最低でもpublicとprivateの区別はつける。
- 昔はね...
- C言語ではpublicやprivateといった可視性をコントロールする機能がなかった。
10. 変更履歴をコード中にコメントとして残す (ADDやDELみたいなコメントがたくさん付いている)。
- 問題点
- コードがコメントだらけになり、可読性が下がる。
- 改善方法
- 変更履歴をコメントとして残さない。履歴はバージョン管理システムとDiffツールで確認する。
- 昔はね...
- バージョン管理システムが今ほど広く普及しておらず、コード中に変更履歴を残すのが最善とされていた。(個人的な推測)
11. 変数名やメソッド名を何かと略したがる。
- 問題点
- 第三者には理解できない変数名やメソッド名であふれかえり、可読性が下がる。
- 改善方法
- 多少長くなっても第三者が理解しやすい名前をつける。どうしても省略したい場合は開発チーム内でルールを決める。
- 昔はね...
- プログラムサイズをできるだけ小さくする必要があった。言語や環境によっては識別子の長さに制約があった。変数名や関数名を自動補完するIDEやエディタがあまり普及していなかった。プログラムが複数の開発者で共有されることが少なかった。(などと推測)
該当項目がゼロでも安心しない
該当項目がゼロだった人も安心してはいけません。
「10年以上前の技術の成功体験は実はあまり役立っていないどころか、綺麗なプログラムを書く邪魔をしている時すらある。」という意見もあります*8。
JavaやC#もほぼ10年選手です。つまり、JavaやC#の知識が徐々にレガシー化してきている可能性もあるわけです。
たとえば上の改善方法でforループをforeach文に変更する例を挙げましたが、最近のC#だったらLINQで処理する方法もありますし、Rubyならeachメソッドとブロックで処理する方法もあります。
こうした方法は10年前に存在しなかったり、あまり知られていなかったりする方法です。
JavaやC#を使いこなしているプログラマがレガシープログラマを笑っていても、ぼーっとしてたら10年後には自分がレガシープログラマと笑われている可能性もあります。
過去の成功体験に満足せず、これまでの成功体験をぶち壊しながらでも新しい技術を学んでいくのが真のモダンプログラマですよね?
あわせて読みたい
レガシープログラマさんと一緒にリファクタリングをする、の巻 - give IT a try
レガシープログラマさんと一緒に実務で使うコードをリファクタリングしてみました。
Javaプログラマが知るべき9のこと - @katzchang.contexts
視点は若干違いますが、ダメコードを実例とともに紹介してくれています。いくつかの項目は参考にさせてもらっています。
C#プログラマのための理解度チェックリスト - give IT a try
C#らしいプログラムを書くためのチェックリストです。レガシープログラマの判断基準に重なる部分もあります。
CODE COMPLETE 第2版 上 完全なプログラミングを目指して
- 作者: スティーブマコネル,Steve McConnell,クイープ
- 出版社/メーカー: 日経BP社
- 発売日: 2005/03/26
- メディア: 単行本
- 購入: 44人 クリック: 1,166回
- この商品を含むブログ (288件) を見る
*1:最初は「C言語病」って呼んでたんですが、C言語に限定されないネタもあったのでやめました
*2:2010.02.18 追記 ここではシステムハンガリアン記法を指します。二つのハンガリアン記法があるとは知りませんでした。勉強不足でごめんなさい。Wikipediaの解説 http://fwd4.me/vyW
*3:ただし、JavaScriptはブロックスコープを持たないので当てはまらない
*4:長くなるので割愛しますが、C#ならこのサイトが参考になります: http://blogs.msdn.com/b/nakama/archive/2008/12/29/net-part-1.aspx
*5:システムハンガリアン記法の方です
*6:くどいですがシステムハンガリアン記法の方です
*7:Data Transfer Object = DTOクラスと呼ばれることもある
*8:http://forza.cocolog-nifty.com/blog/2011/02/xp2011agileagil.html