대상:


문제 인식 — 무엇이 문제였나?

현재 코드 혹은 구조에서 느낀 불편함, 버그, 유지보수 어려움 등을 구체적으로 기록하세요.

문제 상황

예약 도메인은 상태 전이가 중요한 핵심 비즈니스 로직이다.

  • PENDING
  • CONFIRMED
  • COMPLETED
  • CANCELLED

4가지 상태에 따른 각 상태마다 허용되는 행동이 다르다.

즉, 단순 ENUM으로 관리한다면 서비스나 엔티티에서 조건 분기가 오염되고 상태가 추가될 수록 코드가 변경에 어려워진다.

문제가 되는 코드 / 구조

public class Reservation {
    private ReservationStatus status; 
}

public enum ReservationStatus {
    PENDING, CONFIRMED, COMPLETED, CANCELLED
}

문제 유형 체크

  • 중복 코드 / 로직
  • 불명확한 이름 (변수, 메서드, 클래스 등)
  • 단일 책임 원칙(SRP) 위반 — 너무 많은 역할
  • 높은 결합도 — 변경 시 여러 곳에 영향
  • 낮은 응집도 — 관련 없는 것들이 한곳에
  • 확장하기 어려운 구조 (OCP 위반)
  • 테스트하기 어려운 구조
  • 성능 문제
  • 가독성 / 이해하기 어려움
  • 기타:

변경 이유 — 왜 바꿔야 하는가?

지금 당장 동작하더라도 왜 바꾸어야 하는지 그 필요성을 설득력 있게 정리하세요.

  • 유지보수 측면: 상태가 추가될때마다 하나씩 엔티티에 메서드를 추가해야하는 문제가 있다.
  • 확장성 측면: 새로운 상태가 추가되더라도, EXPIRED나 NO_SHOW라는 신규 상태가 도입되더라도 서비스 레이어 전체가 영향 받지 않도록 OCP가 지켜지도록 해야합니다.
  • 가독성 측면: CONFIRMED 상태가 어떤 행위가 가능한지 파악하기 위해서 서비스 코드를 다 뒤져보아야 한다. 즉, 상태에 해당하는 클래스 하나만 열어보면 그 상태의 모든 가능한 행위를 알 수 있는 구조가 생긴다.
  • 테스트 용이성 측면: 해당 상태별로 해당 상태의 동작 테스트를 단위로 테스트할 수 있다.
  • 기타 이유:

변경 방향 — 어떻게 바꿀 것인가?

어떤 방식으로 접근할지, 어떤 기법·패턴·원칙을 적용할지 계획을 기록하세요.

접근 전략

상태 인터페이스

ReservationState

상태 구현 클래스

상태 클래스 4개 생성

싱글톤 객체 생성 (상태는 유일하게 생성)

  • PendingStatus
  • ConfirmedStatus
  • CompleteStatus
  • CancelledStatus

PENDING → CONFIRMED → COMPLETED

PENDING → CANCELLED

PENDING → CONFIRMED → CANCELLED

Entity에서는?

@Transient는 뭔가요?

적용할 기법 / 패턴 / 원칙

  • 메서드 추출 (Extract Method)
  • 클래스 / 인터페이스 추출 ReservationStatus 이넡페이스에 4개 구현 클래스
  • 디자인 패턴 적용 (패턴명: State Pattern)
  • 레이어 / 모듈 분리
  • 의존성 역전 (DIP) 적용
  • 불변 객체 / VO 도입
  • 기타:
  • SRP 단일 책임 원칙
  • OCP 개방-폐쇄 원칙

변경 결과 — 어떻게 바뀌었나?

변경된 코드 / 구조

// 리팩터링 후 코드나 구조를 붙여넣으세요

Before / After 비교


회고

배운 점

  • 상태를 ENUM으로 하는 것보다 상태를 객체 행동으로 한다.
  • ENUM은 유지하고, 런타임 행위는 Transient 상태 객체가 담당하는 구조로 한다.
  • 싱글톤은 선택사항이라고 하지만 현재 상태 객체는 내부에 필드가 없는 행동만 존재하기 때문에 객체를 생성하는 것은 불필요한 GC의 압박이라고 한다.
  • 도메인 로직이 서비스에서 제거되고, 엔티티, 상태 클래스로 이동하게 된다. DDD 적인 설계가 되어진다.