Command UseCase (Port-In) — 상태 변경 추상화
Command UseCase는 상태 변경(CUD)을 추상화하는 Inbound Port입니다.
Command,Response는 별도 DTO 패키지로 분리하여 관리합니다.
1) 핵심 역할
- 상태 변경: Create, Update, Delete 담당
- CQRS Command 담당: 쓰기(CUD) 전용 Port
- DTO 패키지 분리: Command/Response는 dto 패키지에 정의
- Transaction 경계: Service 구현체에서
@Transactional적용 - 반환 타입: Response DTO 또는 void (CQRS 순수 패턴)
2) 핵심 원칙
원칙 1: DTO 패키지 분리
- ✅ Command는
dto/command/패키지에 정의 - ✅ Response는
dto/response/패키지에 정의 - ❌ UseCase 인터페이스 내부에 Record 정의 금지
원칙 2: 단일 메서드
- ✅ 하나의 UseCase는 하나의 비즈니스 액션만 수행
- ❌ 여러 액션을 하나의 UseCase에 넣지 않음
원칙 3: Assembler 사용
- ✅ Command → Domain, Domain → Response 변환은 Assembler에 위임
- ❌ Service에서 직접 변환 로직 작성 금지
원칙 4: Transaction 경계
- ✅ Service 구현체에
@Transactional적용 - ❌ UseCase 인터페이스에
@Transactional적용 금지
3) 패키지 구조
application/order/
├── dto/
│ ├── command/
│ │ ├── PlaceOrderCommand.java
│ │ ├── CancelOrderCommand.java
│ │ └── UpdateOrderCommand.java
│ └── response/
│ ├── OrderResponse.java
│ └── OrderSummaryResponse.java
└── port/
└── in/
└── command/
├── PlaceOrderUseCase.java
├── CancelOrderUseCase.java
└── UpdateOrderUseCase.java
4) 템플릿 코드
UseCase Interface (Response 반환)
package com.ryuqq.application.{bc}.port.in.command;
import com.ryuqq.application.{bc}.dto.command.{Action}{Bc}Command;
import com.ryuqq.application.{bc}.dto.response.{Bc}Response;
/**
* {Action} {Bc} UseCase (Command)
*
* <p>상태 변경을 담당하는 Inbound Port</p>
*
* @author development-team
* @since 1.0.0
*/
public interface {Action}{Bc}UseCase {
/**
* {Action} {Bc}
*
* @param command {Action} 명령
* @return {Action} 결과
*/
{Bc}Response execute({Action}{Bc}Command command);
}
UseCase Interface (void 반환 - CQRS 순수 패턴)
package com.ryuqq.application.{bc}.port.in.command;
import com.ryuqq.application.{bc}.dto.command.Delete{Bc}Command;
/**
* Delete {Bc} UseCase (Command)
*
* <p>삭제/확인 등 결과 반환이 필요없는 경우 void 반환</p>
*
* @author development-team
* @since 1.0.0
*/
public interface Delete{Bc}UseCase {
/**
* {Bc} 삭제
*
* @param command 삭제 명령
*/
void execute(Delete{Bc}Command command);
}
void 반환 사용 시기:
- 삭제 작업 (DeleteXxxUseCase)
- 확인/승인 작업 (ConfirmXxxUseCase, ApproveXxxUseCase)
- 알림/발송 작업 (SendXxxUseCase)
- 결과 조회가 필요 없는 경우
6) Do / Don’t
❌ Bad Examples
// ❌ UseCase 내부에 Command/Response Record 정의
public interface PlaceOrderUseCase {
Response execute(Command command);
record Command(...) {} // 금지!
record Response(...) {} // 금지!
}
// ❌ 여러 액션을 하나의 UseCase에
public interface OrderUseCase {
OrderResponse placeOrder(PlaceOrderCommand command); // 금지!
OrderResponse cancelOrder(CancelOrderCommand command); // 금지!
}
// ❌ UseCase 인터페이스에 @Transactional
@Transactional // 금지!
public interface PlaceOrderUseCase {
OrderResponse execute(PlaceOrderCommand command);
}
// ❌ Domain Entity 직접 반환
public interface PlaceOrderUseCase {
Order execute(PlaceOrderCommand command); // 금지! Domain 노출
}
✅ Good Examples
// ✅ 별도 DTO 패키지
// dto/command/PlaceOrderCommand.java
public record PlaceOrderCommand(...) {}
// dto/response/OrderResponse.java
public record OrderResponse(...) {}
// port/in/PlaceOrderUseCase.java
public interface PlaceOrderUseCase {
OrderResponse execute(PlaceOrderCommand command);
}
// ✅ 단일 액션
public interface PlaceOrderUseCase {
OrderResponse execute(PlaceOrderCommand command);
}
public interface CancelOrderUseCase {
OrderResponse execute(CancelOrderCommand command);
}
7) 체크리스트
Command UseCase 작성 시:
- 인터페이스명:
{Action}{Bc}UseCase - 패키지:
application.{bc}.port.in - Command DTO:
dto.command.{Action}{Bc}Command - Response DTO:
dto.response.{Bc}Response - 단일 메서드:
{Bc}Response execute({Action}{Bc}Command command) - Command 검증: Compact Constructor 사용
- 불변성:
List.copyOf()사용 - Domain 노출 금지: Response로만 반환
- Javadoc 포함:
@author,@since
📖 관련 문서
- Command DTO Guide - Command DTO 작성 규칙
- Response DTO Guide - Response DTO 작성 규칙
- PersistencePort Guide - Command Port 구현
- Query UseCase Guide - Query Port (읽기 전용)
- Assembler Pattern - DTO ↔ Domain 변환
작성자: Development Team 최종 수정일: 2025-11-12 버전: 2.0.0 (DTO 패키지 분리)