定数定義

プログラムを書くときに、変数とか定数に適切な名前をつけることが良いことであることに異論のある人はあまりいないと思うけど、現実には結構ひどいのとよく遭遇する。

文字そのまま

final static String COMMA = “,”;

記号系に英語名つけて、グローバル定数クラスに定数定義。これよく見るんだけど、なんのためにやっているのか理解に苦しむ。これを書く人の大半は文字列をそのまま使うのはいけない、というルールを何も考えずに適用して責任逃れをしているにすぎないのではないか。「, 」をそのまま書くよりも明らかに長くてコード書きづらいし、名前みても追加情報が得られるわけでもなく、何も嬉しくない。

文字の説明ではなく意味の説明を

カンマとかはよくCSVのセパレータとして定義されているけど、それを定数定義するなら何の文字が入っているかではなく、何のための記号なのかを書くべきではないか。例えばFIELD_SEPARATORとか。java.io.Fileにもいい例があるでしょ、File.separator。(まぁあっちはまたプラットフォームによって値が変わるとかちょっと色合いが違うけど)。

中の文字ではなく何のための識別子なのか定義しておけば、後から仕様変更がきてセパレータがタブになったとしても、FIELD_SEPARATORの定義箇所だけ直せば済む(これが元々文字列を定数定義する意義だろう)。COMMAって名前にしちゃう人は、名前がCOMMAのままで内容がタブだと混乱するので、(中身だけ修正するというのは議論するまでもないので置いておいて)final static String TAB = “\t”;とかにRefactoringで名称変更するのだろうけど、それ自体無駄な作業だし、Refactoringが正しく実施できるのは、修正対象の最新ソースをすべてワークスペースに持っている前提だ。大規模プロジェクトで一部のコンポーネントのみ開発している人は全ソースを手元に持っていなかったりするから、Refactor漏れする可能性もある。Refactoringってみんなが思っているほど当てにならない。

それに、ソースコードのオーナーシップを変な風に適用して、自分の担当分のソース以外はチェックインしない、みたいな人も結構いる(これもひどい責任逃れだよね…)。それじゃあんたがチェックインしたところ以外が軒並みビルドエラーですがな。

定数定義のスコープ

変数とか定数には適用されるコンテキストとスコープがある。本来モジュール間の結合度を下げるためにあっちのクラスからもこっちのクラスからも参照されるものは極力減らすべきだけど、大規模と呼ばれる案件でトラブっているところに支援で入ると確実に遭遇するのが巨大な定数定義クラス。CommonConstとかConstantsとかSharedConstantsとか[プロジェクト名]Constとか。みんなが使いそうな定数を定義してあちらこちらに同じようなものが定義されているのを防いでいるのだろうけど、使い方が正しいかというとたぶん半分くらいは間違ってると思う。

たとえば先のCOMMA。これを全体で使う定数インターフェースに定義したとき、カンマを使う人はこの定数を参照するようにはするだろうけど、果たしてそのときにただの「カンマという文字の別名」として扱うのか、あるいは「外部連携ファイルのファイルセパレーター文字」として使うのか意識しているだろうか?ファイルセパレーターがかわったときにこの定数の値を変更したら、ただのカンマだと思って使っていた人のプログラムは軒並み壊れるよね。

だから定数なり変数なりを定義するときは、その値がどこまで見えていればよいのかをちゃんと考えるべきで、自分が定義したその値は他の人にとって混乱するものではないか、誤解されないか、そもそも他の人に見える必要があるのか、をグローバルなインターフェースに置く前に考えろという話である(そういうコードを平気で書く人たちはモジュールの設計してないだろ絶対、って思うわけで)。

要するに

最初に戻って結論はグローバルの定数クラスにCOMMAとか意味不明な変数・定数を定義するなバカモノ、ってことである。フツーのプログラマだったらそんなことわざわざ書くなよ、って思う訳なんだが、自分が参加するプロジェクトはこんなのばっか。悲しい。

Advertisements