728x90
MVC + DDD
┌─────────────────────────────┐
│ Presentation Layer (MVC) │ ← Spring MVC의 @Controller, @RestController
│ • View / API Endpoint │
└────────────┬────────────────┘
│ calls
┌────────────▼────────────────┐
│ Application Layer │ ← Use Case / Application Service
│ • 트랜잭션 경계 관리
│ • 도메인 모델 orchestration
└────────────┬────────────────┘
│ uses
┌────────────▼────────────────┐
│ Domain Layer (DDD) │ ← Aggregate, Entity, Value Object, Domain Service
│ • 핵심 비즈니스 로직
└────────────┬────────────────┘
│ persists via
┌────────────▼────────────────┐
│ Infrastructure Layer │ ← Repository 구현, 외부 API 연동
│ • DB, 메시징, 캐시, 파일 I/O
└─────────────────────────────┘
Presentation Layer (MVC)
- 목적
- 사용자 요청(HTTP, WebSocket 등)을 받아 Controller에서 처리 → Service 호출 → View나 JSON/XML 응답 생성
- 화면(UI)과 서비스 로직의 분리
- 주요 구성 요소
- Controller (@Controller / @RestController)
- 엔드포인트 정의 (@GetMapping, @PostMapping 등)
- 입력 파라미터 바인딩, 예외 핸들링
- DTO
- Request/Response 전용 객체
- Validation(@Valid) 적용 위치
- View Resolver / Message Converter
- Thymeleaf, Mustache, JSON 변환(Gson, Jackson) 등
- Controller (@Controller / @RestController)
- 원칙
- Thin Controller: 최대한 로직을 두지 않고 Application Layer로 위임
- Validation: Controller 레벨에서 입력 검증 후 Service 진입
- Exception Handling: @ControllerAdvice를 이용해 전역 예외 처리
Application Layer (Use Case)
- 목적
- 트랜잭션 경계 설정 및 Use Case orchestration
- 여러 도메인 객체 협업 → 업무 흐름(시나리오) 구현
- 주요 구성 요소
- Application Service (@Service)
- @Transactional 설정
- 도메인 객체 조회/저장, 도메인 서비스 호출
- 외부 API 호출도 여기서 어댑터(Port) 통해 수행
- Port / Input–Output Port (Hexagonal Architecture)
- 애플리케이션이 외부(인프라, UI)와 소통할 인터페이스 정의
- 예: ProblemFetchPort, AnalysisResultPort
- DTO (Use Case 요청/응답 전용)
- Presentation DTO와 구분해 쓰거나, 동일 DTO를 재활용
- Application Service (@Service)
- 원칙
- Use Case 중심: 하나의 메서드가 하나의 시나리오(Use Case)를 완결
- Side Effect 최소화: 외부 호출·영속화는 Port 인터페이스로 추상화
- 트랜잭션 분리: 필요한 범위에서만 @Transactional 지정
Domain Layer (DDD)
- 목적
- 비즈니스 규칙과 도메인 개념을 캡슐화
- 엔티티, 값 객체, 애그리거트, 도메인 서비스로 비즈니스 로직 구현
- 주요 구성 요소
- Entity: 고유 식별자를 가진 객체 (Problem, User)
- Value Object: 식별자 없이 속성으로만 구분 (Money, Coordinates)
- Aggregate: 관련 Entity/Value Object 묶음, 불변식(Invariant) 관리
- Domain Service: 엔티티에 두기 애매한 비즈니스 로직
- Repository (Interface)
- public interface ProblemRepository { Optional<Problem> findById(ProblemId id); Problem save(Problem problem); }
- 원칙
- 프레임워크 의존 최소화(순수 Java)
- 유비쿼터스 언어 기반 네이밍
- 불변식(Invariant) 보존
Infrastructure Layer
- 목적
- 도메인 레이어가 정의한 Repository/Port 인터페이스 구현
- DB, 메시징, 캐시, 외부 API 등 구체 기술 담당
- 주요 구성 요소
- Repository 구현체 (@Repository)
- @Repository public class JpaProblemRepository implements ProblemRepository { private final SpringDataProblemJpaRepository jpaRepo; // toDomain(), fromDomain() 매핑 로직 포함 }
- Client/Adapter
- REST API 클라이언트, 메시지 브로커 연동, 파일 I/O
- DTO ↔ 도메인 모델 변환
- Configuration
- DataSource, MongoTemplate, RedisTemplate
- 트랜잭션 매니저, 모니터링·보안 설정
- 원칙
- 오직 기술 스택에만 의존
- 변경 시 이 레이어만 수정 (예: JPA → MyBatis)
이렇게 네 개 레이어를 분리하면, 각 책임이 명확해지고 유지보수·테스트·기술 교체가 모두 쉬워집니다.
728x90