見出し画像

そのフラグ変数、追加するのちょっと待った!

フラグ変数を1つ追加すると、取り得る状態の数は2倍になることを意識してください。

この記事では、プログラミングに関する知識やテクニックを共有しています。

注)この記事で出てくるプログラミング言語は、言語を特定していません。だいたい意味が通じるであろう架空の言語を使用しています。

いま、以下のようなLoaderクラスを考えます。このLoaderクラスは、サーバからデータを取得する機能を持っているとします。

class Loader {
    // ロード中かを表すフラグ
    bool isLoading
    // ロードが完了しているかを表すフラグ
    bool isLoaded

    // ロードを開始するメソッド
    func load() {
        // Something to do.
    }
}

ロード処理の進行状況を知るためにisLoading変数とisLoaded変数を持っています。
もう既にむむっと思う方もいるかもしれません。しかし、世の中にはこのようなプログラムが実在するのです。

さて、このLoaderクラスが取り得る状態の数は、

  1. isLoading=false, isLoaded=false

  2. isLoading=true, isLoaded=false

  3. isLoading=false, isLoaded=true

  4. isLoading=true, isLoaded=true

の4通りがあります(2 × 2 = 4通り)。まだこのくらいなら状態管理できそうですね。

ここで新しい仕様が追加されることになりました。

ロード処理が何らかの原因で失敗してしまうことがありました。そこで、エラー終了したかを知るためにisFailed変数を追加することになりました。

class Loader {
    // ロード中かを表すフラグ
    bool isLoading
    // ロードが正常に完了しているかを表すフラグ
    bool isLoaded
    // ロードがエラー終了したかを表すフラグ
    bool isFailed

    // ロードを開始するメソッド
    func load() {
        // Something to do.
    }
}

このときLoaderクラスが取り得る状態の数は、
2 × 2 × 2 = 8通り
となります。先程の状態数から2倍になってしまいました!

クラスにフラグ変数を1つ追加すると、そのクラスの取り得る状態の数は2倍になることを意識してください。

状態数が増えると、それだけ管理が難しくなっていきます。つまりバグを生みやすくなります。

ここでLoaderクラスが取り得る状態のパターンを見てみます。

  1. isLoading=false, isLoaded=false, isFailed=false

  2. isLoading=true, isLoaded=false, isFailed=false

  3. isLoading=false, isLoaded=true, isFailed=false

  4. isLoading=false, isLoaded=false, isFailed=true

  5. isLoading=true, isLoaded=true, isFailed=false

  6. isLoading=true, isLoaded=false, isFailed=true

  7. isLoading=false, isLoaded=true, isFailed=true

  8. isLoading=true, isLoaded=true, isFailed=true

そもそも上記の5,6,7,8の状態は起こりえないことを開発者は分かっています。
例えば、ロード中(isLoading=true)とロード完了(isLoaded=true)は同時には成り立ちません。正常終了(isLoaded=true)と異常終了(isFailed=true)も同時には成り立ちません。

このように開発者が分かっていても、プログラム上起きる可能性があるとき、意図せずバグを埋め込んでしまうことがあります。
例)フラグのリセットし忘れなど

バグを生まないためにも、できる限り可能性は潰しておきたいところです。

さて、上記のような同時に起こりえない事象を扱うときはenumを使うと便利です。

enum State {
    // 初期状態
    INIT,
    // ロード中
    LOADING,
    // ロードが正常終了した
    LOADED,
    // ロードが異常終了した
    FAILED
}

class Loader {
    // 状態変数
    State state = State.INIT

    // ロードを開始するメソッド
    func load() {
        // Something to do.
    }
}

enum Stateを使うことで、Loaderクラスが取り得る状態数は4通りに限定されます。

フラグ変数を安直に追加する前に、扱う事象を観察し、enumなどでリファクタリングできないか、検討してみてください。


この記事が気に入ったらサポートをしてみませんか?