JPA 엔티티에서의 연관관계
최근 모바일앱 사이드 프로젝트를 진행하면서 모바일 앱용 API 서버를 구축하고 있다. 프로젝트를 진행하면서 기존에 사용하던 SQL mapper(=MyBatis) 대신에 ORM(Object Relational Mapping) JPA를 이용하고 있다. 테이블 설계를 진행하면서 DB 접근 방식을 바꿨기 때문이라고 하기에는 그 이상으로 어색하고 작업이 더딤을 느끼게 되었다. 그러다가 내가 스스로 일을 어렵게 만들고 있다는 생각에 다다르게 되었는데 바로 테이블 설계
를 해야하는가의 고민이었다.
기존 프로젝트들을 생각해보면 데이터 기준으로 테이블 구조를 먼저 설계하고 설계된 테이블 구조 위에 비즈니스 로직을 구성하였다. 그렇기 때문에 모든 로직을 테이블 구조를 거스르지 않도록 설계할 수 밖에 없고, 헷갈리는 상황에서도 무조건 테이블을 따라갈 수 밖에 없다. 하지만 JPA를 사용한다면 테이블 설계가 아닌 엔티티(객체) 설계
를 생각해야 한다. 기존 테이블 설계 전략에서는 Entity = Table 이었다면, ORM에서는 테이블을 먼저 고려할 필요가 없다. 실제 비즈니스 로직에서 사용하게 될 엔티티(객체)를 설계해보는 것이다. 바로 이 부분이 나를 힘들게 했다. 실컷 엔티티(객체) 설계를 통해 로직을 만들어놓고, 빌드를 돌려 생성되는 테이블을 확인하고 있던 것이었다. 그러다보니 내가 구상 한 대로 테이블 형태가 나오지 않으면 엔티티를 변경하고, 테이블 설계에 맞도록 끼워 맞추고 있었다.
잠시 DB 테이블은 잊자
Persist framework로 ORM을 사용하기로 결정했다면 초기 설계 단계에서는 의도적으로 DB 테이블은 생각하지 않으려고 노력하는게 도움이 될 수 있다. 테이블 설계 위주의 프로그래밍이 익숙할 수록 관성적으로 테이블 구조를 신경쓰기 때문에 고의적으로 테이블을 보지 않으려고 노력하는 것이 방법이 될 수 있는 것이다. 물론 ORM을 사용한다고 해도 결국은 테이블에 데이터가 쌓이는 것이기 때문에 어느정도 엔티티 구성이 끝난 후 세밀한 테이블 튜닝을 할 필요가 없다는 것은 아니다.
예를 들어 아래와 같은 엔티티 구성을 보면 양방향 다대일 관계
의 엔티티 연관관계가 맺어져 있다. (한 유저가 여러개의 채팅방에 들어갈 수 있기 때문에 현실에서는 다대다 관계이지만 설명을 위해 유저는 한개의 채팅방에만 참여할 수 있다고 가정한다) ChatRoom에서도 참가한 User List을 찾을 수 있고, User를 통해서도 참가한 ChatRoom을 찾을 수 있다. 그리고 해당 연관관계의 주인은 N에 해당하는 User가 될 것이다.
이를 단방향 연관관계로 바꾼다면 아래와 같이 ChatRoom에서 User List를 뺄 수 있다. 이때 ChatRoom의 참가자를 확인하기 위해서는 반드시 User를 통해 접근해야 한다. 엔티티 연관관계 측면에서는 두 개의 설계는 서로 다르지만 Table은 동일하게 생성 될 것이다. 양방향과 단방향 모두 연관관계의 주인인 User쪽에만 FK가 생기는 것이다.
만약 JPA에 익숙하고 처음부터 JPA를 통해 개발 업무를 해왔다면 당연한 이야기로 들리겠지만 Table 구조 설계에 익숙한 나에게는 위와 같은 상황이 어렵게 느껴졌다. DB layer에서 생각하는 PK, FK 등의 개념과 엔티티의 N:N 연관관계, 양방향/단방향 등의 관계 등을 혼재해서 생각했기 때문이다. 그렇기 때문에 의도적으로 DB 테이블 설계를 하지 않으려고 노력했고, 객체간의 관계에만 집중을 하기 시작했다. 이 방법은 나에게 꽤나 효과가 있었고, 막혀있는 무언가를 뚫어주는 느낌을 받을 수 있었다. 혹시나 나와 같은 어려움을 겪고 있는 사람이 있다면 이 방법을 추천하고 싶다.
📌 ORM(JPA) 방식의 DB 접근전략을 사용하기로 했다면 의도적으로 DB 테이블은 생각하지 말자.