1. 現象の説明:肥大化したServiceクラスの一例

まずは現場でよく見かける“ロジックが詰まりすぎたServiceクラス”の状態を確認します。

public class UserService {
    private final UserRepository repository;
    public void register(UserDto dto) {
        // バリデーション
        if (dto.getEmail() == null || !dto.getEmail().contains("@")) {
            throw new IllegalArgumentException("invalid email");
        }
        // ユーザー生成
        User user = new User(dto.getName(), dto.getEmail());
        // 重複確認
        if (repository.existsByEmail(user.getEmail())) {
            throw new IllegalStateException("already exists");
        }
        // 保存
        repository.save(user);
        // 通知
        sendWelcomeMail(user);
    }
    private void sendWelcomeMail(User user) {
        // SMTP通信など
    }
}
問題の兆候
  • バリデーション/重複チェック/ドメイン生成/永続化/外部通知が1メソッドに混在
  • Serviceクラスが“実務ロジックの吹き溜まり”となっている

2. 構造を見直すべき判断ポイントとレビュー観点

◼︎ レビューアーが注目すべきチェックリスト

  • 複数の「意味的な処理単位」が1つのメソッド内に混在していないか?
  • 外部リソース(DB、メール、外部API)への依存が、ドメインロジックと分離されているか?
  • 再利用可能な処理や副作用の大きい処理が“直書き”されていないか?
判断基準のイメージ

Serviceクラスは「ユースケースの構成点」。
その中で「処理内容の責務」が混在していたら、分離して再利用可能な部品として扱う方が構造的な見通しが良くなります。

3. リファクタリング提案:構造の分割と整理

構造ごとの役割分担へ分割

public class UserService {
    private final UserRepository repository;
    private final UserFactory userFactory;
    private final EmailValidator emailValidator;
    private final MailNotifier mailNotifier;
    public void register(UserDto dto) {
        emailValidator.check(dto.getEmail());
        User user = userFactory.create(dto);
        if (repository.existsByEmail(user.getEmail())) {
            throw new IllegalStateException("already exists");
        }
        repository.save(user);
        mailNotifier.sendWelcome(user);
    }
}

担当クラス(単一責務)

クラス 責務
EmailValidator メール形式の検証
UserFactory DTO → Entity の変換
MailNotifier 通知処理(副作用の切り離し)

4. 分割の意図とレビューコメント例

実装者に伝えるべきレビューコメント

Comment
`register()`メソッド内に複数の処理が集まっており、少しずつ肥大化傾向が見えます。
- バリデーション
- ドメイン変換
- 重複チェック
- 外部通知
それぞれを部品化して責務を分けることで、構造上の可読性・変更耐性が向上すると思います。
再利用しやすい構造の意味

バリデーションや通知処理などは他ユースケースでも再利用される可能性が高く、共通化しやすい粒度に分けておくことで保守性が大きく向上します。

5. リファクタリング適用後の構造とユースケースの見通し

リファクタリング後は、以下のようにユースケース(register)を構成するServiceが、“役割を割り振った部品”によって形作られている状態になります。

UML Diagram

6. まとめ:レビューアーの設計判断の型として

✔ この記事の要点

  • Serviceクラスが肥大化していたら、「責務単位で処理を切り出す」ことを第一に検討する
  • ユースケース(登録/更新/削除)はServiceクラスが持ち、処理単位ごとの部品に委譲する構造を意識する
  • ValidatorFactoryNotifier のように、名前から目的が明確な粒度でクラスを切り出すと、チーム内でも共有しやすくなる

ベストプラクティスとして明文化

  • Serviceクラスにはユースケースを一段構造化する責務のみを持たせ、処理そのものは外部に委譲する
  • 複雑なロジックを“そのまま直書き”するのではなく、後から切り出せる設計の余白を意識する
  • 再利用しやすい責務を見極め、構造的に部品化を提案するのがレビューアーの重要な役割

レビューとは、「実装されたコードの動作」だけを見るのではなく、コードの進化の方向や拡張への耐性をどう構造化するかを判断する技術的な対話でもあります。

この構造的視点を、次のレビューに持ち込んでみてください。