5-6
マジックナンバーを定数に
ロジックの中に直書きされた数値は、書いた本人にしか意味が分からず、同じ数値があちこちに複製される。仕様変更のとき grep で全部を探し当てる賭けになる。意図を表す名前を付けた定数として1か所で宣言する。
報酬の源泉徴収計算
✕ Bad
def withholding_tax(fee: int) -> int:
if fee <= 1_000_000:
return int(fee * 0.1021)
return int(1_000_000 * 0.1021 + (fee - 1_000_000) * 0.2042)
def net_payment(fee: int) -> int:
# 同じ 0.1021 がここにも。税率改定で片方だけ直すと事故る
return fee - int(fee * 0.1021)✓ Good
from dataclasses import dataclass
from decimal import Decimal
WITHHOLDING_RATE = Decimal("0.1021") # 源泉徴収税率(100万円以下)
WITHHOLDING_RATE_OVER = Decimal("0.2042") # 100万円超過分の税率
HIGH_RATE_THRESHOLD = 1_000_000
@dataclass(frozen=True)
class ProfessionalFee:
amount: int
def withholding_tax(self) -> int:
base = min(self.amount, HIGH_RATE_THRESHOLD)
over = max(self.amount - HIGH_RATE_THRESHOLD, 0)
return int(base * WITHHOLDING_RATE + over * WITHHOLDING_RATE_OVER)
def net_payment(self) -> int:
return self.amount - self.withholding_tax()定数化はゴールではなく入口。その定数を使う計算ロジックごと値オブジェクトに寄せると、税率改定が定数1行の修正で完結する。定数だけ共通モジュールに置いてロジックを散らかすと、低凝集に逆戻りする。