WEB+DB PRESS Vol.51 特集2「“巧い”メソッド設計」連動企画

第3回 構造化技法でプログラムの品質を上げる 可読性の高いメソッドを書くための実践テクニック

この記事を読むのに必要な時間:およそ 3 分

呼び出し階層を浅く保つ

抽象化の階層は深いほうがよいのでしょうか? それとも浅いほうがよいのでしょうか? 具体例でみてみましょう。

処理A・処理B・処理Cを順番に実行するリスト1リスト2の2つの例を見てください。

リスト1 呼び出し階層が深い

public SomeObject doSomething() {
    [処理A...]
    return doB(a);
}

private SomeObject doB(Object b) {
    [処理B...]
    return doC(b);
}

private SomeObject doC(Object c) {
    [処理C...]
    return obj;
}

リスト2 呼び出し階層が浅い

public SomeObject doSomething() {
    Object a = doA();
    Object b = doB(a);
    return doC(b);
}

private SomeObjectA doA() {
    [処理A...]
    return a;
}

private SomeObjectB doB(SomeObjectA a) {
    [処理B...]
    return b;
}

private SomeObject doC(SomeObjectB b) {
    [処理C...]
    return obj;
}

どちらの構造が保守性が高いでしょうか。たとえば,処理A・処理B・処理Cがそれぞれ,データベースにアクセスする処理だったとします。パフォーマンスや同時実行性の観点から処理の順番を入れ替えることになった場合,呼び出し階層が浅いリスト2のほうが簡単に順番を入れ替えられます。 もし,リスト2のように処理の順番が呼び出し階層で表現されているとの順番の入れ替えが難しくなります。

次に,処理A・処理Bには副作用がなく,処理Cだけ副作用がある場合を考えてみます。具体的には,処理Cはファイルの読み込み処理だったり,ダイアログボックスを表示してユーザ入力を待ったり,といったケースです。

リスト1の形だと,結局doSomething・doB・doCのすべてのメソッドで副作用が発生することになり,たとえばJUnitでのテストが困難,あるいは不可能,というデメリットが発生します。

リスト2の形になっていれば,doA doBメソッドについてはピンポイントでJUnitテストケースを作成できるでしょう。

リファクタリングで「メソッドの抽出」を進めていくと,どうしてもメソッドの呼び出し階層が深くなりがちです。

しかし,上記の例から,メソッドの呼び出し階層を浅く保ち,階層の上下ではなく同じ階層の横の関係で処理の順序を表現したほうが保守性が高くなることがわかります。

メソッドの記述順序について

C言語などの古い言語と違い,Javaではメソッドの記述順序について煩わしい制約がなく,自由な順序で記述できます。

高度なソースコードブラウジング機能を備えたIDEIntegrated Development Environment; 統合開発環境)が簡単に利用できるようになった昨今,メソッドの記述順序が話題に上ることはめったにありません。

どのコーディング規約を見ても「可視性の高い順」「わかりやすい順序」といった大雑把な定義しかなかったり,そもそもメソッドの記述順序にはまったく触れていない,といったものが大多数です。

それでも,これまでに説明した内容を踏まえ,一歩踏み込んで,図4のような一連のメソッドをリスト3のような順序できれいに構造化して記述することを提案してみたいと思います。

図4 メソッドの構造化された配置

図4 メソッドの構造化された配置

リスト3 メソッドの構造化された配置

public class Foo {

    public void method1 {
        [処理1]
    }

    private void method1_1 {
        [処理1.1]
    }

    private void method1_1_1 {
        [処理1.1.1]
    }

    private void method1_1_2 {
        [処理1.1.2]
    }

    private void method1_2 {
        [処理1.2]
    }

    private void method1_2_1 {
        [処理1.2.1]
    }

}

publicメソッドが複数ある場合は,publicメソッドをどう配置するかは2パターンに分かれます。

1つはpublicメソッドを先頭にまとめて配置する方法です。これはpublicメソッドが目次の役割を果たします。

もう1つは,文書と同じく各章の先頭にpublicメソッドを配置する方法です。

これは,プロジェクトのコーディング規約に従ってどちらのパターンを採用するか決めれば良いでしょう。たとえば「メソッドは可視性の高い順に並べる」というコーディング規約があれば,前者しか選択の余地はありません。

おわりに

保守性の高い,すなわち品質の高いプログラムを書くということは,読み手に優しく,読み手の理解を助けるような,きれいに構造化されたプログラムを書くことにほかなりません。

しかし,これが唯一の正しい方法だとは思いません。ここに記載した方法がみなさんにとっての「巧いプログラム」の書き方についての議論の出発点になれば幸いです。

バックナンバー

WEB+DB PRESS Vol.51 特集2「“巧い”メソッド設計」連動企画