카테고리 없음

만들면서 배우는 클린아키텍처를 읽고(3/4)

truly-sparkle2 2024. 3. 10. 16:11

만들면서 배우는 클린아키텍처를 읽고(1/4) (tistory.com)

만들면서 배우는 클린아키텍처를 읽고 (2/4) (tistory.com)

 

4장 유스케이스 구현하기

도메인 모델 구현하기

  • Account 도메인의 컨셉
    • ActivityWindow에 Activity 목록을 가지고있으며, Activity 목록을 계산하여 balance를 계산
    • 최적화를 위해 특정 기간내의 Activity만 불러오며, 그 이전의 값은 baselineBalance로 미리 계산

유스케이스 둘러보기

  • 유스케이스는 도메인 로직만 있어야함.
    • 즉, 입력 유효성 검증은 이미 되었다고 가정
  • 그러나, 비즈니스 규칙의 검증은 해야됨

입력 유효성 검증

  • 유스케이스의 입력 모델을 이용해서 입력 유효성 검증을 진행
  • Bean Validation API를 이용하면, 생성자가 아니라 annotation을 이용해서 검증 가능함

생성자의 힘

  • 생성자 파라미터가 많아지면 Builder 패턴을 쓰는것을 권장하지만 저자는 chaining할 때 빼먹을 수 있으니, 강제력 측면에서 생성자 사용을 추천함

유스케이스마다 다른 모델

  • 유스케이스마다 비슷한 데이터여도 다른 입력모델을 사용하는 것을 권장
    • 비슷해보이지만, 서로 다른 유효성 검증 규칙을 가지기 때문에 code smell이 될 가능성이 높음

비즈니스 규칙 검증하기

  • 입력 유효성 검증은 syntactical 측면이고 비즈니스 규칙은 semantical 측면을 검증하는 것
  • 비즈니스 검증 규칙의 위치
    • 도메인 엔티티 내 비즈니스 규칙에 위치 (비즈니스로직과 검징이 같이 있어 가독성이 좋음)
    • 유스케이스 코드에서 도메인 엔티티 사용 전에 사용

풍부한 도메인 모델 vs. 빈약한 도메인 모델

  • 풍부한 도메인 모델
    • 엔티티에서 많은 로직을 구현하고 유스케이스는 엔티티의 진입점으로 활용
  • 빈약한 도메인 모델
    • 도메인은 Getter, Setter 만 활용하고 유스케이스에서 비즈니스 로직을 구현

유스케이스마다 다른 출력 모델

  • 호출자에게 꼭 필요한 데이터만 들고 있어야한다.
  • 잘 모르겠다면, 가능한 적게 반환하자
  • 같은 출력 모델을 사용하게되면, 강하게 결합되는거기 때문에 조심해서 사용해야된다. (단일책임원칙)

읽기 전용 유스케이스는 어떨까?

  • 유스케이스로 분류하지 않고 Query 서비스로 구분하여 읽기 전용 서비스 제공
  • CQRS 패턴과 일맥상통

유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?

  • 입출력모델을 독립적으로 모델링 한다면, 원치 않는 부수효과를 피할 수 있다.

==> 객체지향적인게 아니고 절차지향적이게 되는건 아닌가?

5장 웹 어댑터 구현하기

의존성 역전

  • 웹 어댑터와 유스케이스 사이에 포트를 둬서 의존성 역전을 적용함
    • 포트는 Application Core와 외부 세계와 통신하기위한 명세
    • 포트의 적절한 배치를 통해 외부와 어떤 통신을 하는지 명확히 구분 가능

웹 어댑터의 책임

  • 웹 어댑터가 하는 일
    • HTTP 요청을 자바 객체로 매핑
    • 권한 검사
    • 입력 유효성 검증
    • 입력을 유스케이스의 입력 모델로 매핑
    • 유스케이스 호출
    • 유스케이스의 출력을 HTTP로 매핑
    • HTTP 응답을 반환
  • 어플리케이션은 웹 어댑터가 HTTP 관련 처리를 하는지 상관없이 독립적으로 구현되야함

컨트롤러 나누기

  • 웹 어댑터는 한개 이상의 컨트롤러로 만들어도 됨
  • 컨트롤러를 나눌수록 서로 독립적인 입출력 모델을 사용하게되고 독립적이게 됨
  • 동시작업이 쉬워짐

유지보수 가능한 소프트웨어를 만드는데 어떻게 도움이 될까?

  • 웹 어댑터는 HTTP 요청 -> 유스케이스 요청 -> 유스케이스 반환 -> HTTP 반환 역할
    • 즉, HTTP는 도메인 로직 없이, 변환만 해야됨
  • 애플리케이션 계층은 HTTP와 관련된 작업을 하면 안됨 (독립적)
  • 작은 클래스 만드는게 귀찮을 수 있지만, 유지보수에 빛을 발하리..

6장 영속성 어댑터 구현하기

의존성 역전

  • 주도되는(driven) 아웃고잉 어댑터
    • 호출만될뿐 호출하지는 않음 (외부 요인에 의해 작동하거나 영향을 받는)
  • 계층간 의존성을 역전하여 서로 독립적인 개발이 가능

영속성 어댑터의 책임

  • 영속성 어댑터가 하는일
    • 입력을 받는다.
    • 입력을 DB 포맷으로 매핑한다.
    • 입력을 DB로 보낸다.
    • DB 출력을 애플리케이션 포맷으로 매핑한다.
    • 출력을 반환한다.
  • 영속성 어댑터 입력 모델이 어플리케이션 코어에 있기 때문에, 어댑터를 변경하는 것이 코어에 영향을 미치지 않음

포트 인터페이스 나누기

  • 넓은 포트 인터페이스를 사용하면 테스트 하기 어려움
    • ISP 원칙에 따라 인터페이스를 분리
    • 좁은 포트를 만들어서 플러그 앤 플레이 방식으로 개발을 할 수 있음

영속성 어댑터 나누기

  • 영속성 어댑터는 도메인의 경계에 따라서 자연스럽게 분리
  • 도메인 클래스 하나당 하나의 영속성 어댑터를 구현하는 방식
    • 어그리거트 당 하나의 영속성 어댑터 접근방식 사용
    • 바인디드 컨텍스트 영속성 요구사항을 분리하기위한 토대
    • 바운디드 컨텍스트 끼리는 인커밍 포트르 통해 통신해야함
    • 어그리거트는 바운디드 컨텍스트 하위에 속하는 개념

스프링 데이터 JPA 예제

  • 매핑하지 않기 전략
    • Account와 Activity를 연관관계 매핑하면 불러오기 편한데, 분리해서 호출함
    • JPA는 기본생성자를 필요로 함 (불필요한 생성자 생성 필요)
    • 항상 데이터의 일부만 가져오기 때문에, 연관관계 매핑이 불필요함
  • 영속성 측면과의 타협 없이 풍부한 도메인 모델을 생성하고 싶다면, 도메인 모델과 영속성 모델을 매핑하는걸 추천

데이터베이스 트랜잭션은 어떻게 해야할까?

  • 트랜잭션은 영속성 어댑터 호출을 관장하는 서비스에 위임해야됨
  • Spring 라이브러리에 독립적이고 싶으면, AOP를 통해서 위빙(weaving) 하는 방법 추천

유지보수 가능한 소프트웨어를 만드는데 어떻게 도움이 될까?

  • 도메인 코드에 플러그인 처럼 동작하는 영속성 어댑터를 만들면 도메인 코드가 영속성과 분리되어 풍부한 도메인 모델 생성 가능
  • 좁은 포트 패턴을 사용하면, 포트마다 다른 방식으로 구연하는 유연함이 생김

7장 아키텍처 요소 테스트하기

테스트 피라미드

  • 테스트는 만드는 비용이 적고, 유지보수하기 쉽고, 빨리 실행되고, 높은 커버리지를 유지
  • 여러개의 단위, 단위를 넘는 경계, 아키텍처 경계, 시스템 경계를 결합하는 테스트는 비용이 높음
  • 단위 테스트 > 통합 테스트 > 시스템 테스트
  • 단위 테스트
    • 클래스를 인스턴스화하여 기능들을 테스트
    • 다른클래스 의존이 있을 경우 mocking해서 테스트
  • 통합 테스트
    • 연결된 여러 유닛을 인스턴스해서 시작점이 되는 클래스가 데이터를 보내 테스트
    • 두 계층 간의 경계를 테스트할 수 있기 떄문에, mocking해서 테스트
  • 시스템 테스트
    • end-to-end 테스트

얼만큼의 테스트가 충분할까?

  • 얼마나 마음 편하게 배포할 수 있냐를 기준으로 삼자

유지보수 가능한 소프트웨어를 만드는데 어떻게 도움이 될까?

  • 육각형 아키텍처는 도메인 로직과 바깥으로 향한 어댑터를 깔끔하게 분리한다
  • 도메인 로직은 단위테스트, 어댑터는 통합테스트로 정의 가능해진다.
  • 좁은 포트를 이용할 수록, mocking이 시워지고 테스트하기 편함
    • mocking이 어려울 경우, 분리해야하는 경고 신호가 될 수 있음
반응형