본 포스트 시리즈는 「도메인 주도 설계 철저 입문」책을 요약한 내용입니다.
이전 발행 글 보기
2024.09.04 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 2장 (1)
2024.09.04 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 2장 (1)
2024.09.05 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 2장 (2)
2024.09.09 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 3장 (1)
2024.09.09 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 3장 (1)
2024.09.11 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 3장 (2)
2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 4장
2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 5장 (1)
2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 5장 (2)
2024.09.30 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 5장 (3)
2024.10.05 - [DDD/도메인 주도 설계 철저 입문] - 도메인 주도 설계란? - 「도메인 주도 설계 철저 입문」 6장 (1)
06장 유스케이스를 구현하기 위한 '애플리케이션 서비스'
(1) 애플리케이션 서비스 구현과 DTO 활용
애플리케이션 서비스 (2) Read
CRUD 중 Read를 구현한 코드는 다음과 같다.
public class UserApplicationService {
private final IUserRepository userRepository;
private final UserService userService;
public UserApplicationService(IUserRepository userRepository, UserService userService) {
this.userRepository = userRepository;
this.userService = userService;
}
public UserData get(String userId) {
UserId targetId = new UserId(userId);
User user = userRepository.find(targetId);
if (user == null) {
throw new IllegalArgumentException("사용자를 찾을 수 없습니다.");
}
return new UserData(user.getId().getValue(), user.getName().getValue(), user.getMailAddress().getValue());
}
}
DTO의 사용
주목할 점은 사용자 데이터를 조회하는 "get" 함수의 반환 값을 User 클래스가 아닌 새로 정의한 DTO인 `UserData`로 구현한 점이다. User 인스턴스가 `UserApplicationService`에 의해 외부에 공개되어버리면, `UserApplicationService`의 클라이언트들이 이를 조작할 수 있는 문제가 있다.
접근제어자를 활용해서 User의 setter를 감출 수 있다고는 하나 같은 패키지에 있는 객체로부터 보호하기는 어렵다. 따라서 User엔티티를 직접 반환하는 것이 아니라 DTO를 반환하는 것이 좋다.
DTO의 생성자
이때 DTO의 생성자가 User의 아이디, 이름 등 필드를 개별 인자로 받게 되면 파라미터가 추가될 때마다 UserData를 생성하는 모든 곳에서 수정을 해주어야 하기 때문에 DTO의 생성자는 엔티티를 직접 받는 것이 좋다. 이렇게 하면 파라미터가 추가될 때 UserData 클래스만 수정하면 된다.
public class UserData {
private final String id;
private final String name;
public UserData(User source) {
this.id = source.getId().getValue(); // User 도메인 객체에서 id를 가져옴
this.name = source.getName().getValue(); // User 도메인 객체에서 name을 가져옴
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
파사드 패턴
사용자 정보를 수정할 때는, 수정할 필드가 때마다 다를 수 있기 때문에 다음과 같은 커맨드 객체를 정의하여 활용하는 것이 좋다. 커맨드 객체란 클라이언트가 전달해주는 파라미터 데이터를 주입 받기 위해 사용되는 객체를 말한다.
public class UserUpdateCommand {
private final String id;
private final String name;
private final String mailAddress;
public UserUpdateCommand(String id, String name, String mailAddress) {
this.id = id;
this.name = name;
this.mailAddress = mailAddress;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getMailAddress() {
return mailAddress;
}
}
커맨드 객체(수정을 위한 DTO라고 볼 수 있다) 를 사용하면 update 메소드 시그니처가 다음과 같이 한 가지, `public void update(UserUpdateCommand command)`만 있으면 된다.
public class UserApplicationService {
private final IUserRepository userRepository;
private final UserService userService;
public UserApplicationService(IUserRepository userRepository, UserService userService) {
this.userRepository = userRepository;
this.userService = userService;
}
public void update(UserUpdateCommand command) {
UserId targetId = new UserId(command.getId());
User user = userRepository.find(targetId);
if (user == null) {
throw new UserNotFoundException(targetId);
}
String name = command.getName();
if (name != null) {
UserName newUserName = new UserName(name);
user.changeName(newUserName);
if (userService.exists(user)) {
throw new CanNotRegisterUserException(user, "이미 등록된 사용자입니다.");
}
}
String mailAddress = command.getMailAddress();
if (mailAddress != null) {
MailAddress newMailAddress = new MailAddress(mailAddress);
user.changeMailAddress(newMailAddress);
}
userRepository.save(user);
}
}
이처럼 커맨드 객체는 파사드 역할을 한다.
요약
1. 어플리케이션 서비스를 구현할 때는 Entity를 직접적으로 드러내기 보다 DTO를 활용해야 한다. 2. 조회의 결과를 DTO로 표현할 시 데이터에 대한 수정을 막을 수 있다. 3. 수정할 데이터를 DTO로 표현할 시 수정 메소드의 시그니처를 하나로 통일할 수 있다. |
'DDD > 도메인 주도 설계 철저 입문' 카테고리의 다른 글
앱 서비스 인터페이스로 구현하기 - 「도메인 주도 설계 철저 입문」 6장 (4) (1) | 2024.10.06 |
---|---|
유스케이스의 응집도와 구현 - 「도메인 주도 설계 철저 입문」 6장 (3) (0) | 2024.10.06 |
유스케이스란? - 「도메인 주도 설계 철저 입문」 6장 (1) (1) | 2024.10.05 |
레포지토리 구현 시 팁 - 「도메인 주도 설계 철저 입문」 5장 (3) (0) | 2024.09.30 |
레포지토리 구현 방법과 테스트 방법 - 「도메인 주도 설계 철저 입문」 5장 (2) (2) | 2024.09.30 |