kee-log

Leaf UseCase — 유스케이스도 트리로 생각하기

Leaf UseCase — 유스케이스도 트리로 생각하기

인터페이스는 언제 만들어야 하는가에서 Application Service를 어디까지 쪼갤지 고민하다 보면 자연스럽게 만나는 개념이 Leaf UseCase입니다. 나무 구조에서 더 이상 가지가 뻗지 않는 끝단의 잎(leaf)처럼, 더는 하위 단계로 쪼갤 수 없는 최소 단위의 독립적인 유스케이스를 말합니다.

특징

  • 단일 책임: 하나의 Leaf UseCase는 정확히 하나의 명확한 비즈니스 행위만 수행한다 (예: "주문 생성", "비밀번호 변경").
  • 재사용성과 조립성: 거대한 서비스 클래스 하나에 로직을 몰아넣는 대신, Leaf UseCase를 모듈식으로 쪼개두면 다른 상위 유스케이스에서 부품처럼 가져다 쓸 수 있다.
  • 높은 응집도: 특정 목적에만 집중하므로 코드가 간결하고 테스트하기 쉽다.

구조 예시

배달 앱의 "음식 주문하기" 기능을 예로 들면:

Composite UseCase: 주문하기 (전체 프로세스를 관장)
 ├─ Leaf UseCase: 장바구니 검증하기
 ├─ Leaf UseCase: 결제 요청하기
 └─ Leaf UseCase: 쿠폰 소모하기

거대한 OrderService 클래스 하나에 수십 개 메서드를 넣는 대신, 하나의 유스케이스를 하나의 클래스(또는 함수)로 독립시키는 방식입니다.

// 하나의 목적만 가진 Leaf UseCase 예시
public class CancelOrderUseCase {
    private final OrderRepository orderRepository;
 
    public CancelOrderUseCase(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
 
    public void execute(Long orderId) {
        // 1. 주문 조회
        // 2. 취소 가능 여부 검증 (도메인 엔티티에 위임)
        // 3. 상태 변경 및 저장
    }
}

승격 타이밍과의 연결

Leaf UseCase 개념은 인터페이스는 언제 만들어야 하는가의 기준과 자연스럽게 이어집니다. 여러 Composite UseCase에서 같은 Leaf가 반복적으로 필요해지는 순간이, 바로 그 Leaf를 Application Service(필요하면 interface까지)로 승격시킬 타이밍입니다. 반대로 아직 한 Composite UseCase에서만 쓰인다면 굳이 독립된 클래스나 인터페이스로 만들 필요가 없습니다.

시리즈를 마치며

세 편에 걸쳐 다룬 고민의 공통 분모는 하나였습니다.

지금 필요한 만큼만 추상화하고, 필요해지는 시점을 신호로 삼아 그때 한 단계씩 승격시킨다.

미리 만든 인터페이스와 서비스 계층은 대부분 과잉 설계로 남고, 반대로 실제 재사용이 확인된 순간 리팩터링을 미루면 그건 그것대로 기술 부채가 됩니다.