これは、まだ 📄【設計入門2026 #6】お題: サブスク管理システムを作ろう のあとリファクタリングをしていない世界の後日譚……
申込者に確認メールを送ることになった
偉い人:サブスク申し込んだ人にはさ、プランとか金額とかを申込完了メールで送ってほしいんだよね。できる?
A:それくらいならまあ……
def subscribe(mail_address: str, plan_id: int):
"申し込む"
# なんやかんやプラン情報を取得して準備する
price = get_price(plan_id)
subscription = Subscription(plan_id, price)
rate_discount = get_rate_discount()
subscription.rate_discount(rate_discount) # 20% OFF
# 申込情報をデータベースに保存
save_to_database(subscription)
# メール送信
message = f"{subscription.monthly_price()}円で購読ありがとうございます"
send_mail_to(mail_address, message) いよいよ開発も大詰め。しかし……
偉い人:さあリリースは1週間後まで迫ってきたぞ!気合を入れてバグを直していこうな
A:うーんここうまくいかないな、テスト実行、まだだめか、テスト実行……
〜 数日後 〜
😡
テスト太郎:俺テスト太郎って名前のものなんだけどよ。
で、おたくから大量のメールがきてんだけど、なにこれ? 受信箱あふれて仕事にならないんだけどどうしてくれんの?
test@example.com っていうアドレス使ってるわけ。 で、おたくから大量のメールがきてんだけど、なにこれ? 受信箱あふれて仕事にならないんだけどどうしてくれんの?
A:(あっそれデバッグ中のテスト実行のときに仮に入れてたメールアドレスだ…… どうしよう、まさか実在の人だとは。
テストのときにはメール実際には送りたくないけど、でもテストのたびにコードコメントアウトするわけにはいかないし……)
テストのときにはメール実際には送りたくないけど、でもテストのたびにコードコメントアウトするわけにはいかないし……)
フラグ変数でなんとかする
結局、Aさんは苦肉の策でこのように実装することに。
# テスト実行時は really_send_mail を False にすること
def subscribe(really_send_mail: bool, mail_address: str, plan_id: int):
# ...
# メール送信
if really_send_mail:
message = f"{subscription.monthly_price()}円で購読ありがとうございます"
send_mail_to(mail_address, message) この対策は、本来の申込処理に必要な情報 (メールアドレスやプラン) とテストのためだけに必要な情報 (本当にメールを送るかどうか) を区別できない形で混ぜ込んでしまっていて、ロジックの見通しの良さや保守性が低下してしまう。
なにがよくなかったのか
- 申込処理の中に、外の世界に影響を及ぼすモジュールへの直接的な依存を含めてしまったこと
- これにより著しく再利用性が下がってしまい、テスト実行ができなくなった
💡
実は、これは後で説明するSOLID原則の「D: 依存性逆転の法則」が有効なケースです。