見出し画像

【AI文芸 シリーズ玲奈様のコードレビュー】「フラグの使い方が無駄に複雑 → 余計な変数が多すぎる」

元ネタは情報処理安全確保支援士試験令和2年午後Ⅱ問題1のJavaコードです。
前段、後段もありますが、これだけで十分長いので、この部分だけで載せます。


コードの中で childChecked というフラグが使われているけど、このフラグ、本当に必要? という疑問がある。
今のコードの流れを整理しながら、なぜ不要なのかを詳しく解説する。


問題のコード

public int checkChild() throws NamingException {
    // サイトの識別文字列のチェック
    childChecked = childSite.equals("siteQ") || childSite.equals("siteR");
    if (!childChecked) { 
        return ERROR_SITE_UNAVAILABLE;
    }

    switch (childSite) {
        case "siteQ":
            try {
                // 認証情報チェック
                if (siteQAuth(childID, childPW) == NO_ERROR) {
                    childChecked = true; //認証成功
                } else {
                    childChecked = false; //認証失敗
                }
            } catch (NamingException e) {
                throw e;
            }

            if (!childChecked) {
                return ERROR_ID_OR_PW;
            } else {
                return NO_ERROR;
            }
        case "siteR":
            (省略)
        default:
            (省略)
    }
}

このフラグの問題点

問題点①:初期化時にフラグを設定しているけど、結局上書きしてる

childChecked = childSite.equals("siteQ") || childSite.equals("siteR");
  • ここで childChecked に true を代入してるけど、この値は サイトの識別文字列が正しいかどうかをチェックするだけの値

  • その後、認証の成否でまた childChecked を上書きしてるので、この初期化の意味が薄い


問題点②:認証結果を childChecked に詰め込む意味がない

if (siteQAuth(childID, childPW) == NO_ERROR) {
    childChecked = true; //認証成功
} else {
    childChecked = false; //認証失敗
}
  • 「認証に成功したかどうか」なら siteQAuth() の戻り値をそのまま使えばいい

  • わざわざ childChecked に値を詰め直す必要がない
    → ここの if-else 分岐は 無駄な代入 を生んでいるだけ。

書き換え例(簡潔化)

int authResult = siteQAuth(childID, childPW);
if (authResult != NO_ERROR) {
    return ERROR_ID_OR_PW;
}
return NO_ERROR;
  • 認証成功かどうかは siteQAuth() の戻り値で直接判断できる

  • childChecked を使う必要がない


問題点③:フラグを別の用途で使い回しすぎ

if (!childChecked) {
    return ERROR_ID_OR_PW;
} else {
    return NO_ERROR;
}
  • ここでも childChecked に頼りすぎ

  • 「認証に成功したか?」は siteQAuth() の戻り値で判断するのが正しい方法

  • そもそも、childChecked という変数名も意味があいまいすぎる。

    • 「チェック済み」なのか、「認証成功」なのか、どっちの意味?

    • 名前の意味が曖昧だと、コードを読む側が混乱する。


フラグをなくした修正後のコード

public int checkChild() throws NamingException {
    // サイトの識別文字列のチェック
    if (!isValidSite(childSite)) {
        return ERROR_SITE_UNAVAILABLE;
    }

    switch (childSite) {
        case "siteQ":
            try {
                return (siteQAuth(childID, childPW) == NO_ERROR) ? NO_ERROR : ERROR_ID_OR_PW;
            } catch (NamingException e) {
                throw e;
            }
        case "siteR":
            (省略)
        default:
            return ERROR_SITE_UNAVAILABLE;
    }
}

private boolean isValidSite(String site) {
    return "siteQ".equals(site) || "siteR".equals(site);
}

改善点

childChecked を完全に削除
フラグを使わず、直接 siteQAuth() の戻り値で判断する
サイトの識別文字列のチェックは isValidSite() に切り出し、コードの意図を明確化


「フラグのせいで逆にバグが生まれる」ケース

フラグを多用すると、バグを誘発しやすくなる。例えば、こんなバグが潜む可能性がある。

「フラグを使ったせいで誤判定が起きるケース」

childChecked = false; // 初期化
if (childSite.equals("siteQ") || childSite.equals("siteR")) {
    childChecked = true; // ここで true
}
if (!childChecked) {
    return ERROR_SITE_UNAVAILABLE;
}

// 認証失敗した場合
childChecked = false; // ここで false に戻る
if (!childChecked) {
    return ERROR_ID_OR_PW;
}
  • childChecked の用途が二重になっているせいで、間違った判定が発生する可能性がある。

  • 認証の成否と、サイトの識別の妥当性を同じ変数で管理してしまうと、意図しないバグが起きる。


フラグを無駄に増やすことのデメリット

  1. 何のための変数なのかが分かりにくくなる

    • childChecked は 「認証成功か?」と「サイトの識別文字列が正しいか?」を兼ねている

    • 一つのフラグで複数の状態を表すのは危険

  2. 誤ったフラグの上書きが発生しやすい

    • childChecked = true だったのに、途中で false に上書きされるとバグにつながる。

  3. 不必要な if-else 文が増えてコードが読みにくくなる

    • childChecked を条件にする if-else 文が増えて、無駄な分岐が増える。


結論

☠️ フラグを乱用すると、バグの温床になる

  • 「状態管理」は、可能な限りメソッドの戻り値で表現するのが正しいアプローチ

  • 「認証成功したか?」は boolean ではなく、戻り値(エラーコード)で管理するのがスッキリする

  • フラグを一つに詰め込むと、バグを生むリスクが増大する


玲奈様の最終コメント

「フラグをこうやって使い回すの、クソコードの典型よ。
そもそも、状態管理を boolean フラグでやろうとするのが間違い。
コードの意図を明確にするために、フラグなしで管理する設計を考えなさい。

いいなと思ったら応援しよう!