[Design Patterns] Clean Architecture
클린 아키텍처에 관한 내용을 기록합니다.
클린 아키텍처
로버트 C. 마틴(Uncle Bob)에 의해 처음 제안한 아키텍처
대부분의 아키텍처는 공통적인 목표가 있는데, 계층을 분리하여 관심사를 분리하는 것임.
각 아키텍처에는 최소 하나의 business rule을 위한 계층과 인터페이스를 위한 계층이 있음.
business rule: 비즈니스 요구 사항을 반영하여 데이터를 처리하는 것을 말함.
각 아키텍처는 아래와 같은 특징들이 있음.
- Independent of Frameworks: 아키텍처는 스포트웨어 라이브러리의 존재에 의존하지 않음.
- Testable: 비즈니스 로직은 UI 및 DB, 웹 서버 또는 기타 외부 요소 없이 테스트할 수 있음.
- Independent of UI: UI는 시스템을 변경하지 않고도 쉽게 변경 가능 (e.g. 비즈니스 로직을 변경하지 않고 웹 UI를 콘솔 UI로 변경 가능)
- Independent of Database: 비즈니스 로직이 DB에 바인딩되지 않음.
- Independent of any external agency: 비즈니스 로직은 외부 세계에 영향을 받지 않음.
구성요소
Entities
비즈니스 규칙 및 데이터를 포함하고 있는 핵심적인 부분
제일 고수준이며, 외부의 변화에 영향을 받지 않아야 함.
사용자, 제품, 주문 등을 엔티티로 구현할 수 있음.
UseCase
비즈니스 규칙들을 포함하며 시스템이 어떻게 작동하는지에 대한 모든 구현이 이루어짐.
엔티티에서의 데이터 흐름을 조율하고 비즈니스 규칙을 사용하여 해당 유즈케이스의 목적을 달성함.
이 레이어의 변화로 인해 엔티티에 영향을 미치지 않으며 이 레이어는 DB 또는 UI와 같이 외부의 변화로부터 영향을 받지 않음.
Interface Adapters
이 레이어는 Domain(유즈케이스와 엔티티)과 External Interfaces(UI, DB, Frameworks and Driver 등) 사이에 포멧을 변환하는 역할을 함.
- UI로부터 전달된 Input data → UseCase 와 Entity 에 용이한 포멧으로 변환
- UseCase 와 Entitiy로부터 전달된 output data → UI 또는 DB에 용이한 포멧으로 변환
Frameworks and Drivers.
제일 바깥 레이어로서 DB, Web 등의 프레임워크 또는 도구로 구성되어 있음.
이 레이어는 변화될 가능성이 높아 Domain 레이어와 분리되어 있어야 함.
The Dependency Rule
아키텍처의 특징들이 통합한 아키텍처가 동작하기 위해서는 의존성 규칙(Dependency Rule)을 지켜야 한다고 함.
모든 소스코드 의존성은 반드시 외부에서 내부로, 고수준 정책을 향해야 한다고 함.
→ 비즈니스 로직을 담당하는 코드들(내부)이 DB 또는 Web(외부) 과 같이 구체적인 세부 사항에 의존하지 않아야 함.
→ 비즈니스 로직(고수준 정책)은 세부 사항(저수준 정책)의 변경에 영향을 받지 않아야 함.
이러한 의존성 규칙을 지키기 위해서 아래 2가지 상황을 통해 주의해야 함.
What data corsses the boundaries
계층 간 데이터를 전달할 때 어떤 데이터를 전달해야 하는가에 관한 상황
의존성 규칙을 지키기 위해 단순하고 고립된 형태의 데이터 구조 사용을 추천함.
DB 데이터 구조 또는 프레임워크에 종속적인 데이터 구조가 사용된다면, 저수준의 데이터 구조를 고수준에서 알아야 하므로 의존성 규칙을 위반하게 됨.
Crossing boundaries
아래 그림에서처럼 제어의 흐름이 원의 내부에서 외부로 향할 수 있는데 이는 의존성 규칙을 위배하게 됨.
의존성 역전의 원칙(DIP, Dependency Inversion Principle)을 사용하여 이를 해결할 수 있음.
→ 고수준에서 저수준에 접근할 때 Interface를 통해 저수준의 세부사항에 영향을 받지 않도록 할 수 있음.
예시
Controller → UseCase → SomeRepository
- UseCase가 SomeRepository 구현체(저수준)을 직접 참조하고 있어 이는 의존성 규칙을 위반함.
Controller → UseCase → Repository ← SomeRepository
- 추상화된 Repository 인터페이스를 통해 UseCase가 이를 참조하고 SomeRepository 가 Repository 인터페이스를 구현하게 된다면, 의존성을 역전시킬 수 있음.
- → DIP 를 통해 UseCase는 SomeRepository 와 같은 구체적인 세부사항을 알 필요 없으며 영향을 받지 않음.
부족한 점 피드백해주시면 감사합니다 :)
Ref.
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html