컴포넌트 응집도
응집력은 뭘까? 같은 종류의 분자나 원자들이 서로 끌어당겨 뭉치는 성질이다.

프로그래밍의 응집도는 여기서 왔다. 응집도는 모듈 내의 요소들이 얼마나 밀접하게 관련되어 하나의 책임을 수행하는지 나타내는 정도이다. 동일한 목적을 위해 긴밀하게 협력할수록 높은 응집도를 가졌다고 한다.
어떤 클래스를 어느 컴포넌트에 포함시켜야 할까? 이는 중요한 결정이므로 제대로 된 소프트웨어 엔지니어링 원칙의 도움을 받아야 한다.
- REP: 재사용/릴리스 등가 원칙 (Reuse/Release Equivalence Principle)
- CCP: 공통 폐쇄 원칙 (Common Closure Principle)
- CRP: 공통 재사용 원칙 (Common Reuse Principle)
REP: 재사용/릴리스 등가 원칙
재사용 단위는 릴리스 단위와 같다.
우리는 이제 소프트웨어 재사용의 시대에 살고 있다.
돌이켜 보면 재사용/릴리즈 등가 원칙(REP)은 너무 당연해 보인다. 컴포넌트가 릴리스 절차를 통해 추적 관리되지 않거나 릴리스 번호가 부여되지 않는다면 재사용하고 싶어도 할 수도 없고 하지도 않을 것이다.
릴리스 번호가 없다면 재사용 컴포넌트들이 서로 호환되는지 보증할 방법이 없다. 그 무엇보다 새 버전이 언제 출시되고 무엇이 변했는지를 개발자들이 알아야 하기 때문이다.
CCP: 공통 폐쇄 원칙
동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어라. 서로 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 분리하라.
어디서 많이 본 것 같지 않은가? 이는 단일 책임 원칙(SRP)을 컴포넌트 관점에서 다시 쓴 것이다. 단일 클래스의 변경 이유가 여러 개 있어서는 안되는 것처럼 이 원칙에서도 단일 컴포넌트는 변경의 이유가 여러 개 있어서는 안된다고 말한다.
대다수의 애플리케이션에서 유지보수성(maintainability)은 재사용성보다 훨씬 중요하다. 코드가 반드시 변경되어야 한다면, 이러한 변경이 여러 컴포넌트 도처에 분산되어 발생하기보다는, 차라리 변경 모두가 단일 컴포넌트에서 발생하는 편이 낫다.
CCP는 같은 이유로 변경될 가능성이 있는 클래스는 모두 한곳으로 묶을 것을 권한다. 물리적 또는 개념적으로 강하게 결합되어 항상 같이 변경되는 클래스들은 하나의 컴포넌트에 속해야 한다.
이 원칙은 개방 폐쇄 원칙(OCP)과도 밀접하게 관련되어 있다. CCP에서의 폐쇄와 OCP에서의 폐쇄는 같은 단어고 그 뜻이 같다.
100% 완전한 폐쇄란 불가능하므로 발생할 가능성이 있거나 과거에 발생했던 대다수의 공통적인 변경에 대해서 닫혀 있도록 전략적인 설계가 필요하다.
SRP와의 유사성
CCP는 컴포넌트 수준의 SRP다. SRP는 서로 다른 이유로 변경되는 메소드를 서로 다른 클래스로 분리하라고 한다. CCP는 서로 다른 이유로 변경되는 클래스를 서로 다른 컴포넌트로 분리하라고 한다. 두 원칙은 다음과 같은 교훈으로 요약할 수 있다.
동일 시점에 동일 이유로 변경되는 것을 한데 묶어라. 다른 시점에 다른 이유로 변경되는 것들은 서로 분리하라.
CRP: 공통 재사용 원칙
컴포넌트 사용자들을 필요하지 않는 것에 의존하게 강요하지 말라.
공통 재사용 원칙(CRP)도 클래스와 모듈을 어느 컴포넌트에 위치시킬지 결정할 때 도움이 되는 원칙이다. CRP에서는 같이 재사용되는 경향이 있는 클래스와 모듈들은 같은 컴포넌트에 포함해야 한다고 말한다.
개별 클래스가 단독으로 사용되는 경우는 잘 없다. 보통 재사용 가능한 클래스는 재사용 모듈의 일부로써 해당 모듈의 다른 클래스와 상호작용하는 경우가 많다. CRP에서는 이런 클래스들이 동일한 컴포넌트에 포함되어야 한다고 말한다.
반대로 CRP는 동일한 컴포넌트로 묶어서는 안되는 클래스가 무엇인지도 말해준다. 어떤 컴포넌트가 다른 컴포넌트를 사용하면, 둘 사이엔 의존성이 생겨난다. 어쩌면 다른 컴포넌트에서 단 하나의 클래스만 사용할 수도 있다. 그렇다해서 의존성이 전혀 약해지지는 않는다.
이는 변경, 재컴파일, 재검증, 재배포를 해야하는 가능성이 여전히 남아있다는 것을 말해준다. 따라서 의존하는 컴포넌트가 있다면 해당 컴포넌트의 모든 클래스에 대해 의존함을 확실히 인지해야 한다.
따라서 CRP는 묶어도 되는 것보다는 묶어서는 안되는 것을 더 크게 이야기 한다.
ISP와의 관계
CRP는 인터페이스 분리 원칙(ISP)의 포괄적인 버전이다. ISP는 사용하지 않는 메소드가 있는 클래스에 의존하지 말라고 한다. CRP는 사용하지 않는 클래스를 가진 컴포넌트에 의존하지 말라고 한다. 그 둘을 정리하면 아래와 같은 교훈을 얻을 수 있다.
필요하지 않은 것에 의존하지 말라.
컴포넌트 응집도에 대한 균형 다이어그램
아마도 응집도에 관한 세 원칙이 서로 상충된다는 사실을 눈치챘을 거라고 본다. REP와 CCP는 포함(inclusive) 원칙이다. 즉, 두 원칙은 컴포넌트를 더욱 크게 만든다. CRP는 배제(exclusive) 원칙이며, 컴포넌트를 더욱 작게 만든다.

REP와 CRP에만 중점을 두면, 사소한 변경이 생겼을 때 너무 많은 컴포넌트에 영향을 준다. 반대로 CCP와 REP에만 집중하면 불필요한 릴리스가 너무 빈번해진다.
뛰어난 아키텍트라면 개발팀이 현재 관심을 기울이는 부분을 충족시키는 위치를 찾아야 하며, 이 또한 시간이 흐르면서 주의를 기울이는 부분 역시 변한다는 사실도 이해하고 있어야 한다. 초기에는 CCP가 REP보다 훨씬 중요한데, 개발 가능성(developability)가 재사용성보다 중요하기 떄문이다.
일반적으로 프로젝트는 삼각형의 오른쪽에서 시작하는 편이며, 이때는 오직 재사용성만 희생하면 된다. 프로젝트가 성숙하면서 삼각형이 점차 왼쪽으로 이동해간다. 즉, 프로젝트의 컴포넌트 구조는 시간과 성숙도에 따라 변한다.
결론
우리는 과거에 응집도를 '모듈은 단 하나의 기능만 수행해야 한다'는 속성 정도로 단순하게 이해한 적도 있다. 하지만 컴포넌트 응집도에 관한 세 가지 원칙은 응집도가 가질 수 있는 훨씬 복잡한 다양성을 설명해준다.
컴포넌트를 만들 때 재사용성과 개발 가능성이라는 상충되는 점을 반드시 고려해서 균형을 잡아야 한다. 이 균형은 거의 항상 유동적이며 프로젝트의 성숙도에 따라 초점이 바뀌어 컴포넌트를 구성하는 방식도 진화한다.