🚀 ニフティ’s Notion

【オブジェクト指向2024 #8】お題: 契約者にメールを送ろう

これは、まだ 📄 【オブジェクト指向2024 #4】お題: サブスク管理システムを作ろう のあとリファクタリングをしていない世界の後日譚…

申込者に確認メールを送ることになった

偉い人: サブスク申し込んだ人にはさ、プランとか金額とかを申込完了メールで送ってほしいんだよね。できる?
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)

この対策は、本来の申込処理に必要な情報 (メールアドレスやプラン) とテストのためだけに必要な情報 (本当にメールを送るかどうか) を区別できない形で混ぜ込んでしまっていて、ロジックの見通しの良さや保守性が低下してしまう。

なにがよくなかったのか

  1. 申込処理の中に、外の世界に影響を及ぼすモジュールへの直接的な依存を含めてしまったこと。
    • これにより著しく再利用性が下がってしまい、テスト実行ができなくなった。
Icon
実は、これは後で説明するSOLID原則の「D: 依存性逆転の法則」が有効なケースです。

どうすればよかったのか

→ メール送信機能を状況によって 外からつけ外しできるように する。


次: 📄 【オブジェクト指向2024 #9】インターフェース