[스프링 부트와 JPA 활용] 1. 도메인 분석 설계, 애플리케이션 구현 준비

건우·2025년 12월 12일

Back-end / Java, Spring

목록 보기
10/14
post-thumbnail

1. 요구사항 분석 – CRUD가 아니라 도메인을 본다

단순 기능만 보면 회원/상품/주문 CRUD 시스템이다.
그런데 이걸 그냥 CRUD 테이블 구조로 만들면 이후 확장에 바로 한계가 온다.

핵심은 “주문 도메인”이 중심이라는 것이다.

  • 회원은 주문을 한다.
  • 주문은 여러 상품을 가진다.
  • 상품은 재고를 가진다.
  • 주문은 취소될 수 있다.
  • 취소되면 재고가 복구된다.

→ 즉, 이 시스템은 단순 CRUD가 아니라
상태 변화와 비즈니스 규칙이 존재하는 도메인 모델이다.


2. 주문–상품을 M:N으로 두지 않는 이유

처음 보면 주문과 상품은 다대다다.

하지만 JPA에서 @ManyToMany는 거의 사용하지 않는다.

왜?

  • 중간 테이블에 추가 컬럼을 넣을 수 없다.
  • 실무에서 주문상품에는 수량, 주문 당시 가격 같은 정보가 반드시 필요하다.
  • 유지보수 난이도가 급격히 올라간다.

그래서 우리는 이렇게 푼다.

Order 1 : N OrderItem N : 1 Item

OrderItem이 단순 중간 테이블이 아니라
비즈니스 개념이 있는 엔티티가 된다.

이 설계 하나로 시스템 확장성이 완전히 달라진다.


3. 상품 상속 구조 – 현실적인 타협

상품은 도서/음반/영화로 나뉜다.

공통 속성:

  • name
  • price
  • stockQuantity

→ 공통 부모 Item

JPA 상속 전략을 사용해 하나의 테이블에 DTYPE으로 구분했다.

실무에서는 상속을 무조건 쓰기보다
구조 복잡성 vs 유지보수성을 비교해야 한다.


4. 연관관계의 주인은 “외래키가 있는 쪽”

이건 JPA에서 정말 중요한 개념이다.

연관관계의 주인은

비즈니스 주인이 아니라
외래키를 가진 쪽이다.

Ex.

  • Order가 MEMBER_ID를 가진다 → Order가 주인
  • OrderItem이 ORDER_ID를 가진다 → OrderItem이 주인

왜냐하면
외래키를 가지지 않은 쪽을 주인으로 잡으면
불필요한 UPDATE 쿼리가 추가로 발생한다.

이건 단순 문법 문제가 아니라
SQL 발생 구조와 직결된 설계 문제다.


5. 엔티티 설계 시 중요한 점

Setter를 막아야 한다

Setter가 열려 있으면
엔티티 상태 변경 지점이 무한대로 늘어난다.

→ 도메인 로직이 흩어진다.
→ 유지보수 난이도 급상승

그래서

  • 생성 메서드
  • 연관관계 편의 메서드
  • 비즈니스 메서드

위주로 설계하는 해야한다.

⸻

모든 연관관계는 LAZY

기본 전략:

@ManyToOne(fetch = LAZY)

왜?
• EAGER는 예측이 안 된다.
• JPQL 사용 시 N+1 지뢰가 된다.
• 운영 중 쿼리 튀어나오는 순간 디버깅 난이도 상승

실무에서의 원칙은:
“기본은 LAZY, 필요하면 fetch join”

⸻

컬렉션은 필드에서 초기화

private List<OrderItem> orderItems = new ArrayList<>();

이건 단순 취향 문제가 아니다.

  • null 안정성
  • 하이버네이트 내부 컬렉션 래핑 문제 방지

엔티티 설계에서 이런 디테일이 쌓여서
코드 안정성이 만들어진다.


6. 계층 구조 – 전형적인 DDD-lite 구조

controller → service → repository → domain
  • controller: HTTP 처리
  • service: 트랜잭션 + 비즈니스 흐름
  • repository: JPA 접근
  • domain: 엔티티

이 구조는 단순하지만
트랜잭션 경계와 도메인 책임 분리가 명확하다.


7. 정리

이 예제는 단순 CRUD 예제가 아니라

  • 다대다를 어떻게 풀 것인가
  • 연관관계 주인은 왜 FK 쪽인가
  • 왜 LAZY가 기본인가
  • 왜 Setter를 막아야 하는가
    를 학습하는 설계 예제다.

출처
스프링 부트와 JPA 활용 (김영한, 인프런, 2019)

0개의 댓글