Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

csct3434

[만들면서 배우는 클린 아키텍처] 03. 코드 구성하기 본문

개발 서적/만들면서 배우는 클린 아키텍처

[만들면서 배우는 클린 아키텍처] 03. 코드 구성하기

csct3434 2024. 3. 3. 21:02

송금하기 유스케이스

계층으로 구성하기

  • domain : 도메인 계층 / persistence : 영속성 계층 / web : 웹 계층
  • domain 패키지에 AccountRepository 인터페이스를 추가하고, persistence 패키지에 AccountRepositoryImpl 구현체를 둠으로써 의존성을 역전함
  • 문제점
    1. 애플리케이션의 기능 조각이나 특성을 구분 짓는 패키지 경계가 존재하지 않는다.
      • 서로 연관되지 않은 기능들끼리 엉망진창으로 묶여 예상하지 못한 부수효과를 일으킬 가능성이 크다
    2. 애플리케이션이 어떤 유스케이스들을 제공하는지 파악할 수 없다.
      • AccountService가 어떤 유스케이스를 구현하는지 패키지 구조만으로는 파악할 수 없다
      • 특정 기능을 찾기 위해서는 어떤 서비스가 이를 구현했는지 추측해야 하고, 해당 서비스 내의 어떤 메서드가 그에 대한 책임을 수행하는지도 찾아야 한다
    3. 패키지 구조를 통해 아키텍처를 파악할 수 없다
      • 육각형 아키텍처 스타일을 따랐다고 추측할 수는 있어도, 인커밍 포트와 아웃고잉 포트가 코드속에 숨겨져있어 한눈에 파악할 수가 없다

기능으로 구성하기

  • 계좌와 관련된 모든 코드를 최상위 account 패키지에 포함시킨 구조
  • 패키지 외부에서 접근되면 안되는 클래스들에 대해 package-private 접근 수준을 설정함으로써 불필요한 의존성을 방지할 수 있다
  • AccountService의 책임을 좁히기 위해 SendMoneyService로 클래스명을 변경함
  • 문제점
    1. 계층형 구조보다 아키텍처의 가시성이 훨씬 떨어진다
    2. 도메인 코드가 실수로 영속성 코드에 의존하는 것을 막을 수 없다
      • 의존성을 역전시켰음에도 불구하고, AccountService가 AccountRepositoryImpl 구현체에 의존하는 것을 방지할 수 없음

육각형 아키텍처로 구성하기

  • 패키지 구조
    • domain 패키지 : 도메인 모델을 포함
    • application 패키지
      • 애플리케이션 계층의 서비스는 in-coming 포트에 대한 구현을 제공하고, out-going 포트를 호출한다
    • adapter 패키지
      • in-coming 어댑터 : 애플리케이션 계층의 in-coming 포트를 호출한다
      • out-going 어댑터 : 애플리케이션 계층의 out-going 포트에 대한 구현을 제공한다
  • 장점
    1. ‘아키텍처-코드 갭’ 혹은 ‘모델-코드 갭’을 효과적으로 다룰 수 있다
      • 즉, 패키지 구조가 아키텍처를 반영하여 아키텍처만 보고도 어느 패키지에서 작업해야 할지 쉽게 파악할 수 있음
      • ex) 아키텍처를 표현한 그림을 보면서 현재 사용 중인 서드파티 API에 대한 변경을 논의하는 상황
        • 이해를 돕기 위해 서드파티 API에 해당하는 out-going 어댑터 그림을 바로 가리킬 수 있음
        • 논의 후, 해당 API의 코드를 곧바로 adapter/out/<어댑터 이름> 에서 찾을 수 있음
    2. 어댑터 코드를 자체 패키지로 이동시키면 필요한 경우 하나의 어댑터를 다른 구현으로 쉽게 교체할 수 있다
    3. 패키지 구조를 DDD 개념에 직접적으로 대응시킬 수 있다
  • 접근 수준
    • 어댑터 : 외부에서 호출되지 않기 때문에 public일 필요가 없다
    • 서비스 : in-coming 포트 뒤에 숨겨지기 때문에 public일 필요가 없다
  • 의존성 주입
    • 포트 인터페이스를 구현한 실제 객체를 서비스와 in-coming 어댑터에 제공하는 역할은 모든 계층에 의존성을 가진 중립적인 컴포넌트 의존성 주입을 통해 수행한다