아키텍처 - 경계 S/W 설계

- 이 글은 로버트 C.마틴의 Clean Architecture를 기반으로 작성되었습니다. (가능하면 책을 읽어보는것을 추천한다.)

- 개요
소프트웨어 아키텍처는 경계 설정을 잘해야 한다. 경계는 요소를 분리하며, 특정 요소들끼리 서로 알지 못하게 한다. 어떤 경계 설정은 초기에 이루어 지며 어떤 경계 설정은 나중에 이루어진다.
초기의 섣부른 결정은 불필요한 결합을 만든다. 유스케이스와 관련없는 결정들, 예를 들어 프레임워크, DB, 웹 서버, 유틸리티 라이브러리등이 있다. 좋은 아키텍처는 이런 요소를 부수적인것으로 만들 수 있으며, 이런 결정을 최대한 미룬다. 또한 이런 결정이 변경됨에 따른 영향도가 크지 않게 만든다.
경계는 관련이 있는 것과 없는 것 사이에 긋는다. GUI, 업무규칙, 데이터베이스 이 세 가지는 서로 관련이 없기 때문에 이 사이에는 경계가 존재해야 한다.

- 업무규칙과 데이터베이스
업무규칙에 의해 데이터가 생성되고, 데이터를 불러와서 업무규칙을 수행하는데 왜 관련이 없느냐고 생각할 수도 있다. 하지만 데이터베이스는 업무규칙이 사용할 수 있는 도구에 불과하다.
위 다이어 그램을 보자. Business Rules는 Database Interface를 통해 데이터를 조회 및 저장한다. DatabaseAccess는 해당 인터페이스를 구현하며, 실제로 Database를 조작한다. 업무규칙이 알아야 하는 것은 데이터 조회 및 저장에 쓰이는 함수들이 있다는 정도만 알아야 한다.
그렇다면 우리가 주제로 다루고 있는 경계는 어디에 위치해야 할까?
위 다이어 그램에서 경계(Boundary) 는 Database Access와 Database Interface 사이에 존재한다. 왜 하필이면 이 사이에 존재해야 할까? 
Business Rules과 Database Interface 사이에 존재하면 안되는걸까? 오히려 이름으로만 보면 Database 라는 이름이 있으니 일리가 있어 보인다. 하지만 앞의 글을 제대로 보았던 사람이라면 왜 여기여야 하는지 알 수 있다.
Business Rules와 Database Interface를 Business Rules 라는 컴포넌트로 묶고, Database Access와 Database를 Database 컴포넌트로 묶고 그림을 다시 한번 보자.
저수준의 컴포넌트인 Database Component가 고수준의 컴포넌트인 Business Rules Component 에 의존하고 있다. 만약 Database Interface와 Business Rules 사이에 경계를 설정했다면 고수준의 컴포넌트가 저수준의 컴포넌트에 의존했을 것이다
여기서 이 화살표 방향이 무엇을 의미할까? 저수준의 컴포넌트가 고수준의 컴포넌트에 의존하면 뭐가 좋을까? 고객이 Oracle을 사용하다가 재정적 부담을 줄이기 위해 무료 데이터베이스로 변경한다고 해보자. 위와 같이 설계했다면 중요한 업무규칙에 영향을 미치지 않고 Database 컴포넌트를 변경할 수 있게 된다.

- 업무규칙과 GUI
고객은 시스템이 빨리 만들어 지길 원한다. 만약 우리가 업무규칙을 구현하고 그에 따른 데이터 저장 및 조회로직도 다 구현했다면 개발자들은 "이제 View단만 구현하면 되므로 거의 다 했다."라고 생각할것이다. 하지만 고객은 눈에 보이는게 없으므로 "아직 시작도 안했다"고 생각하거나 "별로 진척이 안됐네"고 생각한다. 
고객이 알아주면 정말 베스트이지만 그런 사람을 만날 가능성은 희박하다. 다만 고객은 그렇게 생각하지 않아도 개발자라면 당장 눈에 보이는 GUI 보다 업무규칙이 중요하다는 사실을 알아야 한다.
데이터베이스와 마찬 가지로 GUI 컴포넌트는 업무규칙 컴포넌트에 의존한다. 따라서 추가적인 다른 종류의 인터페이스가 필요하다면 얼마든지 추가하거나 교체할 수 있어야 하며, 이때 업무규칙에 영향을 주지 않아야 한다.

- 플러그인 아키텍처
여태까지 알아본 GUI, 업무규칙, DB간 관계를 한꺼번에 그리면 아래와 같은 다이어그램이 된다.
핵심적인 업무규칙은 분리된 채 GUI와 DB 컴포넌트는 플러그인 형태와 같이 설계되었다. 인터페이스를 콘솔이나 웹 기반으로 변경하거나 DB를 NoSQL이나 파일시스템으로 변경하는것도 가능하다. 물론 실제 구현은 말처럼 간단하진 않지만, 그래도 핵심적인 업무규칙에는 최대한 영향을 적게 줄 것이다.

- 결론
경계를 설정하려면 시스템을 컴포넌트 단위로 분할해야한다. 업무규칙이 중심 컴포넌트가 되며, 나머지는 유연하게 변경할 수 있는 컴포넌트가 된다. 이때 반드시 화살표(의존성)은 업무규칙을 향하도록하여 저수준의 컴포넌트가 고수준의 컴포넌트를 향해야 한다.

컴포넌트 결합 - SAP (안정된 추상화 원칙) S/W 설계

- 이 글은 로버트 C.마틴의 Clean Architecture를 기반으로 작성되었습니다. (가능하면 책을 읽어보는것을 추천한다.)

- 고수준의 정책
컴포넌트는 안정된 정도만큼만 추상화 되어야 한다.
시스템에서 업무규칙은 안정된 (I = 0, 즉 불안정성이 작은컴포넌트여야 한다. (I 개념을 모른다면 http://cplusplus5.egloos.com/6735907 글을 먼저 숙지해야 한다.) 업무규칙은 고수준의 정책이기 때문이다. 반면 불안정한(I = 1) 컴포넌트는 변동성이 큰 컴포넌트여야 한다.
이 문장만 읽었을 때 이상함을 느껴야 한다. "업무규칙은 안정된 컴포넌트 여야 한다"는 말이 당연한 얘기인가? 앞서 SDP 원칙에서 안정된 컴포넌트는 변경을 하기가 어렵다고 하였다. 그런데 SOLID 원칙에서는 고수준의 시스템의 업무규칙을 유연하게 하기 위해 인터페이스를 분리하거나, 단일 책임을 갖도록 하고, 의존성을 역전시키면서 온갖 난리를 쳤다. 이 얘기를 종합해보면 "업무규칙을 변경하기 어렵게 설계하라는 소리인가?라는 결론에 이른다.
컴포넌트가 안정적이면서도 변경에 유연하게 만들 수 있는가? 답은 SOLID-OCP 의 추상클래스에 있다. OCP 에서는 저수준의 컴포넌트가 고수준의 컴포넌트에 의존하게 하거나 정보 은닉을 위해 인터페이스를 사용하였다. 이점을 잘 생각해보길 바란다.

- SAP(안정된 추상화 원칙)
SAP는 이름 그대로 안정성과 추상화의 관계 정의이다. 안정된 것은 추상 컴포넌트이며, 불안정한것은 구체 컴포넌트이다. SAP와 SDP를 결합하면 컴포넌트에 대한 DIP 이다. 왜 이렇게 말을할 수 있는지 천천히 생각해보자. 이해를 쉽게 하기 위해 SDP, SAP, DIP 순으로 생각해보자.
  • SDP - 앞서 SDP 에서는 컴포넌트가 의존하는 쪽(화살표가 가리키는 쪽)의 I (불안정성)값이 낮아야 한다고 했다. 그렇다면 컴포넌트 관계에서 화살표 방향으로 갈수록 안정성이 있는 컴포넌트라는 말이 된다. 
  • SAP - 안정된것은 추상 컴포넌트라고 하였다. 이제 두 개를 조합해보면 "화살표 방향으로 갈수록 추상화 레벨이 커진다."는 얘기가 된다. 
  • DIP - 화살표 방향으로 갈수록 추상화 레벨이 커진다는 것은 DIP의 "구체 컴포넌트는 추상 컴포넌트에 의존해야 한다." 개념을 컴포넌트 레벨에서 적용했다는 의미이다.
SOLID - DIP의 추상화 정도는 0 아니면 1이다. 구체 클래스(Concrete Class) 이거나 추상 클래스(Abstract Class) 이기 때문이다. 반면 컴포넌트는 SDP와 유사한 개념으로 0 ~ 1 범위의 값을 가질 수 있다.

- 추상화 정도 측정
SDP에서 I 를 이용하여 불안정성을 나타내듯이 SAP에서는 A를 이용하여 추상화 정도는 나타낸다.
  • Nc: 컴포넌트의 클래스 개수(Concrete Class 뿐만이 아니라 인터페이스, 추상 클래스도 포함한다.)
  • Na: 컴포넌트의 추상 클래스 + 인터페이스
  • A: 추상화 정도, Na / Nc
A는 0 ~ 1 범위의 값을 가지며 0 이면 추상 클래스가 하나도 없음을 1 이면 모두 추상 클래스이거나 인터페이스임을 나타낸다.

- 추상화 정도와 불안정성
불안정성 I와 추상화 정도 A를 결합하여 A / I 그래프를 그려보자.
A 를 나타내는 Y축의 (0,1)은 안정적이고 추상화된 컴포넌트이며, I 를 나타내는 X축의 (1,0) 은 불안정하며 구체적인 컴포넌트이다. 사실 위의 그림에서 두 지역(고통의 구역과 쓸모없는 구역)은 사실 부채꼴모양인데 그리기가 귀찮아서 네모로 표시하였다.
  • 고통의 구역 : A (추상화 정도)가 낮아 구체적이면서 I (불안정성)가 낮아 타 컴포넌트에서 참조를 많이 하며 구체적인 컴포넌트라는 말이 된다. DB의 엔티티나 사용하는 라이브러리가 여기에 해당된다. DB의 엔티티는 변경가능성이 커서 고통스럽지만, 라이브러리는 보통 변동성이 크지 않아서 괜찮다. 사실은 변동성도 영향을 미치므로 또 하나의 축으로 생각할 수 있다.
  • 쓸모없는 구역 : A (추상화 정도)가 크면서 I (불안정성)도 큰 컴포넌트이다. 만약 여러분이 인터페이스를 정의했는데, 참조하는 컴포넌트가 없다면? 추상화를 한 의미가 있을까?
따라서 변동성이 큰 컴포넌트를 두 지역으로부터 떨어트리는것이 이상적이라 할 수 있겠다. 두 지역에서 가장 먼 지점은 어디일까? 바로 (0,1) -> (1,0)를 잇는 직선일 것이다. 컴포넌트들을 좌표계의 점으로 생각한다면 모니터링 할 수 있을까? 
점(해당 컴포넌트)과 이 직선사이의 거리를 구한다면 해당 컴포넌트가 얼마나 이상적인 직선에 가까운지, 아니면 고통의 구역이나 쓸모없는 구역에 가까운지 알 수 있을것이다.

- 주의점
다만 주의할 점이 있는데, 무조건 좋은것이라 이 지표를 맹신하면 부작용이 따를 수 있다는점이다. 
책임있는 아키텍처 설계자이거나 품질팀의 담당자라면 이 지표를 일종의 위험신호로 참고하면 될 일이다. 특히 사람이 많으면 지표를 정해놓고 무조건 따르라고 하거나 단순하게 수치를 넘으면 어떤 이유를 말해도 무시하는 경향이 있는데, 이는 실무팀을 무시하는점이 될 수 있다는 점에 유의해야 한다.

컴포넌트 결합 - SDP(안정된 의존성 원칙) S/W 설계

- 이 글은 로버트 C.마틴의 Clean Architecture를 기반으로 작성되었습니다. (가능하면 책을 읽어보는것을 추천한다.)

- 개요
더 안정된쪽으로 의존하라.
프로그램이 완성되거나 유지보수됨에 따라 설계는 계속 변한다. 초기에 변동성이 큰 컴포넌트를 만들었다고 가정하자. 추후 변경이 쉽지 않은 컴포넌트가 변동성이 큰 쪽에 의존한다면 어떨까? 
변동성이 큰 컴포넌트를 변경하면 변경이 쉽지 않은 컴포넌트도 영향을 받으므로 변경이 어렵게 된다. SDP(안정된 의존성 원칙)를준수하면 변경하기 어려운 모듈이 변경이 쉬운 모듈에 의존하지 않도록 만들 수 있다.

- 안정성
안정성이란 여러가지 의미가 될 수 있다. 책을 세웠다고 가정해보자. 이 책을 쓰러트리려면 대단한 수고를 들여야할까? 그렇지 않다. 손가락 하나도 밀어도 눕힐 수 있다. 반면 냉장고를 눕히려면 대단한 에너지를 소모해야 한다. 이런관점에서 안정성이란 어떤 물체에 행위를 가해서 해당 물체의 상태를 변화시키는데 큰 에너지가 소모된다면 그 물체는 안정적이라고 할 수 있다.
소프트웨어 컴포넌트 관점에서 생각해보자. 우리가 흔히 개발을 하다가 어떤 요청을 받을 때 이렇게 말해본적이 있을 것이다. "그건 변경하기가 어려워요. 이거 바꾸면 다른소스에서 영향을 너무 많이 받아서 테스트 다 다시해야합니다."
이 말을 고상하게 표현하면 컴포넌트 안쪽으로 들어오는 의존성이 크면 그 컴포넌트는 안정적이다. (해당 컴포넌트를 사용하는 다른 컴포넌트가 많다면 해당 컴포넌트는 안정적이다.)
세 컴포넌트가 Stable Component 에 의존하고 있다. 이 말을 다르게 표현하면 Stable Component는 Component1, 2, 3 을 책임진다. Stable Component 를 변경하면 세 컴포넌트가 영향을 받아 변경하기가 어려우므로(에너지가 많이 소모해야하므로) Stable Component 는 안정적이다. 냉장고를 눕히는 것과 같다.
반대로 Unstable Component는 불안정한 컴포넌트라고 할 수 있다. 책임지는 컴포넌트가 없으며, 변경해도 영향받는 컴포넌트가 없다. 해당 컴포넌트를 변경해도 영향 받는 컴포넌트가 없어 변경이 쉽다. 마치 책을 눕히는것과 같다.

- 지표
안정성에 대해 한 가지 생각해볼 문제가 있다. 프로젝트 마다 규모가 다른데 단순히 참조 되는 개수로 안정하다 불안정하다라고 할 수 있을까? 자신이 참조되면서 동시에 의존하는 컴포넌트들도 있다면 이 컴포넌트는 안정적일까 불안정할까? 
참조 되는것과 의존하는 것 그리고 안정성에 대한 정의를 알아보자.
  • Fan-in: 안으로 들어오는 의존성(화살표가 들어오는 개수를 나타낸다.)
  • Fan-out: 바깥으로 나가는 의존성(화살표가 나가는 개수를 나타낸다.)
  • I(불안정성): I = Fan-out / (Fan-in + Fan-out), 나가는 의존성 / 전체 개수이다. 비율이기 때문에 0에서 1의 범위를 갖는다. 이 값이 클수록(1에 가까울수록) 전체 의존성 개수 대비 나가는 의존성이 크기 때문에 불안정한 컴포넌트다.
여기서 생각하는 방식에 따라 헷갈릴 가능성이 있다. 우리는 유지보수를 할 때 "이 소스는 변경해도 다른 소스에 영향을 주지 않기 때문에 변경해도 안전하다." 라고 생각할수도 있다. 이 말은 안정적이라는 말을 다른 소스에 영향을 주는 정도의 측면에서 생각한것이다. 컴포넌트 SDP 원칙에서 안정성을 언급할 때에는 앞에서 말했듯이 해당 컴포넌트를 변경하는데 소모해야 하는 에너지 관점에서 생각해야 한다.
C 컴포넌트의 I(불안정성) 를 계산해보자. Fan-in은 3이고 Fan-out은 1이다. 따라서 I = Fan-out / (Fan-in + Fan-out) = 1/4 이 된다.
I(불안정성) 값이 1이라면 불안전한 컴포넌트이다. 해당 컴포넌트에 의존하는 컴포넌트가 없으므로, 변경하기가 쉽다. 
반면 I(불안정성) 값이 0이라면 안정성이 큰 컴포넌트이다. 해당 컴포넌트는 의존하는 컴포넌트만 있으므로, 변경하기가 어렵다.
SDP에서는 I (불안정성) 값이 해당 컴포넌트가 의존하는 다른 컴포넌트보다 커야 한다고 말한다. 이 말을 다이어그램측면에서 생각하면 화살표 방향으로 갈수록 안정성이 큰 컴포넌트여야 한다는(I, 즉 불안정성 값이 작아져야 한다.)의미가 된다.

- 안정성의 오해
"안정적이다"라는 어감은 긍정적인 느낌을 준다. 그렇다면 모든 컴포넌트를 안전성있게 만들면 되는걸까?
"모든 컴포넌트가 안정적이다" 라는 얘기는 앞의 정의에 따르면 모든 컴포넌트의 변경이 어렵다는 말이며, 프로그램을 변경하기 힘들다는 의미이다.
좋은 설계는 안정적인 컴포넌트와 불안정한 컴포넌트가 함께 존재하는 것이다.
다이어그램에서는 관례적으로 불안정한 컴포넌트를 위에 둔다. I (불안정성)의 값은 해당 컴포넌트가 의존하는 다른 컴포넌트보다 커야 한다. 라는 법칙에 따라 위 다이어그램의 설계는 상당히 이상적이라 할 수 있다.
반면 이 다이어그램은 그렇지 않은데 I (불안정성)가 1/4 인 컴포넌트가 I (불안정성)가 1인 컴포넌트를 참조하고 있기 때문이다. 그냥 이대로 쓰면 안되는걸까? I (불안정성)가 작은값이 I (불안정성)가 큰값을 참조하는게 뭐가 그렇게 잘못됐을까?
D 컴포넌트가 자주 변경되는 컴포넌트 일수도 혹은 아닐수도 있다. 하지만 일단 D가 변경이 되면 C가 영향을 받고, C가 영향을 받으면 이에 의존하던 A, B가 영향을 받는다.

- 해결법
눈치가 빠른 사람이라면 화살표 방향을 바꾸면 위 문제가 해결될 것 같다라는 것을 꼭 논리적으로 깊게 생각해보지 않아도 직감적으로 생각해볼 수 있다. 화살표의 방향을 바꾸는 거라면 SOLID의 DIP 원칙을 이용하면 되지 않을까?
CD 컴포넌트를 보자. C1 에서 D1에 대해 사용하는 메소드를 정의한 D1 Interface 인터페이스를 만들고, D 컴포넌트의 D1이 해당인터페이스를 구현한다. 이렇게 되면 의존하는 방향으로 가면서 I (불안정성) 값이 작아져야 한다는 법칙을 따르게 된다. 이제 D 컴포넌트를 변경해도 C, A, B에 연쇄적으로 영향을 주지 않는다.


컴포넌트 결합 - ADP(의존성 비순환 원칙) S/W 설계

- 이 글은 로버트 C.마틴의 Clean Architecture를 기반으로 작성되었습니다. (가능하면 책을 읽어보는것을 추천한다.)

- 개요
컴포넌트 의존성 그래프에 순환이 있어서는 안 된다.
소스를 수정한 후, 테스트를 하고 뿌듯한 마음으로 퇴근을 하였다. 그런데 다음날 회사에 와서 보니 소스가 수정한대로 동작하지 않는다. 이게 뭔일이지 하고 원인을 추적해보니 다른사람이 고친 부분때문에 내 코드가 동작하지 않는다.
작은 프로젝트에서는 이런일이 일어날 가능성이 작고, 일어난다고 해도 금방 고칠 수 있다. 하지만 프로젝트가 크면 문제가 심각해진다.
이를 위한 해결책에 두 가지 방법이 있다. 첫번째는 주 단위 빌드이며, 두번째는 의존성 비순환 원칙(ADP)이다.

- 주 단위 빌드
주 단위 빌드 과정은 다음과 같다. 4일동안 개발자는 소스를 수정한다. 그러다 마지막 금요일이 되면 소스를 통합한다. 프로그램 규모가 작은 초기에는 순조롭게 진행된다. 하지만 프로그램은 커지고 점차 소스 통합이 오래 걸리기 시작한다. 상황이 심각해지면 개발자들은 금요일 하루에 소스통합이 불가능해져 목요일부터 수행하기 시작한다.
상황은 점점 악화되고, 빌드 일정은 점점 늘린다.

- 컴포넌트 의존성
이 문제 해결책은 릴리스 가능한 컴포넌트 단위로 분리하는것이다. 컴포넌트는 특정 개발 담당자나, 큰 규모 프로젝트의 경우 개발팀이 관리한다.
개발자는 자신의 컴포넌트를 개발한 후 릴리스 한다. 이에 번호를 부여하고, 타 컴포넌트에서 자신의 컴포넌트를 사용할 수 있도록 한다. 
타 컴포넌트 담당자는 해당 컴포넌트가 릴리스 될 때, 그것을 곧바로 적용할 지 아니면 추후 적용할 지 판단한다. 이렇게 서로 즉각적인 영향없이 작업이 진행된다.
컴포넌트만 분리된다고 문제가 해결되는것은 아니다. 이 전략을 성공적으로 수행하려면 컴포넌트 간의 의존성을 관리해야한다. 아래 다이어그램을 보도록 하자.
위 다이어그램에서 각 컴포넌트를 정점으로 생각하고, 의존성을 간선으로 생각하면 방향 그래프가 된다. 
이 간선의 의미는 간선의 출발지가 간선의 목적지 컴포넌트에 영향을 받는다는 얘기가 된다. Interactor 컴포넌트 개발자가 릴리스를 새로 찍으면 Interfactor에 의존하던 Main, Controller, Authorizer, Database 컴포넌트가 모두 영향을 받는다.
전체 시스템을 빌드해야 하는 상황이오면 상향식으로 빌드 한다. 위 그래프에서는 Entities 를 먼저 빌드 후, Interactor를 그리고 Database, Authorizer, Controller, Main 으로 빌드한다. 그래프를 탐색하면서 차수를 기록해둔다면, 차수가 높은것에서 낮은순 방향으로 빌드를 하면 되겠다. 

- 순환의 문제점
만약 기능이 변경되어 Entities가 Authorizer를 사용한다면 다이어그램은 아래와 같다. 이 때 Interactor, Entities, Authorizer에 생기는 순환때문에 문제가 발생한다.
Database 컴포넌트 담당자는 자신의 컴포넌트가 Interactor 에 영향을 받는다는 사실을 알고 있다. Interactor는 Entities에, Entities는 Authorizer에, Authorizer는 Interactor에 영향을 받는다. 기껏 영향을 적게 받으려고 컴포넌트로 분리해놓았는데 하나의 거대한 컴포넌트가 되어버렸다.
또 앞에서 전체 빌드시 차수가 높은 순에서 낮은 순으로 빌드를 해야 한다고 했는데, 어떤 순서로 빌드를 먼저 해야할지도 상황이 애매해졌다.

- 해결책
인터페이스를 이용하여 DIP(의존성 역전)로 Entities와 Authorizer 컴포넌트의 의존 관계를 역전시킨다. 이 때 인터페이스는 Entities에 이 인터페이스를 상속받는 파일을 Authorizer 컴포넌트에 위치한다.
또 다른 해결책은 아래와 같이 새로운 New Component 를 따로 분리하여 의존 관계에 순환이 생기지 않게 재설정한다.

- 컴포넌트 의존관계 설계 시점
흔히 하는 착각중에 하나가 시스템의 전체적인 컴포넌트를 설계 하고, 프로그램을 작성한다는것이다. 컴포넌트 의존성 다이어그램은 기능사이의 상관관계를 표현한것이 아니다. 빌드 가능성 및 유지보수성과 관련이 있다. 유지보수할 프로그램이 없는 프로젝트 초기에 빌드 가능성과 유지보수를 미리 설계하는가?
프로젝트가 진행됨에 따라 컴포넌트가 늘어나고 시스템 변경범위를 줄이기 위해 SRP(단일 책임)와 CCP(공통 폐쇄)를 적용한다.
여기서 더 진행이 되면 재사용 가능한 요소를 만드는 일에 집중한다. 이 때 CRP(공통 재사용)이 관여하기 시작한다. 이런 컴포넌트 의존관계 설정시점을 관찰하다가 순환 관계가 생기면 ADP를 적용하여 순환을 제거해야 한다.

컴포넌트 - 응집도(REP, CCP, CRP) S/W 설계

- 이 글은 로버트 C.마틴의 Clean Architecture를 기반으로 작성되었습니다. (가능하면 책을 읽어보는것을 추천한다.)
- https://adriancitu.com/tag/the-reuse-release-equivalence-principle/

- 개요
우리는 프로그램을 개발할 때 어떤 클래스를 어떤 컴포넌트에 포함시킬것이가에 대해 진지하게 생각해보지 않는다. 
사실은 엔지니어링 원칙을 고려해보면서 생각해보아야 하지만 몰라서 고려하지 않을 수도 있고, 귀찮아서 하지 않을 수도 있다. 컴포넌트 응집도에는 아래와 같이 세 가지의 원칙이 있다.
  • REP: 재사용/릴리스 등가 원칙
  • CCP: 공통 폐쇄 원칙
  • CRP: 공통 재사용 원칙

- REP: 재사용/릴리즈 등가 원칙
재사용 단위는 릴리스 단위와 같다.
소프트웨어 컴포넌트가 릴리스를 통해 추적 관리 되지 않거나, 릴리즈 번호가 없다면 사용하는 입장에서 혼돈에 빠질것이다. 우리는 버전명과 릴리스 노트를 보고 해당 컴포넌트를 신규버전으로 업데이트 할지 그대로 사용할지를 결정한다.
아키텍처 관점에서 이 원칙을 생각해보면 단일 컴포넌트는 응집성 높은 클래스와 모듈들로 구성되어야 함을 의미한다. 클래스들을 아무거나 선택해서 컴포넌트로 묶으면 안된다는 뜻이다.
이 원칙은 너무도 당연해서 어기면 안된다는 늬앙스가 강하다. 하지만 이 원칙자체는 아키텍처 설계에 있어서 중요하다.

- CCP: 공통 폐쇄 원칙
동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어라. 
어디서 많이 들어본말이지 않은가? SOLID 원칙중 SRP 원칙을 컴포넌트 레벨에서 적용한것이다.
대다수 어플리케이션에서 유지보수는 매우 중요하다. 어떤 요구사항이나 이유로 코드를 변경할 때, 여러 컴포넌트를 모두 변경하는것이 아니라 단일 컴포넌트만 변경할 수 있도록 설계 했다면 훌륭한 설계라 할 수 있다.
배포 측면에서도 해당 컴포넌트만 배포하면 되기 때문에 작업이 훨씬 수월하다. 테스트를 할 때에도 여러 컴포넌트가 수정되면 해당 컴포넌트들은 모두 테스트를 다시 해야 한다.
CCP는 컴포넌트 수준에서의 SRP이다. SRP에서는 클래스는 다른 이유로 변경되는(다른 액터에 의해서 변경되는) 메소드를 클래스로 추출, 분리하라고 말한다. CCP 에서는 서로 다른 이유로 변경되는 클래스들을 다른 컴포넌트로 분리하라고 말하고 있다.
동일 시점 및 동일 이유로 변경되는 것들을 한데로 묶고, 다른 시점 및 다른 이유로 변경되는 것들을 분리하라.

- CRP: 공통 재사용 원칙
컴포넌트 사용자들을 필요하지 않은 것에 의존하게 하지 마라.
CCP와 SRP의 유사성처럼 SOLID를 조금이나마 기억하고 있다면 위 문구를 보고 ISP 원칙을 떠올릴 수 있어야 할것이다. 앞서 SOLID-ISP 원칙 에서 사용자들이 필요하지 않은 행위에 의존하지 않게 하기 위해 각 사용자별로 인터페이스를 만들고, 각 사용자들이 필요한 행위의 메소드들만 인터페이스에 정의하여 분리하였다. CRP는 ISP의 컴포넌트 레벨의 버전인셈이다.
CRP 에서는 재사용되는 경향이 있는 클래스와 모듈을 같은 컴포넌트로 배치해야 한다고 말한다. 예를 들어 컨테이너 클래스와 클래스의 이터레이터는 서로 강결합이라 함께 재사용된다. 따라서 이들 클래스는 동일 컴포넌트에 위치해야 한다.
필요하지 않은 것에 의존하지 말라.

- 컴포넌트 응집도 다이어그램
REP와 CCP는 포함원칙이며, CRP는 배제원칙이다. 이들 세 원칙은 서로 상충된다. 아래 그림은 응집도와 관련한 원칙에서 유명한 다이어그램이다. 각 변은 맞은편 정점을 포기했을 때 치뤄야 하는 댓가를 나타내고 있다.
REP와 CRP에만 중점을 두면 사소한 변경시에 너무 많은 컴포넌트에 영향(그림에서 Too many components change)을 미친다.
CCP와 REP에만 중점을 두면 릴리스(그림에서 Too many unneeded releases)가 너무 빈번해진다.
프로젝트 초기에는 재사용성 보다는 생산성이 중요하다. 위의 그림에서 오른쪽(CCP)에 중점적인 가치를 둔다. 프로젝트가 완료되어 유지보수하거나 해당 프로젝트로 부터 고도화나 또 다른 프로젝트가 파생되면 왼쪽(REP)이 중요해진다. 

- 결론
어떤 클래스들을 묶어서 컴포넌트로 만들 때 재사용성과 개발성이라는 상충하는 힘을 고려해야한다. 또한 지금 내가 중점적으로 두고 있는 가치가 시간이 흐름에 따라 변할 수도 있다는 사실을 명심하고 균형을 맞추도록 노력해야한다.

1 2 3 4 5 6 7 8 9 10 다음