이전 포스트에서 서비스가 무엇인지 알아보았으며, 비즈니스 로직은 최대한 도메인의 책임으로 부여하고 나머지 애매한 계산 로직은 Manager클래스를 만들어 서비스 레이어를 구성하는 것이 좋다는 것을 알았다.
하지만 비즈니스 로직을 서비스 클래스가 아닌 도메인으로 옮길 수 있다. 이 방식은 그렇게 어렵지 않다. PriceManager의 클래스명을 Cashier로 변경해보자.
이렇게 도메인 서비스로 만들어졌어야할 클래스를 도메인으로 만들면 조금 더 능동적인 객체들이 협력하도록 할 수 있다. 따라서 객체 지향에 조금 더 가까워진 것이다.
이름 하나 바꿨는데 도메인으로 평가 받는 것이 갸우뚱할 수 있다. 하지만 이름은 생각보다 더 많은 것을 결정한다. 클래스의 역할은 이름을 짓는 순간 결정된다. Cashier라는 이름은 점원을 역할을 수행하며 능동적으로 일할 것 같은 이름이지만, PriceManager라는 이름은 가격과 관련된 ‘연산’ 로직만 갖고 있을 것처럼 느껴진다. 그래서 이 클래스로 만들어진 객체는 자아를 가진 객체로 사용하는 것이 아니라 그저 계산식을 여러 개 가지고 있는 유틸리티로서의 역할을 기대받으며 사용될 것이다. 따라서 이는 유의미한 도메인 객체로 확장되기 어렵다.
- 서비스는 가능한 적게 만들고, 얇게 유지해야한다.
- 서비스보다 풍부한 도메인 모델을 만들어야한다.
서비스를 얇게 만든다는 것은 로직의 길이를 최대한 짧게 유지하라는 의미이며, 이는 비즈니스 로직을 도메인 객체로 옮기는 것으로 해결할 수 있다.
서비스 코드를 작성하기에 앞서 조금만 더 생각해보자. 지금 작성하는 코드가 사실 도메인 모델의 코드가 될 수 있을지 조금만 더 생각해보면 객체 지향에 가까운 코드에 한걸음 더 가까워질 수 있다.
개발 우선 순위
도메인 모델 > 도메인 서비스 > 어플리케이션 서비스
이 개발 우선순위는 테스트에 용이한 순서이기도하다. 어플리케이션 서비스의 역할을 상기해보자.
어플리케이션 서비스는 어플리케이션을 구축하는데 필요하지만, 도메인 모델로 표현하기 까다로운 연산 로직을 갖고 있는 객체라고 했다. 그래서 데이터베이스 연동과 같은 코드가 포함된 스프링 서비스 컴포넌트가 여기에 해당한다. 이처럼 어플리케이션 서비스는 JPA와 관련된 저장소 코드나 네트워크 호출 같은 까다로운 외부 연동을 수행할 확률이 높다. 상식적으로 외부 연동을 테스트 환경에서 재현하기란 아주 까다롭다.
하지만 도메인 모델과 도메인 서비스는 그렇지 않다. 이는 외부 인프라에 의존하지 않기 때문에 비교적으로 테스트가 수월하다.