프레젠터는 험블 객체(Humble Object) 패턴을 따른 형태로, 아키텍처 경계를 식별하고 보호하는 데 도움이 된다.
험블 객체 패턴
험블 객체 패턴은 디자인 패턴으로, 테스트하기 어려운 행위와 테스트하기 쉬운 행위를 단위 테스트 작성자가 분리하기 쉽게 하는 방법으로 고안되었다.
- 행위들을 두 개의 모듈 또는 클래스로 나눈다.
- 가장 기본적인 본질은 남기고, 테스트하기 어려운 행위를 모두 험블 객체로 옮긴다.
- 나머지 모듈에는 험블 객체에 속하지 않은, 테스트하기 쉬운 행위를 모두 옮긴다.
프레젠터와 뷰
GUI는 화면에서 각 요소가 필요한 위치에 적절히 표시되었는지 테스트 해야하므로 작성하기 어려운 반면, GUI에서 수행하는 행위의 대다수는 쉽게 테스트할 수 있다.
험블 객체 패턴을 사용하면 두 부류의 행위를 분리하여 프레젠터와 뷰라는 서로 다른 클래스로 만들 수 있다.
뷰
뷰는 데이터를 GUI로 이동시키지만, 데이터를 직접 처리하지는 않는다.
- 험블 객체이고 테스트하기 어렵다.
- 포함된 코드를 가능한 간단하게 유지한다.
프레젠터
애플리케이션으로 부터 데이터를 받아 화면에 표현할 수 있는 포멧으로 만든다.
- 뷰가 데이터를 받아 화면에 전달하는 간단한 일만 처리하도록 만들어준다.
- 테스트하기 쉬워진다.
뷰는 뷰 모델의 데이터를 화면으로 로드할 뿐이며, 이 외에 뷰가 맡은 역할은 전혀 없기 때문에 뷰는 보잘것없다(Humble)
테스트와 아키텍처
테스트 용이성은 좋은 아키텍처가 지녀야 할 속성으로 오랫동안 알려저 왔다.
험블 객체 패턴은 테스트하기 쉬운 부분과 테스트하기 어려운 부분으로 분리하여 아키텍처 경계를 정의하므로 테스트가 용이하다.
즉, 아키텍처에 험블 객체 패턴을 적절히 활용하면 프레젠터와 뷰와 같이 테스트가 용이한 구조를 만들 수 있다.
데이터베이스 게이트웨이
유스케이스 인터랙터와 데이터베이스 사이에는 데이터베이스 게이트웨이(데이터베이스의 쿼리를 처리하는 모든 메서드가 포함)가 위치한다.
유스케이스 레이어는 SQL을 허용하지 않아야 하므로 필요한 메서드를 제공하는 게이트웨이 인터페이스를 호출하게 되는데, 이 때 데이터베이스 레이어에 존재하는 인터페이스의 구현체가 험블 객체이다.
이와 달리 인터랙터는 애플리케이션에 특화된 업무 규칙을 캡슐화화기 때문에 험블 객체가 아니기 때문에 게이트웨이는 가짜 데이터(Mock, stub, test-double, fake)를 통해서도 테스트를 할 수 있으므로 테스트하기 쉬워진다.
데이터 매퍼
하이버네이트와 같은 ORM은 어느 계층에 속하는가?
ORM 시스템은 데이터베이스 레이어에 위치하며 게이트웨이 인터페이스와 데이터베이스 사이의 일종에 또 다른 험블 객체 경계를 형성한다.
- 사용자 관점에서 객체는 공개된 메서드만 볼 수 있으므로, 단순히 오퍼레이션의 집합이다.
- 데이터 구조는 함축된 행위를 가지지 않는 공개된 변수의 집합이다.
객체는 데이터 구조가 아니기 때문에, 사실 객체 관계 매퍼(Object Relational Mapper, ORM)는 관계형 데이터베이스 테이블로부터 가져온 데이터를 데이터 구조에 맞게 담아주는 역할을 수행하므로 사실 데이터 매퍼라고 볼 수 있다.
서비스 리스너
서비스에서도 험블 객체 패턴을 발견할 수 있다.
애플리케이션은 데이터를 간단한 데이터 구조 형태로 로드한 후, 이 데이터 구조를 경계를 거슬러 특정 모듈로 전달하고, 데이터 구조를 전달받은 모듈이 적절한 포맷으로 만들어 외부 서비스로 전송하게 된다.
외부로부터 데이터를 수신하는 서비스는 서비스 리스너가 서비스 인터페이스로부터 데이터를 수신하고, 데이터를 애플리케이션에서 사용할 수 있게 간단한 데이터 구조로 포맷을 변경하여 서비스 경계를 가로질러 내부로 전달된다.
결론
아키텍처 경계마다 험블 객체 패턴을 발견할 수 있다.
경계를 넘나드는 통신은 거의 모두 간단한 데이터 구조를 수반할 때가 많고, 대개 그 경계는 테스트하기 어려운 무언가와 테스트하기 쉬운 무언가로 분리된다.
이러한 아키텍처 경계에서 험블 객체 패턴을 사용하면 전체 시스템의 테스트 용이성을 크게 높일 수 있다.