본문 바로가기

Design/Architecture

[Clean Architecture] 컴포넌트 사이의 관계와 원칙(1) : ADP

ADP (의존성 비순환 원칙) 란?

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

ADP를 이야기하기 전에 숙취 증후군에 대해서 알아보자.

숙취 증후군은 당신이 하루종일 작업하여 무언가를 작동하게 만들어 놓았지만, 그 기능이 의존하는 무언가를 다른 팀이 수정하여, 다음 날 출근하면 그 기능이 전혀 돌아가지 않는 것을 이야기한다. 

숙취 증후군 해결책으로 두 가지 방법이 발전되어 왔는데 하나씩 알아보도록 하자.

 

1. 주단위 빌드

  • 모든 개발자는 일주일의 첫 4일 동안은 각자 개발을 진행한다.
  • 금요일이 되면 변경된 코드를 모두 통합하여 시스템을 빌드하는 작업을 진행한다.
  • 하지만 금요일 안에 모든 작업이 완료되지 못하는 경우가 발생하고, 결국 기존에 계획했던 4일 개발 하루 통합이 지켜지지 못하는 상황이 발생한다. 
  • 따라서 통합 및 테스트 수행은 어려워지고, 빠른 피드백이 주는 장점을 상실하게 된다.

2. 순환 의존성 제거하기.

  • 개발 환경을 릴리스 가능한 컴포넌트 단위로 분리하는 것이 핵심.
  • 이를 통해 컴포넌트는 개별 개발자(또는 단일 개발팀)이 책임질 수 있는 작업 단위가 됨.
  • 개발자가 해당 컴포넌트를 동작하도록 만든 후, 해당 컴포넌트를 릴리스하여 다른 개발자가 사용할 수 있도록 만든다.
  • 새로 릴리스된 컴포넌트는 해당 컴포넌트에 의존하는 다른 팀에서 사용할지 안할지 결정할 수 있음.
  • "따라서 어떤 팀도 다른 팀에 의해 좌우되지 않는다."
  • 이 절차가 반드시 성공하려면 의존성 구조에 순환이 있어서는 안된다.

주단위 빌드는 사실상 채택이 어려운 해결책이고, 우리는 순환 의존성에 관해서 더 자세히 알아보도록 하자.

 

ADP 원칙을 준수한 케이스

[Clean Architecture 비순환 다이어그램]

  • 위 컴포넌트 다이어그램을 보게 되면 비순환 방향 그래프(DAG)임을 알 수 있다.
  • Presenters를 담당하는 팀에서 새로운 릴리스를 만들면, View와 Main 컴포넌트에서 영향을 받는다. 따라서 두 컴포넌트를 담당하는 개발자는 새로운 Presenters의 릴리스를 언제 통합할지 결정해야한다.
  • Main은 새로 릴리스되더라도 해당 컴포넌트에 의존하고있는 다른 컴포넌트가 없으므로 영향이 거의 없다고 볼 수 있다.
  • Presenters 컴포넌트를 테스트 하고자 한다면, Interactors와 Entities를 이용해서 Presenters 자체 버전을 빌드하면 된다.
  • 시스템 전체를 릴리스해야한다면 릴리스 절차는 상향식으로 진행된다.
    (Entities -> Database,Interactors -> Presenters, View, Controllers, Authorizer -> Main 순으로 컴파일, 테스트, 릴리스한다.)

ADP 원칙이 준수되지 않은 케이스

[Clean Architecture 순환 다이어그램] 

  • Entities의 User 클래스가 Authorizer의 Permission클래스를 사용한다고 가정
  • 순환 의존성이 발생하게 된다.
  • 만약 Database컴포넌트를 릴리스 해야한다면, Entities 컴포넌트와 반드시 호환이 되어야한다. 
    하지만 순환이 있기 때문에 Database컴포넌트는 Authorizer와도 호환이 되어야하고, 따라서 Interactors에도 호환이 되어야한다.
  • Entities, Authorizer, Interactors는 사실상 하나의 거대한 컴포넌트가 되어버린다.
    (모두 항상 정확하게 동일한 릴리스를 사용해야함)
  • 이 말은 이들 컴포넌트들 중 하나를 개발하더라도 숙취 증후군을 경험을 하게될 가능성이 크다는 것이다. 

순환 의존성이 있을 경우 문제점

  1. 의존성으로 인해 컴포넌트를 분리하기가 어려워짐.
  2. 단위 테스트를 하고 릴리스하는 일이 어려워지고 에러도 쉽게 발생.
  3. 컴포넌트를 어떤 순서로 빌드해야 올바를지 파악하기 어려워짐. (순환이 생기면 사실상 올바른 순서라는 것이 있을 수 없음)

 

순환끊기

컴포넌트 사이의 순환을 끊고 의존성을 다시 DAG로 원상복구하는 일은 언제라도 가능하다.

 

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

[Clean Architecture 의존성 역전]

  • User가 필요로 하는 메서드를 제공하는 인터페이스 생성 
  • 이 인터페이스는 Entities에 위치, Authorizer에서는 이 인터페이스를 구현한다.
  • 이를 통해 의존성을 역전시킬 수 있고, 이를 통해 순환을 끊을 수 있다.

2. Entities와 Authorizer가 모두 의존하는 새로운 컴포넌트를 만든다.

[Clean Architecture 모두가 의존하는 새로운 컴포넌트]

  • Entities와 Authorizer가 모두 의존하는 새로운 컴포넌트를 만든다.
  • 두 컴포넌트가 모두 의존하는 클래스들을 새로운 컴포넌트로 이동.
  • 이 해결책이 시사하는 바는 요구사항이 변경되면 컴포넌트 구조도 변경될 수 있다는 사실이다.
  • 애플리케이션이 성장함에 따라 컴포넌트 의존성 구조는 서서히 흐트러지며 성정한다.