본문 바로가기

클린 아키텍처

4부 컴포넌트 원칙 - 컴포넌트 결합도

컴포넌트의 결합도

컴포넌트사이의 관계를 설명한다

 

ADP : 의존성 비순환 원칙

컴포넌트 의존성 그래프에 순환이 있어서는 안 된다.

소스코드를 작동하도록 작성하였는데 내 코드가 의존하는 소스가 누군가에 의해 수정되어 정상 작동하지 않는 것을 숙취 증후군이라고 한다. 이러한 숙취 증후근을 피하기 위한 해결책은 두가지가 있다. 주단위 빌드와 ADP이다.

 

주단위 빌드

각각의 개발자는 4일간 서로 신경쓰지 않고 개발한다. 그후 5일 째되는날(아마 금요일)에 통합 후 빌드한다.

  • 장점 : 
    • 4일간 독립된 상태에서 개발 할 수 있다.
  • 문제점 :
    • 프로그램이 커질 수록  통합하는 시간이 늘어난다.
    • 시간이 갈 수록 빌드 일정을 계속 늘려야한다.
    • 통합과 테스트가 프로그램이 커질 수록 어려워 진다.
    • 이에 팀이 주는 빠른 피드백의 장점이 사라진다.

ADP

순환 의존성 제거하기

위 주단위 빌드의 문제점을 해결하는 해결책은 릴리스 가능한 컴포넌트 단위로 분리하는 것이다.(이 컴포넌트는 개별 개발자 혹은 단일 개발팀이 책임 질수 있는 작업 단위이다.)

  • 장점
    • 개발자는 독립된 상태에서 개발 할 수 있다.
    • 릴리지 되어 있는 버전이 있으므로 릴리즈를 결정 할 수 있다.
    • 통합또한 작고 점진적으로 이루어진다.
  • 주의점
    • 의존성에 순환이 있으면 안된다. 순환이 있다면 숙취증후근이 발생한다.

이상적인 컴포넌트 의존성의 예

 

이상적인 컴포넌트 의존성 그래프

컴포넌트의 의존선 그래프는 DAG를 형성해야한다.

 

순환이 컴포넌트 의존성 그래프에 미치는 영향

순환이 생긴 그래프

위 그림과 같이 Entiest,Autorizer,Interactors가 순환하고 있다. 위와 같이 순환이 존제한다면 예를 들어 Database를 릴리스 하고자 한다면 Entites컴포넌트와 호환 되어야하는데 Entites는 Autorizer를 의존하므로 DB는 Entites와 Autorizer둘다 호환되어야 한다. Autorizer는 Interactors에 의존하므로 DB는 이 3개다 호환되어야 한다고 볼 수 도 있다.

이처럼  Entiest,Autorizer,Interactors위 3개의 컴포넌트들은 하나으 큰 컴포넌트처럼 되어 버렸다. 개발자는 3개중 하나를 수정하더라도 숙취 증후근을 경험하게된다.

 

문제점 

  • 테스트,통합,빌드가 어려워진다.
  • 에러가 쉽게 발생한다.
  • 어떤순서로 빌드하면되는지 파악하기 어려워 진다.

순환 끊기

순환을 DAG로 원상복구하는 방법을 두가지 살펴보자

 

1. DIP를 적용한다.

위 처럼 Enities 컴포넌트가 필요로 하는 메소드를 제공하는 인터페이스를 Entites에 생성하여 사용하고 그것을 다른컴포넌트가 상속받아서 사용한다 그렇게되면 의존성의 방향은 역방향으로 나아가 순환이 사라지게 된다.

 

2.두 컴포넌트가 의존하는 하나의 컴포넌트를 생성한다.

위처럼 두 컴포넌트가 하나의 컴포넌트에 의존하도록 하나의 컴포넌트를 생성하고 두 컴포넌트의 의존성을 수정한다. 그렇게되면 위 그림처럼 사이클이 사라지게 된다.

 

SDP: 안정된 의존성 원칙

더 안정된 쪽에 의존하라.

OCP에서 보았듯이 변경에서 완전히 벗어나는 건 불가능하다. 하지만 어떠한 컴포넌트가 변경이 쉽게 설계되었을 때 변경이 어려운 컴포넌트가 변경이 쉬운 컴포넌트를 의존하는 순간 이 컴포넌트는 변경이 어려워진다. 이러한 문제를 해결하는 것이 SDP이다.

 

안전성

웹스터의 사전에서 안정성은 "쉽게 움직이지 않는"이라고 정의한다.

소프트웨어에서 안정성은 무엇인가? 여러가지가 있지만 이번에는 한가지에만 주목하겠다. 어떤 컴포넌트에 여러가지 컴포넌트가 의존한다면 해당 컴포넌트가 변경이 되면 다른 컴포넌트가 영향을 받기에 변경을 해서는 안되는 이유가 여러가지가 생긴다. 이처럼 변경이 힘든 컴포넌트를 안정된 컴포넌트라고 할 수 있다.

안정된 컴포넌트

안정되지 않은 컴포넌트는 반대이다. 다른 컴포넌트에 많이 의존하는 컴포넌트를 말한다.

불안정한 컴포넌트

 

안정성 지표

안정성을 측정할수있는 방법을 제시한다.

Fan-In : 안으로 들어오는 의존성. 컴포넌트 외부의 클래스가 내부의 클래스에 의존하는 외부클래스의 개수

Fan-Out : 밖으로 나가는 의존성. 컴포넌트 내부에서 외부 컴포넌트 클래스에 의존하는 내부클래스의 개수

 I: 불안정성 I가 0이면 안정된 컴포넌트이며 1이면 불안정한 컴포넌트이다. 

계산법 I=Fan-Out/(Fan-In+Fan-out)

 

모든 컴포넌트가 안정적이여야 하는 가?

모든 컴포넌트가 최고로 안정적인 스스템이라면 변경이 불가능하다. 이는 바람직하지 못하다. 우리가 구조를 설계할때 기대하는 것은 안정적이 컴포넌트와 불안정한 컴포넌트가 둘다 있는 구조이다.

 

SAP: 안정된 추상화 원칙

컴포넌트는 안정된 정도만큼만 추상화되어야 한다.

안정된 추상화 원칙(Stable Abstractions Principle, SAP)은 안정성(stability)과 추상화 정도(abstractness) 사이의 관계를 정의한다.

 

고수준 정책을 어디에 위치시켜야 하는가?

 

시스템에서는 자주 변경해서는 절대 안되는 소프트웨어도 있다. 고수준 아키텍처나 정책 결정과 관련된 소프트웨어가 그 예다.

그렇다고 해서 고수준 정책을 안정된 컴포넌트에 위치시키면, 그 정책을 포함하는 소스코드는 수정 하기가 어려워진다. 컴포넌트가 최고로 안정된 상태이면서도(I=0) 동시에 변경에 충분히 대응할 수 있을 정도로 유연하게 만들 수 있는 방법은 OCP(개방폐쇄원칙)에서 찾을 수 있다.

 

안정된 추상화 원칙

안정된 추상화 원칙(Stable Abstractions Principle, SAP)은 안정성(stability)과 추상화 정도(abstractness) 사이의 관계를 정의한다.
안정된 컴포넌트는 추상 컴포넌트여야 하며, 안정성이 컴포넌트를 확장하는 일을 방해해서는 안 된다고 말한다.
불안정한 컴포넌트는 반드시 구체 컴포넌트여야 하며, 불안정하므로 컴포넌트 내부의 구체적인 코드를 쉽게 변경할 수 있어야 하기 때문이다.
SAP와 SDP를 결합하면 컴포넌트에 대한 DIP나 마찬가지가 된다.

실제로 SDP에서는 의존성이 반드시 안정성의 방향으로 향해야 한다고 말하고 SDP에서는 안정성이 결국 추상화를 의미한다고 말하기 때문이다

 

추상화 정도 측정

A:추상화 정도이다

Nc : 컴포넌트 클래스의 개수

Na : 추상클래스와 인터페이스의 개수

A= Na/Nc

 A가 0이라면 컴포넌트에 추상클래스와 인터페이스가 하나도 없다는 뜻이며,A가 1이면 전체가 인터페이스와 추상클래스라는 의미이다.

.

주계열

아래 그림은 안정성(I)과 추상화 정도(A) 사이의 관계 그래프다.

최고로 안정적이며 추상화된 컴포넌트는 (0, 1)에 위치한다.
최고로 불안정하며 구체화된 컴포넌트는 (1, 0)에 위치한다.

 

모든 컴포넌트가 이 두 지점에 위치하는 것은 아니다.
아래 그림의 궤적은 컴포넌트가 절대로 위치해서는 안 되는 영역, 배제할 구역이다.

고통의 구역

(0, 0) 주변 구역에 위치한 컴포넌트는 매우 안정적이며 구체적이다. 뻣뻣한 상태이다. 추상적이지 않아서 확장할 수 없고, 안정적이므로 변경하기 상당히 어렵다.
(0, 0) 근처에 위치한 소프트웨어는 구체적인 유틸리티 라이브러리이다.
하지만 변동성이 없는 컴포넌트는 (0, 0) 구역에 위치하더라고 해롭지 않다. 변동될 가능성이 없기 때문이다.

 

쓸모없는 구역

(1, 1) 주변의 컴포넌트는 최고로 추상적이지만, 누구도 그 컴포넌트에 의존하지 않는다.
이러한 컴포넌트는 쓸모가 없다.
따라서 이 구역은 쓸모없는 구역이라고 부른다.

 

배제 구역 벗어나기

변동성이 큰 컴포넌트 대부분은 두 배제 구역으로부터 가능한 한 멀리 떨어뜨려야 한다.
최대한 멀리 떨어진 점의 궤적은 (1, 0)과 (0, 1)을 잇는 선분이다.
주계열 위 또는 가깝게 위치해야 하며, 이렇게 위치하면 '너무 추상적'이지도 않고, 추상화 정도에 비해 '너무 불안정'하지도 않다.

 

주계열과의 거리

D : 주계열로부터의 거리

D = | A + I - 1 |

D가 0이면 컴포넌트가 주계열 바로위에 위치하며, 1이면 주계열로부터 가장 멀리 위치함을 뜻한다.