요구사항과 규모에서 시작하는 리액션 기능 설계
모호한 좋아요 요구를 정책으로 구체화하고, 데이터 증가량과 조회 비용을 계산해 리액션 모델과 변경 시점을 설계한다.
출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다.
gpt-5.6-sol모델을 사용해 생성·편집했습니다.
“좋아요 수를 보여주고 누를 수 있게 해 주세요”라는 요구는 정수 컬럼 하나와 증가 연산이면 끝날 것처럼 보인다. 가장 작은 구현인 것은 맞지만, 눈앞의 화면만 만족시키고 다음 요구에 필요한 정보를 버리는 선택일 수도 있다. 좋아요 기능에 거창한 아키텍처가 필요한지가 핵심은 아니다. 이미 이 기능에 어떤 의미가 들어 있는지, 데이터가 얼마나 생길 수 있는지, 단순한 조회가 언제까지 버틸지를 먼저 판단해야 한다.
테이블을 고르기 전에 정책부터 구체화한다
명세가 화면 한 장이나 문장 하나뿐이라면 상호작용의 의미를 되물어야 한다. 로그인한 회원만 누를 수 있는가? 한 회원이 같은 대상에 여러 번 반응할 수 있는가? 취소할 수 있는가? 나중에 사용자가 자신이 좋아요 한 목록을 봐야 하는가? 좋아요가 여러 감정 표현으로 늘어날 가능성이 있는가?
이 질문의 답에 따라 보존해야 할 데이터가 달라진다. 대상 테이블의 카운터는 합계를 보여줄 수 있지만 누가 그 수를 만들었는지는 남기지 않는다. “내가 좋아요 한 것은 무엇인가?”라는 질문이나 여러 리액션 유형에도 자연스럽게 답하지 못한다. 카운터 컬럼을 계속 추가하면 불명확한 정책이 스키마로 옮겨갈 뿐이다.
상상 가능한 기능을 전부 미리 설계하자는 뜻은 아니다. 되돌리기 어려운 표현을 고르기 전에 모호한 요구를 명시적인 규칙으로 바꾸자는 뜻이다. 첫 버전의 정책은 이를테면 회원 한 명이 특정 대상에 한 번만 좋아요 할 수 있고, 취소할 수 있으며, 요청을 반복해도 수가 더 오르지 않는다는 정도로 정할 수 있다.
앞으로 쓸 관계 정보는 남겨 둔다
이 정책이라면 별도의 리액션 레코드에 사용자 ID, 대상 유형, 대상 ID, 리액션 유형, 활성 상태를 둘 수 있다. 같은 구조로 다른 대상이나 리액션 유형을 수용할 수 있고, 사용자와 대상의 관계가 남으므로 사용자별 목록도 조회할 수 있다.
취소한 기록을 나중에 활용할 가능성이 있다면 실제 삭제 대신 비활성화나 소프트 삭제로 표현할 수 있다. 다시 좋아요 하면 기존 레코드를 활성화하므로 반응이 중복되지 않는다. 이는 취소 이력을 나중에 활용할 수 있다는 가정에 따른 선택이지 보편 규칙은 아니다.
경계마다 용어를 다르게 쓸 수도 있다. UI는 엄지 표시, 도메인은 좋아요, 저장소는 더 넓은 개념인 리액션이라고 부를 수 있다. 다만 각 경계에 정말 다른 언어가 필요할 때만 의미가 있다. 분리 자체를 보여주기 위한 번역은 불필요한 무게가 된다.
현재 행 수보다 증가하는 모양을 계산한다
리액션을 분리하면 모델은 분명해지지만 합계는 보통 인덱스를 이용해 행을 세어야 한다. 이 방식이 충분한지는 실제 규모와 접근 패턴에 달렸다.
거친 상한은 사용자 수와 대상 수를 곱해 볼 수 있다. 모든 사용자가 모든 대상에 반응한다는 일부러 극단적인 전제다. 실제 사용은 훨씬 희소할 가능성이 크다. 그래도 이 계산은 필요한 질문을 드러낸다. 사용자마다 대상이 하나인가, 여러 개를 만들 수 있는가? 사용자와 대상은 얼마나 빠르게 늘어나는가? 읽기가 쓰기보다 훨씬 많은가? 합계를 얼마나 자주 보여주는가?
한 시점의 행 수보다 증가 곡선이 중요하다. 대상이 사용자와 일대일로 늘어나는 제품과 사용자마다 여러 대상 묶음을 만드는 제품은 상한이 전혀 다르다. 지금 편안한 카운트 쿼리도 어느 한 축이 커지면 비싸질 수 있다. 추정치가 의미 있는 한계에 가까워지면 대표 데이터를 넣어 측정해야 한다. 산술은 판단을 거르는 도구이지 성능의 증명이 아니다.
근거가 생길 때 읽기 전략을 바꾼다
작은 서비스라면 정규화한 리액션 테이블과 인덱스 기반 카운트가 좋은 출발점일 수 있다. 필요한 정보를 보존하면서 이해하기도 쉽다. 그렇다고 영원히 행을 세겠다는 약속은 아니다.
측정 결과 반복 카운트가 읽기 비용을 지배한다면 합계 캐시, 미리 계산한 카운터, 비동기로 동기화하는 집계 같은 선택지를 검토할 수 있다. 더 안전한 변경을 준비하는 동안 일시적으로 장비 용량을 늘리는 방법도 있다. 이런 대안이 만드는 복잡성은 서비스의 증가세와 조회 비용이 요구할 때만 감수할 만하다.
따라서 결정에는 두 시간대가 있다. 지금 무엇이면 충분한지, 어떤 변수가 이 선택을 무효로 만드는지다. 사용자 증가, 사용자당 대상 수, 리액션 밀도, 조회 빈도를 기록하고 관찰하자. 예상 밖의 폭발적 성장은 첫 설계가 모든 미래를 맞히지 못했다는 죄책감이 아니라 재설계의 신호다. 현재의 대가가 분명하고 어떤 근거가 생기면 바꿀지 팀이 알고 있다면, 그 리액션 모델은 충분히 좋은 설계다.