clean-architecture-book-thumbnail

프레젠터는 험블 객체(Humble Object) 패턴을 따른 형태로, 아키텍처 경계를 식별하고 보호하는데 도움이 된다.

  • 전 글에서 "클린 아키텍처"는 험블 객체 구현체들로 가득 차 있다.

Table of Contents

험블 객체 패턴

  • 디자인 패턴
  • 테스트하기 어려운 행위와 테스트하기 쉬운 행위를 분리하기 쉽게 하는 목적으로 고안됨
  • 가장 기본적인 본질은 남기고, 테스트 하기 어려운 행위를 모두 험블 객체로 옮긴다.
  • 나머지 모듈에는 험블 객체에 속하지 않은, 테스트하기 쉬운 행위를 모두 옮긴다.

예를 들어 GUI의 경우 단위 테스트가 어렵다.

  • 화면을 보면서 각 요소가 필요한 위치에 적절히 표시되었는지 검증하는 테스트는 작성하기 매우 어렵다.

하지만 GUI에서 수행하는 행위의 대다수는 쉽게 테스트할 수 있다.

  • 험블 객체 패턴을 사용하면 두 부류의 행위를 프레젠터와 뷰로 분리할 수 있다.

프레젠터와 뷰

뷰는 험블객체이고 테스트하기 어렵다.

  • 뷰는 데이터를 GUI로 이동시키지만, 데이터를 직접 처리하지 않는다.

프레젠터는 테스트하기 쉬운 객체다.

  • 프레젠터의 역할은 애플리케이션(server)으로부터 데이터를 받아 화면에 표현할 수 있는 포맷으로 만드는 것이다.
  • 따라서 뷰는 데이터를 건들지 않고 화면으로 전달하기만 하면 된다.

예를 들어 특정 부분에 날짜를 표시하고자 한다면, 애플리케이션(server)은 프레젠터에 Date 객체를 전달한다. 그 다음 프레젠터는 해당 데이터를 적절한 포맷의 문자열로 만들고, 이 문자열을 뷰 모델(view model)이라고 부르는 간단한 데이터 구조에 담는다. 그러면 뷰는 뷰 모델에서 이 데이터를 찾는다.

  • 폰트 색깔을 상황에 따라 바꾼다는 등 상황에선 불(boolean) 타입 플래그를 뷰 모델에 두고 적절한 값으로 설정한다(문자열, 열거형(enum) 형태).
  • 뷰는 뮤 모델의 데이터를 화면으로 로드할 뿐, 아무 역할이 없다.

    • 보잘것 없다(humble).

테스트와 아키텍처

테스트가하기 쉬운 구조는 아키텍처가 필수로 지녀야 한다.

  • 험블 객체 패턴이 좋은 예인데, 행위를 테스트하기 쉬운 부분과 어려운 부분으로 분리하면 아키텍처 경계가 정의되기 때문이다.
  • 프레젠터와 뷰 사이의 경계는 이러한 경계중 하나이며, 수많은 경계가 존재한다.

데이터베이스 게이트웨이

유스케이스 인터랙터와 데이터베이스 사이에는 데이터베이스 게이트웨이가 존재한다.

  • 이 게이트웨이는 다형적 인터페이스로, 애플리케이션이 데이터베이스에 수행하는 CRUD 작업과 관련된 모든 메서드를 포함한다(Spring JPA 등).

유스케이스 계층은 SQL을 허용하지 않는다.

  • 그러므로 유스케이스 계층은 필요한 메서드를 제공하는 게이트웨이 인터페이스를 호출한다.
  • 인터페이스의 구현체(험블 객체)는 데이터베이스 계층에 위치한다.
  • 구현체에서 직접 SQL을 사용하거나 데이터베이스에 대한 임의의 인터페이스를 통해 게이트웨이의 메서드에 필요한 데이터에 접근한다.

이와 달리 인터랙터는 애플리케이션에 특화된 업무 규칙을 캡슐화 하기 때문에 험블 객체가 아니다.

  • 따라서 테스트하기 쉽다.
  • 게이트웨이는 스텁(stub), 모의(mock)나 테스트 더블(test-double)로 적당히 교체할 수 있기 때문이다.

데이터 매퍼

하이버네이트 같은 ORM은 어느 계층에 속한다고 봐야할까?

저자는 객체 관계 매퍼(Object Relational Mapper, ORM) 같은 건 존재하지 않는다고 한다.

  • 객체는 데이터 구조가 아니기 때문이다.
  • 데이터는 모두 private으로 감춰져 있기 때문에 사용자는 데이터를 볼 수 없닫.
  • 사용자는 객체에서 public 메서드만 볼 수 있다.
  • 사용자 입장에서 볼 때 단순히 오퍼레이션의 집합이다.

객체와 달리 데이터 구조는 함축된 행위를 가지지 않는 public 데이터 변수의 집합이다.

  • ORM보다 차라리 '데이터 매퍼(Data Mapper)'라고 부르는 편이 나아 보인다.

    • 관계형 데이터베이스 테이블로부터 가져온 데이터를 데이터 구조에 맞게 담아주기 때문이다.

이러한 ORM 시스템은 어디에 위치해야 하는가?

  • 물론 데이터베이스 계층이다.
  • 실제로 ORM은 게이트웨이 인터페이스와 데이터베이스 사이에서 일종의 또 다른 험블 객체 경계를 형성한다.

서비스 리스너

애플리케이션이 다른 서비스(server)와 통신해야 하거나 일련의 서비스를 제공해야 한다면 어떨까?

  • 이 경우에도 서비스 경계를 생성하는 험블 객체 패턴을 발견할 수 있다.

서비스 리스너(service listener)가 서비스 인터페이스로부터 데이터를 수신하고, 데이터를 애플리케이션에서 사용할 수 있게 간단한 데이터 구조로 포맷을 변경한다.

  • 그 후 이 데이터 구조는 서비스 경계를 가로질러서 내부로 전달된다.

결론

  • 각 아키텍처 경계마다 경계 가까이 숨어 있는 험블 객체 패턴을 발견할 수 있다.
  • 경계를 넘나드는 통신은 거의 다 간단한 데이터 구조를 수반할 때가 많고 그 경계는 테스트하기 어려운 무언가와 쉬운 무언가로 분리된다.
  • 이렇게 아키텍처 경계에서 험블 객체 패턴을 사용하면 전체 시스템의 테스트 용이성을 크게 향상시킬 수 있다.

References

  • 모든 출처는 Clean Architecture 도서에 있습니다.