SOLID 원칙이 벽과 방에 벽돌을 배치하는 방법을 알려준다면
컴포넌트 원칙은 빌딩에 방을 배치하는 방법을 알려준다.
컴포넌트
: 시스템의 구성 요소로 배포할 수 있는 가장 작은 단위
ex) 자바의 컴포넌트 = jar 파일, 루비의 컴포넌트 = gem 파일. 닷넷의 컴포넌트 = DLL 파일
- 잘 설계된 컴포넌트는 독립적으로 배포 가능해야한다
컴포넌트 응집도 - 어떤 클래스를 어떤 컴포넌트에 포함시켜야할까?
1. REP (Reuse/Release Equivalence Principle) : 재사용/릴리스 등가 원칙
: 재사용 단위는 릴리스 단위와 같다
릴리스 절차에는 적절한 공지와 함께 문서 작성도 포함되어야 한다.
-> 단일 컴포넌트는 응집성 높은 클래스와 모듈들로 구성돼야한다.
-> 하나의 컴포넌트로 묶인 클래스와 모듈들은 반드시 함께 릴리스할 수 있어야 한다.
2. CCP (Common Clousure Principle) : 공동 폐쇄 원칙
- 물리적 또는 개념적으로 강하게 결합되어 항상 함께 변경되는 클래스들은 하나의 컴포넌트에 속해야 한다. -> 소프트웨어 릴리즈, 재검증, 배포 작업량을 최소화할 수 있다.
- SRP, OCP와 관련이 있다.
동일한 이유로 동일한 시점에 변경되는 클래스는 같은 컴포넌트로 묶고,
서로 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 분리하기
3. CRP (Common Reuse Principle) : 공통 재사용 원칙
: 컴포넌트 사용자들을 필요하지 않는 것에 의존하지 않게 하기
: 강하게 결함되지 않은 클래스들을 동일한 컴포넌트에 위치시키면 안된다.
- ex) 컨테이너 클래스, 해당 클래스의 이터레이터 클래스 -> 서로 강하게 결합되어 있어서 함께 재사용된다. -> 반드시 동일한 컴포넌트에 위치해야 한다
- 각 컴포넌트에 어떤 클래스들을 포함시켜줘야하는지 설명, 동일한 컴포넌트로 묶으면 안되는 클래스가 무엇인지 설명
- ISP의 포괄적인 버전
균형 다이어그램
- REP, CCP - 포함원칙 -> 컴포넌트를 더욱 크게 만든다
- CRP - 배제원칙 -> 컴포넌트를 더욱 작게 만든다.
=> 이 원칙들이 균형을 이뤄야한다.
컴포넌트 결합 - 컴포넌트 사이의 관계
1. ADP (Acyclic Dependencies Principle) : 의존성 비순환 원칙
: 컴포넌트 의존성 그래프에 순환이 있어서는 안된다
숙취 증후군 ?
: 많은 개발자가 동일한 소스 파일을 수정하는 환경에서 발생
- ex) 마지막 수정으로 인해 다시 수정해야하는 상황
- 해결책 -> 1. 주단위 빌드, 2. ADP
방법1) 주단위 빌드 (weekly build)
- 중간 규모의 프로젝트에서 흔히 사용됨
- 방법: 4일동안은 개인 개발 -> 금요일 변경된 코드를 모두 통합하여 시스템 빌드
- 단점: 하루만에 해결되지 않는다 -> 빌드 일정이 늘어나고, 빌드 주기가 늦어지며, 통합 테스트가 어려워짐
방법2) 순환 의존성 제거하기
- 개발환경을 릴리스 가능한 컴포넌트 단위로 분리 -> 컴포넌트는 개발자 또는 개발팀이 책임질 수 있다
- 방법: 작업 후 컴포넌트를 릴리스 -> 다른 개발자는 해당 릴리스를 사용할지 말지 정해서 개발
- 장점: 특정 컴포넌트가 다른 컴포넌트에 영향을 주지 않는다.
- 주의할점: 컴포넌트 사이의 의존성 구조를 반드시 관리해야한다. 서로 순환이 있어서는 안된다
순환 의존성이 발생하면 컴포넌트를 어떤 순서로 빌드해야할지 모른다
컴포넌트 다이어그램
주의할점: 어느 컴포넌트에서 시작하더라도 의존성 관계를 따라가면서 최초의 컴포넌트로 돌아갈 수 없다!
-> 구조에 순환이 없다 -> 비순환 방향 그래프 (DAG Directed Acyclic Graph)
시스템 전체를 릴리스해야한다면 릴리스 절차는 상향식으로 진행된다. (Entities -> Database, Interactors -> Presenters, View, Controllers, Authorizer -> Main 순으로 컴파일, 테스트, 릴리스한다.)
흐트러짐 Jitters
: 요구사항이 변경되면 컴포넌트 구조도 변경될 수 있다.
- 애플리케이션이 성장할수록, 순환이 발생하는지 항상 관찰해야한다. -> 발생하면 어떤식으로든 끊어야 한다.
- 순환을 끊는 법: 1) 새로운 컴포넌트를 생성 2) 컴포넌트 간의 의존성을 역전시킨다 (DIP)
하향식 설계 (top-down)
컴포넌트 구조는 하향식으로 설계될 수 없다, 컴포넌트는 시스템이 성장하고 변경될 때 함께 진화한다.
컴포넌트 의존성 다디어그램은 애플리케이션의 빌드가능성, 유지보수성을 보여준다.
-> 컴포넌트 구조는 프로젝트 초기에 설계 불가능
-> 그래도 숙취 증후군을 겪지 않으려면, 의존성 관리 필요 (SRP, CCP)
2. SDP (Stable Dependencies Principle) : 안정된 의존성 원칙
: 더 안정된 쪽에 의존하기
변경이 쉽지 않은 컴포넌트가 변동이 예상되는 컴포넌트에 의존하게 만들어서는 안된다.
-> SDP를 준수하면 변경하기 어려운 모듈이 변경하기 쉽게 만들어진 모듈에 의존하지 않도록 만들 수 있다.
안정된 컴포넌트 vs 불안정한 컴포넌트
왼쪽
X는 어디에도 의존하지 않는다. X를 변경이 발생하게 할 수 없음 -> 안정적인 컴포넌트, 독립적
오른쪽
Y는 세개의 컴포넌트에 의존하므로 변경이 발생할 수 있는 외부 요인이 3가지 이다. -> 불안정한 컴포넌트, 의존적
안정성 지표
1) Fan-in
: 안으로 들어오는 의존성
: 컴포넌트 내부의 클래스에 의존하는 컴포넌트 외부의 클래스의 개수
2) Fan-out
: 바깥으로 나가는 의존성
: 컴포넌트 외부의 클래스에 의존하는 컴포넌트 내부의 클래스의 개수
3) I (불안정성)
- I = Fan-out / (Fan-in + Fan-out)
- I = 0 : 최고로 안정된 컴포넌트
- I = 1 : 최고로 불안정한 컴포넌트
모든 컴포넌트가 안정적일 수는 없다.
-> 불안정한 컴포넌트, 안정된 컴포넌트로 구성되는게 이상적인 구조
* 다이어그램에서 불안정한 컴포넌트를 위에둔다
SDP 위반 -> DIP 도입하여 해결하기
왼쪽
안정적인 컴포넌트 Stable 가 불안정한 컴포넌트 Flexible 에 의존성을 걸었다 -> SDP 위반
오른쪽
DIP 도입하여 해결 -> 추상 컴포넌트를 생성하여 두 컴포넌트가 모두 UServer 컴포넌트를 의존하도록 한다.
-> UServer은 I = 0 이되며, Flexible은 I = 1을 유지
3. SAP (Stable Abstractions Principle) : 안정된 추상화 원칙
컴포넌트는 안정된 만큼만 추상화되어야 한다
컴포넌트가 안정된 상태이면서(I=0) 동시에 변경에 충분히 대응할 수 있을까? -> OCP
SAP는 의존성이 반드시 안정성의 방향으로 향해야 한다고 말하며, SAP에서는 안정성이 결국 추상화를 의미한다고 말하기 때문에 -> SAP와 SDP를 결합하면 컴포넌트에 대한 DIP가 된다. -> 의존성은 추상화의 방향으로 향하게 된다.
클래스는 추상적이거나 아니거나 둘 중 하나다.
'클린아키텍처' 카테고리의 다른 글
[클린아키텍처] 17장 경계: 선긋기, 18장 경계 해부학 (0) | 2022.03.10 |
---|---|
[클린아키텍처] 15장 아키텍처란?, 16장 독립성 (0) | 2022.03.06 |
[클린아키텍처] 7장~11장 설계원칙 - SOLID 원칙 (0) | 2022.02.27 |
[클린아키텍처] 3장~6장 프로그래밍 패러다임 - 구조적 프로그래밍, 객체 지향 프로그래밍, 함수형 프로그래밍 (0) | 2022.02.27 |
[클린아키텍처] 1장 설계와 아키텍처란? 2장 두가지 가치에 대한 이야기 (0) | 2022.02.27 |
댓글