[Clean Architecture] 사례연구, 빠져 있는 장

휴먼스케이프

안녕하세요. 휴먼스케이프 휴 입니다.

오늘은 Clean Architecture 33, 34장의 내용을 알아보겠습니다.

34장 사례연구: 비디오 판매

이번 장에서는 지금까지 살펴본 아키텍처에 대한 규칙과 견해를 종합하여 사례 연구에 적용해 봅니다.

제품

사례 연구를 위한 제품으로는 비디오 판매 사이트를 선택했습니다. 판매하길 원하는 비디오가 있고, 개인과 기업에게 웹을 통하여 판매합니다. 개인은 가격을 지불하고 스트리밍으로 보거나 다운로드를 할 수 있고, 기업은 라이선스를 구매할 수 있습니다.

시스템의 초기 아키텍처를 결정하는 첫 단계는 액터와 유스케이스를 식별하는 일입니다.

유스케이스 분석

비디오 판매 사이트에서의 액터는 제작자, 구매자, 관리자, 시청자로 구분됩니다. 단일 책임 원칙에 따르면 이들 네 액터가 시스템이 변경되어야 할 네 가지 주요 근원이 됩니다. 그리고 특정 액터를 위한 변경은 나머지 액터에게 영향을 주지 말아야 합니다.

유스케이스중 범용적인 정책을 담고 있는 부분은 추상 유스케이스로 두고 이를 다를 유스케이스에서 더 구체화 시킵니다.(예: 카탈로그 조회하기가 추상 유스케이스라면, 사용자 입장에서 카탈로그 조회하기와 구매자 입장에서 카탈로그 조회하기 유스케이스가 있을 수 있습니다.)

컴포넌트 아키텍처

액터와 유스케이스를 식별했으면, 예비 컴포넌트 아키텍를 만들어 볼 수 있습니다. 뷰, 프레젠터, 인터랙터, 컨트롤러로 분할하고 각 사이에 경계를 긋습니다. 그리고 각 컴포넌트는 네 종류의 액터에 따라 카테고리로 분리합니다.

각 컴포넌트는 단일 .jar 파일 또는 단일 .dll 파일에 해당합니다. 이렇게 컴포넌트 단위로 분할해서 후에 변경되는 시스템의 상황에 맞게 컴포넌트들의 조합으로 더 큰 .jar 파일로 합칠 수 있도록 선택지를 열어 둘 수 있습니다.

의존성 관리

모든 의존성은 경계선을 한 방향으로만 가로지르고 항상 더 높은 수준의 정책을 포함하는 컴포넌트를 향합니다.

결론

위에서 두 가지 서로 다른 차원의 분리개념을 포함하였습니다. 단일 책임 원칙에 기반한 액터 분리, 그리고 의존성 규칙입니다. 이 두 규칙은 서로 다른 이유로, 서로 다른 속도로 변경되는 컴포넌트를 분리하는 데 그 목적이 있었습니다. 이런 방식으로 구조화하면 시스템을 배포할 때 상황에 맞게 컴포넌트들을 배포 가능한 단위로 묶을 수 있습니다.

35장 빠져 있는 장

계층 기반 패키지

기술적인 관점에서 해당 코드가 하는 일에 기반해 그 코드를 분할합니다. 코드는 계층이라는 얇은 수평 조각으로 나뉘며, 각 계층은 유사한 종류의 것들을 묶는 도구로 사용됩니다. 엄격한 계층형 아키텍처의 경우 계층은 반드시 바로 아래 계층에만 의존해야 합니다. 전형적인 계층형 아키텍처에는 웹, 업뮤 규칙, 영속성 코드를 위한 계층이 각 하나씩 존재합니다.

이 아키텍처는 복잡한 과정을 겪지 않고도 무언가를 빠르게 만들기 적합합니다. 하지만 소프트웨어가 커지다보면 큰 그릇 세 개 만으로는 부족하다는 고민을 하게 될 것 입니다. 또 어떤 업무 도메인이라 하더라도 같은 모습으로 구성된 모습을 볼 수 있을 것입니다.

기능 기반 패키지

계층 기반 패키지에서 등장하는 인터페이스와 클래스는 이전과 같지만, 세 개가 아닌 모두가 하나의 패키지에 속하게 됩니다. 이 코드가 이제서야 주문과 관련한 무언가를 한다는 걸 볼 수 있고, ‘주문 조회하기’ 유스케이스가 변경될 경우 변경해야할 코드들이 모두 한 패키지에 담겨있기 때문에 더 수월할 수 있습니다. 하지만 계층, 기능 기반 패키지 모두 차선책입니다.

포트와 어댑터

포트와 어댑터 방식으로 접근하는 이유는 업무/도메인에 초점을 둔 코드가 프레임워크나 데이터베이스 같은 기술적인 세부 구현과 독립적이며 분리된 아키텍처를 만들기 위해서입니다. 코드 베이스는 내부(도메인)와 외부(인프라)로 구성되는데 여기서 규칙은 외부가 내부에 의존하여야 합니다.

여기에서 com.mycompany.myapp.domain 패키지가 내부이며, 나머지는 모두 외부입니다.

<왼쪽부터 계층, 기능, 포트와 어댑터, 컴포넌트 기반 패키지>

컴포넌트 기반 패키지

이 접근법은 앞 서 살펴본 접근법의 모든 것을 담고 있습니다. 큰 단위의 단일 컴포넌트와 관련된 모든 책임을 하나의 자바 패키지로 묶는 데 주안점을 둡니다. 이 접근 법에서는 업무 로직과 영속성 관련 코드를 하나로 묶는데 이 묶음을 컴포넌트(컴포넌트는 시스템의 구성요소로, 배포할 수 있는 가장 작은 단위)라 부릅니다.

컴포넌트 기반 패키지 접근법의 주된 이점은 주문과 관련된 무언가를오직 한 컴포넌트만 둘러보면 된다는 점입니다. 그리고 컴포넌트 내에서는 여전히 관심사의 분리는 유효합니다.

조직화 vs 캡슐화

만약 자바 애플리케이션에서 모든 타입을 public으로 지정한다면, 패키지는 단순히 조직화를 위한 메커니즘으로 전락하여 캡슐화를 위한 메커니즘이 될 수 없습니다. 앞 서 소개한 네 가지 접근법에서 모든 접근 지시자를 public으로 지정한다면 네 가지 접근법은 모두 같아집니다.

접근 지시자를 적절하게 사용한다면 다이어그램은 다음과 같이 변합니다. 따라서 우리는 컴파일러의 도움을 받아서 컴포넌트 기반 패키지 접근법을 강제할 수 있게 됩니다.

<제한적인 접근 지시자를 사용한 다이어그램>

다른 결합 분리 모드

프로그래밍 언어가 제공하는 방법외에도 소스 코드 의존성을 분리하는 방법은 존재합니다. 예를 들어 자바에는 OSGi 같은 모듈 프레임워크나 자바9에서 제공하는 새로운 모듈 시스템이 있습니다. 모듈 시스템을 사용하면 public 타입으로 지정하더라도 일부 타입만을 외부에서 사용할 수 있도록 공표가 가능합니다.

다른 선택지로는 소스 코드 수준에서 의존성을 분리하는 방법도 있습니다. 각 코드가 컴파일 시점에 의존성을 가지도록 빌드 도구(메이븐, 그래들, MSBuild)를 사용해서 모듈이나 프로젝트가 서로 분리되도록 구성합니다.

하지만 이것은 너무 이상적인 해결책이라 현실에서는 이처럼 나누다보면 성능, 복잡성, 유지보수 문제가 생길 수 있습니다.

포트와 어댑터 접근법을 적용할 때는 이보다 간단한 방법으로 소스 코드 트리를 두 개만 만드는 것입니다.

<포트와 어댑터 접근법 다이어그램>

다이어 그램에서는 인프라는 도메인에 대해 컴파일 시점의 의존성을 가집니다. 이 접근은 소스 코드를 조직화 할 때는 효과가 있지만 절충해야 할 부분이 있음을 알고 있어야 합니다. 인프라와 도메인의 관계를 잘 고려하여 접근 지시자를 적절히 적용해야 합니다.

결론

이 장은 최적의 설계를 꾀했더라도, 구현 전략에 얽힌 복잡함을 고려하지 않으면 설계가 순식간에 망가질 수도 있다는 사실을 강조하는데 목적이 있습니다. 가능하다면 선택사항은 열어두되, 실용주의적으로 행해야 합니다. 팀의 규모, 기술 수준, 해결책의 복잡성을 일정과 예산이라는 제약과 동시에 고려해야 합니다. 또한 선택된 아키텍처 스타일을 강제하는데 컴파일러의 도움을 받을 수 있을지 고민하며, 데이터 모델과 같은 다른 영역에 결합되지 않도록 주의합니다. 구현 세부사항에는 항상 문제가 있는 법입니다.

여기까지 Clean Architecture 33, 34장을 알아보았습니다.

감사합니다.

Get to know us better! Join our official channels below.

Telegram(EN) : t.me/Humanscape KakaoTalk(KR) : open.kakao.com/o/gqbUQEM Website : humanscape.io Medium : medium.com/humanscape-ico Facebook : www.facebook.com/humanscape Twitter : twitter.com/Humanscape_io Reddit : https://www.reddit.com/r/Humanscape_official Bitcointalk announcement : https://bit.ly/2rVsP4T Email : support@humanscape.io

기업문화 엿볼 때, 더팀스

로그인

/