클린 아키텍처 요약 - 4부. 컴포넌트 원칙
- SOLID 원칙 : 벽과 방에 벽돌을 배치하는 방법
- 컴포넌트 원칙 : 빌딩에 방을 배치하는 방법
12장. 컴포넌트
컴포넌트는 배포할 수 있는 가장 작은 단위이다. java에서는 .jar, C#에서는 .dll파일을 말한다.
컴포넌트의 간략한 역사
- 과거엔 메모리가 작았다.
- 어플리케이션에 라이브러리를 모두 포함하면 메모리가 부족해진다. 때문에 라이브러리 함수 코드를 직접 옮겨 컴파일 했다.
- → 컴파일 시간 증가
- 라이브러리 함수만 컴파일하고 컴파일된 바이너리를 어플리케이션 메모리의 특정 위치에 로드했다
- → 단편화 현상 (ex. Application - [단편화]- Function - [단편화] - Application ….)
재배치성
위 문제를 해결한 개념.
- 지능적인 로더가 코드 삽입 위치 정보(플래그)를 전달받아 재배치했다.
- 이 플래그는 메모리 참조의 시작 주소가 됐다.
- 프로그래머는 필요한 함수만 로드할 수 있게 되었다.
라이브러리 함수를 호출한다면 컴파일러는 라이브러리 함수 이름을 외부 참조로 생성 ⇒ 외부 정의를 로드 할 위치가 정해지기만 하면 로더가 외부 참조를 외부 정의에 링크시킬 수 있다. → 링킹 로더의 탄생
링크
링크와 로더의 분리 (1970년)
- 점점 프로그램의 크기가 커지고 링킹 로더도 느려졌다. 때문에 링크와 로더를 분리했다.
- 링크가 완료된 재배치 코드를 만들어 주었고, 덕분에 로더의 로딩 과정이 아주 빨라졌다.
- 한번 만들어둔 실행 파일은 언제라도 빠르게 로드할 수 있게됐다.
C언어 출시 (1980년)
- 프로그램이 더욱더 커졌음. 코드 수십만 라인을 넘었다.
- 소스 모듈 → .c → .o 컴파일 후 링커로 전달되는 구조로 변화
- 로드 시간은 빨랐지만, 여전히 컴파일 -링크 시간이 길었다.
무어 등장 (1990년)
- 하드웨어 급속 발전
- 링킹-로더 처리가 매우 빨라짐.
결론
런타임에 플러그인 형태로 결합할 수 있는 동적 링크 파일 개념이 생겨났고, 과거 이 파일이 컴포넌트에 해당한다.
13장. 컴포넌트 응집도
컴포넌트 응집도 관련 세가지 원칙.
REP: 재사용/릴리스 등가 원칙
- 하나의 컴포넌트로 묶인 클래스와 모듈은 버전 번호가 같아야 하며, 동일한 릴리스로 추적 관리되고, 동일한 릴리스 문서에 포함되어야 한다.
- “이치에 맞다“와 같은 약한 조언일 뿐이지만, 지켜야 하는 원칙임에 분명하다.
어떤 어플리케이션들은 버전관리를 함으로써, 업데이트를 하지 않아도 사용이 가능하다.
CCP: 공통 폐쇄 원칙
- 동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트에 묶어라.
- 서로 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 분리해라.
- SRP, OCP원칙을 컴포넌트 관점에서 다시 쓴 것.
배포 관점에서 SRP, OCP로 이해할 수 도 있겠다.
CRP: 공통 재사용 원칙
- 필요하지 않는 것에 의존하지 말아라.
- 컴포넌트가 변경될 때마다 사용하는 컴포넌트도 변경해야 할 가능이 높다.
배포 관점에서 ISP로 이해할 수 도 있겠다.
컴포넌트 응집도에 대한 균형 다이어그램
- REP, CCP는 포함원칙 / CRP는 배제원칙
- 프로젝트 시작에서 성숙 순서로 생각해보면, 오른쪽에서 왼쪽으로 간다.
- 시작 : CCP, CRP
- 성숙 : REP, CRP
결론
어플리케이션 요구에 맞게, 원칙 간에 균형잡는 일이 중요하다. 잘 분배했더라도, 시간이 지나면 달라질 수 있다.
14장. 컴포넌트 결합
ADP: 의존성 비순환 원칙
컴포넌트 의존성 그래프에 순환이 있어서는 안된다.
순환 의존성 제거
- 배포 가능한 형태로 컴포넌트 단위를 분리한다.
- 컴포넌트 간 순환구조를 만들지 않는다.
순환 끊기
요구사항에 의해 순환구조가 이루어지는 상황이 발생할 수 있다.
Entites가 Authorizer를 사용해야 하는 상황이라고 가정해보자. 그럼 왼쪽 그림과 같이 순환구조가 만들어진다. 이 구조는 순환참조를 야기하여 향후 많은 문제를 일으킨다. 때문에 오른쪽과 같이 인터페이스를 두어 의존관계를 끊어내야 한다.
Top-Down 설계
컴포넌트 구조는 하향식으로 설계될 수 밖에 없다.
컴포넌트 의존성 다이어그램은 어플리케이션의 빌드가성과 유지보수성을 보여주는 지도와 같다. 이러한 이유로 구조를 초기에 설계할 수 없다. 아무런 클래스도 설계하지 않은 상태에서 컴포넌트 의존성 구조를 설계하려고 시도한다면 큰 실패를 맛볼 것이다.
컴포넌트 의존 구조는 시스템의 논리적 설계에 맞춰 성장해야 한다.
SDP: 안정된 의존성 원칙
더 안정된 방향으로 의존해라. Stable → Flexible (X)
‘변경이 쉽지 않은 컴포넌트’가 ‘병경이 예상되는 컴포넌트’에 의존하게 만들어서는 절대로 안된다.
안정성
쉽게 움직이지 않는것.
컴포넌트를 변경하기 어렵게 만드는 방법은 수많은 다른 컴포넌트가 해당 컴포넌트를 의존하게 만드는 것이다
안정성 지표
의존 관계의 클래스 수를 세어 계산하는 방법
- Fan.in : 안으로 들어오는 의존성
- Fan.out : 바깥으로 나가는 의존성
- I(불안정성) : Fan.in + Fan.out
추상 컴포넌트
오로지 인터페이스만을 포함하는 컴포넌트를 생성하는 방식은 java와 같은 정적 언어에서는 흔하다. 그리고 꼭 필요한 전략이다. 다만, python과 같은 동적 언어에서는 추상 컴포넌트는 없다.
SAP: 안정된 추상화 원칙
컴포넌트는 안정된 정도 만큼만 추상화되어야 한다.
고수준 정책을 어디에 위치시켜야 하는가?
- 추상화 클래스에 위치 시켜야 한다.
- 변경해서는 절대로 안되는 소프트웨어도 있다. 고수준 아키텍처나 정책 결정과 관련된 소프트웨어가 그렇다.
- 의존성은 추상화 방향으로 향하게 된다.