회사에서 작은 회의를 하다가 패키지 구조에 대한 이야기를 한 적이 있다. 패키지 구조 설정에 있어서 "도메인 위주로 할 것이냐 레이어 위주로 할 것이냐"에 대한 논의였다. 그 중, 한 프로젝트 내에서 다른 도메인으로 구분되는 경우, 각 도메인들은 어떻게 통신을 해야하느냐 부분에서 열띤 토론을 한 경험이 있다.
회사의 아키텍처는 마이크로서비스 아키텍처 기반의 사가 패턴이 기본 기조이다. 따라서 서비스는 크게 도메인 서비스와 오케스트레이션 서비스로 나뉘어 움직인다. 이 말인 즉슨... 핵심이 되는 도메인 별로 서비스가 개별 프로젝트로 나뉘고 따라서 도메인 서비스는 일반적으로 패키지 구조가 하나의 응집력 있는 계층 구조를 형성한다. 그렇기 때문에 도메인 서비스에 다른 도메인이 있다? 조금 이례적인 질문이지만 그럼에도 또 나올 법한 질문이기도 했다.
도메인 주도 설계의 저자인 에릭 에반스는 책에서 "유연하고 풍부한 지식이 담긴 설계를 만들려면 다용도로 사용할 수 있는 팀의 공유 언어와 그 언어에 대한 활발한 실험이 필요하다."고 말하면서 유비쿼터스 언어가 얼마나 잘 공유되고 사용되는가가 성공적인 프로젝트의 핵심 요소라고 이야기했다. 작은 궁금증에서 시작된 물음에 꼬투리를 잡고 아래와 같은 글을 써서 팀내에 공유했었다. 글의 목적은 어느 것이 맞다 틀리다를 논하기 보다 지식의 회색지대를 좁히고 공통 언어의 영역을 넓혀서 공통과 차이를 잘 이해해보자는 것이였다. 그때 쓴 글을 조금 각색해서 다시 정리해보았다. 용어나 코드는 다른 것으로 각색하거나 추상화하였다.
아키텍처 논의에 앞서 이견이 없었던 부분은 다음과 같다고 생각합니다.
즉, 비즈니스 요구사항을 만족시킨다는 대전제 하에, 안정적이면서도 유연한 설계를 목표로 하는 것입니다.
한 프로젝트 내에 서로 다른 도메인이 나뉘는 경우 통신을 어떻게 해야 하나요?
파사드에서 해당 서비스들을 의존하고 해당 서비스에 위임된 역할을 호출하여 조합합니다.
파사드에서 다른 파사드를 의존하고 해당 파사드에 필요한 내용을 요청합니다.
AService
를 예로 들어 설명해보겠습니다. AService
에는 ADomain
과 BDomain
이라는 하위 도메인이 존재합니다. 이때 ADomain
에서 BDomain
엔티티의 정보가 필요한 경우 어떻게 해야 할까요?
첫 번째 답변의 경우, ADomainFacade
는 BService
의존을 추가합니다.
public class SimpleADomainFacade implements ADomainFacade {
private final ADomainCrudService aDomainCrudService;
private final BService bService;// BService 의존성 추가// ADomain에서 BDomain 정보를 가져와 조합합니다.public BDomainResponse somethingToDoWithBDomain(String aDomainId) {
// ADomainId를 사용하여 BDomainId를 찾는 로직
String bDomainId = findBDomainIdByADomainId(aDomainId);
// 가져온 정보로 무언가를 조합...
}
}
반면 두 번째 답변의 경우 service
가 아니라 facade
를 의존성으로 추가할 것입니다.