좋아요 중복 방지 설계 면접: 한 사람 한 번을 무엇으로 지키나
시스템 디자인 Vol.1 · 07장 「좋아요는 한 사람 한 번」에서
이런 화면입니다
마음에 드는 게시물에 하트를 누릅니다. 한 번 더 누르면 취소됩니다. 아무리 연타해도 내 좋아요는 한 개입니다.
하트 연타는 아주 흔한 일입니다. 화면은 한 개로 보여도 저장소에 두 줄이 생기는 순간이 있습니다.
면접관이 이렇게 묻습니다
게시물 좋아요 기능을 설계해 보세요. 한 사람이 한 게시물에 좋아요를 한 번만 누를 수 있고, 취소도 됩니다.
범위부터 좁힙니다
한 줄로 좁힙니다. 한 사람이 한 게시물에 한 번, 다시 누르면 취소. 좋아요 수는 일단 단순 집계로 두고, 한 번만이라는 규칙을 지키는 데 집중합니다.
같은 사람의 좋아요 기록이 두 줄 생기지 않게 하는 것. 하트를 연타하는 순간에도 이 규칙이 지켜지는지가 핵심 질문입니다.
가장 많이 나오는 답
있나 먼저 보고, 없으면 넣습니다.
SELECT 1 FROM likes WHERE post_id = :post AND user_id = :me;
-- 없으면
INSERT INTO likes (post_id, user_id) VALUES (:post, :me);
한 번씩 천천히 누르면 문제없이 돕니다.
그런데 여기서 깨집니다
선착순 쿠폰과 같은 틈입니다. 연타한 두 요청이 동시에 SELECT를 하고, 둘 다 "없음"을 봅니다. 둘 다 INSERT합니다. 한 사람의 좋아요가 두 줄이 됩니다.
버튼을 비활성화해도 막히지 않습니다. 네트워크 재시도와 다른 기기는 버튼 바깥에서 들어옵니다.
떨어지는 답은 이런 모양입니다
- SELECT로 확인했으니 중복은 없다고 답합니다.
- 프론트에서 버튼을 비활성화하면 된다고 답합니다.
- 두 기기에서 동시에 누르는 경우를 생각하지 못합니다.
면접관은 여기서 멈추지 않습니다
취소와 다시 좋아요가 빠르게 섞이면요?
누르기와 취소가 엇갈려 도착할 때 마지막 상태가 맞는지 봅니다.
취소를 지우지 말고 남기라면요? 소프트 삭제가 정석 아닌가요?
흔히 정석이라 부르는 방법이 이 규칙과 부딪히는 지점을 아는지 봅니다.
유명인 게시물에 초당 수만 개가 몰리면요?
한 행에 몰리는 쓰기를 어떻게 다룰지 봅니다.
이 다음 판단은 책에서 이어집니다
책은 이 규칙을 누가 지킬지 정한 뒤, 같은 사람이 다시 눌렀을 때 손님이 무엇을 보게 할지, "이 사람이 눌렀나"와 "이 글에 누가 눌렀나"를 각각 어떻게 빠르게 답할지까지 풉니다.
07장에서 이어지는 것
- 한 사람 한 번을 지키는 위치
- 다시 누른 손님이 보게 될 것
- 이 사람이 눌렀나, 이 글에 누가 눌렀나
- 실제 요청이 흐르는 순서