[DDD START] 6장 응용 서비스와 표현 영역 - 응용 서비스의 역할
21 Jul 2019응용 서비스의 역할
- 도메인 객체 간의 실행 흐름을 제어한다
- 트랜잭션 처리
응용 서비스는 도메인 객체 간의 흐름을 제어하기 때문에 단순하다
public Result doSomeFunc(SomeReq req) {
// 1. 리포지터리에서 애그리거트를 구한다
SomeAgg agg = someAggRepository.findById(req.getId());
checkNull(agg);
// 2. 애그리거트의 도메인 기능을 실행한다
agg.doFunc(req.getValue());
// 3. 결과를 리턴한다
return createSuccessResult(agg);
}
public Result doSomeCreation(CreationSomeReq req) {
// 1. 데이터 중복 등 데이터가 유효한지 검사한다
checkValid(req);
// 2. 애그리거트를 생성한다
SomeAgg newAgg = createSome(req);
// 3. 리포지터리에 애그리거트를 저장한다
someAggRepository.save(newAgg);
// 4. 결과를 리턴한다.
return createSuccessResult(newAgg);
}
응용 서비스가 이것보다 복잡하다면 응용 서비스에서 도메인 로직의 일부를 구현하고 있을 가능성이 높다
예)암호 변경은 Member 도메인의 핵심 로직이므로 도메인에서 구현한다
public class ChangePasswordService {
public void changePassword(String memberId, String oldPw, String newPw) {
Member member = memberRepository.findById(memberId);
checkMember(member);
member.changePassword(oldPw, newPw);
}
}
public class Member {
public void changePassword(String oldPw, String newPw) {
if (!matchPassword(oldPw)) throw new BadPasswordException();
setPassword(newPw);
}
// 현재 암호와 일치하는지 검사하는 도메인 로직
public boolean matchPassword(String pwd) {
return passwordEncoder.matchs(pwd);
}
private void setPassword(String newPw) {
if (isEmpty(newPw)) throw new IllegalArgumentException("no new password");
this.password = newPw;
}
}
아래 코드처럼 응용 서비스에서 암호 변경을 구현하면 안된다
public class ChangePasswordService {
public void changePassword(String memberId, String oldPw, String newPw) {
Member member = memberRepository.findById(memberId);
checkMember(member);
if (!passwordEncoder.matchs(oldPw, member.getPassword())) {
throw new BadPasswordException();
}
member.setPassword(newPw);
}
}
도메인 로직을 도메인 영역과 응용 서비스에 분산해서 구현하면
- 코드의 응집성이 떨어진다
- 여러 응용 서비스에서 동일한 도메인 로직을 구현할 가능성이 높아진다