도메인 주도 설계 철저 입문 6장 학습 내용을 정리 한다.
유스케이스를 구현하기 위한 '애플리케이션 서비스'
애플리케이션 서비스를 한마디로 표현하면 유스케이스를 구현하는 객체라고 할 수 있다. 애플리케이션이란 일반적으로 사용자의 목적에 부응하는 프로그램을 의미한다. 서비스는 클라이언트가 목적하는 바를 제공하는 것을 의미한다. 앞서 도메인 지식을 도메인 객체 모델로 정의했으나 이것만으로는 사용자의 필요를 만족시키거나 문제를 해결하지 못한다. 문제를 해결해주는 소프트웨어가 되려면 이들 도메인 객체가 한 덩어리가 되어 문제를 해결할 수 있게 이끌어야 한다. 애플리케이션 서비스는 도메인 객체가 수행하는 태스크를 관리하고 문제를 해결하게 이끄는 존재다.
애플리케이션 서비스를 구현할 때 유의할 점
1. 서비스는 무상태다.
서비스는 자신의 행동을 변화시키는 것을 목적으로 하는 상태를 갖지 않는다.
2. 도메인 규칙이 유출되는 것을 방지해야 한다.
애플리케이션 서비스는 도메인 객체가 태스크를 조율하는 책임만을 갖도록 해야 한다. 애플리케이션 서비스에 도메인 규칙을 기술해서는 안된다. 도메인 규칙이 애플리케이션 서비스에 기술되면 여러 곳으로 파편화 될 수 있고, 중복 될 수 있다.
3. 응집도에 따라 적절한 크기로 분리할 수 있다.
User의 여러 유스케이스가 존재할 때 반드시 UserApplicationService에 모든 로직을 넣어야 하는 것은 아니다. 해당 서비스가 너무 비대해지는 현상을 방지하기 위해 적절한 크기로 분해하고 싶을 수 있는데 이때 참고할 수 있는 기준으로 응집도라는 개념을 참고해 볼 수 있다. 응집도는 모듈의 책임 범위가 얼마나 집중되어 있는지 나타내는 척도다. 응집도가 높으면 모듈이 하나의 관심사에 집중하고 있다는 의미이므로 모듈의 견고성, 신뢰성, 재사용성, 가독성의 측면에서 바람직하다. 응집도 계산은 클래스 내에 있는 인스턴스 변수와 메서드 내에서 인턴스 변수 사용되는지에 따라 계산해 볼 수 있다.(LCOM)
public class Program
{
private string value1 = "";
private string value2 = "";
private string value3 = "";
private string value4 = "";
public void MethodA()
{
Console.WriteLine(value1 + value2);
}
public void MethodB()
{
Console.WriteLine(value3 + value4);
}
}
public class ProgramA
{
private string value1 = "";
private string value2 = "";
public void MethodA()
{
Console.WriteLine(value1 + value2);
}
}
public class ProgramB
{
private string value3 = "";
private string value4 = "";
public void MethodB()
{
Console.WriteLine(value3 + value4);
}
}
4. Command객체의 활용
Command객체는 UseCase를 수행하기 위해 필요한 파라미터를 묶는 DTO다. 각 UseCase에 메시지를 전달할 때 필요한 파라미터들을 개별적으로 전달할 수 있고, 하나의 명령 객체로 묶어 전달하는 것도 가능할 것이다. 미미한 성능저하는 일어날 수 있으나 변경에 강점이 있다.
interface IUserApplicationService
{
Task Register(string id, string name, string email) // X
Task Register(UserRegistrationCommand command) // O
}
5. Response 객체의 활용
애플리케이션 서비스의 메서드의 반환 타입에 대해서 고민해 보면 두 가지 방법이 존재할 것이다. 첫번째는 도메인 객체 타입을 그대로 반환하는 방법, 두번째는 DTO 객체로 변환 후 반환하는 방법이다. 도메인 객체 타입을 그대로 반환하는 것은 두 가지 문제가 있을 수 있다. 도메인 객체가 외부로 공개된다는 점, 애플리케이션 서비스를 참조하는 곳에서 도메인 객체의 행동에 대해서 알 수 있다는 것이다. 물론 도메인 객체의 행동을 호출한다고 해서 Repository에 저장만 안시키면 되는 것 아닌가라는 생각을 할 수도 있지만 도메인 객체에 대한 의존성이 많아지게 되고, 변경에 조금 더 조심스러워질 것이다. 도메인 객체의 행동을 호출하는 것은 애플리케이션 서비스의 책임이다. 될 수 있으면 DTO로 변환하여 반환하자.
interface IUserApplicationService
{
User FindUserBy(Guid userId); // X
UserResponse FindUserBy(Guid userId); // O
}
public class UserApplicationService : IUserApplicationService
{
// 생략...
public User FindUserBy(Guid userId)
{
User user = this._userRepository.FindBy(new UserId(userId));
return user;
}
public UserResponse FindUserBy(Guid userId)
{
User user = this._userRepository.FindBy(new UserId(userId));
return new UserResponse(user.Id, user.Name, user.Email);
// 속성이 많은 경우, mapper를 사용
}
}
'서적 > 도메인 주도 설계 철저 입문' 카테고리의 다른 글
[도메인주도설계철저입문] 9장 팩토리 패턴 (0) | 2024.03.20 |
---|---|
[도메인주도설계철저입문] 7장 소프트웨어의 유연성을 위한 의존 관계 제어 (0) | 2024.03.14 |
[도메인주도설계철저입문] 5장 리포지토리 (0) | 2023.10.16 |
[도메인주도설계철저입문] 4장 도메인 서비스 (0) | 2023.10.16 |
[도메인주도설계철저입문] 3장 도메인 엔티티 (0) | 2023.10.15 |