도메인 기반 디자인-엔터티 문제의 외부 종속성


22

Domain-Driven-Design을 시작하고 싶지만 시작하기 전에 해결하고 싶은 몇 가지 문제가 있습니다. :)

그룹과 사용자가 있고 사용자가 그룹에 가입하려고 할 때 groupsService.AddUserToGroup(group, user)메소드를 호출한다고 가정 해 봅시다 . DDD에서해야 할 일은 group.JoinUser(user)꽤 좋아 보인다.

사용자를 추가하기위한 유효성 검사 규칙이 있거나 사용자가 그룹에 추가 될 때 일부 외부 작업을 시작해야하는 경우 문제가 나타납니다. 이러한 작업을 수행하면 엔터티가 외부 종속성을 갖게됩니다.

예를 들어 사용자가 최대 3 개의 그룹에만 참여할 수 있다는 제한이 있습니다. 이를 위해서는 내부 그룹의 DB 호출이 필요합니다.

그러나 엔터티가 일부 외부 서비스 / 클래스에 의존한다는 사실은 나에게 좋지 않고 "자연스러워"보입니다.

DDD에서 이것을 처리하는 올바른 방법은 무엇입니까?

답변:


15

그룹과 사용자가 있고 사용자가 그룹에 가입하려고 할 때 groupsService.AddUserToGroup (group, user) 메서드를 호출한다고 가정 해 봅시다. DDD에서는 group.JoinUser (user)를 수행해야합니다.

그러나 DDD는 현재 수행중인 작업이 너무 복잡하거나 엔터티 모델에 맞지 않을 경우 (상태 비 저장) 서비스를 사용하여 작업을 수행하도록 권장합니다. 도메인 계층에 서비스를 제공해도됩니다. 그러나 도메인 계층의 서비스에는 비즈니스 논리 만 포함되어야합니다. 반면에 외부 작업 및 전자 메일 전송과 같은 응용 프로그램 논리는 응용 프로그램 계층에서 도메인 서비스를 사용해야합니다. 예를 들어 별도의 (응용 프로그램) 서비스가있을 수 있습니다.

사용자를 추가하기위한 유효성 검사 규칙이 있으면 문제가 발생합니다 ...

유효성 검사 규칙은 도메인 모델에 속합니다! 도메인 개체 (엔티티 등) 안에 캡슐화해야합니다.

또는 사용자가 그룹에 추가 될 때 일부 외부 작업을 시작해야합니다. 이러한 작업을 수행하면 엔터티가 외부 종속성을 갖게됩니다.

어떤 종류의 외부 작업에 대해 알지 못하지만 이메일을 보내는 것과 같은 것으로 가정합니다. 그러나 이것은 실제로 도메인 모델의 일부가 아닙니다. 응용 프로그램 계층에 있어야하며 imho에 저장해야합니다. 응용 프로그램 계층에 도메인 서비스 및 엔터티에서 작동하여 해당 작업을 수행하는 서비스가있을 수 있습니다.

그러나 엔터티가 일부 외부 서비스 / 클래스에 의존한다는 사실은 나에게 좋지 않고 "자연스러워"보입니다.

부자연스럽고 일어나지 않아야합니다. 실체는 책임이 아닌 것을 알지 않아야한다. 엔티티 상호 작용을 조정하기 위해 서비스를 사용해야합니다.

DDD에서 이것을 처리하는 올바른 방법은 무엇입니까?

귀하의 경우 관계는 아마도 양방향이어야합니다. 사용자가 그룹에 참여하는지 또는 그룹이 사용자를 참여하는지는 도메인에 따라 다릅니다. 사용자가 그룹에 참여합니까? 또는 사용자가 그룹에 추가 되었습니까? 도메인에서 어떻게 작동합니까?

어쨌든 양방향 관계가 있으므로 사용자가 사용자 집계 내에서 이미 속한 그룹의 수를 결정할 수 있습니다. 담당 클래스를 결정한 후에는 사용자를 그룹으로 전달하거나 그룹을 사용자에게 전달하는지 여부는 기술적으로 사소한 것입니다.

그런 다음 엔터티에서 유효성 검사를 수행해야합니다. 모든 것은 응용 프로그램 계층의 서비스에서 호출되며 전자 메일 보내기와 같은 기술적 인 작업도 수행 할 수 있습니다.

그러나 유효성 검사 논리가 실제로 복잡한 경우 도메인 서비스가 더 나은 솔루션 일 수 있습니다. 이 경우 비즈니스 규칙을 캡슐화 한 다음 응용 프로그램 계층에서 호출하십시오.


그러나 우리가 너무 많은 논리를 실체 외부로 옮기면 무엇을 내부에 보관해야합니까?
SiberianGuy

실체의 직접적인 책임! 예를 들어 "사용자가 그룹에 가입 할 수 있습니다"라고 말할 수있는 경우 사용자 엔터티의 책임입니다. 때로는 기술적 인 이유로 트레이드 오프 결정을 내려야합니다. 나는 양방향 관계를 좋아하는 팬이 아니지만 때로는 모델에 가장 잘 맞습니다. 따라서 도메인에 대해 이야기 할 때주의 깊게 들어보십시오. "엔티티는 ..." "엔티티는 ..."그런 문장을들을 때, 그 오퍼레이션은 엔터티에 속할 가능성이 높습니다.
팔콘

또한, 관련이없는 두 개 이상의 객체가 작업을 수행하여 무언가를 달성해야하는 경우 서비스가 필요하다는 것을 알고 있습니다.
팔콘

1
대답 해 주셔서 감사합니다, 팔콘! Btw, 나는 항상 상태 비 저장 서비스를 사용하려고 시도 했으므로 DDD에 한 걸음 더 다가 섰습니다.) 도메인 에서이 UserJoinsToGroup 작업이 Group에 속한다고 가정 해 봅시다. 문제는 해당 작업의 유효성을 검사하기 위해 사용자가 이미 참여한 그룹 수를 알아야합니다 (이미 3 이상인 경우 작업을 거부하려면). 데이터베이스를 쿼리해야한다는 것을 알기 위해. 그룹 엔터티에서 어떻게 할 수 있습니까? 엔티티에 자연스럽게 속 해야하는 작업에서 DB를 터치해야 할 때 더 많은 예가 있습니다 (필요한 경우 게시 할 것입니다).
Shaddix

2
글쎄, 내가 생각하면 : GroupMembership 엔티티는 어떻습니까? 팩토리에서 구성 할 수 있으며이 팩토리는 리포지토리에 액세스 할 수 있습니다. 그것은 좋은 DDD 일 것이며 회원 가입을 캡슐화합니다. 팩토리는 리포지토리에 액세스하고 멤버쉽을 생성 한 후이를 사용자와 그룹에 각각 추가 할 수 있습니다. 이 새로운 엔터티는 권한을 캡슐화 할 수도 있습니다. 아마 좋은 생각 일 것입니다.
팔콘

3

유효성 검사 문제에 접근하는 방법은 다음과 같습니다. 다음과 같은 도메인 서비스를 만듭니다 MembershipService.

class MembershipService : IMembershipService
{
   public MembershipService(IGroupRepository groupRepository)
   { 
     _groupRepository = groupRepository;
   }
   public int NumberOfGroupsAssignedTo(UserId userId)
   {
        return _groupsRepository.NumberOfGroupsAssignedTo(userId);
   }
}

그룹 엔티티는로 주입되어야 IMemberShipService합니다. 이것은 클래스 레벨 또는 메소드 레벨에서 수행 할 수 있습니다. 메소드 레벨에서 수행한다고 가정 해 봅시다.

class Group{

   public void JoinUser(User user, IMembershipService membershipService)
   {
       if(membershipService.NumberOfGroupsAssignedTo(user.UserId) >= 3)
         throw new BusinessException("User assigned to more than 3 groups. Cannot proceed");

       // do some more stuff
   }
}

응용 프로그램 서비스 : 생성자 GroupService주입을 IMemberShipService사용하여 주입 할 수 있으며 클래스의 JoinUser메소드 로 전달할 수 있습니다 Group.


1
가독성을 위해 게시물의 소스 코드 형식 을 고려할 수 있습니다.
Benni
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.