메모장 프로젝트에 좋아요 기능을 넣어두고 좋아하던 중, 뜻하지 않은 난관에 마주했다. 바아로 리팩터링에 들어가서 고친 후 기록으로 남겨본다.
튜터님께서 제안 해 주신 부분이다. 좋아요 기능이 실행되려면 어떤 API가 필요할까?
위와 같은 따봉을 누를 때, 즉 하트 아이콘이 활성화되지 않은 상태일 때 누르면 좋아요가 +1 되어야 한다.
반대로 위 하트 아이콘이 활성화되어 있는 상황에서는 좋아요가 취소되어야 한다.
-> 결국, API는 두개로 분리되어야 하는 것이다.
그렇다면 이전에 만든 서비스 로직과 API는 어땠을까?
위와 같이 if문을 사용해서 리퍼지토리에서 findById했을 때 비어있다면 추가를 하고, 이미 존재한다면 delete하는 방식이다. 컨트롤러 단도 살펴보자
컨트롤러도 이런 식으로 하나의 API 요청밖에는 없다.
음? like하는 API는 여기 와서 받았는데, 그럼 취소 할 땐 어떤 API를 써야하지?
음...API명세에 없나? 뭐지? 쭉쭉 더 글을 읽다가 마지막에 저~~ 아래에
- 좋아요 실행할땐 뭐 3020 취소할땐 4321 뭐 이렇게 보낼거에요~
-> 극대노, 퇴사, 명세를 너무 자세히 읽은 나머지 시력감퇴
예를 들어 저 로직 안에서 문제가 발생했다고 하자. 좋아요수가 올라가기는 하는데 내려오질 않아. 그렇다면 저 로직을 다 뜯어고쳐야 한다.
그런데, 이렇게 간단한 게 아니라 엄청 복잡한 로직이면?
테스트 코드 작성 테스트 등등 여러가지 문제를 해결하는데 걸리는 시간과 비용이 어마어마 할 것이다.
우리는 위와 같은 문제점을 살펴봤다. 즉, 이렇게 하면 지구는 멸망하게 된다. 그렇다면 어떻게 해야할까?
관심사의 분리가 필요하다. API를 나눠서 다르게 요청을 보내야 한다.
위와같이 API를 나눠서 맵핑한다. 이렇게되면 더 기능의 분리가 명확하고, 혹시 delete부분에 문제가 생겼다고 한다면 delete 부분의 컨트롤러와 서비스 등등을 살펴보면 되고, 테스트 코드 작성에도 훠얼씬 훨씬 용이 할 것이다.
서비스 로직을 다시 한 번 살펴보자.
위와 같은 형태로 되어있다. 저렇게 되면 문제가 뭘까? 아래 responseDto의 형태를 보면서 다시 생각해보자.
comments.getlikes 가 문제이다. 왜냐?
-> 하나의 댓글에 따봉이 100만개, 2000만개가 달렸다고 생각해보자. getLikes를 하면 엔티티 테이블을 싹다 훑어서 다 가져온 후에 사이즈만 쏙 빼먹고 다시 돌려준다. DB 입장에서 받는 부하가 너무너무너무 커진다. 이렇게 되면 서버는 Out of memory로 다운되고 지구는 멸망한다.
그렇다면 어떻게 해야하지? repository에 수만 빼오는 방법이 있나? 뭐 countNumberBy...이런게 있어?
있다.
서비스단에서 적용한 모습이다. 이렇게되면 무슨 장점이 있을까?
Memo가 Likes와 연관관계를 맺지 않아도 된다.
-> 원래는 Memo가 OneToMany로 List 형태의 Likes를 소유했다. 그러나 위와 같이 바꾸게 되면 Memo엔티티는 좋아요 수 카운트! 만 가지고 있으면 된다. 직접 참조 할 필요가 없다.
DB의 부하가 줄어든다.
-> Likes 엔티티 전체를 불러오는 게 아니라 count만 불러온다. DB의 부하가 훨 씬 적어지게 된다.
좋아요를 누르면 카운트 올라가고 다시 누르면 내려요~
라고 했다고 정말 하나에 다 때려박으면 나중에 아주 곤란해진다.