[Project] 나만의 블로그 만들기 (7) - 게시글 작성과 게시글 태그 등록 로직 변경 + UUID 사용

    제일 처음으로 작성한 게시글을 등록하는 방식은 다음 로직과 같이 되어있다.

    1. 글쓰기 버튼 클릭 [POST] -> 백엔드에서 pk값과 createdAt 만 가지는 빈 내용의 entity 생성 후 클라이언트측에 pk값 전달
    2. 클라이언트측에서는 제목, 내용, 태그 등을 작성
    3. 제목, 내용 전달 [PATCH : /contents] -> update 로직을 통해 내용 수정
    4. 태그 전달 [POST : /contentTags] -> 새로운 contentTag 엔티티 생성 후 DB에 저장

    하지만 이 방법은, 글쓰기 버튼을 누르는 순간 DB에 새로운 데이터가 생성되기 때문에 필요하지 않아진 데이터도 만들어질 것으로 생각되었고 이는 불필요한 pk값 증가 등으로 관리하는 데 있어서 불필요할 것 같다는 생각을 하였다.

    따라서, 다음에 시도한 방법은 다음과 같다.

    1. 프론트엔드의 글쓰기 페이지에서는 제목, 내용, 태그등을 입력
    2. 제목, 내용을 담은 데이터를 백엔드쪽으로 POST요청을 보내 새로운 content entity 생성 후 DB에 저장
    3. 응답으로 contentId를 내려주고, 이 contentId를 useEffect 구문을 사용하여 리렌더링 후 contentId가 undefined가 아닌 경우 태그 등록 진행

    코드로 작성하면 아래와 같다.

    먼저, 게시글을 등록하고 setContentId을 통해서 contentId를 세팅한다.

    그 다음 contentId가 세팅되면 새로 리렌더링 되고 contentId가 undefined가 아니기 때문에 tagRegister() 구문이 실행된다.

    하지만 이 방식에도 문제가 있었는데 문제는 다음과 같았다.

    1. 게시글에 사용할 제목과 글 내용을 작성하고, 태그 또한 등록한다
    2. 그런데, 게시글 생성에는 문제가 없었는데 태그 등록에는 문제가 발생한다
    3. 결과적으로 태그가 등록되지 않은 게시글이 형성된다

    사진으로 과정을 본다면 다음과 같게 된다.

    먼저 게시글을 하나 생성한다. 게시글에 제목 내용을 적고 spring이라는 태그를 선택한다. 그러고 백엔드로 요청을 보냈을 때 다음과 같이 실패 메시지가 뜬다

    하지만 게시글 목록으로 되돌아간다면?

    다음과 같이, 태그만 등록되지 않은 게시물이 생성되어 있다.

     

    이는 프론트엔드 코드에서 확인할 수 있듯이, 게시글을 먼저 생성하고 그에 따른 content id값을 받아서 새로운 페이지를 렌더링한 후 실행하기 때문이다.

     

    이를 해결하기 위해서 생각한 방법은 다음과 같은 방법이었다.

    • 그렇다면, content id값을 handleComplete 함수에서 실행하도록 하면 안되는걸까?

    라는 생각을 가지고 프론트엔드 코드를 다음과 같이 변경해보았다.

     

    변경된 코드에서는, 첫 post요청을 보낸 후 값을 받아서 setContentId을 통해서 contentId을 set하고 이에 해당하는 contentId로 tag에 POST요청을 보내는것이었다.

     

    결과는 위 사진과 같았다.

    setContentId의 경우 정상적으로 작동하였지만, 실제 post 요청 주소를 보면 undefined로 되어 있다.

    프론트엔드 쪽에 대해서 자세히 알지는 못하지만, fetch요청이 비동기로 작동하면서 첫 요청에 대한 결과를 받고 contentId가 업데이트 된 후에 진행되는 것이 아니라 그전에 2번째 POST 요청이 전달된 것으로 생각된다.

     

    이러한 문제점때문에 useEffect을 사용했던 것을 생각해보며 다른 방법을 생각해보기로 했다.

    내가 원하는 결과는 한문장으로 말하자면, 게시글과 태그가 둘 다 정상적이어야 게시글을 생성한다 이기 때문에 백엔드적인 측면에서 해결할 수 있는 방법이 없을까 고민하게 되었다.

     

    생각해본 변경 방법은 다음과 같았다

    1. 현재 2개의 엔드포인트로 작성되어 있는 요청을 1개의 엔드포인트로 변경한다 -> 이를 위해, content을 생성할 때 tag의 데이터를 함께 보내준다(현재는 제목, 내용, 작성완료 여부만 받고 있음)
    2. 들어온 데이터를 통해서, contentService와 contentTagService의 두 로직을 하나의 트랜잭션에서 실행하게 한다.
    3. 이렇게 된다면 태그가 제대로 등록되지 않는다면 게시글도 생성되지 않게 되지 않을까?

    즉, 게시글을 생성할 때부터 태그 데이터를 함께 등록하여 2번의 처리과정을 1번의 처리과정으로 바꾸기로 했다. 처음부터 이렇게 작성하지 않았던 이유는, 첫 계획에는 태그등록이 없어 추후에 추가하게 되어 content와 contentTag을 나누어 작업하였기 때문이었다.

     

    결과적으로 현재 변경한 최종 프론트 코드는 다음과 같다.

     

    백엔드 코드는 다음과 같이 변경하였다

    (create으로 하는 것이 맞는 것 같지만, 수정 로직도 함께 사용하기 때문에 modify로 현재는 사용중)

    하나의 트랜잭션 내에서 content관련 service 로직과, contentTag 관련 서비스 로직이 돌아가기 때문에, 게시글은 정상이고 태그 등록에서 문제가 생기더라도 롤백되어 게시글 자체가 생성되지 않는다.

     

    태그 등록 로직 변경


    content에 태그를 등록하고, 수정하고 또한 새로운 tag를 만드는 부분 또한 변경 및 구현하게 되었다.

    먼저, 기존 로직의 문제는 다음과 같았다.

    • 중복되는 태그가 등록이 되었다. (진짜 말도 안되는 상황. 사실 처음부터 이렇게 진행되면 안되는 것이었다.)
    • 추가를 하는 로직과 제거를 하는 로직이 분리되어 있음 -> 클라이언트 측에서는 단순히 List<String> 형태로 데이터를 보내주는데, 어떤 데이터는 delete로 어떤 데이터는 add로 하는 번거로움을 가지는 것 자체가 문제라 생각하였다
    • API를 통합한 만큼 추가/제거 로직도 통합할 필요성을 느끼고 아래와 같이 변경하였다.

    먼저, for 루프를 순회하며, 현재 등록되어 있는 contentTag가 tags 목록에 있는지 판단한다.

    또한 존재하는데 요청으로 들어온 tag 목록에는 없는 경우 삭제한 것으로 판단하여 제거를 한다.

    만약 존재한다면 굳이 건드릴 필요가 없기 때문에 request tag 목록에서 제거한다.

    만약 남은 데이터가 없다면 그대로 return을 하고 그렇지 않다면 tag 추가 목록으로 진입한다.

    만약 존재하지 않는 이상한 태그가 들어왔다면 바로 에러를 내뱉어 트랜잭션을 롤백하고, 그렇지 한다면 새로운 엔티티를 생성하여 DB에 저장한다.

     

    또한, 글 작성 페이지에서 태그를 바로 추가할 수 있도록 하기 위해서 프론트 쪽 코드를 일부 수정하였다.

     

    MUI의 Dialog를 이용해 입력칸을 만들었다.

    백엔드에서는, 단순하게 이미 존재하는 태그인지 확인한 후 존재하지 않는다면 등록해주는 방식으로 진행했다.

     

    이러한 방식으로 새로운 태그를 즉시 만들고 추가할 수 있게 구현하였다.

    UUID 사용


    중간에 코드를 보다보면 기존에는 contentId를 사용하고 있다가 UUID 를 사용하는 것으로 변경하였다. 이유로는

    • 게시글의 pk값을 클라이언트 측에서 노출시키고 싶지 않았다
    • pk값이 노출하지 않으면서 게시글을 판단하기 위해서는 별도의 컬럼이 필요했고, 중복 가능성이 매우 낮은 UUID를 사용하였다.

    대부분의 클라이언트 측 로직에서는 UUID로 사용되며, 백엔드에서는 UUID로 entitiy 찾을 때만 이용하고 이외에는 pk값을 이용하여 로직이 진행되는데, UUID를 사용하는 것보다 pk 값을 이용하는 것이 더 단순하여 조회 속도에 영향을 줄 수 있기 때문이다.

    사실, pk를 사용하지 않고 싶다는 목적이 더 강했으며 성능 문제의 경우에는 테스트를 진행해보지 않아서 현재로써는 확실하지 않다. 기능을 추가할 때마다 점점 검증하고 해나가야 할 것이 많아지는데 이것 또한 하나의 재미인 것 같다.

    댓글