본문 바로가기
SW core/SW Architecture

컴포넌트 결합 - SDP(안정된 의존성 원칙)

by ocwokocw 2021. 2. 10.

- 이 글은 로버트 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에 연쇄적으로 영향을 주지 않는다.

댓글