Service Layer를 도입해야 하는 시점 — Controller 비대화와 로직 재사용을 막는 기준

조회수 35

Service Layer는 “있으면 좋아 보이는 계층”이 아니라, 코드가 무너지기 시작할 때 필요한 안전장치다.
Controller에 로직이 쌓이기 시작하면 기능 추가 속도는 잠깐 빨라지지만, 수정 비용이 급격히 증가한다.

Service Layer를 도입해야 하는 시점은 명확한 신호가 있다.
아래 항목 중 여러 개가 동시에 보이면, 이미 도입 시점을 지나쳤다고 보는 편이 맞다.

1. Controller가 비대해지는 순간

Controller에서 조건 분기, 예외 처리, 상태 변경 로직이 길어지면 Service가 필요하다.
Controller는 요청 수집·검증·응답만 담당하고, 업무 규칙은 Service로 내려야 한다.

다음 같은 형태가 늘어나면 Controller는 더 이상 “입구” 역할을 하지 못한다.


public function pay()
{
    // 입력 검증
    // 회원 상태 확인
    // 쿠폰 적용 여부 판단
    // 결제 요청
    // 결제 성공/실패 분기
    // 정산 데이터 생성
    // 알림 발송
}

이런 흐름은 Controller에 있으면 테스트도 어렵고 수정 범위도 예측이 안 된다.
한 번 꼬이면 “어디서 무슨 일이 일어나는지” 파악부터 시간이 든다.

2. 같은 로직이 여러 Controller에서 반복될 때

결제 검증, 권한 체크, 포인트 차감 같은 로직이 여러 엔드포인트에서 반복되면
중복은 곧 불일치로 이어진다.

한 곳만 수정하고 다른 곳을 누락하면, 서비스 정책이 엔드포인트마다 달라지는 문제가 발생한다.
Service Layer는 로직을 중앙 집중화해 이런 불일치를 막는다.

3. 트랜잭션이 필요한 작업이 생겼을 때

한 요청에서 여러 테이블을 동시에 변경하면 트랜잭션이 필요하다.
이 시점부터는 Controller에 로직을 두는 것이 위험해진다.

Controller에서 트랜잭션을 열고 닫기 시작하면 예외 처리 누락이 생기기 쉽다.
트랜잭션 경계를 Service로 묶고, 예외 발생 시 롤백을 일관되게 처리하는 것이 안정적이다.


$pdo->beginTransaction();

try {
    // 여러 테이블 변경
    $pdo->commit();
} catch (Throwable $e) {
    $pdo->rollBack();
    throw $e;
}

트랜잭션 경계는 “업무 단위”와 맞춰야 한다.
이 역할을 Controller가 담당하면 구조가 흔들린다.

4. 외부 연동이 들어오는 순간

PG 결제, SMS/메일 발송, S3 업로드 같은 외부 연동이 들어오면 흐름이 복잡해진다.
실패 케이스, 재시도, 보상 처리까지 고려해야 한다.

이런 로직이 Controller에 있으면 분기만 늘어나고 재사용도 불가능해진다.
Service로 내려서 “업무 흐름”으로 관리해야 한다.

flowchart TD A["Controller"] B["Service
업무 흐름 통제"] C["Repository"] D["External API"] E["DB"] A --> B B --> C C --> E B --> D

5. 테스트가 필요해지는 순간

Service Layer가 없으면 단위 테스트가 사실상 불가능해진다.
Controller는 HTTP, 세션, 요청 파라미터, 응답 포맷에 묶이기 때문이다.

핵심 로직을 Service에 두면 입력과 출력만으로 테스트할 수 있다.
운영에서 장애가 잦아지는 시점에는 테스트 가능한 구조로 바꾸는 것이 먼저다.

6. “기능 추가가 느려지기 시작할 때”

새 기능을 추가할 때 기존 코드에 손대는 부분이 많아졌다면 구조가 이미 복잡해졌다는 신호다.
작은 수정이 다른 기능에 영향을 주기 시작하면, 로직의 경계를 분리해야 한다.

Service Layer는 기능을 쪼개기 위한 기준선을 만들어 준다.
업무 단위로 메서드를 분리하고 책임을 명확히 하면 변경 영향 범위를 줄일 수 있다.

7. 도입 기준 요약 체크리스트

  • Controller가 200~300줄을 넘어가고 조건 분기가 늘어난다
  • 같은 로직이 여러 Controller/Endpoint에 반복된다
  • 트랜잭션이 필요한 작업이 늘어난다
  • 외부 API 연동이 들어오며 실패 케이스가 복잡해진다
  • 테스트 필요성이 생기거나 장애 대응이 반복된다

한 줄 요약

Controller가 비대해지고 로직 중복·트랜잭션·외부 연동·테스트 요구가 생기면 Service Layer 도입 시점이다. 업무 흐름과 트랜잭션 경계를 Service로 묶으면 유지보수와 장애 대응이 안정된다.

댓글 0

  • 첫 번째 댓글을 남겨보세요.