클린 아키텍처 한눈에 보기
1) 요약
- 목적: 기술 독립성, 테스트 용이성, 유지보수성 극대화
- 원리: 의존성 역전 원칙(DIP). 코어(엔티티·유스케이스)는 추상(포트)에 의존하고, 외부는 어댑터로 구현
- 관계: 헥사고날(Ports & Adapters) 사상을 동심원 구조로 일반화. UI는 MVP/MVVM 등으로 구성
- 효과: 데이터베이스·프레임워크·UI 교체 시 코어 변경 최소화
2) 구조
[Frameworks & Drivers]
└─ DB, Web, UI, Devices, External Services
▲
│ Adapters (구현)
│
[Interface Adapters]
└─ Presenter / Controllers / Gateways / Repository Impl
▲
│ (Ports: Interfaces)
[Use Cases]
└─ Application Business Rules
▲
[Entities]
└─ Enterprise Business Rules
핵심: 모든 의존 화살표는 안쪽(엔티티·유스케이스)으로 향함. 안쪽은 바깥을 모릅니다.
3) 배경과 발전 흐름
- DIP: 고수준·저수준 모두 추상에 의존해야 함 → 의존 방향을 코어 쪽으로 역전
- 헥사고날(2005): 포트와 어댑터로 코어와 외부를 분리
- UI 패턴(MVP/MVVM): 표시와 로직 분리는 헥사고날에서도 UI를 Primary Adapter로 배치해 달성 가능. 클린은 이를 Interface Adapters 층에서 MVP/MVVM 등으로 더 명시적·체계적으로 활용한다고 서술
- 통합: 클린 아키텍처는 위 개념들을 동심원으로 통합해 기술 독립성을 체계화
3.1 헥사고날 ⇒ 클린
- 모델링 관점: 헥사고날은 코어와 외부를 이분법적으로 가르되, 포트를 입·출력으로 구분합니다. 클린은 이를 동심원으로 표현해 “모든 의존 화살표는 안쪽으로”라는 단일 규칙으로 일반화합니다.
- 계층 역할 명시: 클린은 Interface Adapters 층을 별도 계층으로 두어 Presenter·Controller·Gateway·Repository 구현의 역할을 분리해 서술합니다. 헥사고날에서 어댑터가 맡던 폭넓은 역할을 세분화해 팀 커뮤니케이션을 돕습니다.
- 모델 분리 엄격화: 엔티티·유스케이스 모델과 DTO·프레임워크 모델을 분리하도록 강하게 권고합니다. 이로써 데이터 누수와 프레임워크 결합을 줄입니다.
3.2 UI 관리(헥사고날 vs 클린)
- 헥사고날: UI는 Primary Adapter로서 Inbound Port를 구현해 코어를 호출합니다. 패턴 선택은 자유도가 높습니다.
- 클린: UI는 Interface Adapters 층에 배치되며, MVP·MVVM 등 패턴을 명시적으로 활용해 View와 Presenter/ViewModel, 변환 계층을 도식화합니다. 테스트 경계와 모델 변환 지점이 명확해집니다.
10.6 헥사고날 ↔ 클린 비교
| 항목 | 헥사고날 | 클린 |
|---|
| 핵심 개념 | Ports(계약)와 Adapters(구현) | 동심원과 의존성 규칙(안쪽을 향함) |
| UI 위치 | Primary Adapter | Interface Adapters 층 내부(프레젠터/뷰모델 활용) |
| 포트 구분 | Inbound/Outbound 포트를 명확히 구분 | 포트 개념은 유지하되 계층 역할 서술이 더 일반화 |
| 모델 전략 | 코어와 어댑터 모델 분리 권장(표현은 비교적 느슨) | 엔티티·유스케이스 모델 vs DTO·프레임워크 모델 강한 분리 |
| 팀 온보딩 | 간결하고 직관적이지만 해석 여지 큼 | 역할 명세가 자세해 대규모 팀에 유리 |
4) 핵심 원칙
- 의존성 규칙: 내부는 외부를 모르고, 외부가 내부에 맞춥니다
- 경계 계약: Port(인터페이스)로 계약을 정의하고 Adapter가 구현
- 모델 분리: 엔티티·유스케이스 모델과 전송/프레임워크 모델을 분리
- 테스트 우선: 코어는 순수 로직으로 테스트가 빠르고 안정적
5) 레이어드 아키텍처와 비교
- 공통점: 관심사 분리, 계층적 구조로 변경 영향 축소
- 차이점: 레이어드는 구현 계층 간 의존이 수직 고정되기 쉬움. 클린은 포트·어댑터로 의존 방향을 항상 코어 쪽으로 강제하여 기술 독립성 강화
- 실무 포인트: 기존 레이어드 위에 포트/어댑터를 덧대 코어 의존 역전을 달성하는 하이브리드가 현실적
6) 장단점
장점
- 기술 교체 용이: DB, 메시징, UI, 프레임워크 교체 시 코어 변경 최소
- 테스트 용이: 어댑터 대체로 코어 단위 테스트가 빠르고 견고
- 유지보수성: 경계가 명확해 변경 범위가 좁음
단점
- 초기 비용: 포트/어댑터, 경계 모델, 매핑 코드 필요
- 과설계 리스크: 작은 서비스에 과도하면 생산성 저하
- 팀 합의 필요: 경계, 계약, 패키징 규칙을 지속적으로 지켜야 함
7) 적용 체크리스트
- 포트: 유스케이스가 필요로 하는 외부 기능을 인터페이스로 정의했는가
- 어댑터: UI·DB·API 구현은 포트를 통해서만 코어에 접근하는가
- 모델: 엔티티·유스케이스 모델과 DTO를 분리하고 매핑을 일관화했는가
- 의존 화살표: import 방향이 항상 코어를 향하도록 패키징했는가
- 테스트: 코어는 순수 단위 테스트, 어댑터는 계약 테스트를 갖추었는가
9) 안티패턴과 회피법
- 리포지토리 누수: 어댑터 상세 타입이 코어로 새어 들어오지 않게 Port를 도메인 모델 기준으로 정의
- 거대 유스케이스: 유스케이스가 오케스트레이션·검증·권한·트랜잭션까지 모두 품지 않도록 분리
- 양방향 의존: 유스케이스가 어댑터 구현을 import하면 규칙 위반. 의존성은 항상 안쪽으로만
- 경계 무시 매핑: DTO ↔ 도메인 매핑 로직을 일관된 위치에서 수행하여 중복·누락 방지
10) 헥사고날 아키텍처 (Ports & Adapters)
10.1 개요
- 목적: 애플리케이션 코어와 외부 세계를 ‘포트(계약)’와 ‘어댑터(구현)’로 분리
- 효과: 코어는 외부 세부사항을 모른 채로 기능을 유지. 구현 교체가 쉬움
10.2 구조 도식
[Primary Adapters] [Secondary Adapters]
(UI, CLI, HTTP Inbound) (DB, HTTP Outbound, MQ)
│ ▲
▼ │
Inbound Port ───► Application ├──► Outbound Port ───► Adapter(외부)
(인터페이스) (UseCases) (구현)
- Inbound Port: 외부가 코어 기능을 호출하는 계약(Controller, Handler가 구현 가능)
- Outbound Port: 코어가 외부 기능을 필요로 할 때 호출하는 계약(Repository 인터페이스 등)
10.3 클린 아키텍처와의 차이·관계
- 차이: 헥사고날은 입·출력 방향을 분리해 포트를 두 축으로 명시. 클린은 동심원과 의존 규칙으로 일반화
- 관계: 클린의 Interface Adapters 층이 헥사고날의 어댑터 군과 개념상 대응
10.5 장단점 요약
- 장점: 입출력 포트를 분리해 의사소통 경계를 명확히 하고 테스트 대체가 용이
- 단점: 포트 수가 증가해 인터페이스 관리 비용이 커질 수 있음