[Clean Architecture] 23장. 프레젠터와 험블 객체

Introduction Link to heading

  • 프레젠터는 험블 객체 패턴을 따른 형태
    • 아키텍처 경계를 식별하고 보호하는 데 도움이 됨

험블 객체 패턴 Link to heading

  • 디자인 패턴
  • 테스트하기 어려운 행위와 테스트하기 쉬운 행위를 단위 테스트 작성자가 분리하기 쉽게 하는 방법으로 고안됨
  • 아이디어는 매우 단순
    • 행위들을 두 개의 모듈 또는 클래스로 나눔
    • 이들 모듈 중 하나가 험블
    • 가장 기본적인 본질은 남기고, 테스트하기 어려운 행위들을 모두 험블 객체로 옮김
    • 나머지 모듈에는 험블 객체에 속하지 않은, 테스트 하기 쉬운 행위를 모두 옮김
  • 험블 객체 패턴을 사용하면 두 부류의 행위를 분리하여 프레젠터와 뷰라는 서로 다른 클래스로 만들 수 있음

프레젠터와 뷰 Link to heading

    • 험블 객체
    • 테스트하기 어려움
    • 이 객체에 포함된 코드는 가능한 한 간단하게 유지
  • 프레젠터
    • 테스트하기 쉬운 객체
    • 애플리케이션으로부터 데이터를 받아 화면에 표현할 수 있는 포맷으로 만드는 것
  • 뷰는 뷰 모델의 데이터를 화면에 로드할 뿐이며, 이 외에 뷰가 맡은 역할은 전혀 없음
  • 뷰는 보잘 것 없다. → 험블!

테스트와 아키텍처 Link to heading

  • 테스트 용이성은 좋은 아키텍처가 지녀야 할 속성으로 오랫동안 알려져 옴
  • 험블 객체 패턴이 좋은 예
    • 행위를 테스트하기 쉬운 부분과 테스트하기 어려운 부분으로 분리하면 아키텍처 경계가 정의되기 때문

데이터베이스 게이트웨이 Link to heading

  • 유스케이스 인터렉터와 데이터베이스 사이에는 데이터베이스 게이트웨이가 위치함
  • 이 게이트웨이는 다형적 인터페이스
    • 애플리케이션이 데이터베이스에 수행하는 CRUD 작업과 관련된 모든 메서드를 포함함
  • 유스케이스 계층은 SQL 을 허용하지 않음
  • 따라서 유스케이스 계층은 필요한 메서드를 제공하는 게이트웨이 인터페이스를 호출함
  • 그리고 인터페이스의 구현체는 데이터베이스 계층에 위치함
    • 이 구현체는 험블 객체
    • 구현체에서 직접 SQL을 사용하거나 데이터베이스에 대한 임의의 인터페이스를 통해 게이트웨이의 메서드에서 필요한 데이터에 접근함
  • 이와 달리 인터렉터는 애플리케이션에 특화된 업무 규칙을 캡슐화하기 때문에 험블 객체가 아님
    • 따라서 테스트 하기 쉬운데, 게이트웨이는 스텁이나 테스트 더블로 적당히 교체할 수 있기 때문

데이터 매퍼 Link to heading

  • 하이버네이트 같은 ORM 은 어느 계층에 속한다고 보는가?
  • 객체 관계 매퍼 ORM 같은건 사실 존재하지 않음
    • 이유는 간단
    • 객체는 데이터 구조가 아니기 때문에
    • 최소한 객체를 사용하는 사람 관점에서 객체는 데이터 구조가 아님
    • 데이터는 모두 private 으로 선언되므로 객체의 사용자는 데이터를 볼 수 없음
    • 사용자는 객체에서 public 메서드만 볼 수 있음
    • 따라서 사용자 관점에서 볼 때 객체는 단순히 오퍼레이션의 집합
  • 객체와 달리 데이터 구조는 함축된 행위를 가지지 않는 public 데이터 변수의 집합
  • ORM 보다는 차라리 “데이터 매퍼 Data Mapper” 라고 부르는 편이 나아 보임
    • 관계형 데이터베이스 테이블로부터 가져온 데이터를 데이터 구조에 맞게 담아주기 때문
  • 다시 돌아와서, ORM 시스템은 어디에 위치해야 하는가?
    • 물론 데이터베이스 계층
  • 실제로 ORM 은 게이트웨이 인터페이스와 데이터베이스 사이에서 일종의 또 다른 험블 객체 경계를 형성함

서비스 리스너 Link to heading

  • 애플리케이션이 다른 서비스와 반드시 통신해야 한다면, 또는 애플리케이션에서 일련의 서비스를 제공해야 한다면, 우리는 여기에서 서비스 경계를 생성하는 험블 객체 패턴을 발견할 수 있음
    • 애플리케이션은 데이터를 간단한 데이터 구조 형태로 로드한 후, 이 데이터 구조를 경계를 가로질러서 특정 모듈로 전달함
    • 그러면 해당 모듈은 데이터를 적절한 포맷으로 만들어서 외부 서비스로 전송함
  • 반대로 외부로부터 데이터를 수신하는 서비스의 경우
    • 서비스 리스너가 서비스 인터페이스로부터 데이터를 수신
    • 데이터를 애플리케이션에서 사용할 수 있게 간단한 데이터 구조로 포맷을 변경함
    • 그런 후 이 데이터 구조는 서비스 경계를 가로질러서 내부로 전달됨

결론 Link to heading

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