"이걸 왜 이렇게 쪼개야 하지? 그냥 Request → Entity로 바로 가면 안 되나?"
이런 의문을 가진 분들을 위해, 각 계층이 나뉘는 이유를 정리해봅니다.
| 타입 | 이름 예시 | 역할 | 소속 계층 |
|---|---|---|---|
| Request | CreateBannerRequest | 클라이언트 요청 바인딩, API 입력 검증 (@RequestBody) | Controller |
| Command | CreateBannerCommand | 유스케이스 실행에 필요한 비즈니스 데이터 | Application (UseCase) |
| Entity | BannerEntity 또는 Banner | DB 저장을 위한 영속 객체, 도메인 규칙 내포 | Domain / Infrastructure |
예:
CreateBannerRequest가 바뀌어도Entity는 영향 없음
@Valid, @NotBlank 등 API 요청 유효성 검사에 초점CreateBannerCommand는 API 외에도 Kafka 소비, 배치 작업 등 다양한 유입 경로에서 재사용 가능Entity는 저장 전용이므로 다른 계층에 노출하지 않아도 됨| 기준 | 분리하지 않음 | 분리했을 때 |
|---|---|---|
| 변경 전파 위험 | 높음 | 낮음 |
| 단위 책임 | 뒤섞임 | 명확함 |
| 재사용성 | 낮음 | 높음 |
| 테스트 | 어렵고 모호함 | 계층별 용이함 |
실무에서 DTO를 구분하는 건 단순한 클래스 나누기가 아니라, 계층 간 의존성을 끊고, 유지보수를 용이하게 하기 위한 핵심 설계 원칙입니다.
Spring 기반 MSA, DDD 구조라면 꼭 이 구조를 고려해보세요.