도메인 서비스 : 도메인 모델 내 무상태 오퍼레이션 제공
애그리게잇이나 값 객체의 행위로써 어울리지 않는 것
before
class Product {
Set backlogItems ;
BusinessPriorityTotals businessPriorityTotals () {
//...
}
}
모델 정제를 통해 Set backlogItems 를 분리
그렇다면 businessPriorityTotals() 메서드는 어떻게 되는가?
after
class Product {
static BusinessPriorityTotals businessPriorityTotals (
Set aBacklogItems ) {
// ...
}
}
정적 메소드로 변경 - 하지만 과연 이것은 옳은가?
도메인 서비스 가 필요한 시점이다!
도메인 서비스란 무엇인가
하지만 그보다 먼저 도메인 서비스가 아닌 것은 무엇인가?
도메인 서비스 : 도메인 로직이 있다.
애플리케이션 서비스 : 도메인 로직이 없다. (보안, 트랜잭션 등)
정의
엔터티나 값객체의 책임이 아닌 (도메인적) 행위
유비쿼터스 언어로써 표현
무상태!
예시
중요 비즈니스 프로세스
복수 개 의 도메인 객체에서 필요로 하는 계산
한 조합에서 다른 조합으로 도메인 객체를 변형 할 때
서비스가 필요할지 확인하자
도메인 특화 지식은 클라이언트로 절대 유촐돼선 안된다.(클라이언트가 애플리케이션 서비스일지라도)
도메인 객체에 위치 시키기 애매하면 도메인 서비스 에 담는다.
주의 : 도메인 서비스를 남용하면 빈약한(Anemic) 도메인 모델이 된다.
도메인에서 서비스를 모델링하기
AuthenticationService
package com . saasovation . identityaccess . domain . model . identity ; // !!
interface AuthenticationService {
UserDescriptor authenticate (
TenantId tenantId ,
String username ,
Strin password );
}
EncryptionAuthenticationService
package com . saasovation . identityaccess . infra . services ; // !!
class EncryptionAuthenticationService implements AuthenticationService {
@Override
UserDescriptor authenticate (
@NonNull TenantId tenantId ,
@NonNull String username ,
@NonNull Strin password ) {
Tenant tenant = tenantRepository . findById ( tenantId );
if ( tenant == null || ! tenant . isActive ()) {
throw new TenantNotFoundException ( tenantId );
}
String encryptedPassword =
encryptService . encryptedValue ( passwod ); // 암호화 책임도 도메인 서비스?
User user = userRepository . findByTenantAndUsernameAndPassword (
tenant , username , encryptedPassword );
if ( user == null || ! user . isEnabled ()) {
throw new UserNotFoundException ( username );
}
return user . userDescriptor ();
}
}
분리된 인터페이스가 꼭 필요할까
다형성이 요구되지 않는다면 굳이 분리된 인터페이스는 필요하지 않다고 본다.
다형성 등으로 인한 추상화가 요구될 때 분리된 인터페이스로 리팩토링 하자
생각 : 구현클래스에 Impl 접미사를 붙이는 것은 가능하면 피하는 것이 좋다고 본다.
DI 프레임워크(ex:Spring)를 사용하면 분리된 인터페이스를 사용하기 더 편하다.
계산 프로세스
생각 : 계산(연산)은 변하지 않는 행동이므로 분리된 인터페이스 는 필요하지 않다.
대부분 경우 계산 프로세스를 정적 메서드 로 해결하는 경향이 많다.
이는 잘못된 행동이며 계산이 도메인 로직을 표현한다면 당연히 도메인 모델 내에 도메인 서비스로써 존재 해야 한다.
참고 : p.369 ~ 371 소스코드
변환 서비스
타 서비스와 통합을 위해 사용
이것도 도메인 서비스 였다니
Adapter
package com . saasovation . collaboration . infra . services ;
class UserInRoleAdapter {
T toCollaborator (
Tenant tenant , String identity , String role ,
Class collaboratorClass );
}
Translator
package com . sasovation . collaboration . infra . services ;
class CollbaratorTransaltor {
T toCollaboratorFrom (
String json , Class collaboratorClass );
}
생각 : translator도 도메인 서비스 인가?
도메인 서비스의 미니 계층 사용하기
가능하면 미니 계층은 사용하지 말자 - 안티패턴!
하지만 필요하다면 특정 도메인만 제한적으로 사용하는 것도 좋다.
마무리
도메인 서비스는 필요할 때 사용
남용하면 빈약한 도메인 모델화
무상태
VS 애플리케이션 서비스
IDDD 7장. 서비스 was originally published by MJ at DevOOOOOOOOP on May 18, 2018.
source : http://redutan.github.io/2018/05/18/IDDD-chapter07
---------------------------------------------------------------------------
Visit this link to stop these emails: http://zpr.io/nXidW