Chapter 7

사례 연구와 부록

  • 7.1 비디오 판매 사이트
  • 7.2 유스케이스 분석
  • 7.3 컴포넌트 아키텍처
  • 7.4 의존성 관리
  • 7.5 코드 조직: 계층 기반 패키지
  • 7.6 코드 조직: 기능 기반 패키지
  • 7.7 포트와 어댑터
  • 7.8 컴포넌트 기반 패키지
  • 7.9 조직화 vs 캡슐화

지금까지 배운 원칙들이 실제로 어떻게 적용되는지, 그리고 코드를 어떻게 조직해야 아키텍처가 살아남는지를 사례로 확인할 거야.

온라인 비디오 판매 사이트를 설계한다고 해보자. 개인과 기업에 비디오를 판매하고 스트리밍하는 서비스야. 개인은 개별 가격, 기업은 대량 구매 할인이 적용되고, 판매자가 비디오를 업로드하고 구매자가 시청하는 구조지.

먼저 유스케이스를 식별해. 액터별로 분류하면 -- 시청자(비디오 시청, 라이선스 구매), 구매자-개인(비디오 구매), 구매자-기업(대량 라이선스 구매), 저자/판매자(비디오 업로드, 시리즈 관리), 관리자(가격 설정, 할인 정책 관리, 콘텐츠 추가/삭제). SRP에 따라 각 액터가 변경의 이유를 제공하니까, 다른 액터를 위한 유스케이스는 분리되어야 해.

컴포넌트 아키텍처는 유스케이스를 기반으로 나눠. 수평 분리로 뷰, 프레젠터, 인터랙터, 컨트롤러 계층을 만들고, 수직 분리로 액터별(시청자, 구매자, 저자, 관리자)로 나누면 격자(grid) 형태의 컴포넌트 구조가 나와. 행이 액터이고 열이 계층인 구조지. 의존성은 위를 향해 -- 뷰에서 프레젠터로, 프레젠터에서 인터랙터로. 모든 컴포넌트가 의존하는 중심에는 엔티티가 있어.

의존성 관리는 두 개의 차원으로 이뤄져. SRP에 기반한 액터 분리(서로 다른 이유로 변경되는 것을 나눈다)와 의존성 규칙에 기반한 계층 분리(고수준 정책이 저수준 세부사항을 모르게). 이 두 축의 분리가 합쳐져서, 시스템의 변경이 최소한의 컴포넌트에만 영향을 미치게 돼. 새 유스케이스를 추가해도 기존 유스케이스에 영향이 없고, 뷰를 변경해도 업무 규칙에 영향이 없지.

이제 사이먼 브라운이 쓴 "빠져있는 장" -- 코드를 실제로 어떻게 조직하느냐의 문제야. 계층 기반 패키지 -- 가장 흔한 방식으로 web/, service/, repository/ 같은 기술적 계층으로 나눠. 문제는 기능이 여러 패키지에 흩어지고 유스케이스가 보이지 않는다는 거야.

기능 기반 패키지 -- orders/, products/, customers/ 같은 기능 단위로 나눠. 소리치는 아키텍처에 더 가깝지 -- 패키지 이름만 봐도 이 시스템이 뭘 하는지 알 수 있어. 하지만 패키지 안에서 계층 분리가 안 되면 결국 패키지 안의 진흙 덩어리가 돼.

포트와 어댑터 -- 클린 아키텍처, 헥사고날 아키텍처의 접근법이야. 코드를 domain/(내부)과 infrastructure/(외부)로 나눠. 의존성은 항상 바깥에서 안으로 향하지. 이전 방식들보다 아키텍처 의도가 명확하지만, 패키지 구조로 강제하기가 쉽지 않아.

사이먼 브라운이 제안하는 컴포넌트 기반 패키지 -- 기능 기반과 계층 분리를 결합해. 컴포넌트가 하나의 배포 단위 안에서 업무 로직과 데이터 접근을 캡슐화하고, 외부에서는 컴포넌트의 인터페이스만 볼 수 있어. 컨트롤러가 리포지토리에 직접 접근하는 걸 패키지 접근 제어를 통해 컴파일 타임에 막을 수 있지.

결국 핵심은 조직화 vs 캡슐화야. 아무리 좋은 아키텍처를 그려도 코드 수준에서 강제하지 않으면 무너져. 모든 타입을 public으로 선언하면 패키지 구조가 무의미해지거든 -- 아무 데서나 아무거나 접근할 수 있으니까. 자바라면 public이 아닌 **패키지 프라이빗(package-private)**을 적극적으로 활용해야 해. 잘 정리된 디렉터리 구조가 있다고 좋은 아키텍처인 건 아니야. 진짜 아키텍처는 접근 제한에 의해 만들어져. 볼 수 없는 것에는 의존할 수 없으니까. 컴파일러가 아키텍처 규칙을 강제해야 해. 다이어그램이 아니라 코드가 아키텍처를 지켜야 하지.


정리

7장 읽고 기억할 거 세 가지:

  1. 유스케이스와 액터를 기반으로 컴포넌트를 나누고, SRP와 의존성 규칙이라는 두 축으로 분리해. 수평(계층)과 수직(액터) 분리가 합쳐지면 변경의 영향 범위를 최소화할 수 있어.
  2. 패키지 구조는 아키텍처적 결정이야. 계층 기반, 기능 기반, 포트와 어댑터, 컴포넌트 기반 -- 각각의 장단점이 있지만, 중요한 건 선택한 구조가 실제 코드 수준에서 강제되는 거야.
  3. 다이어그램만으로는 아키텍처를 지킬 수 없어. 접근 제어를 통해 의존성 규칙을 컴파일 타임에 강제해야 해. public을 남발하면 아무리 예쁜 패키지 구조도 무의미하지.