배포 단위, 잘 설계된 컴포넌트라면 반드시 독립적으로 빼포 가능하고 독립적으로 개발 가능해야 한다.
컴포넌트의 간략한 역사
과거의 소프트웨어는 메모리에서 프로그램의 위치와 레이아웃을 직접 프로그래머가 제어.
프로그램이 접근하는 라이브러리도 같이 포함을 하여 단일 프로그램으로 컴파일 했는데, 하드웨어적인 제약 때문에 컴파일이 매우 오래 걸림.
컴파일 시간을 줄이기 위해 라이브러리를 분리했고, 이러한 라이브러리 역시 메모리에 할당.
하지만 이 역시 어플리케이션의 크기가 커짐으로 인해 문제가 발생
재배치성
지능적인 로더를 사용해서 메모리에 재배치할 수 있는 형태의 바이너리를 생성하도록 컴파일러를 수정.
로더는 재배치 코드가 자리할 위치 정보를 전달 받음.
재배치 코드에는 로드한 데이터에서 어느 부분을 수정해야 정해진 주소에 로드할 수 있는지를 알려주는 플래그가 삽입.
-> 이를 통해 프로그래머는 함수 라이브러리를 로드할 위치와 애플리케이션을 로드할 위치를 로더에게 지시할 수 있게 됨.
로더는 여러개의 바이너리를 입력 받은 후, 차례대로 메모리로 로드하면서 재배치하는 작업을 처리했고 이를 통해 프로그래머는 오직 필요한 함수만 로드하는 것이 가능.
컴파일러는 재배치 가능한 바이너리 안의 함수 이름을 메타데이터 형태로 생성하도록 수정하여 라이브러리 함수를 호출할때 함수 이름을 외부 참조로 생성하고, 라이브러리 함수를 정의하는 프로그램이라면 해당 이름을 외부 정의로 생성.
외부 정의를 로드할 위치가 정해지면 로더가 외부 참조를 외부 정의에 링크하였고 이것이 링킹 로더의 탄생.
프로그램이 점점 커짐에 따라 링킹로더의 한계가 발생하여 링크와 로드 2단계로 분리.
프로그래머가 링커라는 별도의 애플리케이션을 링크 과정을 맡음
-> 로더의 로딩 과정이 아주 빨라짐
프로그램이 커지는 속도보다 하드웨어의 발전 속도가 커져 로드와 링크를 동시에 처리하는 것이 가능해짐.
다수의 파일 또는 다수의 공유 라이브러리를 링크 한 후 실행하는 컴포넌트 플러그인 아키텍처가 가능해졌다.
컴포넌트 응집도와 관련된 3가지 원칙은 REP, CCP, CRP이다.
재사용 단위는 릴리스 단위와 같다.
단일 컴포넌트는 응집성 높은 클래스와 모듈들로 구성되어야 한다.
컴포넌트를 구성하는 모든 모듈은 서로 공유하는 중요한 테마나 목적이 있어야 한다.
동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶는 원칙.
SOLID 원칙 중 SRP를 컴포넌트 관점에서 다시 쓴 것.
유지보수가 재사용성보다 중요한데, 한 컴포넌트가 하나의 역할만 맡게 된다면 해당 컴포넌트만 변경 및 테스트를 진행하면 되고 나머지 컴포넌트들은 그대로 유지시켜도 괜찮기 때문애 유지보수가 수월.
서로 다른 이유로 변경되는 클래스들을 다른 컴포넌트로 분리해야한다.
컴포넌트 사용자들을 필요하지 않는 것에 의존하게 강요하지 않아야 한다.
재사용이 되는 경향이 있는 클래스와 모듈들을 같은 컴포넌트에 포함해야 한다.
SOLID 원칙 중 ISP를 컴포넌트 레벨로 확장시켰다고 볼 수 있다.
REP와 CCP는 포함원칙이어서 컴포넌트를 더 크게 만든다.
CRP는 배제 원칙이어서 컴포넌트를 더 작게 만든다.
이 셋 중 특정한 부분에 너무 포커스를 맞추면 아래와 같은 문제가 발생.
뛰어난 아키텍트라면 이 셋의 적절한 밸런스를 잡는 것이 중요.
일반적으로 프로젝트를 처음 시작할때는 삼각형의 오른쪽, 프로젝트가 성숙하면 삼각형의 왼쪽으로 점점 이동하게 된다.
어떤 클래스들을 묶어서 컴포넌트로 만들 때 재사용성과 개발성이라는 상충하는 힘을 고려해야한다. 또한 지금 내가 중점적으로 두고 있는 가치가 시간이 흐름에 따라 변할 수도 있다는 사실을 명심하고 균형을 맞추도록 노력해야한다.
컴포넌트 의존성 그래프에 순환이 있어서는 안 된다.
의존성 때문에 잘 동작하던 코드가 갑자기 동작하지 않는 '숙취 증후군'을 해결하기 위한 방법으로 주단위 빌드와 ADP가 널리 사용된다.
주 단위 빌드
4일 동안은 독립적으로 개발 후 금요일에 빌드를 하는 방식의 개발.
프로젝트가 커지면 실효성이 떨어진다.
순환 의존성 제거하기
릴리즈 단위의 컴포넌트를 한 개발자 또는 한팀이 맡게하여, 버전에 맞게 선택을 하게한다.
의존성 구조를 반드시 관리해야 이런 개발이 가능하다.
어느 컴포넌트에서 시작하더라도, 의존성 관계를 따라가면서 최초의 컴포넌트로 되돌아 갈 수 없다.
특정 컴포넌트를 개발할때 테스트를 구성할 때 대체로 적은 노력이 들고, 고려해야 될 변수도 상대적으로 적다.
시스템을 릴리스 할 경우 릴리스 절차는 상향식으로 작은 컴포넌트 부터 큰컴포넌트 식으로 진행하면 된다.
의존성의 순환이 발생하게 되면 숙취 증후군은 피할 수 없어진다.
의존성 순환이 발생이 된다면 인터페이스를 사용해 의존성을 역전 시키거나, 의존하는 클래스를 새로운 컴포넌트로 이동시킨다.
하향식 설계
컴포넌트는 하향식으로 설계 될 수 없으며, 컴포넌트는 시스템에서 가장 먼저 설계할 수 있는 대상이 아니며, 오히려 시스템이 성장하고 변경될 때 함께 진화.
컴포넌의 의존성 다이어그램은 애플리케이션의 기능을 기술하지 않고 빌드 가능성과 유지보수성을 보여주는 지도이다.
안정성의 방향으로 의존해야 한다.
소프트웨어에서 변경은 불가피한데, 이때 변경이 잦을 컴포넌트와 변경이 잦지 않은 컴포넌트를 잘 구분해야한다.
소프트웨어는 변경이 잦은 컴포넌트 보다는 변경이 적은 컴포넌트에 의존하도록 설계가 돼야 한다.
컴포넌트가 많은 컴포넌트에 의지할 수록 해당 컴포넌트는 불안정한 컴포넌트이다.
의존성의 방향으로 갈수록 I 지표 값이 감소해야한다.
컴포넌트는 안정된 정도만큼만 추상화되어야 한다.
안정적인 컴포넌트는 인터페이스와 추상 클래스로 구성되어 쉽게 확장할 수 있어야 한다.
안정된 컴포넌트가 확장이 가능해지면 유연성을 얻게 되고 아키텍처를 과도하게 제약하지 않게된다.
의존성은 추상화의 방향으로 향하게 해야한다.
추상화 정도
추상화 정도(A) = 컴포넌트의 추상 클래스와 인터페이스 개수/컴포넌트의 클래스 개수
추상화 정도 측정
1. 고통의 구역
D=|A+I-1|
D가 0에 가까울수록 이상적.
D가 0에서 가깝지 않다면 해당 컴포넌트는 재검토한 후 재구성할 수 있다.
D지표의 평균과 분산을 통해 다른 컴포넌트에 비해 예외적인 컴포넌트 추출 가능.
의존성 관리 지표를 통해, 설계의 의존성과 추상화 정도가 내가 생각하는 훌륭한 수준에 얼만큼 부합하는지 측정 가능.
하지만 이 지표는 절대적인 것이 아니라 내가 맞게 설계를 했는지 알게 해주는 참고 자료일뿐.