클린 아키텍처
더 많은 작업
- Clean Architecture; 클린 아키텍처
- 업무 규칙을 중심에 두고 소스 코드 의존성이 항상 안쪽(업무 규칙)으로만 향하도록 동심원 계층을 구성하는 소프트웨어 아키텍처 원칙
클린 아키텍처는 로버트 C. 마틴(Robert C. Martin, 'Uncle Bob')이 2012년 8월 블로그 글 "The Clean Architecture"에서 제안하고, 2017년 책 Clean Architecture: A Craftsman's Guide to Software Structure and Design에서 체계화했다. 마틴은 헥사고날 아키텍처, 어니언 아키텍처, 스크리밍 아키텍처, DCI, BCE 등 기존 아키텍처들이 공통적으로 관심사의 분리를 추구하며 업무 규칙 계층과 인터페이스 계층을 나눈다는 점에 주목하고, 이를 하나의 규칙으로 통합했다.
블로그 글은 이 원칙을 따르는 시스템의 특성으로 다음을 든다.
- 프레임워크 독립: 프레임워크를 도구로만 사용하며 시스템을 프레임워크의 제약에 가두지 않는다.
- 테스트 용이: UI, 데이터베이스, 웹 서버 없이 업무 규칙을 테스트할 수 있다.
- UI 독립: 업무 규칙을 바꾸지 않고 UI를 교체할 수 있다.
- 데이터베이스 독립: Oracle, SQL Server, MongoDB 등으로 바꿔도 업무 규칙은 영향을 받지 않는다.
- 외부 에이전시 독립: 업무 규칙은 외부 세계의 인터페이스를 알지 못한다.
| 계층(안→밖) | 내용 | 예 |
|---|---|---|
| 엔티티(Entities) | 전사적 핵심 업무 규칙을 캡슐화한 객체 또는 데이터 구조와 함수. 외부 변화에 가장 영향을 덜 받는다. | 계좌, 이자 계산 규칙 |
| 유스케이스(Use Cases) | 애플리케이션 고유의 업무 규칙. 엔티티로 들어가고 나오는 데이터 흐름을 조정한다. | 계좌 이체 처리(Interactor) |
| 인터페이스 어댑터(Interface Adapters) | 유스케이스·엔티티에 편리한 형식과 DB·웹 등 외부에 편리한 형식 간의 데이터 변환 | 컨트롤러, 프레젠터, 게이트웨이, MVC의 구성요소 |
| 프레임워크와 드라이버(Frameworks and Drivers) | 가장 바깥의 세부 사항. 연결 코드 외에는 거의 작성하지 않는다. | 웹 프레임워크, DB, UI, 외부 장치 |
마틴은 네 개의 원이 개념도일 뿐이며 필요하면 더 많은 계층을 둘 수 있지만, 의존성 규칙은 항상 적용된다고 설명한다.
의존성 규칙(The Dependency Rule)은 "소스 코드 의존성은 반드시 안쪽으로만 향해야 한다"는 것이다. 안쪽 원은 바깥쪽 원의 함수, 클래스, 변수 등 어떤 이름도 알아서는 안 된다.
실행 흐름은 컨트롤러 → 유스케이스 → 프레젠터처럼 바깥에서 안으로 들어왔다가 다시 바깥으로 나가지만, 소스 코드 의존성은 안쪽을 향해야 한다. 이를 위해 의존성 역전 원칙(DIP)을 사용한다. 유스케이스가 프레젠터를 호출해야 할 때, 유스케이스 계층 안에 출력 포트(인터페이스)를 정의하고 바깥 계층의 프레젠터가 이를 구현하게 한다. 경계를 넘는 데이터는 DTO나 단순한 구조체 같은 단순 데이터 구조로 전달하며, 엔티티나 데이터베이스 행(row)을 그대로 넘기지 않는다.
| 구분 | 제안자 | 핵심 |
|---|---|---|
| 헥사고날 아키텍처(Ports and Adapters) | 앨리스터 코번(Alistair Cockburn) | 애플리케이션 핵심을 포트로 둘러싸고 UI·DB 등은 어댑터로 연결한다. 안과 밖의 대칭 구조를 강조 |
| 어니언 아키텍처 | 제프리 팔레르모(Jeffrey Palermo) | 도메인 모델을 중심에 두고 도메인 서비스, 애플리케이션 서비스, 인프라를 양파 껍질처럼 배치 |
| 클린 아키텍처 | 로버트 C. 마틴 | 위 아키텍처들의 공통점을 엔티티·유스케이스 중심의 동심원과 의존성 규칙으로 일반화 |
세 아키텍처 모두 도메인(업무 규칙)을 인프라로부터 격리하고, 인터페이스를 통해 의존 방향을 도메인 쪽으로 향하게 한다는 점에서 본질이 같다.
- SRP(단일 책임 원칙): 변경 이유(액터)가 다른 코드를 분리한다는 원칙이 계층 분리의 근거가 된다.
- OCP(개방-폐쇄 원칙): 업무 규칙을 수정하지 않고 UI나 DB 어댑터를 추가·교체할 수 있다.
- LSP(리스코프 치환 원칙): 포트 인터페이스의 구현체는 서로 치환 가능해야 한다.
- ISP(인터페이스 분리 원칙): 유스케이스별로 필요한 만큼만 포트를 정의한다.
- DIP(의존성 역전 원칙): 경계를 넘는 의존성을 안쪽으로 향하게 만드는 핵심 수단이다.
책은 SOLID 외에도 컴포넌트 응집도·결합도 원칙과 경계, 험블 객체(Humble Object) 패턴 등을 함께 다룬다.
- 동심원 4계층(엔티티, 유스케이스, 인터페이스 어댑터, 프레임워크와 드라이버)의 순서와 역할
- 의존성 규칙: 소스 코드 의존성은 안쪽으로만 향하며, 경계를 넘을 때 DIP를 적용
- 헥사고날(포트와 어댑터), 어니언 아키텍처와의 공통점