동적 컨텐츠의 무한 스크롤 방식을 구현할 때 고려해야 할 점

| 2015. 3. 17. 21:15

얼마 전에 버그 리포트가 들어왔다. 무한 스크롤 방식으로 로드되는 컨텐츠 목록에 종종 중복되는 컨텐츠가 있다는 것이었다. 얼마 전, 다소 고통스럽긴 했지만 큰 교훈을 얻고 고친 바로 그 부분에서 발생한 버그라 조금 놀랐다. 개선한 방식에서 좀처럼 빈틈을 찾기가 어렵다고 생각했기 때문이다.

문제는 무한 스크롤 방식으로 새로운 목록을 계속 서버에 요청해 클라이언트에서 사용자에게로 뿌려주는 동안 새로운 컨텐츠가 등록이 될 때 발생했다. 데이터베이스에 새로운 엔트리가 등록되었기 때문에 서버는 그 엔트리가 등록된 것과는 무관하게 클라이언트에서 날아온 인덱스(index)와 리미트(limit) 값을 토대로 새로운 목록을 내려주는데, 그 순번이 그 사이에 등록된 컨텐츠의 수만큼 밀리기 때문이다.

가장 손쉽게 이 문제를 해결하려면 O(n^2)의 방식인, 현재 목록에 있는 모든 컨텐츠의 고유 아이디와 새롭게 추가될 컨텐츠의 고유 아이디를 하나씩 대조해 중복된 컨텐츠는 목록에 추가하지 않는 방식이 있을 것이다. 실제로 코드를 짜는 양에 있어서, 그리고 로직의 복잡도 면에서 가장 쉬운 방법이다. 동적으로 생성되는 컨텐츠의 양이 상대적으로 적거나 컨텐츠의 중복이 그다지 중요하지 않은 상황에서라면 고려해봄직한 방법이다.

하지만 한정된 리소스를 가진 모바일 환경의 클라이언트라면 10초 정도 더 문제를 고민할 필요가 있다. 그 다음으로 간단한 방법이라면 해시 테이블을 만들어 목록에 컨텐츠가 추가될 때마다 고유 아이디로 해싱을 해 해시 테이블에 엔트리를 추가하고 계속 추가되는 컨텐츠의 고유 아이디도 같은 방식으로 처리, 중복되는 고유 아이디라면 목록에 추가하지 않는 방식으로 해결이 가능하다. 이 정도라면 웬만한 환경에서 동작하는데 무리가 없을 것이다.

서버와 클라이언트를 모두 건드리지만 조금 더 탄탄한 로직을 가지고 있는 방법은, 클라이언트에서 다음 목록을 요청할 때 현재 자기가 가지고 있는 처음 또는 마지막 컨텐츠의 고유 아이디를 같이 보내는 것이다. 서버는 그 정보를 토대로 중복되는 컨텐츠, 또는 누락된 컨텐츠(새 목록을 받아오는 사이에 앞 목록의 컨텐츠가 지워지는 상황을 고려해보자.)를 미리 계산한 목록을 클라이언트에 내려줄 수 있다. 웬만한 경우라면 이 수준에서 문제를 종결해도 될 것 같다는 생각이다.

페이지네이션에서라면 사용자가 쉽게 목록을 앞뒤로 돌릴 수 있기 때문에 컨텐츠의 누락과 중복(페이지네이션의 경우라면 밀림이라고 표현하는 것이 더 옳다.)의 처리가 까다롭지 않지만 사용자가 직접 목록을 조회하기 어려운 무한 스크롤 방식에서는 이와 같은 점을 주의해서 API를 설계해야 할 것이다.