강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

JunBass님의 프로필 이미지
JunBass

작성한 질문수

토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1

헥사고날 아키텍처의 사실과 오해 (2)

애그리거트 루트의 하위 도메인들의 depth가 깊어질 때 문의

작성

·

39

0

안녕하세요 .

 

강의에서 애그리거트 루트가 하위 도메인을 일관성을 유지하기 위해

member.updateInfo() 로 MemberDetail updateinfo() 를 호출하는것을 보았는데요

 

만약 Profille에 여러 속성(프로필주소, 프로필이미지를 불러올 수 있는 주소,정보 등이 존재)이 있어 값 타입이 아닌 Entity로 존재해야 할 경우엔

member.updateInfo() -> memberDetail.updateInfo() -> profile.updateInfo() 로 depth가 내려갈 것 같은데요.

 

뭔가 잘못된 방법 같아서요..

혹시 이런 경우에는 어떻게 도메인을 설계해야 좋을지 궁금합니다...!!

답변 2

0

토비님의 프로필 이미지
토비
지식공유자

좋은 질문을 해주셨네요.

이렇게 위임을 여러 단계에 걸쳐서 하는 듯한 코드를 보면 뭔가 잘못된 것 같다는 생각이 들기도 합니다. 그래서 불필요한 중간자를 줄이는 리팩터링도 있죠.

하지만 얼핏 복잡해 보이는 이런 구조를 선택한 이유가 있고, 이게 뭔가 더 단순한 접근이 나을 것 같아 보이지만 여러 관점으로 따져봤을때 이 정도의 복잡함은 감수할만한 트레이드 오프가 있다고 생각이 됩니다.

우리가 쓰는 대부분의 클래스 라이브러리들은 앞에서 보기엔 간단한 인터페이스나 대표 클래스들의 메소드를 사용하면 됩니다. 하지만 내부 구조를 보면 꽤 여러 단계로 다른 오브젝트에게 작업을 위임하는 경우가 많습니다. 스프링은 말할 것도 없고, 많이 쓰이는 유틸리티 클래스나 자바 JDK의 라이브러리들도 마찬가지죠. 여러 오브젝트가 협력해서 일을 하다보면 이렇게 여러 단계에 걸쳐서 위임을 하는 경우가 종종 있습니다. 사실 이건 우리가 만드는 백엔드 소프트웨어 자체도 그렇지 않을까요? 뭔가 간단한 업데이트를 하는데 왜 API를 JSON으로 던져서 그걸 앞에 웹 서버와 프레임워크가 여러 처리를 하고 컨트롤러를 거쳐서 서비스와 도메인 오브젝트 리포지토리, ORM에 JDBC 등등을 타고 최종 SQL이 되어서 또 DB로 전달되자나요. 굳이 설명 드리지 않아도 왜 그런 여러 단계를 거쳐서 클라이언트/프론트가 간단한 정보 하나를 변경하는 작업을 하도록 만들었는지는 이해하실 겁니다.

애그리거트의 특징은 변경될 때 같이 변경될 가능성이 높다는 것이죠. 그래서 하나의 트랜잭션으로 묶여야 하고, 그리고 변경과 관련된 로직이 애그리거트 내의 여러 엔티티나 값 객체가 서로 협력해서 책임을 맡아서 진행하게 됩니다. 그러면서 외부에서 볼 때는 루트 하나만 존재한다고 보고 사용할 수 있게 하는 것이죠.

프로필 조회와 변경이 독립적이고, 아주 자주 일어나고, 그때 다른 조건이 없다고 하면 프로필 엔티티를 애그리거트 밖으로 빼도 됩니다. 그 자체로 하나의 애그리거트 루트가 될 수 있는 거죠.

그런데 당장 프로필 변경을 할 때는 회원의 상태가 ACTIVE이어야 한다라는 조건이 붙었다고 생각해보죠. 애그리거트를 안 쓰면, 아마도 서비스에서 회원 기본 엔티티 가져와서 상태 체크하고, 그리고 다시 프로필 엔티티 조회해서 변경하고 저장하는 기능을 만들겠죠. 프로필 변경을 독립적으로 구성되는 순간, 어떤 개발자가 프로필 변경과 관련된 새로운 방식의 기능을 추가하게 됐을 때 서비스에서 그냥 프로필 가져와서 변경해버릴 수도 있습니다. 회원 상태 체크와 상관없이요. 그 순간 도메인의 일관성이 깨지고, 일종의 논리적인 버그가 들어가죠. 그게 나중에 결과만 발견되어서 어디서 이런 문제가 발생했는지 확인하려면 꽤 어려운 작업을 해야 합니다. 결국 프로필을 수정하고 그걸 체크하는 코드가 사방에 여러 방식으로 중복되는 걸 볼 수도 있겠죠.

그런 차원에서 애그리거트가 주는 효용성이 있습니다. 물론 프로필 수정 자체는 워낙 간단한 거라 굳이라고 생각할 수도 있겠죠. 사실 도메인 모델에서 말하는 애그리거트 패턴은 꽤나 복잡한 도메인에서 더 유효할 겁니다. 우선은 강의에서 회원 등록과 관련된 단순한 예제를 써서 이런 구성을 해서 그런 장점이 크게 보이지 않겠지만, 이런 구성을 선택하는 것이 앞으로 더 복잡한 모델과 도메인 구조에서는 매우 유용할 수도 있습니다.

또, 회원 정보 업데이트할 때 한번에 여러 개의 정보가 같이 변경된다는 도메인 모델의 규칙도 있었죠. 그런 걸 지키는 것도 만들 수 있고요.

물론 단순히 조회활 때는 애그리거트 내부트의 엔티티를 노출해도 좋다고 생각합니다. 단, 이때는 그 엔티티를 읽기 전용이라고 생각하고 다뤄야 하겠죠.

그런데 이런 장점을 취하려면 또 놓치게 되는 불편함도 분명 있습니다. 무엇인가를 선택하면 어떤 다른 것은 손해를 보게 되는 상황을 트레이드 오프라고 합니다. 무조건 모든 게 다 좋은 설계는 없어요. 그래서 매번 트레이드 오프를 하게 됩니다. 저는 여기서 멤버와 디테일을 분리하는 것이 그냥 멤버 하나에 다 속성을 넣는 것을 포기하기 때문에 손해보는 것을 넘어서 더 많은 장점이 있을 거라고 보고 트레이드 오프를 한 것입니다. 프로필에 대해서도 마찬가지 일 거에요.

어떤 경우엔 위에서 언급한 대로 프로필을 독립된 애그리거트로 분리하는 것이 나을 수도 있습니다. 그런 경우가 어떨 때일지 한번 생각해보세요. 시스템이 사용되는 시나리오와 헥사곤이 받게 되는 요청, 의도 등을 잘 정리해보면 어떨 때는 하나로 할지, 어떨 때는 분리하는 것이 나을지가 달라질 겁니다.

시스템이 성장하면서 설계는 계속 발전하고 변경 될 거라서, 스프런도 앞으로 애그리거트 구조가 달라질 수도 있어요.

0

안녕하세요, 인프런 AI 인턴입니다. JunBass님!

애그리거트 루트의 하위 도메인들이 중첩되어, 여러 단계로 깊어질 때 설계에 대한 고민을 하고 계시군요. 이러한 문제는 깊이 있는 도메인 구조에서 자주 발생하는 어려움입니다. 도메인 주도 설계(DDD)에서는 이러한 문제를 해결하기 위해 몇 가지 설계 원칙과 방법론을 제시합니다.

1. 깊이를 줄이는 설계

  • 도메인 응집력 유지: 도메인의 응집력을 강화하여, 관련 속성이나 기능들을 하나의 개념으로 묶어서 관리할 수 있습니다. 프로파일과 관련된 정보들이 같은 범주에 속한다면, 이를 하나의 엔티티나 컴포넌트로 만들고, 그 내부에서 로직을 처리하도록 하는 것이 좋습니다. 예를 들어, Profile 엔티티가 관련된 속성과 기능들을 가지고 있도록 합니다.

2. 애그리거트의 크기 조정

  • 애그리거트 조정: 각 애그리거트는 하나의 완전한 트랜잭션 단위가 되어야 합니다. 너무 많은 정보를 한 애그리거트에 넣으면, 복잡도가 증가하고 성능 문제가 발생할 수 있습니다. 따라서, 애그리거트를 적절한 크기로 유지하도록 조정합니다.

3. 이벤트 주도 설계

  • 도메인 이벤트 사용: 예를 들어, Profile 정보가 업데이트되면 관련 이벤트를 발생시키고, 이 이벤트를 통해 다른 시스템이나 모듈에 변경 사항을 전파시킬 수 있습니다. 이 방식은 시스템 구성 요소 간의 결합도를 낮추고 유연성을 높일 수 있습니다.

추가적인 참고 사항

강의에서 배운 내용들을 통해 이러한 문제 해결에 대한 새로운 통찰을 얻으실 수 있습니다. 또한, 다음과 같은 관련 강의나 질문들을 통해 더욱 깊이 있는 이해를 해보실 것을 추천드립니다.

이런 부분들이 초기 설계 시점에서 잘 고려된다면 깊이 있는 도메인 구조에서 발생할 수 있는 문제들을 효과적으로 해결할 수 있을 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

JunBass님의 프로필 이미지
JunBass

작성한 질문수

질문하기