메인 페이지 인기·최신 섹션 중복 노출 버그 수정
목차
메인 페이지에서 같은 글이 두 번 나타나는 버그를 수정했다.
뭐가 문제였냐
ssul 메인 화면에는 크게 두 가지 섹션이 있다. 카테고리별 인기 글(popularByCat)과 최신 글(latest). 언뜻 보면 역할이 달라 보이지만, 현실에서는 꽤 자주 겹친다. 어떤 글이 방금 올라왔는데 동시에 해당 카테고리에서 인기를 끌고 있으면? 양쪽 섹션에 동시에 등장한다. UX 입장에서 메인 한 페이지 안에서 동일한 콘텐츠가 반복되면 밀도가 높아 보이기는커녕 오히려 "이 서비스 콘텐츠 별로 없나?" 하는 인상을 준다. 실제로 그 느낌을 받았고, 코드를 열어보니 역시 중복 필터링 로직이 없었다.
변경 내용
src/lib/db.ts와 src/pages/index.astro 두 파일을 수정했다.
| 파일 | 역할 | 변경 포인트 |
|---|---|---|
src/lib/db.ts |
DB 쿼리 / 데이터 조회 로직 | 중복 제거를 위한 조회 조건 또는 필터 추가 |
src/pages/index.astro |
메인 페이지 렌더링 | 두 섹션에 넘기는 데이터에서 교집합 제거 |
로직은 단순하다. popularByCat 데이터를 먼저 수집한 다음, latest를 가져올 때 이미 등장한 ID를 제외하거나, 렌더링 직전에 latest 배열에서 popularByCat에 포함된 항목을 걸러낸다. 대략 아래 패턴이다.
// db.ts 혹은 index.astro 쪽 어딘가
const popularItems = await getPopularByCat();
const popularIds = new Set(popularItems.map((item) => item.id));
const latestItems = (await getLatest()).filter(
(item) => !popularIds.has(item.id)
);
Set을 쓰는 이유는 단순 Array.includes로 루프를 돌면 O(n²)이 되기 때문. 섹션당 10~20개 수준이라면 큰 차이가 없지만, 습관적으로 Set 기반 lookup을 쓰는 게 낫다. 코드리뷰할 때도 이런 부분은 짚어주는 편이다.
왜 이런 구조가 생기나
이런 중복 노출 문제는 각 섹션이 독립적인 쿼리로 데이터를 가져오는 구조에서 자연스럽게 발생한다. 초기 개발 단계에서는 "인기 섹션", "최신 섹션" 각각을 빠르게 구현하는 데 집중하다 보면 두 쿼리의 교집합을 굳이 고려하지 않는 경우가 많다. 콘텐츠가 적을 때는 잘 안 보이다가, 데이터가 쌓이고 활성 유저가 늘면서 "신규 인기글"이 자주 생기는 시점에 드러난다.
비슷한 패턴으로 "추천 섹션 + 최신 섹션", "에디터픽 + 전체 목록" 조합에서도 동일한 문제가 생긴다. 메인 페이지 설계 시점에 각 섹션이 상호 배타적이어야 하는지 아니면 독립적이어도 되는지를 명시적으로 결정해두는 게 좋다. 결정이 늦어질수록 나중에 손대야 할 곳이 두 배가 된다. db.ts와 index.astro 양쪽을 건드린 것도 그 결과다. 쿼리 레벨에서 해결할지, 뷰 레벨에서 해결할지 선택지가 있었는데, 이번에는 두 파일 모두 손댔다는 게 약간 신경 쓰인다. 이상적으로는 데이터를 조립하는 책임을 한 레이어에 몰아두는 편이 나중에 테스트하거나 로직 변경할 때 편하다.
간단 회고
작은 수정이지만 메인 페이지 품질에 직결되는 변경이었다. 중복 노출은 버그라기보다 정책 부재에 가까운 문제인데, 그렇기 때문에 오히려 오래 방치되는 경향이 있다. 기능이 "안 되는" 게 아니라 "이상하게 되는" 문제니까. 팀에서 메인 페이지 섹션 구성을 바꾸거나 새 섹션을 추가할 때마다 이 중복 필터링 로직을 다시 점검하는 루틴이 필요하다. 다음 메인 개편 때는 섹션 간 exclusion 정책을 문서화해두는 걸 먼저 챙겨야겠다.
끝.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.