メソッド設計
12-4

1つのメソッドに2つの意味を持たせない

「正常なら計算結果、異常なら -1」のように、戻り値に本来の意味とエラー通知の二役を背負わせると、呼び出し側全員にチェックの義務が生まれる。チェックを1か所でも忘れれば、エラー値がただの数値として下流の計算に混ざり込む。エラーは戻り値で表現せず、例外として早く・大きく失敗させる。

家事按分の計算がエラー値 -1 を返す

Bad

按分率が不正なとき -1 を返す設計。チェックを忘れた呼び出し側で、-1 円がそのまま経費合計に混ざる

戻り値が「経費額」と「エラー通知」の二役
def business_portion(expense: int, ratio: float) -> int:
    """家賃などを家事按分して事業分の経費を返す"""
    if ratio < 0 or 1 < ratio:
        return -1  # エラー値。呼び出し側がチェックする約束
    return int(expense * ratio)


total = 0
for expense, ratio in monthly_expenses:
    total += business_portion(expense, ratio)  # チェック忘れ。-1 が混入
Good

按分率を不変の値オブジェクトにして、不正値は生成時に例外で遮断。計算メソッドの戻り値は常に「事業分の経費額」1つの意味だけ

不正値は例外で遮断し、戻り値の意味を1つに保つ
@dataclass(frozen=True)
class ApportionRatio:
    """家事按分率(0〜1)"""
    value: float

    def __post_init__(self) -> None:
        if not 0 <= self.value <= 1:
            raise ValueError("按分率は 0〜1 で指定してください")


def business_portion(expense: int, ratio: ApportionRatio) -> int:
    return int(expense * ratio.value)


total = sum(
    business_portion(expense, ratio)
    for expense, ratio in monthly_expenses
)  # ここに届く ratio は必ず正当。チェック義務が消える

C 言語由来の「エラーコードを返す」習慣の名残がこのアンチパターンを生む。Python なら例外、もしくは「失敗があり得る」と型で示したいなら Result 風に成功・失敗を別の型で返す設計もある。いずれにせよ1つの戻り値に2つの意味を重ねないことが軸。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第12章。コード例は原則を自分の題材で表現し直したオリジナル。
12-4

1つのメソッドに2つの意味を持たせない

「正常なら計算結果、異常なら -1」のように、戻り値に本来の意味とエラー通知の二役を背負わせると、呼び出し側全員にチェックの義務が生まれる。チェックを1か所でも忘れれば、エラー値がただの数値として下流の計算に混ざり込む。エラーは戻り値で表現せず、例外として早く・大きく失敗させる。

家事按分の計算がエラー値 -1 を返す

Bad

按分率が不正なとき -1 を返す設計。チェックを忘れた呼び出し側で、-1 円がそのまま経費合計に混ざる

戻り値が「経費額」と「エラー通知」の二役
def business_portion(expense: int, ratio: float) -> int:
    """家賃などを家事按分して事業分の経費を返す"""
    if ratio < 0 or 1 < ratio:
        return -1  # エラー値。呼び出し側がチェックする約束
    return int(expense * ratio)


total = 0
for expense, ratio in monthly_expenses:
    total += business_portion(expense, ratio)  # チェック忘れ。-1 が混入
Good

按分率を不変の値オブジェクトにして、不正値は生成時に例外で遮断。計算メソッドの戻り値は常に「事業分の経費額」1つの意味だけ

不正値は例外で遮断し、戻り値の意味を1つに保つ
@dataclass(frozen=True)
class ApportionRatio:
    """家事按分率(0〜1)"""
    value: float

    def __post_init__(self) -> None:
        if not 0 <= self.value <= 1:
            raise ValueError("按分率は 0〜1 で指定してください")


def business_portion(expense: int, ratio: ApportionRatio) -> int:
    return int(expense * ratio.value)


total = sum(
    business_portion(expense, ratio)
    for expense, ratio in monthly_expenses
)  # ここに届く ratio は必ず正当。チェック義務が消える

C 言語由来の「エラーコードを返す」習慣の名残がこのアンチパターンを生む。Python なら例外、もしくは「失敗があり得る」と型で示したいなら Result 風に成功・失敗を別の型で返す設計もある。いずれにせよ1つの戻り値に2つの意味を重ねないことが軸。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第12章。コード例は原則を自分の題材で表現し直したオリジナル。