스프링 프로젝트의 구조를 잡음에 있어 다양한 아키텍처가 사용된다
구성: Presentation → Service → Repository → Domain
장점: 이해하기 쉽고, 스프링의 DI와 AOP 기능과 잘 맞물림
단점: 계층 간 결합도가 높아지기 쉬움, 테스트 어려움
적용 예: 이벤트 소싱과 함께 사용하면 강력함
장점: 복잡한 도메인에 적합, 읽기/쓰기 최적화 가능
단점: 구현 복잡도 증가, 유지보수 어려움
구성: Entities → Use Cases → Interface Adapters → Frameworks & Drivers
장점: 비즈니스 로직 중심, 테스트 용이
단점: 구조가 복잡해질 수 있고, 학습 비용이 있음
장점: 마이크로서비스의 장점 일부를 가져오면서도 배포는 단일
단점: 모듈 간 경계 설정이 어렵고, 잘못하면 레이어드 아키텍처와 다를 바 없음
장점: 확장성, 독립 배포, 팀 간 분업 용이
단점: 인프라 복잡도 증가, 분산 시스템의 어려움
계층 설명
Domain : 순수한 비즈니스 로직. 외부 기술에 의존하지 않음
Application (Use Case) : 도메인 로직을 조합하여 유즈케이스를 구현. 포트를 통해 입출력 처리
Ports : 인터페이스. 어플리케이션이 외부와 통신하는 계약
Adapters : 포트를 구현한 실제 클래스. DB, 웹, 메시지 브로커 등과 연결
Infrastructure : 기술 세부사항(JPA, Redis, Kafka 등)을 포함하는 구현체
흐름예시 : 영화 목록 조회 API
1) 사용자가 /movies API 호출
2) Inbound Adapter (예: MovieController)가 요청을 수신
3) MovieController는 Input Port 인터페이스를 호출
4) Application Layer에서 유즈케이스 실행
5) 유즈케이스는 Output Port를 통해 DB 접근 요청
6) Outbound Adapter (예: JpaMovieRepository)가 실제 DB에서 데이터 조회
7) 결과가 다시 유즈케이스 → 컨트롤러 → 사용자에게 반환
장점 :
기술 독립성: 도메인 로직이 JPA, Redis, Kafka 등 기술에 오염되지 않음
테스트 용이성: 외부 의존성을 Mock으로 대체 가능
유지보수성: 기술 교체가 쉬움 (예: JPA → MyBatis)
확장성: 다양한 입출력 채널을 쉽게 추가 가능 (예: REST, gRPC, CLI 등)
단점 :
초기 설계 복잡도: 작은 프로젝트에는 과할 수 있음
학습 비용: 팀원 간 이해도 차이 발생 가능
구조 오용 위험: Adapter와 Port의 경계가 모호해질 수 있음
언제 쓰면 좋을까?
도메인 로직이 복잡하거나 장기적으로 유지보수가 필요한 프로젝트
다양한 입출력 채널을 고려해야 하는 시스템
기술 교체 가능성을 염두에 둔 설계가 필요한 경우