이전에 패키지 구조를 개선 한 후 본격적으로 미리 만들어두었던 기획서에 맞게 기능을 다시 구현하기로 하였다.

그래서 처음으로 돌아가서 엔티티 설계부터 다시 하게 되었다.

기존에도 크게 문제가 있던 수준까지는 아니었지만, 전체 기능을 파악하고 설계했던 것이 아니라서 몇몇 컬럼이 빠져있기도 했고, 회원과 관련된 부분이 설계되지 않아서 완성된 느낌은 아니었다.

그래서 이번에는 회원 엔티티까지 설계를 해서 전체적으로 mvp 정도의 느낌은 나오도록 재설계 했고, 댓글 같은 기능은 추후에 구현할 기능이라서 일단 모델 설계에서도 제외했다. 또 실제 기능과 관련없는 운영을 위한 통계 테이블도 아직 내 수준에서는 완벽하게 설계하기 힘들다고 판단했고, 제대로 된 근거도 많이 찾지 못해 나중에 데이터베이스 설계를 더 깊게 배운 후 설계하기로 결정하였다. 어짜피 기능과 관련된 부분은 아니라서 지금 당장 필요하다고 생각하지는 않았다.

이 설계에 관해서는 해야 될 얘기가 좀 많아서 1~3편 정도로 나누어 작성하기로 하였다. 1편은 전체적인 구조와 각 엔티티의 역할을 설명하려고 한다.

ERD

테이블들의 전체 구조는 다음과 같다.

novel-service.png

우선 테이블들의 이름은 집계 테이블들을 제외하고 단수형으로 통일하였다. 물론 복수형으로 쓰는 경우도 있고 나도 지금까지는 복수형으로 쓰긴 했지만 다시 찾아보니 단수형으로 쓰는 경우도 꽤 있다는 것을 알게 되었다.

또 하나의 종류의 데이터만 저장하는 엔티티 라고 본다면 복수형으로 쓰는 것 보다는 단수형이 더 자연스럽다고 판단했다. 하지만 집계 같은 통계용 테이블들은 맥락상 3일치, 7일치 혹은 특정 기간 사이의 조회수, 좋아요 수 등 여러 종류의 데이터를 담을 수 있기 때문에 novel_daily_stats 와 같이 더 명확히 복수형으로 통일하였다.

그리고 user, novel, episode 3개의 엔티티는 api 에서 외부에 노출되어야 하는 엔티티인데, 여러번 고민하다가 공개용 대체 키(public id)를 두는 것으로 결정하였다. 자세한 근거는 2편에서 설명한다.

또 생성일, 수정일, 삭제일 같은 기존의 timestamp 컬럼들은 datetime으로 변경하였다. 이유는 공부 정리에도 잘 쓰여있어서 간단히 말하면 timestamp 는 2038년까지밖에 지원하지 못하고, 이제는 datetime 도 timestamp 의 기능을 모두 사용할 수 있어서 굳이 timestamp 를 사용하지는 않았다.

마지막으로 소개글 같은 선택적 필드는 NULL 허용으로 변경해 명시적으로 NULL 을 저장하도록 하였다. 기존에는 빈 문자열을 저장하였지만, 생각해보니 문자열 만큼은 비어있다 와 존재하지 않는다가 명확히 구분되어야 사용자가 입력한 값인지, 처음부터 입력한 적이 없었는지를 구분할 수 있기 때문에 NULL 이 더 어울린다고 판단했다.

다만 정수형은 수학적으로도 기본값을 0으로 설정하는게 더 자연스럽고, 리스트 조회에서도 결과가 없다면 빈 배열을 반환하는게 결과를 조회했지만 비어있다 라는 맥락이라서 더 자연스럽다고 생각한다.

그리고 기존에는 에러 응답의 원인에 null 을 넣으면 빈 객체로 대체되도록 하였었는데, 이 부분도 생각해보면 빈 객체는 에러는 발생하였는데 원인이 비어있다 라는 맥락이라서 조금 부자연스럽다고 보았다. 차라리 null 를 명시적으로 설정하는 것이 에러는 발생하였지만 응답으로 보여줄 수 있는 원인은 없다(숨긴다) 라는 맥락이 더 잘 드러난다고 보아서 조만간 수정할 예정이다.

novel (소설)