Search
Duplicate
🎖️

14. 컴포넌트 결합

: 컴포넌트 사이의 관계를 설명하는 원칙들
: 개발 가능성과 논리적 설계 사이의 균형을 다룬다. 컴포넌트 구조와 관련된 아키텍처를 침범하는 힘은 기술적이며 정치적이고 가변적이다.

ADP: 의존성 비순환 원칙

컴포넌트 의존성 그래프에 순환이 존재해서는 안 된다.
: 무언가를 작동하게 만들어 놓고 퇴근했을때, 누군가가 당신이 만든 것이 의존하고 있던 무언가를 수정한다면 작동하지 않게 될 것이다. 이를 숙취 증후군이라 부른다.
: 이는 많은 개발자들이 동일한 소스 파일을 수정하는 환경에서 발생한다, 소수의 개발자로 구성된 상대적으로 작은 프로젝트에서는 이 증후군이 그다지 큰 문제가 되지 않는다.
: 이를 해결하기 위한 두 가지 방법이 제시되었는데, 하나는 주 단위 빌드, 하나는 의존성 비순환 원칙이다.
주 단위 빌드
: 중간 규모의 프로젝트에서 흔하게 사용되는 방법으로 먼저 모든 개발자는 일주일의 첫 4일동안은 서로를 신경쓰지 않는다.
: 그런 후 금요일이 되면 변경된 코드를 모두 통합하여 시스템을 빌드한다. 이는 5일 중 4일을 개발자가 통합에 대한 신경을 쓰지 않게 해주는 장점을 가지지만
: 프로젝트의 규모가 점점 커짐에따라 금요일만으로는 통합이 불가능해지는 상황이 발생한다.
순환 의존성 제거하기
: 이 문제의 해결책은 개발 환경을 릴리즈 가능한 컴포넌트 단위로 분리하는 것이다.
: 자신이 의존하고 있는 컴포넌트의 릴리즈 버전만을 신경쓰면 되며, 릴리즈 버전이 업데이트 되더라도 언제 적용시킬지 고민하기만 하면 된다.
: 비순환 방향 그래프 ⇒ 어느 컴포넌트에서 시작하더라도 의존성 관계를 따라가면 최초의 컴포넌트로 돌아갈수 없다.
: 순환 방향 그래프 ⇒ Database를 릴리즈하려보니 Entities, Authorizer, Interactors가 하나의 거대한 컴포넌트가 되어버린다.
: 이 문제는 의존성 그래프에 순환이 있기 때문이다.
순환 끊기
: 컴포넌트 사이 순환을 끊고 의존성을 다시 비순환 방향 그래프로 원상복구하는 방법
1.
의존성 역전 원칙을 적용한다.
2.
Entities와 Authorizer가 모두 의존하는 새로운 컴포넌트를 만든다. 그리고 두 컴포넌트가 모두 의존하는 클래스를 새로운 컴포넌트로 이동시킨다.
⇒ 해당 해결책을 사용하면 요구사항이 변경되므로 컴포넌트 구조도 변경된다. 즉 컴포넌트 의존성 구조는 애플리케이션이 성장함에 흐트러지며 성장한다.
의존성 구조에 순환이 발생하는 지 항상 관찰해야 하며 순환이 발생하면 어떤식으로든 끊어야 한다.

하향식 설계

: 지금까지 논의로 결론을 지어보면 컴포넌트 구조는 하향식으로 설계될 수 없다는 것이다.
: 컴포넌트는 시스템에서 가장 먼저 설계될 수 있는 대상이 아니다. 시스템이 성장하고 변경되며 함께 진화하는 객체로
: 컴포넌트 의존성 다이어그램은 애플리케이션의 기능을 기술하는 일과 거의 관련이 없다.
: 컴포넌트 의존성 다이어그램은 애플리케이션의 빌드 가능성과 유지보수성을 보여주는 지도와 같다. 이러한 이유로 컴포넌트 구조는 프로젝트 초기에 설계할 수 없다.

SDP: 안정된 의존성 원칙

더 안정된 쪽에 의존하라
: 변경이 쉽지 않은 컴포넌트가 변동이 예상되는 컴포넌트에 의존하도록 만들어서는 절대로 안 된다. 한번 의존하게 되면 변동성이 큰 컴포넌트도 결국 변경이 어려워진다.
안정성
: 컴포넌트 안쪽으로 들어오는 의존성이 많아지면 상당히 안정적이라 볼 수 있다. 사소한 변경이라도 의존하는 모든 컴포넌트를 만족시키면서 변경하기는 어렵기 때문이다.
: 안쪽으로 들어오는 의존성이 많으면 안정적이며 적으면 불안정한 컴포넌트이다.
안정성 지표
: 어떻게 하면 안정성을 측정할 수 있을까? 여기서는 Fan-in과 Fan-out, I(불안정성)을 사용한다.
: I = Fan-out / (Fan-in + Fan-out)으로 나타내며 [0, 1]의 값을 가진다. I = 0이면 최고로 안정된 컴포넌트이며 I = 1이면 최고로 불안정한 컴포넌트란 뜻이다.
모든 컴포넌트가 안정적이어야 하는 것은 아니다.
: 위쪽에는 변경 가능한 컴포넌트가 아래쪽의 안정된 컴포넌트에 의존한다, 다이어그램에서 불안정한 컴포넌트를 관례적으로 위에 두는데, 위로 향하는 화살표가 존재한다면..
그건 큰일이기 때문이다.
추상 컴포넌트
: 오로지 인터페이스만을 포함하는 컴포넌트를 생성하는 방식인 추상 컴포넌트는 상당히 안정적이며 덜 안정적인 컴포넌트가 의존할 수 있는 이상적인 대상이다.
: 동적 타입 언어를 사용할 때는 이러한 추상 컴포넌트가 전혀 존재하지 않을 뿐더러 추상 컴포넌트로 향하는 의존성이 없다.
: 이들 언어에서의 의존성 구조는 훨씬 단순한데, 의존성을 역전시킬 때 인터페이스를 선언하거나 의존성을 상속받는 일이 전혀 필요하지 않기 때문이다.

SAP: 안정된 추상화 원칙

컴포넌트는 안정된 정도만큼 추상화되어야 한다.
고수준 정책을 어디에 위치시켜야 하는가?
: 시스템에는 자주 변경해서는 절대로 안되는 소프트웨어도 있다. 고수준 아키텍처나 정책 결정과 관련된 소프트웨어가 그 예다.
: 따라서 시스템에서 고수준 정책을 캡슐화하는 소프트웨어는 반드시 안정된 컴포넌트에 위치해야 한다.
: 만약 고수준 정책을 안정된 컴포넌트에 위치시키지 않는다면 그 정책을 포함하는 소스 코드는 수정이 어려워 진다.
: 어떻게 컴포넌트가 최고로 안정된 상태이면서도 동시에 변경에 충분히 대응할 수 있을 정도로 유연하게 만들 수 있을까?
안정된 추상화 원칙
: 안정된 추상화 원칙은 안정성과 추상화 정도 사이의 관계를 정의한다.
: 안정된 컴포넌트는 추상 컴포넌트어야 하며 안정성이 컴포넌트를 확장하는 일을 방해해서는 안 된다.
: 불안정한 컴포넌트는 반드시 구체 컴포넌트어야 하며 불안정하므로 컴포넌트 내부의 구체적인 코드를 쉽게 변경할 수 있어야 한다.
⇒ SAP와 SDP를 결합하면 컴포넌트에 대한 DIP나 마찬가지가 되버린다.
⇒ 핵심은 안정적인 컴포넌트라면 반드시 인터페이스와 추상 클래스로 구성되어 쉽게 확장할 수 있어야 한다.

추상화 정도 측정하기

NC: 컴포넌트의 클래스 개수
Na: 컴포넌트의 추상 클래스와 인터페이스의 개수
A: 추상화 정도. A = Na / Nc(A가 0이면 추상 클래스가 한개도 없고, 1이면 오로지 추상 클래스만 있음)
주계열
아래 그림은 안정성(I)과 추상화 정도(A) 사이의 관계 그래프다.
: 최고로 안정적이며 추상화된 컴포넌트는 (0, 1)에 위치한다.
: 최고로 불안정하며 구체화된 컴포넌트는 (1, 0)에 위치한다.
그림 14.12 A/I 그래프
: 모든 컴포넌트가 이 두 지점에 위치하는 것은 아니다.
: 아래 그림의 궤적은 컴포넌트가 절대로 위치해서는 안 되는 영역, 배제할 구역(Zone of Exclusion)이다.
그림 14.13 배제 구역(Zone of Exclusion)
고통의 구역
(0, 0) 주변 구역에 위치한 컴포넌트는 매우 안정적이며 구체적이다. 뻣뻣한 상태이다. 추상적이지 않아서 확장할 수 없고, 안정적이므로 변경하기 상당히 어렵다.(0, 0) 근처에 위치한 소프트웨어는 구체적인 유틸리티 라이브러리이다.하지만 변동성이 없는 컴포넌트는 (0, 0) 구역에 위치하더라고 해롭지 않다. 변동될 가능성이 없기 때문이다.
쓸모없는 구역
(1, 1) 주변의 컴포넌트는 최고로 추상적이지만, 누구도 그 컴포넌트에 의존하지 않는다.이러한 컴포넌트는 쓸모가 없다.따라서 이 구역은 쓸모없는 구역(Zone of Uselessness)이라고 부른다.
배제구역 벗어나기
변동성이 큰 컴포넌트 대부분은 두 배제 구역으로부터 가능한 한 멀리 떨어뜨려야 한다.최대한 멀리 떨어진 점의 궤적은 (1, 0)과 (0, 1)을 잇는 선분이다. → 저자는 주계열(Main Sequence)이라고 부름주계열 위 또는 가깝게 위치해야 하며, 이렇게 위치하면 '너무 추상적'이지도 않고, 추상화 정도에 비해 '너무 불안정'하지도 않다.
주계열과의 거리
지표를 통해 주 계열에서 멀리 벗어난 컴포넌트의 원인을 파악하고 조사하는 것이 중요하다.

결론

: 의존성 관리 지표는 설계의 의존성과 추상화 정도가 저자가 '훌륭한' 패턴이라고 생각하는 수준에 얼마나 잘 부합하는지를 측정한다.