Pocket

判断と処理を分けると、読みやすくなり、テストやデバッグをしやすくなります。

例は javascriptで書いています。

1. 初期バージョン

最初に書くバージョンはだいたいこんな感じです。
「もろもろの処理」は、複数行だったり、if文やfor文を含むことがあります。

function my_func (a) {
    if (a > 10) {
        if (a > 20) {
            if (a > 30){
                もろもろの処理_1
            } else {
                もろもろの処理_2
            }
        } else {
            もろもろの処理_3
        }
    } else {
        もろもろの処理_4
    }
}

2. if文の本体を1行にします。

if文の本体をメソッド化して1行にします。if文の本体を短くしたほうが、ifの流れが読みやすいです。そして、my_func_1からmy_func_4のテストケースを書けるようになります。

function my_func (a) {
    if (a > 10) {
        if (a > 20) {
            if (a > 30){
                my_func_1();
            } else {
                my_func_2();
            }
        } else {
            my_func_3();
        }
    } else {
        my_func_4();
    }
}

function my_func_1() {
    もろもろの処理_1
}

function my_func_2() {
    もろもろの処理_2
}

function my_func_3() {
    もろもろの処理_3
}

function my_func_4() {
    もろもろの処理_4
}

3. 「判断」をメソッド化します。

「判断」をテストするために、メソッド化します。my_func_1からmy_func_4の分岐は、単純なswitch文にします。変数aの値によって、4通りの処理があることが一目瞭然になりました。

function my_func (a) {
    var num = case_number(a);
    switch (num) {
        case 1:
            my_func_1();
            break;
        case 2:
            my_func_2();
            break;
        case 3:
            my_func_3();
            break;
        case 4:
        default:
            my_func_4();
            break;
    }
}

function case_number(a) {
    var num = 0;
    if (a > 10) {
        if (a > 20) {
            if (a > 30){
                num = 1;
            } else {
                num = 2;
            }
        } else {
            num = 3;
        }
    } else {
        num = 4;
    }
    return num;
}

function my_func_1() {
    もろもろの処理_1
}

function my_func_2() {
    もろもろの処理_2
}

function my_func_3() {
    もろもろの処理_3
}

function my_func_4() {
    もろもろの処理_4
}

4. 条件を整理して、if文のネストを浅くします

条件を整理して、デシジョンテーブルを作ります。デシジョンテーブルにしたがって、if文を実装します。コメントにデシジョンテーブルを書いておきます。

/*
| # | a     | action    |
| - | ----- | --------- |
| 4 | <= 10 | my_func_4 |
| 3 | <= 20 | my_func_3 |
| 2 | <= 30 | my_func_2 |
| 1 | > 30  | my_func_1 |
*/
function case_number(a) {
    var num = 0;

    if (a <= 10) {
        num = 4;
    } else if (a <= 20) {
        num = 3;
    } else if (a <= 30) {
        num = 2;
    } else {
        num = 1;
    }

    return num;
}

5. my_funcを別クラスにする

my_func関連のコードが長くなったら、別ファイルの別クラスにします

function my_func (a) {
    (new MyFunc()).main(a);
}
/*
| # | a     | action    |
| - | ----- | --------- |
| 4 | <= 10 | my_func_4 |
| 3 | <= 20 | my_func_3 |
| 2 | <= 30 | my_func_2 |
| 1 | > 30  | my_func_1 |
*/
class MyFunc {
    main(a) {
        var num = case_number(a);
        switch (num) {
            case 1:
                my_func_1();
                break;
            case 2:
                my_func_2();
                break;
            case 3:
                my_func_3();
                break;
            case 4:
            default:
                my_func_4();
                break;
        }
    }

    case_number(a) {
        var num = 0;
        if (a > 10) {
            if (a > 20) {
                if (a > 30){
                    num = 1;
                } else {
                    num = 2;
                }
            } else {
                num = 3;
            }
        } else {
            num = 4;
        }
        return num;
    }

    my_func_1() {
        もろもろの処理_1
    }

    my_func_2() {
        もろもろの処理_2
    }

    my_func_3() {
        もろもろの処理_3
    }

    my_func_4() {
        もろもろの処理_4
    }
}