본문 바로가기

IT Book Summary/Clean Architecture

06세부사항 -4

34장 빠져있는 장

소프트웨어는 올바르게 정의된 경계, 명확한 책임, 통제된 의존성을 가진 클래스와 컴포넌트로 구성되나

디테일(구현 세부사항)을 고려해야 함.

 

온라인 서점 예제. 

설계나 코드 조직화와 관련된 접근법

 

계층 기반 패키지

전통적 수평 계층형 아키텍처

- 기술적 관점에서 해당 코드가 하는일에 기반해 코드 분할.

 

웹, 업무 규칙, 영속성 코드를 위해 수평적 계층이 각각 존재.

자바의 경우 계층은 패키지로 구현.

 

계층 기반 패키지

OrdersController: 웹 기반 요청 처리.

OrdersService: 주문 업무규칙을 정의하는 인터페이스

OrdersServiceImpl: OrdersService 구현체

OrdersRepository: 주문정보에 접근하는 방법 정의하는 인터페이스

JdbcOrdersRepository : OrdersRepository 인터페이스 구현체

 

처음 시작하기에 계층형 아키텍처가 적합. 

소프트웨어가 커지고 복잡해지면 모듈화 고민.

기능 기반 패키지

서로 연관된 기능, 도메인 개념, Aggregate Root(도메인 주도설계 사용시)

에 기반해 코드를 나누는 방식.

 

인터페이스와 클래스는 이전과 같지만, 모두가 단하나의 패키지에 속함.

 

기능 기반 패키지

 

 

포트와 어댑터

업무/도메인에 초점을 둔 코드가 프레임워크나 데이터베이스 간은 세부구현과 분리된 아키텍처를 만들기 위해,

코드 베이스는 내부(도메인) 와 외부(인프라)로 구성.

 

내부와 외부로 나뉘는 코드 베이스

주요규칙은 외부가 내부에 의존.

 

주문 조회하기 유스케이스

com.mycompany.myapp.domain 패키지가 내부이고, 나머지 패키지는 모두 외부.

OrdersRepository 가 Order 로 바뀜. 도메인 주도 설계의 명명법

 

컴포넌트 기반 패키지

코드 베이스의 요소들이 서로 의존할때 몇가지 규칙을 지켜야 함.

 

웹컨트롤러는 절대 리포지토리에 직접 접근해서는 안된다. 와 같은 원칙이 필요.

빌드 시 정적분석도구를 사용해 아키텍처 위반사항이 없는지 검사.

 

포트와 어댑터에서 웹을 전달 메커니즘으로 취급하는 것처럼,

컴포넌트 기반 패키지에서 사용자 인터페이스를 큰 단위의 컴포넌트로부터 분리해서 유지.

 

주문 조회하기 유스케이스

업무로직과 영속성 관련 코드를 하나로 묶음. 컴포넌트

 

- 컴포넌트는 배포단위. 시스템의 구성요소로, 비표할 수 있는 가장 작은 단위. 자바의 경우 jar 파일.

- 인터페이스로 감싸진 연관된 기능들의 묶음. 애플리케이션과 같은 실행환경 내부에 존재. C4 소프트웨어 아키텍처 모델에 따른것.

 

하나 이상의 컨테이너(웹어플리케이션, 데이터베이스, 파일시스템 등)로 구성되고, 각 컨테이너는 하나 이상의 컴포넌트를 포함.

컴포넌트 기반 패키지의 이점은 오직 한 컴포넌트만 둘러보면 된다는 것.

주문처리와 관련된 모든것들을 캡슐화하는 별도의 OrderService 존재.

컴포넌트만 잘 정의하면 MSA로 가기위한 발판으로 삼을수 있음.

 

구현 세부사항엔 항상 문제가 있다

모든 타임에서 public 지시자를 사용하는건 언어가 제공하느 캡슐화 이점을 활용하지 않는것.

 

조직화 vs. 캡슐화

public을 코드베이스 어디에도 사용할 수 있다면 패키지를 사용하는데 이점이 거의 없다.

패키지를 모시하면 최종적으로 어떤 아키텍처 스타일로 만들려고 하는지 아무 의미가 없어짐.

 

네 개의 아키텍처 접근법이 모두 동일

자바에서 접근 지시자를 적절히 사용하면 

타입을 패키지로 배치하는 방식에 따라 각 타입에 접근할 수 있는 정도가 크게 달라짐.

 

회색 처리한 타입은 더 제한적 접근 지시자 사용가능

계층기반 패키지의 경우:

OrdersService, OrdersRepository는 패키지 내부로 들어오는 의존성이 존재하므로 public 선언

그 구현체는 세부사항으로 protected로 제한적 선언.

 

기능기반 패키지의 경우:

OrdersController가 패키지로 들어오는 유일한 통로이므로 나머지 모두 protected 지정.

 

포트와 어댑터 접근법의 경우:

OrdersService, Orders 인터페이스는 public 지정. 구현 클래스는 protected

 

컴포넌트 기반 패키지의 경우:

컨트롤러에서 OrdersComponent 인터페이스로 향하는 의존성. public

그외 모든것은 패키지 protected 지정.

 

아키텍처 원칙을 강제할 때 자기규율이나 컴파일 후처리 두구말고, 반드시 컴파일러에 의지할것 권장.

다른 결합 분리 모드

자바 9에서 제공하는 모듈시스템을 제대로 사용하면 public 타입과 외부에 공표할 타입을 분리 가능.

Orders 모듈을 생성시 모든 타입을 public으로 지정해도 일부 타입만을 외부에 사용 하도록 공표 가능.

 

또는 소스코드 수준에서 의존성 분리. 서로 다른 소스코드 트리로 분리.

  • 업무와 도메인용 소스코드(기술과 독립적)
    OrderService, OrderServiceImpl, Orders
  • 웹용 소스코드
    OrderController
  • 데이터 영속성용 소스코드
    JdbcOrdersRepository

웹용, 데이터 영속성 소스코드는 컴파일 시점에 의존성을 가짐.

이상적으로 모든 컴포넌트 각각을 개별소스코드 트리로 구성해야 하지만 복잡성으로 문제가 생길수도.

 

단순히 소스코드 트리를 두개만 만드는 방법

도메인과 인프라코드

  • 도메인 코드(내부)
  • 인프라 코드(외부)
  • 이 다이어그램에서 인프라는 도메인에 대해 컴파일 시점에 의존성을 가짐.

 

결론 : 빠져있는 조언

최적의 설계를 하더라도, 구현 전략에 얽힌 복잡합을 고려하지 않으면 설계가 망가질수 있다.

코드를 조직화하고 런다임과 컴파일타임에 어떤 결합 분리 모드를 적용할지 고민하라.

외부 제약사항도 고려하라.

구현세부사항과 결합되지않도록 주의하라.

 

 

 

'IT Book Summary > Clean Architecture' 카테고리의 다른 글

06 세부사항 - 2  (0) 2021.04.11
06 세부사항 -1  (0) 2021.04.03
05 아키텍처 - 6  (0) 2021.03.28
05 아키텍처 - 5  (0) 2021.03.28
05 아키텍처 - 4  (0) 2021.03.20