Posts [클린아키텍처] 25장 계층과 경계
Post
Cancel

[클린아키텍처] 25장 계층과 경계

clean-architecture-book

‘클린 아키텍처’ 기술 서적에 대해 학습했던 내용을 정리하기 위한 목적의 TIL 포스팅입니다.🙆‍♂️

  • 시스템은 보통 세 가지 컴포넌트(UI, 업무 규칙, 데이텅베이스)로만 구성된다 생각하기 쉽지만, 하지만 대다수 시스템은 이보다 훨씬 많다.

움퍼스 사냥 게임

image

  • 위 이미지처럼 소스 코드 의존성을 관리하면, UI 컴포넌트가 어떤 언어를 사용하더라도 게임 규칙을 재사용할 수 있다.
  • 게임 규칙은 어떤 종류의 인간 언어가 사용되는지 알지도 못하며 신경 쓸 이유도 없다.

image

  • 또한 게임 규칙은 데이터 저장소와 통신할때 마찬가지로 의존성 관리가 되어 게임 규칙을 의존하는 형태가 되어야 한다.

클린 아키텍처?

  • 위 예제의 맥락이라면 클린 아키텍처 접근법을 적용해서 유스케이스, 경계, 엔티티, 그리고 관련된 데이터 구조를 모두 만드는 일도 쉬운 일이다. 그런데 중요한 아키텍처 경계를 정말 ㄷ모두 발견한 걸까?
  • 예를 들어 UI에서 언어가 유일한 변경의 축은 아니기 때문에 변경의 축에 의해 정의 되는 잠재된 아키텍처 경계가 있을 수 있다. 텍스트를 주고받는 메커니즘, 데이터 저장 매커니즘등을 다양하고 만들고 싶을수도 있다..

image

  • 이 모든 경우에 해당 Boundary 인터페이스가 정의하는 API는 의존성 흐름의 상위에 위치한 컴포넌트에 속한다.
    • 예를 들어, GameRules 를 들여다 보면 GameRules 내부 코드에서 사용하고 Language 내부 코드에서 구현하는 다형적 Boundary 인터페이스를 발견할 수 있다.
  • English, SMS, CloudData 와 같은 변형들은 추상 API 컴포넌트가 정의하는 다형적 인터페이스를 통해 제공되고, 실제 서비스하는 구체 컴포넌트가 해당 인터페이스를 구현한다.
    • 예를 들어, Language 가 정의하는 다형적 인터페이스는 English 나 Spanish 가 구현할 것이다.

image

  • 변형들을 모두 제거하고 순전한 API컴포넌트만 집중하면 위 다이어그램과 같이 단순화할 수 있다.
  • 모든 화살표가 위를 향하도록 맞춰졌다는 점에 주목하자. 그 결과 GameRules 는 최상위 수준의 정책을 가지는 컴포넌트이므로 이치에 맞는 배치다.
  • 정보가 흐르는 방향을 생각해 보자.
    • 모든 입력은 사용자로부터 전달받아 좌측 하단의 TextDelivery 컴포넌트로 전달된다.
    • 이 정보는 Language 컴포넌트를 거쳐 위로 올라가며, GameRules 에 적합한 명령어로 번역된다.
    • GamesRules 는 사용자 입력을 처리 후, 우측 하단의 DataStorage 로 적절한 데이터를 내보낸다.
    • 그런후 GameRules 는 Language 로 출력을 되돌려 보내고, Language 는 API를 다시 적절한 언어로 번역한 후 번역된 언어를 TextDelivery 를 통해 사용자에게 전달한다.
  • 이 구성은 데이터 흐름을 두 개로 효과적으로 분리한다.
    • 왼쪽 흐름은 사용자와의 통신에 관여하며, 오른쪽 흐름은 데이터 영속성에 관여한다.
    • 두 흐름은 상단의 GameRules 에서 서로 만나며, GameRules는 두 흐름이 모두 거치게 되는 데이터에 대한 최종 처리기가 된다.

흐름 횡단하기

  • 데이터 흐름은 시스템이 복잡해질수록 컴포넌트 구조가 더 많은 흐름으로 분리될 것이다.
    • 예를 들어, 움퍼스 사냥 게임을 네트워크 상에서 여러사람이 함께 플레이할 수 있게 만든다 할 때 네트워크 컴포넌트를 추가해야 한다.
    • 이때 데이터 흐름은 세 개로 분리되며, 이들 흐름은 GameRules 가 제어한다.

image

흐름 분리하기

  • 이쯤 되면 모든 흐름이 결국엔 상단의 단일 컴포넌트에서 서로 만난다고 생각할 수 있지만, 현실은 훨씬 복잡하다.

image

  • 움퍼스 게임에서 게임 규칙중 일부인 지도 관련 메커니즘을 처리하는 MoveManagement를 추가한 경우 지도규칙에 의해 플레이어의 지도 관련 사건을 처리한다.
  • 게임중 구덩이에 빠지면 MoveManagement은 이를 판단한 후 고수준인 PlayerManagement정책에게 알려 플레이어의 승리 여부 상태를 결정해준다.

  • 여기서 좀 더 흥미롭게 마이크로서비스까지 추가해보자.(p.242 그림 25.7 참고)
  • 대규모 플레이어가 동시에 플레이할 수 있는 버전의 움퍼스 사냥 게임이 있다고 가정해보자.
  • MoveManagement 는 플레이어 컴퓨터에서 직접 처리되지만 PlayerManagement 는 서버에서 처리된다.
  • PlayerManagement 는 접속된 모든 MoveManagement 컴포넌트에 마이크로서비스 API를 제공한다.
  • 이러할 때 MoveManagement 와 PlayerManagement는 사이에는 아키텍처 경계가 생기게 된다.

결론

  • 위 움퍼스 사냥 게임 예제는 아키텍처 경계가 어디에나 존재한다는 사실을 보여준다.
  • 아키텍트로서 아키텍처 경계가 언제 필요한지를 신중하게 파악해내야 한다.
  • 경계를 제대로 구현하려면 비용이 많이든다는 사리과 경계가 무시되었을때 나중에 추가하는 비요이 크다는 사실도 알아야 한다.
  • 아키텍트는 추상화가 필요하리라고 미리 예측해선 안된다.
    • 이것이 바로 YAGNI 가 말하는 철학이다.
    • 오버 엔지니링이 언더 엔지니어링보다 나쁠떄가 훨씬 많기 떄문이다.
    • 다른 한편으론 어떤 아키텍처 경계도 존재하지 않는 상황에서 경계가 정말로 필요하다는 사실을 발견 후, 그제서야 경계를 추가하려면 비용이 많이 들고 큰 위험을 감수해야 한다.
  • 프로젝트 초반에는 구현할 경계가 무엇인지와 무시할 경계가 무엇인지 쉽게 결정할 수 없다.
  • 대신 지켜봐야 하고, 시스템이 발전함에 따라 주의를 기울여야 한다.
  • 경계가 필요할 수도 있는 부분에 주목하고, 경계가 존재하지 않아 마찰의 어렴풋한 첫 조짐을 신중하게 관찰해야 한다.
  • 첫 조짐이 보이는 시점이 되면, 해당 경계를 구현하는 비용과 무시할 때 감수할 비용을 가늠한다. 그리고 결정된 사항을 자주 검토한다.
  • 우리의 목표는 경계의 구현 비용이 그걸 무시해서 생기는 비용보다 적어지는 바로 그 변곡점에서 경계를 구현하는 것이다.(어려울 것 같다..)
  • 목표를 달성하려면 빈틈없이 지켜봐야 한다..

Reference

This post is licensed under CC BY 4.0 by the author.

[클린아키텍처] 24장 부분적 경계

[클린아키텍처] 26장 메인컴포넌트