保守の観点から見るオブジェクト指向レベルの量り方

保守業務をしていると、十人十色のソースコード・コメントと出逢う。

最近、実装者がどの程度オブジェクト指向を意識しているかは、その人のコード・コメントを少し見るだけで、ある程度わかるようになってきた。

以下、独断と偏見で個人的にオブジェクト指向レベルが推し量れる「短いコード・コメント」の例を挙げてみる。

(勿論、コーディング規約で規定されている場合は除きますし、あくまで独断と偏見です)

1. 参照

Bean bean = dao.getBean();
List list = bean.getHogeList();
list.add("aaa");
list.add("bbb");
// (略)
bean.setHogeList(list);

最後の一行は必要ない。

Bean#getHogeListから変更可能なListオブジェクトが返される事、Bean#setHogeListが定義されている事から

Bean#getHogeListはBean自身のlistオブジェクトを返すただのゲッタだという事がわかる。

Bean#getHogeListからListオブジェクトの参照を取得しているので、その後のListオブジェクトへのList#addによる変更は

Bean#setHogeListを呼び出さずともbeanオブジェクトのプロパティに反映されている。

Javaのオブジェクト参照を意識せずにコーディングされた事が推測できる。

保守対象の機能にこのようなコードである場合、冗長なコードが多いと予測できる為、

修正範囲を見誤らないためにコードリーディングの時間を多めに取るようにしている。

(Bean#getHogeListが上記の予測とは違う動作をしている可能性もあるが、その場合、メソッド名は変えた方がベター。また、上記コードの実装者もその旨 をコメントした方が、保守しやすいコードになる。)

2. メソッドのコメント

public class Dao {
    /**
    * Beanのリストを取得する。
    *
    * @param 検索条件
    * @return 結果
    */
    public List find(Bean bean){
    // (略)
    }
}

「取得する」という言葉は、Daoオブジェクトの視点では無く、

Dao#findを呼び出すクライアントオブジェクト視点のメソッドの概要レベルの言葉。

「クラスを提供する側」・「クラスを利用する側」というオブジェクト指向の基本概念を取らずにこのクラスを定義した事が推測できる。

この場合、「return」の直訳である「返す」・「戻す」とコメントするのが妥当かと。

このケースだと、オブジェクト指向の基本である「責務の分離」がなされていない場合が多いので、

対象機能の影響範囲をしっかり理解してから実際の修正業務に取り掛かる事にしている。

(もちろん、paramとreturnのコメントも、もう少し分かりやすく記述した方が保守作業者に良心的)

3. クラスの定義&コメント

/**
* AAAA : 検索処理
* @author xxxxx
*/
public class AAAAFindLogic{
    public void execute(Bean bean){
    // (略)
    }
}
/**
* AAAA : 登録処理
* @author xxxxx
*/
public class AAAAEntryLogic{
    public void execute(Bean bean){
    // (略)
    }
}

まず、「処理」という言葉からJavaの「クラス」を「プロシージャ」と同類と考えている点が推測できる。

そして、関連があるであろうクラス郡に共通のメソッドシグネチャが定義されているのにも関わらず

継承等のクラスの関係を実装してない事から、リファクタリングをしていない事が推測できる。

同じようなコードが複数クラスで書かれている可能性が高い。

この場合、修正内容にもよるが、AAAA機能全般に及ぶ修正の場合、AAAA機能に関する全クラスに対して

同じような修正を行い、同じようなテストを繰り返し実施し、かつ悪影響が無い事をテストしなければならない。

修正工数を多めに見積もった方が吉。

(このようなクラスが定義されているパッケージは、似たようなクラス名ばかりで保守しづらい。BisinessDelegate一つあれば随分違うのだけれど・・・)

4. 定数クラス(&パッケージ)

package main.java.co.jp.util;
public class Constants{
    public static final String code1 = "AA0000";
    public static final String code2 = "AA0001";
    public static final String code2 = "AA0002";
    public static final String code2 = "AA0003";
    // (略)
}

(個人的に)よく見かける定数クラスだが、この定数自体に修正が加わる場合、少し注意が必要。

まず、utilパッケージに定義されているという事は、この定数が機能別で必要とされている訳では無く、

グローバルな領域で等しく使われている定数であるという事。

どのクラスがどの定数を利用しているか把握してから、テストスケジュールを組まないと、

予想外のクラスに編集が及び、泥沼化する可能性が高い。

また、オブジェクトの振る舞いを左右する定数である場合、各所に同じようなif文が記述され、

テスト対象のクラスが予想以上に多い事がある。

そして一番やっかいなのが、Stringであるが為に、Stringを結合して定数を作成している可能性が少なからずあるという事。

この場合、IDEの検索でも該当箇所を見つける事が難しく、影響範囲の把握に相応の時間が必要。

定数自体に修正がかかる事は稀だが、もしそのような修正業務を行なう場合、細心の注意を払うべき。

まとめ

自分の出逢ったコード・コメントの良い所を自分のコード・コメントに取り入れ、悪い所を反面教師とし、

自分の書くコード・コメントの質を向上できる事は、保守作業者の特権だと思う。

けど、自分のレベルが上がれば上がるほど、「ここらへん全部リファクタリングしてえええええええ」となる事も多くなり、物凄くストレスが溜まったりもする。

自分が開発チームをサポートした時、今までの保守業務で学んだコード・コメントの記述方法を出し切ったつもり。

けど、実際保守しやすいかどうかは、自分のコードを修正する作業にあたった人に聞くしかないのかもしれない。

(そういえば、あの開発チームのプロジェクトはいつになったら終わるんだろう・・・)

このエントリーをはてなブックマークに追加
comments powered by Disqus