[Spring Boot] 해시태그 기능을 가지고 있는 게시판 만들어보기

모지리 개발자·2022년 10월 12일
7

jpa

목록 보기
2/4

Intro

사이드 프로젝트 기획이 다 나오게 되었고 프로젝트는 게시판의 기능을 가지고 있는 커뮤니티입니다. 게시판의 게시글을 작성자가 hashtag를 추가할 수 있는데 이때 테이블 구조를 어떻게 가져갈 것인지에 대해서 고민하면서 낸 결론을 작성한 글입니다.

하고자 하는 것

글로 100번 읽는 것보다 그림 1번 보고 이해하는 것이 더 빠를 수 있기 때문에 게시글의 모습을 보여드리겠습니다.

위의 사진과 같이 게시글을 작성하는 작성자는 작성한 글에 대해 hashtag를 복수개 추가할 수 있습니다.

고민했던 것들

hashtag에 대해 테이블을 어떻게 구성하는지를 찾아보는 중 상당히 많은 분들이 같은 고민을 하고 있는 것을 발견할 수 있었습니다.
다른 분들의 고민의 흔적들도, 제가 보고 참고했던 블로그도 함께 공유하겠습니다.
juna-dev님의 블로그
bp.chys님의 블로그
okky의 게시글

테이블을 어떻게 구성하는 것이 좋을까?

우선 hashtag에 대한 테이블을 구성하는 방법은 크게 2가지 정도로 나뉘는 것 같습니다.

  • 게시글 테이블에 hashtag 칼럼을 추가해서 사용한다.
  • hashtag 테이블을 분리해서 사용한다.

게시글 테이블의 hashtag 칼럼 추가 후 사용

entity를 활용하여 설명해보겠습니다.

Board.java

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "board")
public class Board extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_id")
    private Long id;

    @Column(name = "title", nullable = false)
    private String title;

    @Column(name = "content", nullable = false)
    private String content;

    @Column(name = "hashtag")
    private String hashtag;

}

위와 같이 hashtag 필드를 가지고 있고 유저가 만약 #abc#ㄱㄴㄷ를 입력한다면 그대로 문자열 그 자체로 저장되어 가지고있는 방법입니다.

이렇게 구성한다면 장점과 단점이 뭐가 있을까요?

장점

  • 간단한 추가/수정이 가능합니다.

단점

  • 각각의 해시태그들에 대한 통계를 산출하기 어렵습니다. ex) #abc 가 쓰인 횟수, 모든 해시태그 목록

아래에서는 hashtag테이블을 분리해서 사용하는 방법에 대해 설명해보겠습니다.

hashtag 테이블을 분리해서 사용

총 3개의 entity를 아래에서 보여드릴 예정입니다.
Board entity, Tag entity가 있고 이 둘을 연결해주는 BoardTagMap entity가 있습니다.
테이블 구조는 아래와 같습니다.

Board.java

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "board")
public class Board extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_id")
    private Long id;

    @Column(name = "title", nullable = false)
    private String title;

    @Column(name = "content", nullable = false)
    private String content;

}

BoardTagMap.java

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "board_tag_map")
public class BoardTagMap extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "board_tag_map_id")
    private Long id;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "board_id")
    private Board board;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "tag_id")
    private Tag tag;

}

Tag.java

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "tag")
public class Tag extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "tag_id")
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

}

이렇게 해시태그 테이블을 분리해서 사용한다면 어떤 장단점이 있을까요??

장점

  • 위에서 언급했던 문자열 필드를 가지고 있던 방법보다 더 다양한 기능을 구현할 수 있습니다. ex) 해시태그에 대한 통계 추출 등

단점

  • 우선 테이블이 분리되어있기 때문에 복잡합니다. 생성, 수정, 삭제, 조회가 기존 문자열 필드를 가지고 있던 방법보다 복잡해집니다.

무슨 방법을 선택하는 것이 좋을까?

고민이었습니다. 각각의 방법이 장단점이 있고 당장의 기획에는 hashtag를 이용하여 통계를 내는 기능도 존재하지 않았습니다. 단순히 게시글을 조회 할 때 게시글에 어떤 hashtag가 붙어있는지만 필요했습니다.

하지만 hashtag테이블을 분리하여 관리하는 방법을 선택했습니다.

이유는 확장성을 고려했었습니다. hashtag를 활용하고 있는 다양한 레퍼런스를 참고해봤을 때(인스타그램, okky 등등) 해시태그를 이용한 통계 기능을 잘 활용하고 있는 것을 볼 수 있었습니다.

이러한 기능은 언제든지 추가될 수 있다고 판단하여 hashtag 테이블을 분리했습니다.

결론

이렇게 hashtag를 테이블에서 어떻게 관리할 것인지에 대해 알아보았습니다. 처음에는 막연하게 테이블을 분리하는게 좋다고 생각했었습니다. 다른 분들의 고민도 참고해보니 테이블의 분리만이 정답이 아닌 것을 알게되었습니다. 결국 테이블을 설계 할 때 중요한 것은 우리의 시스템이 어떤 기능을 제공하고 있는지, 또 어떤 기능을 제공할 것인지를 명확하게 알면 알수록 테이블 설계의 의사결정을 더 확실하게 할 수 있다고 느꼈습니다. hashtag와 관련하여 더 필요한 내용이 있거나 담고싶은 내용이 추가적으로 생긴다면 추가하도록 하겠습니다.

제가 잘못이해하고 있거나 잘못 작성한 부분이 있다면 지적, 비판, 피드백 뭐든 해주시면 감사하겠습니다!

profile
항상 부족하다 생각하며 발전하겠습니다.

2개의 댓글

comment-user-thumbnail
2023년 4월 20일

이렇게 글을 잘 정리해주셔서 정말 감사합니다 ㅠㅠ 너무 잘 이해했어요

답글 달기
comment-user-thumbnail
2023년 5월 11일

글 너무 잘 봤습니다 ! 전체적인 코드를 알 수 있을까요 ??

답글 달기