모든 글

핵심 엔티티를 가볍게 지키는 연관관계 설계

생명주기와 책임으로 ORM 연관관계를 판단하고, 검색용 부가 데이터를 분리해 핵심 엔티티를 단순하게 유지합니다.

출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다. gpt-5.6-sol 모델을 사용해 생성·편집했습니다.

태그와 이미지 컬렉션을 가진 Review 엔티티를 보자. 첫 질문은 JPA로 두 컬렉션을 어떻게 매핑할지가 아니다. 리뷰가 그 정보를 알아야 하는지를 먼저 물어야 한다. 테이블은 관련돼 있어도 중심 객체는 그 관계 대부분을 의도적으로 모를 수 있다.

리뷰는 모든 부가 개념이 없어도 리뷰다

분류와 검색에 쓰는 태그는 리뷰의 핵심 책임에서 멀다. 이미지도 선택 사항일 수 있다. Review가 태그, 이미지, 타입, 댓글과 앞으로 생길 부가 개념을 모두 소유하면 데이터베이스 모양을 따라 커지는 갓 오브젝트가 된다.

방향도 중요하다. 이미지 행에서 리뷰를 참조한다고 리뷰에 이미지 컬렉션을 둘 필요는 없다. 매핑할 수 있는지, 대칭인지보다 이 개념이 저 개념을 알아야 하는지와 그 지식이 본질에 속하는지를 묻는다.

테이블을 나눠도 객체 그래프는 만들지 않을 수 있다

검색할 태그를 별도 테이블을 피하려고 문자열 하나에 숨기면 조회가 불편하다. 태그 행은 따로 저장해 검색할 수 있게 하고 이미지 데이터도 별도 테이블에 둘 수 있다. 그래도 Review에 연관관계를 강제할 이유는 생기지 않는다.

유스케이스에서 리뷰를 먼저 저장한 뒤 각 리포지토리로 태그나 이미지 행을 넣을 수 있다. 객체 그래프 하나를 저장하는 코드보다 절차적으로 보일 수 있지만 리뷰는 작게 남는다. 태그가 리뷰의 행위인지 별도의 검색 관심사인지 배울 시간도 번다. 연관관계는 나중에 추가할 수 있지만 처음부터 모두 만들면 모델이 그 무게를 감당할 근거가 생기기 전에 핵심 엔티티가 무거워진다.

필수 이미지라면 생명주기 질문의 답이 달라진다

모든 리뷰에 이미지가 반드시 있고, 리뷰와 함께 생성·변경·삭제된다면 생명주기를 공유하므로 관계를 단단히 묶을 근거가 강하다. 이미지 없이도 리뷰가 존재하고 나중에 이미지를 추가할 수 있다면 두 주기는 덜 일치한다. 이 경우 특히 일대다 컬렉션은 늦추는 편을 택한다.

선택적 연관관계가 틀렸다거나 ORM 관계를 금지하자는 뜻은 아니다. 서비스 동작에 따라 판단하자는 것이다. 부가 개념이 본질인지, 생명주기가 정말 함께 움직이는지, 핵심 객체가 그 관계를 탐색해야 하는지부터 정한다. 조회에 필요한 모양으로 데이터는 저장하되 그 저장 구조가 소유권까지 대신 결정하게 두지 않는다.