9-5
不正値はコンストラクタで遮断する
不正な値の混入をどこでも防げる唯一の関門が、インスタンス生成の瞬間。生成時にガードしておけば「存在するインスタンスはすべて正しい」と信頼でき、利用側のチェックが不要になる。逆に素通しのクラスは、不正値が帳簿の奥まで運ばれてから発覚する。
仕訳金額の検証をどこでやるか
✕ Bad
class JournalEntry:
def __init__(self) -> None:
self.debit_account = ""
self.credit_account = ""
self.amount = 0
entry = JournalEntry()
entry.amount = -3_000 # 負の仕訳金額が誰にも止められない
entry.debit_account = "旅費交通費"
# 発覚するのは月次決算で貸借が合わなくなったとき。原因の特定は困難✓ Good
from dataclasses import dataclass
@dataclass(frozen=True)
class JournalEntry:
debit_account: str
credit_account: str
amount: int
def __post_init__(self) -> None:
if not self.debit_account or not self.credit_account:
raise ValueError("勘定科目は必須")
if self.amount <= 0:
raise ValueError(f"仕訳金額は正の値であること: {self.amount}")
entry = JournalEntry("旅費交通費", "現金", 3_000)
# 不正な金額はこの時点で ValueError になり、混入経路が即座に特定できるfrozen=True と組み合わせれば「正しく生まれ、その後変わらない」インスタンスになる。なお Python では object.__setattr__ や __new__ を使えば frozen もガードも貫通できてしまうが、これは検証を無効化するメタプログラミングであり、型と契約の信頼性を根こそぎ壊す。テストの特殊なセットアップ以外で使わないこと。