많은 SNS에서 댓글을 먼저 보여주고 대댓글을 나중에 보여주는 데에는 이유가 있다고 생각되고, 심지어는 댓글만 띄워도 페이징을 사용하는데, 댓글과 대댓글을 한 번에 불러올 생각을 했다는게 쪼끔 성급했던 것 같습니다...
그리고 댓글과 대댓글을 합치는 것이 둘이 같은 기능이라 생각되어서 합쳐도 될 것 같다! 라고 생각했습니다만, 댓글이 대댓글보다 상위 계층이라는 것 하나만으로도 다른 기능으로 봐야할 것 같단 생각이 들었습니다.
요구사항에 따라 댓글과 대댓글을 구현해야 했다.
두가지 방법이 있다고 생각을 했고, 두가지 방법을 비교해보고 지금 나에게 맞는 방식을 택할 생각이다.
한 게시글에 100개의 댓글이 있고, 각각의 댓글에 1000개의 대댓글이 있는 상황을 가정했다.
처음엔 스프링부트의 메소드 실행시간을 측정하려 했지만, 이후에 비교할 상황들은 클라이언트에서 한 번의 api콜을 필요로 하는 반면에, 이번 구현은 댓글과 대댓글의 api를 나누었기 때문에 클라이언트 상에서의 실행시간을 비교해봐야한다고 생각이 들었다.
물론 실험 환경이 로컬이기 때문에 네트워크 지연속도가 실험에 큰 영향을 미치진 않겠지만, 실 서버 구성에 따라 클라이언트와 서버가 같은 pod안에 있을수도 있기도 하고, 모든 상황을 갖춰놓고 실험하기엔 시간이 너무 많이 들기 때문에 로컬에서 실험해보는것도 꽤나 유의미한 결과를 낼 수 있을것이라 생각했다.
가장 쉽게 생각할 수 있는 방법은 댓글과 대댓글의 테이블을 분리하는 것이다.
1-1
위와 같이 게시글-댓글-대댓글이 각각 계층을 이루도록 하였다.
위와 같이 게시글-댓글이 각각 계층을 이루도록 하였다.
댓글 테이블에 부모 댓글인지의 여부, 부모 댓글의 id를 담도록 하여 대댓글 테이블을 없애고 댓글 테이블 하나로 구성했다.
기존에 두가지의 api를 호출했던것과 달리 한 게시글의 댓글을 호출하면 댓글,대댓글이 모두 호출된다.
따라서 1번 방법에서 100개의 댓글과 그 대댓글을 불러오는데에는 101번의 호출이 필요했던 것이 1번의 호출로 변경된다.
두 결과를 비교해보겠다.
설계 측면에서 생각해보자.
댓글과 대댓글의 테이블을 분리하고, @ManyToOne
어노테이션으로 연관 관계를 지정해준 것은 객체지향적인 설계를 따르는 것이다. 또한 댓글과 대댓글을 나누어 따로 불러오는 것은 둘의 역할에 선을 명확히 그은것이다.
반대로 생각하면 테이블을 나누지 않고 댓글과 대댓글을 구현하는 것은 객체지향적인 설계는 분명히 아니다.
하지만 대댓글이 댓글과 구분해야할 만큼 큰 별도의 역할이 있는지는 잘 모르겠다. 그저 댓글 밑에 달려있는 또다른 댓글이라는 특징을 갖고 있는것 외에는 모든 특성이 일반 댓글(부모 댓글)과 동일하다고 생각했다. 따라서 테이블을 분리하지 않고, 댓글 테이블에 “부모인지 여부”, “부모의 아이디”를 갖도록해서 테이블을 합치는 방법을 고안한 것이다. 물론 JPA를 사용하는 지금 프로젝트에서 아이디를 칼럼으로 갖게 하는것이 좋은 설계는 아니겠지만, 점점 연관관계를 없애려고 하는 시도를 하고 있기에 충분히 수용 가능한 설계라고 생각했다.
따라서 설계 측면에서도 각각의 장단점이 있다고 생각했다.
성능 측면에서 생각해보자.
API 호출횟수는 방법#1은 101번 방법#2는 1번으로 압도적인 차이이다.
하지만 반대로 말하면 방법#1이 101번에 나누어서 받아온 데이터를 방법#2는 한번에 받아온다는 이야기가 되고, 이는 단점으로 작용할 수도 있다고 생각된다.
한번에 요청하면 네트워크 응답비용을 한번만 지불해도 되므로 선뜻 유리해보이기는 한다.
하지만 만약 네트워크 상태가 불안정해서 한번에 많은 데이터를 불러오는것 보단 데이터를 나눠서 받고, 실패지점부터 재요청하는것이 유리할 수도 있다.
또한 반대로 생각하면 서버의 사양이 뛰어나고, 네트워크 성능이 원활할 것으로 예상될 때는 클라이언트-서버 간의 통신 횟수를 줄이는것이 비용적으로 더 이득일 수도 있다.
두 테이블을 합치면 댓글 테이블에 두 개의 칼럼이 추가되는데, 솔직히 이건 성능에 영향을 미치지 않는다고 생각한다.
다음은 대댓글 1000개를 불러오는데 걸리는 시간이다
스프링 메소드 실행시간은 약 84ms인 반면, 포스트맨에서 측정한 응답시간은 113ms이다. 몇 번 측정을 해보니, 네트워크 상황에 따라 포스트맨 응답시간이 1.2배~2배까지 차이가 났다.
이것이 의미하는 바는 다음과 같다고 생각된다.
특정 댓글과 대댓글을 불러오는 기능이 두 개의 api로 나뉘어있다면, 한개로 구성되어있을 경우와 비교해서 한 번의 네트워크 지연시간을 추가로 필요로 하게 되고, 많은 접속자가 몰렸을 때는 더 많은 비용을 필요로 할 것이라는 것이다. 또한 사용자가 많이 몰린다면, 네트워크 비용이 평상시보다 더 늘게되니 클라이언트에서 추가로 지불하는 비용 ( api가 하나 더 늘어난 것에 대한 네트워크 비용)이 늘어나게 된다고 생각된다.
물론 큰 기능을 작은 기능 두개로 나누는것이 나쁜건 아니지만, 대댓글만 따로 불러와야하는 경우가 있는게 아니라면, 같은 기능이라고 보아도 무방할 것 같다.
두 테이블을 합친게 쿼리의 수도 적고, api를 한 번만 호출하면 되기 때문에 네트워크 비용을 조금만 지불하면 되기 때문에 이득이다.
또한 대댓글이라는게 댓글과 크게 다른 개념도 아니기 때문에 하나로 묶는다고 기능적으로, 논리적으로 문제될 것이 없어보인다.