Skip to content

[volume-3] 도메인 모델링 및 구현#114

Open
pable91 wants to merge 56 commits intoLoopers-dev-lab:pable91from
pable91:feature/round3/round3
Open

[volume-3] 도메인 모델링 및 구현#114
pable91 wants to merge 56 commits intoLoopers-dev-lab:pable91from
pable91:feature/round3/round3

Conversation

@pable91
Copy link

@pable91 pable91 commented Feb 26, 2026

📌 Summary

Generated_image
  • 레이어드 아키텍쳐를 기반으로 크게 interface / application / domain / infrastructure 레이어로 나눴습니다.

  • JPA 엔티티와 도메인 객체를 분리하였습니다.

  • interfaces (Controller)

    • 역할: HTTP 요청/응답 변환
    • 책임: 요청 유효성 검사, DTO 변환, 응답을 클라이언트에게 전달
    • 경계: 도메인 객체를 직접 반환하지 않고 Facade/Info 만 의존
    • 협력: Facade를 호출
  • application (Facade)

    • 역할: 1개의 유스케이스 표현
    • 책임: 여러 도메인 서비스 조합, 트랜잭션 경계
    • 경계: 비즈니스 규칙을 직접 구현하지 않고 도메인에 위임
    • 협력: 여러 Domain Service를 호출해 하나의 유스케이스 완성
  • domain (Service + Model)

    • 역할: 비즈니스 규칙의 본체
    • 책임: 도메인 로직 캡슐화, 불변식 보장
    • 경계: 인프라를 모름. Repository 인터페이스만 의존
    • 협력: 같은 도메인 내에서만 직접 협력하고, 타 도메인은 Facade 레이어에서 협력
  • infrastructure (Repository impl, Entity)

    • 역할: 영속성 관리
    • 책임: DB 입출력, Entity ↔ Domain 변환
    • 경계: 도메인 로직을 의존하지 않음
    • 협력: JPA를 통해 DB와 협력

🧭 Context & Decision

문제 정의

  • 현재 동작/제약:
    • Order, OrderItem, OrderStatusHistory를 완전히 분리하여 사용 중
    • JPA Entity와 Domain 객체를 분리하여 JPA 의존성 제거
    • 각 도메인별 Service가 존재하고, Facade에서 조합
  • 문제(또는 리스크):
    • Facade가 비대해짐 (여러 Service 조합 로직이 집중)
    • Order, OrderItem, OrderStatusHistory는 라이프사이클이 같은데 굳이 분리하는 게 맞는지 의문
    • Aggregate로 묶으면 JPA 의존이 생겨서, Entity/Domain 분리의 의미가 퇴색될 수 있음

선택지와 결정

  • 고려한 대안:
    • A: 도메인 완전 분리 (현재) - Domain ↔ Entity 분리, 각 도메인 독립, Facade에서 조합
    • B: Aggregate 묶기 - Order가 Aggregate Root로 OrderItem, OrderStatusHistory 포함, Domain ↔ Entity 분리 유지
    • C: Rich Entity - JPA Entity = Domain 객체, JPA cascade로 관계 관리
  • 최종 결정:
    • 현재는 A (도메인 완전 분리) 유지
    • 학습 목적으로 분리 방식의 장단점을 체험 중
  • 트레이드오프:
    • A (도메인 완전 분리)
      • 장점: JPA 의존 없음, Domain/Service 명확
      • 단점: Facade 비대, 관계가 암묵적
    • B (Aggregate 묶기)
      • 장점: 응집도 높음, 관계 명시적
      • 단점: 변환 복잡, Aggregate 관리 직접 구현 필요
    • C (Rich Entity)
      • 장점: 단순함, JPA cascade로 관계 관리
      • 단점: JPA 강결합, 테스트 시 JPA 필요
  • 추후 개선 여지(있다면):
    • 멘토에게 실무 경험 기반 선택 기준 질문 예정

리뷰 포인트

  1. 저는 지금 Order, OrderItem, OrderStatusHistory 도메인들을 완전 분리하여 사용하고 있습니다. (Entity와 도메인 객체또한 분리하고 있어요.) DomainService랑 Domain이 명확해 져서 직관적이긴 하지만, Facade가 비대해지는건 어쩔수 없는 사이드 이펙트인것 같습니다. 그리고 라이프사이클로 같을텐데, 굳이 이렇게까지 나누는게 맞나라는 생각도 들기도 해요. 반면에 Order, OrderItem, OrderStatusHistory를 Aggregate로 묶어서 Order하나에 책임을 부과하면, Facade를 단순해 지겠지만 불가피하게 JPA에 의존하는 상황이 생길 것 같은데요. 이러면 JPA엔티티와 도메인 객체를 나눠서 JPA 의존을 피한것이 무의미해지는것이 아닌가 라는 생각이 또 드네요ㅠㅠ 트레이드 오프가 있는 상황에서 1가지를 선택하기가 좀 어렵습니다(이 케이스뿐만 아니라 평소에도 트레이드 오프 선택하기가 어려워요). 아마 이 질문에 대해 많이 문의 받으셨겠지만, 방법에 대한 선택 기준과 어떤 마음가짐으로 트레이드 오프를 대해야하는지가 궁금합니다.

✅ Checklist

🏷 Product / Brand 도메인

  • 상품 정보 객체는 브랜드 정보, 좋아요 수를 포함한다.
    • ProductInfo — likeCount, brandId, brandName, brandDescription 포함
  • 상품의 정렬 조건(latest, price_asc, likes_desc) 을 고려한 조회 기능을 설계했다
    • ProductSortType enum, ProductSearchCondition(sortType), ProductService.findProducts(), ProductFacade.getProducts() 모두 구현됨
  • 상품은 재고를 가지고 있고, 주문 시 차감할 수 있어야 한다
    • Product.decreaseStock(), OrderFacade에서 호출
  • 재고의 음수 방지 처리는 도메인 레벨에서 처리된다
    • Product.decreaseStock() 내 hasEnoughStock() 검증 후 예외

👍 Like 도메인

  • 좋아요는 유저와 상품 간의 관계로 별도 도메인으로 분리했다
  • 상품의 좋아요 수는 상품 상세/목록 조회에서 함께 제공된다
    • getProduct(), getProducts() 모두 ProductInfo로 반환 (likeCount 포함)
  • 단위 테스트에서 좋아요 등록/취소 흐름을 검증했다
    • LikeServiceTest — like 성공/중복 실패, unlike 성공/미존재 실패 4개 케이스

🛒 Order 도메인

  • 주문은 여러 상품을 포함할 수 있으며, 각 상품의 수량을 명시한다
  • 주문 시 상품의 재고 차감을 수행한다
  • 재고 부족 예외 흐름을 고려해 설계되었다
    • Product.decreaseStock() + ProductTest.fail_when_not_enough() — 도메인 레벨에서 처리
  • 단위 테스트에서 정상 주문 / 예외 주문 흐름을 모두 검증했다

🧩 도메인 서비스

  • 도메인 내부 규칙은 Domain Service에 위치시켰다
  • 상품 상세 조회 시 Product + Brand 정보 조합은 Application Layer 에서 처리했다
  • 복합 유스케이스는 Application Layer에 존재하고, 도메인 로직은 위임되었다
  • 도메인 서비스는 상태 없이, 동일한 도메인 경계 내의 도메인 객체의 협력 중심으로 설계되었다

🧱 소프트웨어 아키텍처 & 설계

  • 전체 프로젝트의 구성은 아래 아키텍처를 기반으로 구성되었다
    • Application → Domain ← Infrastructure
  • Application Layer는 도메인 객체를 조합해 흐름을 orchestration 했다
  • 핵심 비즈니스 로직은 Entity, VO, Domain Service 에 위치한다
  • Repository Interface는 Domain Layer 에 정의되고, 구현체는 Infra에 위치한다
  • 패키지는 계층 + 도메인 기준으로 구성되었다 (/domain/order, /application/like 등)
  • 테스트는 외부 의존성을 분리하고, Fake/Stub 등을 사용해 단위 테스트가 가능하게 구성되었다

pable91 and others added 30 commits February 18, 2026 10:34
김용권 added 22 commits February 23, 2026 14:55
@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pable91 pable91 changed the title Feature/round3/round3 [volume-3] 도메인 모델링 및 구현 Feb 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant