해시태그 생성 API

bp.chys·2020년 8월 31일
1

Spring Framework

목록 보기
14/15

요구사항

질문 답변 게시판을 만드는데, 질문에 해시태그를 등록하여 카테고리를 나누려고 한다.
해시태그를 질문에 등록하는 API를 만들어보자.

도메인 모델링 (엔티티 관계)

  • 질문과 해시태그의 연관관계를 정의하자.
  • 하나의 질문은 N개의 해시태그를 가질 수 있다. 또한 하나의 해시태그는 여러 개의 질문에서 가질 수 있으므로 질문과 해시태그는 다대다 연관관계를 갖게 된다.
  • JPA에서 제공하는 @ManyToMany 어노테이션을 사용하면 자동으로 연관관계 테이블이 생성되지만, 확장 가능성을 고려하여 QuestionHashtag 이름의 연관관계 엔티티를 별도로 만들기로 했다.

어떤 점을 고려했나?

API 설계(feat. 호출 횟수)

  • 프로젝트 전반적으로 자원을 규칙적이고 통일성있게 관리하도록 REST API를 사용했다.
  • 여기서는 현재 QuestionQuestionHashtag, 그리고 Hashtag 총 세 개의 자원이 존재한다.
  • QuestionHastag를 저장하기 위해서는 반드시 참조할 Question의 id를 알아야 한다.
  • 이때 각각의 자원을 생성하는 API를 순차적으로 요청하면 Question createQuestionHashtag createHashtag create 순으로 API가 호출 되고 호출 횟수는 해시태그 갯수(n)에 비례하여 최대 2n + 1번이 된다.
Request : 
POST '/questions'

Response :
body {
    id : 1
}
Request : 
POST '/questions/1/questionsHashtags'
body {
    name : 'http'
}
Request : 
POST '/hastags'
body {
    name : 'http'
}
  • 이러한 방식은 등록하고자하는 해시태그가 많아지면 많아질수록 요청이 완료되는데 걸리는 응답시간이 기하급수적으로 늘어나는 효과를 가져오게된다.
  • 한번의 API 요청을 보낼 때 드는 비용은 다음과 같다.
    request start + initial connection + SSL negotiation+ time to first byte + content download
  • 따라서 적은 API 호출로 요구사항을 만족할 수 있다면 그 수준을 유지하는 것이 바람직할 것이다.

도메인 컨텍스트 경계와 트랜잭션

  • 사용자는 입력한 해시태그가 달린 질문이 생성되는 것을 원하는 것이지, 해시태그와 질문이 따로 생성되는 것을 원하는 것이 아니다.
  • 각 자원에 대한 API를 따로 호출하게 되면 중간에 오류가 발생했을 때, 요청 도메인 컨텍스트에 대한 원자성이 지켜지지 않게된다.
  • 따라서 Question의 생성과 Hashtag의 생성은 하나의 트랜잭션안에서 이루어져야 한다.
  • Question과 Hashtag는 같은 Aggregate라고 볼 수 있고, Hashtag는 의미상 Question에 의해 생명주기가 관리된다고 볼 수 있다.

Question과 QuestionHashtag는 OneToMany관계이고 cascade=CascadeType.ALL + orphanRemoval = true를 이용하면 부모가 자식 컬렉션의 생명주기를 쉽게 관리할 수 있다.

  • 이 방식을 사용하면 Question을 생성하는 하나의 API 요청으로 Question과 Hashtag를 동시에 저장할 수 있고 트랜잭션을 통해 사용자에게 원하지 않는 불량 질문이 생성되지 않도록 막을 수 있다.

  • String으로 입력받은 Hastag name을 QuestionHashtag 객체로 바꾸는 과정에서 Hastag테이블에 기존에 존재하는 해시태그인지 검사하고 없다면 새로 생성할 수 있도록 HashtagService에서 해당 로직을 수행한다.

  • 각각의 서비스는 모두 @Transactional 어노테이션을 통해 새로운 트랜잭션을 만들고 수행된다.
  • @Transactional 어노테이션은 기본 전파속성이 REQUIRED로 기존에 수행되고 있는 트랜잭션이 있으면 합류하여 하나의 트랜잭션 작업하기 때문에 전체적으로 하나의 트랜잭션에서 세 개의 자원에 대한 처리를 할 수 있다.

결론

API를 개발할 때, REST 방식으로 디자인하되 불필요한 요청을 최소화하는 것이 애플리케이션 성능을 높일 수 있는 기본적인 원칙인 것 같다.
Question이 Hashtag의 생명주기를 관리하고 있다고 했지만, 정확히 말하면 QuestionHashtag의 생명주기를 관리하는 것이지 Hashtag는 Question의 영향을 받지 않는다. 특히 Question을 삭제할 때 그 문제가 드러날 수 있는데, 아무곳에서도 참조하지 않는 Hashtag가 남아있을 수 있기 때문이다.

참조하지 않는 Hashtag를 지우는 방법은 배치 스케줄링을 이용하거나, 질문이 삭제될 때마다 event를 발행하여 Hashtag를 검사하고 지우는 방법을 생각해볼 수 있다. 질문이 지워지는 빈도와 데이터 수를 생각해본다면, 후자의 방식이 효과적일 것이다.

해시태그와 같은 친숙한 기능을 직접 구현해보면서 생각보다 많은 내용을 깊이있게 고민하는 시간을 가질 수 있었던 것 같다.

profile
하루에 한걸음씩, 꾸준히

1개의 댓글

comment-user-thumbnail
2022년 7월 12일

정말 감사합니다

답글 달기