[Clean Architecture] 사례 연구 : 비디오 판매
카테고리: Clean Architecture
저자가 아키텍트가 되어 일을 처리하는 과정과 결정을 내리는 모습을 담은 챕터 입니다.
요구사항
- 웹 사이트에서 비디오를 판매하는 SW이다.
- 판매되는 비디오들이 있고, 그것을 개인과 기업에게 웹을 통해 판매한다.
- 개인은 단품 가격을 지불하여 스트리밍으로 볼 수도 있고, 더 높은 가격을내고 비디오를 다운로드 해서 영구 소장할 수도 있다.
- 기업용 라이선스는 스트리밍 전용이며, 대량 구매를 하면 할인 받을 수 있다.
- 일반적으로 개인은 시청자인 동시에 구매자다. 반면에 기업은 다른 사람들이 시청할 비디오를 구매하는 총무팀 따위가 따로 있다.
- 비디오 제작자는 비디오 파일과 비디오에 대한 설명서, 부속 파일을 제공한다. 부속 파일에는 시험, 문제, 해법, 소스 코드 등이 포함된다.
- 관리자는 신규 비디오 시리즈물을 추가하거나 기존 시리즈물에 비디오를 추가 또는 삭제하며, 다양한 라이선스에 맞춰 가격을 책정한다.
이러한 요구사항을 바탕으로, 먼저 유즈케이스 분석
을 합니다.
유스케이스 분석
유즈케이스를 엑터(제작자, 관리자, 구매자, 시청자)로 나누어서 그림으로 표현하면 다음과 같습니다.
이렇게 나누고 보면, 앞서 다루었던 SRP에 따라 이들 네 엑터가 시스템이 변경되어야 할 네가지 주요 근원이 됩니다. 따라서, 엑터에 따라 시스템을 분할하여, 특정 엑터를 위한 변경이 나머지 엑터에게는 전혀 영향을 미치지 않도록 해야 합니다. (여기서 로그인이나 로그아웃과 같은 4개의 엑터가 동시에 수행하는 행동은 제외되었습니다. -> 이것도 다음에 다룰 추상 유즈케이스로 해결할 수 있을거 같습니다.)
가운데에 점선으로 된 카탈로그 조회 또는 라이센스 구매를 볼 수 있습니다. 이들은 추상 유스케이스이고, 범용적인 정책을 담고 있으며, 다른 유스케이스에서 이를 더 구체화 합니다. 이 추상화를 꼭 생성해야만 제품의 기능을 모두 구현할 수 있는 것이 아니기 때문에, 필수는 아닙니다. 하지만, 이들 두 유스케이스는 너무도 비슷하므로, 유사성을 식별하여 분석 초기에서 부터 통합하는 방법을 찾는 것이 더 현명하다고 판단한 결과라고 합니다.
컴포넌트 아키텍처
이제 엑터와 유즈케이스를 식별했으므로, 예비 단계의 컴포넌트 아키텍처를 만듭니다.
컴포넌트들은 뷰, 프레젠터, 인터랙터, 컨트롤러로 분리된 전형적인 분할 방법임을 볼 수 있습니다. 또한, 대응하는 액터에 따라 카테고리를 분리했다는 사실도 확인할 수 있습니다.
유즈케이스 다이어그램에서 봤던 추상 유즈케이스
를 구현하는 방식을 살펴봅시다. CatalogView와 Catalog Presenter에 주목해 봅시다. 이는 저자만의 추상 유스케이스를 처리하는 방식이라고 합니다. 이 뷰와 프레젠터는 해당 프래젠터는 해당 컴포넌트 내부에 추상 클래스로 코드화 될 것이며, 상속받는 컴포넌트에서는 이들 추상 클래스로부터 상속받은 뷰와 프레젠터 클래스들을 포함시킵니다.
이제, 각 컴포넌트들을 어떻게 쪼갤것인가? 에 대해 생각해봐야 합니다. 이들 컴포넌트들을 전부 분리해서 여러개의 .jar로 만들 수도 있고 아닐 수도 있습니다.
하지만 정석대로라면 컴파일과 빌드 환경은 분명하게 이 형태로 나눠야 하며, 따라서 각 컴포넌트를 독립적으로 전달할 수 있게 빌드하는 것도 가능합니다.
여기에 추가로, 전달해야할 이 모든 단위를 더 적은 개수로 합칠 수도 있습니다. 예를 들어 뷰, 프레젠터, 인터랙터, 컨트롤러, 유틸리티 각각을 합쳐 총 다섯개의 .jar 파일로 쉽게 합칠 수도 있는 것입니다. 그러면 서로 독립적으로 변경 될 가능성이 큰ㄴ 컴포넌트들을 독립적으로 배포할 수 있게 됩니다.
뷰와 프레젠터를 합쳐서 같은 .jar에 두고, 인터랙터/컨트롤러/유틸리티는 그대로 개별 .jar 파일에 두는 방식도 있습니다. 더 원시적으로 두개의 .jar 파일을 생성해 하나에 뷰/프레젠터를, 다른 하나에 나머지 모두를 포함시키는 방식으로 합칠 수도 있습니다. 이처럼 선택지를 열어두고, 후에 시스템이 변경되는 양상에 맞춰 시스템 배포방식을 조정할 수 있게 됩니다.
의존성 관리
위 컴포넌트 다이어그램을 보면, 제어 흐름은 오른쪽에서 왼쪽으로 이동합니다. 입력이 컨트롤러에서 발생하면 인터렉터에 의해 처리되어 결과가 만들어집니다. 그런 후에 프레젠터가 결과의 포맷을 변경하고, 뷰가 화면에 표시합니다.
하지만, 여기서 모든 화살표가 오른쪽에서 왼쪽을 가리키지는 않음을 주목해야 합니다. 사실 대다수의 화살표는 왼쪽에서 오른쪽으로 향합니다. 이는 아키텍처가 의존성 규칙을 준수하기 때문입니다. 모든 의존성은 경계선을 한 방향으로만 가로지르는데, 항상 더 높은 수준의 정책을 포함하는 컴포넌트를 향하게 됩니다.
또 하나, 사용관계(열린 화살표)는 제어흐름과 같은 방향을 가리키며, 상속 관계(닫힌 화살표)는 제어흐름과는 반대 방향을 가리킴에 주목해야 합니다.
이는 OCP를 준수했음을 보여줍니다. 이를 통해 의존성이 올바른 방향으로 흐르며, 따라서 저수주느이 세부사항에서 발생한 병경이 상위로 파금되어서 상위 수준의 정책에 영향을 미치지는 않음을 보장할 수 있습니다.
결론
위 아키텍처 다이어그램은 단일 책임 원칙
, 의존성 규칙
이라는 분리 개념을 포함하고 있습니다. 이들은 모든 서로 다른 이유로, 서로 다른 속도로 변경되는 컴포넌트를 분리하는 데 그 목적이 있습니다.
서로 다른 이유라는 것은 액터와 관련이 있으며, 서로 다른 변경의 속도라는 것은 정책 수준과 관련이 있습니다.
이런 방식으로 코드를 한번 구조화 하고 나면, 시스템을 실제로 배포하는 방식은 다양하게 선택할 수 있게 됩니다. 상황에 맞게 컴포넌트들을 배포가능한 단위로 묶을 수도 있고, 상황이 변하면 변한 상황에 맞추어 묶는 단위를 바꾸기도 쉬워집니다.
댓글 남기기