[Clean Architecture] 14장 컴포넌트 결합

soohee·2022년 5월 11일
0

클린아키텍처

목록 보기
13/15

ADP : 의존성 비순환 원칙

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

동일한 소스코드를 여럿이 건드리면, 서로의 코드에 의존성이 생길 수 있다.

이때, 해결책으로는 두가지가 있다.

주단위 빌드

  • 중간규모 프로젝트에서 흔히 사용
  • 월-목에 각자 코딩, 금 - 통합 및 빌드

장점 : 빠른 피드백 및 서로 신경안쓰고 편하게 개발가능

단점 : 프로젝트 통합하는데 오래걸림.

순환 의존성 제거하기

개발 환경을 릴리스 가능한 컴포넌트 단위로 분리

  • 의존성 구조에 순환이 있으면 안됨.

  • 컴포넌트 다이어그램 설명
    • 이 구조는 방향 그래프(directed graph)이다.
    • 컴포넌트는 정점(vertext)에 해당하고, 의존성 관계는 방향이 있는 간선(directed edge)에 해당한다.
    • 어느 컴포넌트에서 시작하든, 의존성 관계를 따라가면서 최초의 컴포넌트로 돌아갈 수 없다.
    • 이 구조는 순환이 없다. 즉, 비순환 방향 그래프(Directed Acyclic Graph, DAG)다.
    • 시스템 전체를 릴리스해야 하면 상향식으로 진행된다.
      • Entities(컴파일, 테스트, 릴리스) → Database, Interators, → ...
    • 컴포넌트 구성요소 간 의존성을 파악하고 있으면 시스템을 빌드하는 방법과 순서를 알 수 있다

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

새로운 요구사항으로 인해 생긴 Authorizer에 의해 순환 의존성이 생긴다.

이렇게 되면 interactors와 entities와 Authorizer 가 거대한 컴포넌트가 되어버린다.

결국, • 단위 테스트를 하고 릴리스를 하는 일도 굉장히 어려워지며, 에러도 쉽게 발생한다.

순환 끊기

  1. 의존성 역전을 적용한다.

  1. Entities와 Authorizer가 모두 의존하는 새로운 컴포넌트를 만든다. 그리고 모두 의존하는 클래스들을 새로운 컴포넌트로 이동시킨다.

Top-down 설계

컴포넌트는 시스템에서 가장 먼저 설계할 수 있는 대상이 아니기 때문에, 하향식으로 설계될 수 없다.

컴포넌트 의존성 다이어그램은 애플리케이션의 기능을 의미하지는 않는다.

오히려 애플리케이션의 빌드 가능성(buuildability)과 유지보수성(maintainability)을 보여주는 지도(map)와 같다.

따라서, 아무런 클래스도 설계하지 않은 상태에서 컴포넌트 의존성 구조를 설계하려고 하면 실패를 할 것이다.

SDP : 안정된 의존성 원칙

더 안정된 쪽에 의존하라.

변동성을 지닌 컴포넌트는 언젠간 변경된다고 예상한다.

따라서, 변경이 쉽지않은 컴포넌트가 변동성을 지닌 컴포넌트에 의존되면 큰일난다.

안정성

변경을 만들기 위해 필요한 작업량과 관련된다.

  • 소프트웨어 컴포넌트를 변경하기 어렵게 만드는 확실한 방법은 수많은 컴포넌트가 해당 컴포넌트에 의존하게 만드는 것이다.

X는 세 컴포넌트를 책임지고 있다. 그러나, X가 변경되도록 마들 수 있는 외적인 영향은 없기 때문에 독립적이다.


Y는 상당히 불안정한 컴포넌트이다. Y에 의존하는 컴포넌트는 없기 떄문에, 책임성이 없으며, 의존적이라고 볼 수 있다.

안정성 지표

불안정성 : I = Fan-out / (Fan-in + Fan-out) , I =1이면, 최고로 불안정한 컴포넌트, I = 0이면, 최고로 안정한 컴포넌트다.

Fan-in: 안으로 들어오는 의존성. 이 지표는 컴포넌트 내부의 클래스에 의존하는 컴포넌트 외부의 클래스 개수를 나타낸다.

Fan-out: 바깥으로 나가는 의존성. 이 지표는 컴포넌트 외부의 클래스에 의존하는 컴포넌트 내부의 클래스 개수를 나타낸다.

의존성 방향으로 갈수록 I지표 값이 감소해야 한다.

모든 컴포넌트가 안정적이어야 하는 것은 아니다.

모든 컴포넌트가 안정적이라면, 변경은 불가능하다.

위쪽엔 변경 가능한 컴포넌트, 아래쪽엔 안정된 컴포넌트에 의존한다.

추상 컴포넌트

오로지 인터페이스만을 포함하는 컴포넌트를 생성하는 방식인 추상 컴포넌트는 상당히 안정적이며, 따라서 덜 안정적인 컴포넌트가 의존할 수 있는 이상적인 대상이다.

SAP : 안정된 추상화 원칙

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

시스템에는 자주 변경해서는 절대로 안되는 소프트웨어도 있다. 고수준 아키텍처나 정책 결정과 관련된 소프트웨어가 그 예다.
따라서 시스템에서 고수준 정책을 캡슐화하는 소프트웨어는 반드시 안정된 컴포넌트(I = 0)에 위치해야 한다.

하지만 고수준 정책을 안정된 컴포넌트에 위치시키면, 그 정책을 포함하는 소스 코드는 수정하기가 어려워진다. 이로 인해 시스템 전체 아키텍처가 유연성을 잃는다.

그렇다면 어떻게 컴포넌트가 최고로 안정된 상태이면서도(I = 0) 동시에 변경에 충분히 대응할 수 있을 정도로 유연하게 만들 수 있을까?

해답은 개방 폐쇄 원칙(OCP)에서 찾을 수 있다.

안정된 추상화 원칙

  • 안정된 컴포넌트는 추상 컴포넌트여야 하며, 안정성이 컴포넌트를 확장하는 일을 방해해서는 안 된다고 말한다.
  • 불안정한 컴포넌트는 반드시 구체 컴포넌트여야 하며, 불안정하므로 컴포넌트 내부의 구체적인 코드를 쉽게 변경할 수 있어야 하기 때문이다.
  • SAP와 SDP를 결합하면 컴포넌트에 대한 DIP나 마찬가지가 된다.
    • 실제로 SDP에서는 의존성이 반드시 안정성의 방향으로 향해야 한다고 말하고
    • SDP에서는 안정성이 결국 추상화를 의미한다고 말하기 때문이다.
    • 따라서 의존성은 추상화의 방향으로 향하게 된다.

핵심은, 안정적인 컴포넌트라면 반드시 인터페이스와 추상 클래스로 구성되어 쉽게 확장할 수 있어야 한다.

추상화 정도 측정하기

다음은 컴포넌트의 클래스 총 수 대비 인터페이스와 추상 클래스의 개수를 단순히 계산한 값이다.

  • NC: 컴포넌트의 클래스 개수
  • Na: 컴포넌트의 추상 클래스와 인터페이스의 개수
  • A: 추상화 정도. A = Na / Nc(A가 0이면 추상 클래스가 한개도 없고, 1이면 오로지 추상 클래스만 있음)

주계열

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

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

  • 모든 컴포넌트가 이 두 지점에 위치하는 것은 아니다.

아래 그림의 궤적은 컴포넌트가 절대로 위치해서는 안 되는 영역, 배제할 구역(Zone of Exclusion)이다.

그림 14.13 배제 구역(Zone of Exclusion)

고통의 구역

(0, 0) 주변 구역에 위치한 컴포넌트는 매우 안정적이며 구체적이다. 뻣뻣한 상태이다. 추상적이지 않아서 확장할 수 없고, 안정적이므로 변경하기 상당히 어렵다.

하지만 변동성이 없는 컴포넌트는 (0, 0) 구역에 위치하더라고 해롭지 않다. 변동될 가능성이 없기 때문이다.

쓸모없는 구역

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

배제 구역 벗어나기

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

주계열과의 거리

지표를 통해 주 계열에서 멀리 벗어난 컴포넌트의 원인을 파악하고 조사하는 것이 중요하다.

결론

의존성 관리 지표는 설계의 의존성과 추상화 정도가 저자가 '훌륭한' 패턴이라고 생각하는 수준에 얼마나 잘 부합하는지를 측정한다.

profile
🐻‍❄️

0개의 댓글