spring-guide icon indicating copy to clipboard operation
spring-guide copied to clipboard

domain의 결합도

Open corhythm opened this issue 2 years ago • 4 comments

안녕하세요. 너무 질문을 많이 드리는 건 아닌지 죄송하네요 ㅠㅠ 저도 이번 프로젝트를 @cheese10yun 님이 작성하신 방법으로 Domain 별로 패키징을 해서 코드를 작성하고 있는데요, 하지만 제가 하고 있는 프로젝트의 경우, db를 읽어오는 Repository 단에서 해당 도메인이 아닌 타 도메인에 의존을 할 수밖에 없어서 @cheese10yun 님이 작성하신 것처럼 깔끔한 도메인 구조를 가져가는 데 제약이 있습니다.

상황은 다음과 같습니다.

비즈니스 로직이 항상 그룹 단위로 이루어져 있어서, Group Entity에 의존할 수밖에 없습니다. 예를 들어, Owner 정보를 가져오는 데도 현재 currentGroup에 속한 owner를 가져와야 하고, activity 정보를 가져온다고 해도, 현재 currentGroup에 속한 activity만 가져와야 해서. DB에서 데이터를 가져올 때, 반드시 Group entity와 join을 해서 가져와야 합니다. Group 자체적으로 진행되는 API는 없어서 Group만 도메인을 만들기도 참 애매합니다. 그래서 제가 생각한 방법은 아래 두 가지입니다.

  1. Group 도메인을 만들어서 각 도메인의 서비스 단에서 GroupRepository를 이용해 Group 정보를 가져온 다음 각 도메인 서비스 단에서 필요한 정보를 가공하는 방법. 하지만 이렇게 하면 DB 단에서 join하면 되는 걸, Service 단에서 자바 코드를 필터링을 해야하니, 많이 비효율적일 거 같습니다.
  2. Group entity는 그냥 각 도메인 Repository 단에서 join하는 데만 사용하고 별도의 Group 도메인은 두지 않는다.

두 방법 모두 어느 정도의 결합도가 있는 거 같지만, 제 생각에는 2번 방법이 조금 나은 거 같은데 @cheese10yun 님 생각은 어떠신지 궁금합니다.

감사합니다.

corhythm avatar May 31 '22 02:05 corhythm

@corhythm 설명 해주신 부분들이 잘 이해가 안가서 답변이 어렵네요

  1. Group entity는 그냥 각 도메인 Repository 단에서 join하는 데만 사용하고 별도의 Group 도메인은 두지 않는다. Group entity 존재 자체가 Group 도메인이 존재하는거 아닌가요?

비지니스 로직이 항상 그룹 단위로 움직인다고 말씀 하신거 보니까 여러 엔티티들이 그룹이라는 엔티티를 중심으로 동작하는 것으로 보이는데요. 그렇다면 해당 도메인이 필수 사항으로 보이는데요

  1. Group 도메인을 만들어서 각 도메인의 서비스 단에서 GroupRepository를 이용해 Group 정보를 가져온 다음 각 도메인 서비스 단에서 필요한 정보를 가공하는 방법. 하지만 이렇게 하면 DB 단에서 join하면 되는 걸, Service 단에서 자바 코드를 필터링을 해야하니, 많이 비효율적일 거 같습니다.

이 부분도 이해가 안가는 부분이 있는데요. 그룹 테이블과 다른 테이블이 FK로 참조 하는것으로 보이는데 그러면 join을 하셔서 데이터를 가져오면 되지 않나요? 왜 서비스 단에서 자바 코드로 필터링 해야하는지를 모르겠네요

말씀해주신 부분을 다 이해하고 답변을 드리는건 아니라서 조심 스럽게 제 생각을 말씀 드리면

  1. 비즈니스 로직이 항상 그룹 단위로 이루어 지고 있기 때문에 해당 도메인은 필수로 보임 (말씀 해주시는 도메인이 어떤건지는 모르겠네요. group 테이블과 매핑되는 객체를 도메인으라고 하시는 건지 아니면 다른 의미인지 모르겠지만 제가 말한 것은 테이블과 매핑되는 객체를 의미 합니다.)
  2. 그룹 엔티티와 다른 엔티티들의 연관관계 매핑은 DDD에서 말하는 동일한 애그리거트에 속하는 경우에는 객체 매핑 그렇지 않으면 단순 FK 값만 가지고 있게 설정

이렇게 진행할거 같습니다.
Group만 도메인을 만들기가 애매 하다는게 어떤 의미인지 잘 모르겠어서 답변이 어렵네요 추가 적으로 설명 해주시면 조금더 생각 해보겠습니다. 질문은 자주 주셔도 지장은 없습니다. 시간 있을 때 답변 드리면되고 저도 기술적인 고민을 해보게 되고 좋네요

cheese10yun avatar Jun 01 '22 10:06 cheese10yun

아 물론, 도메인별로 spring-guide의 예를 들면, coupon이나 Member Repository에서 Group Entity와 Join을 하면 그게 베스트입니다. 하지만 저는 spring-guide 프로젝트에서 이해하길, 도메인 Repository에서 다른 Entity (여기서는 Group)가 개입되면 도메인의 결합도가 올라가서 지양해야 한다고 생각했습니다. (실제로 spring-guide 프로젝트에서도 Coupon이나 Member Repository에서 다른 도메인이랑 조인한 게 없어서 저는 domain repository에서는 항상 해당 도메인 entity만 참여해야 한다고 생각했습니다) 위와 같이 이해를 해서, 가장 먼저 든 생각은 '그럼 다른 도메인 entity와 조인할 경우에는 타 도메인 Repository를 가져와서 서비스 단에서 자바 코드를 조작해야 하는 건가? 라는 생각을 했습니다.

정리하자면, 도메인별로 구분된 Repository에서 타 도메인 Group Entity와 join을 해도 상관이 없을까요? (제가 너무 기계적으로 도메인 repository를 구분하고 있는 걸까요...)

corhythm avatar Jun 01 '22 16:06 corhythm

제가 가이드한 내용과 다르게 이해하신 부분이 있는거 같아서 그 부분 부터 정리 하겠습니다.

domain repository에서는 항상 해당 도메인 entity만 참여 해야 하는가?

이 부분은 제가 가이드한 내용과는 다릅니다.

실제로 spring-guide 프로젝트에서도 Coupon이나 Member Repository에서 다른 도메인이랑 조인한 게 없어서 저는 domain repository에서는 항상 해당 도메인 entity만 참여해야 한다고 생각했습니다

라고 말씀해 주셨는데요. Coupon 객체에서 연관관계 매핑을 통해서 Member 객체를 가지고 있는데요 이것은 이미 Coupon Repositroy에서 Member 객체가 참여하고 있는 상태입니다. 물론 단순하게 참조 ID를 가지고 있더라도 연관관계 매핑보다는 의존관계가 약하겠지만 그것도 어느 정도 참여는 하고 있다고 저는 봅니다.

정리하자면, 도메인별로 구분된 Repository에서 타 도메인 Group Entity와 join을 해도 상관이 없을까요? (제가 너무 기계적으로 도메인 repository를 구분하고 있는 걸까요...)

그래서 정리하면 도메인 별로 구분된 Repository 끼리 타 도메인의 엔티티를 조인해도 상관이 없고, 오히려 그것을 지향하기 위해서 나온 것이 ORM이라고 생각합니다.

그러기 때문에 Repository에서 다른 도메인을 참조 하는 것은 아무 문제가 없고 사실 객체연관 관계를 맺으면 참조 하고 있다고 저는 보고 있습니다.

물론 모든 것을 객체 연관관계 매핑을 통해서 관계를 맺는 것은 저 개인적인 의견으로는 좋지 않다고 생각합니다. DDD에서 말하는 애그리 거 트 단위로 객체 연관관계를 맺고 그 밖에 바운디드 컨텍스트는 FK 관계를 맺는 것이 바람직하다고 생각합니다.

스크린샷 2022-06-02 23 38 05

이런 구조의 서비스가 있다고 가정한다면 경계 상단의 이름으로 애그리 거 트가 나뉜다고 가정할 수 있습니다. 나뉜 경계를 DDD에서는 바운디드 컨텍스트라고라고 하고 그 경계를 넘어선 객체들의 직접 적인 참조는 지양하고 단순 FK ID 값만 가지고 있는 것을 지향합니다.

그러한 이유는 다음과 같습니다.

JPA를 사용하고 객체 연관관계 매핑을 갖게 되면 각 도메인 간의 경계가 모호하게 되어 책임과 역할을 분리가 어렵습니다. 또 지속적인 연관관계 매핑을 통해서 객체 탐색을 끝 없애 진행할 수 있게 되는 문제 점이 있게 됩니다.

또 JPA 같은 영속성 컨텍스트가 존재하는 ORM의 경우 Order 객체를 조회해서 Member 객체의 이름을 변경할 수 있게 됩니다. 이것은 객체의 변경 포인트가 많이 열려있게 되는 부분이며 위에서 설명한 도메인 간의 경계가 모호해진다는 것입니다.

경계를 명확하게 나누어서 얻는 이점은 경계에 따른 컨텍스트의 해석의 차이입니다.

Order 객체는 Member를 참조하지 않고 Orderer를 참조하고 있습니다. 해당 객체는 테이블과 매핑된 객체는 아니며 JPA로 치면 @Embeddable 객체에 해당한다고 볼 수 있습니다. 이렇게 두 경계 간의 직접적인 연결을 끊으면 컨텍스트를 해석하는 부분에서 장점이 있습니다.

Order 객체에서는 단순히 회원이 아니고 주문자라고 해석되며 주문자에는 회원 주문자, 비회원 주문자로 해석될 수 있습니다. 즉 경계가 나누고 해당 경계에서 더 적절하게 컨텍스트를 풀어낼 수 있다는 장점이 있다고 생각합니다.

DDD에서 주장하는 다양한 것들에 대해서 모두 동의하며 수용하자는 것은 아닙니다. 본인 프로젝트에 적용하면 도움이 될 거 같은 개념들을 선별적으로 적용하는 것이 중요하다고 생각합니다.

마지막으로 드리고 싶은 말은

제가 작성한 기술적인 부분에 대해서 순수성만을 주장하는 것은 아닙니다. 물론 해당 개념을 설명하는 부분에 대해서는 강한 어조로 설명드리는 부분은 있지만 어디까지나 해당 개념을 설명하고자 함이지 이러한 부분들을 반드시 만족시켜야 한다는 것은 아닙니다. 저도 위 개념들을 여러 책을 통해서 학습한 결과로 선택적으로 도입하고 또 어느 프로젝트에서는 철저하게 무시합니다. 제가 학습하고 이해한 개념들에 대해서 정리한 것으로 어디까지나 제3자 입장에서 말씀드리는 것입니다.

참고 위에서 설명한 대부분의 개념은 DDD Start!, 도메인 주도 설계를 보고 학습 했습니다. 개인적으로는 DDD Start를 추천드립니다. 아마 해당 책은 절판된것으로 알고 있는데요 같은 저자가 도메인 주도 개발 시작하기 으로 새롭게 출판 한것으로 알고 있습니다. 해당 책을 읽어 보진 않았지만 목차 구성을 봤을 때 DDD Start 책과 비슷하며 더 최근에 나온 책이기에 더 좋지 않을까 합니다.

cheese10yun avatar Jun 02 '22 15:06 cheese10yun

@cheese10yun 우선 상세하게 설명해주셔서 감사합니다. 프로젝트 패키징을 하면서 항상 어떻게 구성하는 게 좋은 설계인지 고민하였고, @cheese10yun 님이 작성하신 spring-guide와 최대한 비슷하게 구성하다가, 중간중간 생겼던 의문과 @cheese10yun님의 의도를 잘못 이해한 부분과 관련해서 @cheese10yun 님의 의견을 직접 들을 수 있어서 너무 뜻깊은 시간이었습니다. 참조해주신 책 역시 조만간 구매해서 한 번 읽어보도록 하겠습니다. 다시 한 번 감사드립니다!!

corhythm avatar Jun 03 '22 00:06 corhythm