통계 기반 로또 번호 생성기 페이지 신설
목차
통계 기반 번호 생성기 페이지(/generator)를 새로 올렸다.
파일 세 개가 건드려졌는데 — Header.astro, lotto-freq.json, generator.astro — 각각 다른 레이어를 담당한다. 네비게이션 추가, 데이터 정의, 실제 페이지 로직. 작은 피처치고는 관심사 분리가 꽤 깔끔하게 떨어진 케이스다.
왜 지금 이 피처였나
로또 번호 생성기는 사실 단순 랜덤으로도 구현할 수 있다. Math.random() 몇 줄이면 끝난다. 그런데 굳이 lotto-freq.json이라는 별도 데이터 파일을 만들어서 "통계 기반"으로 간 이유가 있다.
단순 랜덤과 통계 가중 랜덤의 차이를 한 줄로 정리하면 이렇다:
| 방식 | 각 번호 확률 | 특징 |
|---|---|---|
| 순수 랜덤 | 균등 1/45 | 구현 간단, 어떤 근거도 없음 |
| 통계 가중 랜덤 | 과거 빈도 비례 | 데이터 기반, 사용자 납득 가능 |
| 빈도 상위 고정 추천 | 고정 | 다양성 없음, UX 빈약 |
통계 가중 랜덤을 선택한 건 "이게 더 잘 맞는다"는 신호가 아니다. 로또는 독립 시행이라 과거 빈도가 미래에 영향을 미치지 않는다. 다만 사용자가 납득 가능한 근거를 화면에 붙여줄 수 있고, 서비스 자체에 데이터 레이어가 생긴다는 점이 중요했다.
lotto-freq.json — 데이터 레이어를 코드 밖으로 꺼낸 이유
통계 데이터를 컴포넌트 안에 하드코딩하는 건 가장 쉬운 선택이지만, 나중에 가장 후회하는 선택이기도 하다. 번호별 빈도 데이터는 회차가 쌓일수록 달라진다. 코드에 묻어두면 업데이트할 때마다 로직 파일을 건드려야 한다.
lotto-freq.json을 src/data/ 아래에 분리한 건 단순한 폴더 정리가 아니라, "이 데이터는 별도 생명주기를 가진다"는 설계 의도다.
{
"1": 172,
"2": 168,
"3": 181,
...
"45": 163
}
이런 구조면 나중에 크롤러나 스크립트가 이 파일만 덮어써도 페이지 로직은 손대지 않아도 된다. 데이터와 로직의 결합도를 낮추는 건 팀 작업에서도 중요한데, 데이터 담당자와 프론트 담당자가 다를 때 서로의 작업 영역이 겹치지 않는다.
generator.astro — 생성 로직 패턴
Astro 페이지 컴포넌트에서 통계 가중 랜덤을 구현할 때 핵심은 가중치 누적합(cumulative weight) 패턴이다.
function weightedRandom(freqMap) {
const entries = Object.entries(freqMap);
const totalWeight = entries.reduce((sum, [, w]) => sum + w, 0);
let rand = Math.random() * totalWeight;
for (const [num, weight] of entries) {
rand -= weight;
if (rand <= 0) return Number(num);
}
}
이걸 중복 없이 6개 뽑으려면 선택된 번호를 제외하고 반복하거나, 풀에서 제거하는 방식으로 처리한다. 단순해 보이지만 중복 처리 로직을 빠뜨리면 6개가 아닌 5개, 4개가 나오는 버그가 조용히 생긴다. 리뷰할 때 이런 엣지케이스를 짚어주는 게 팀장 역할 중 하나다.
Header.astro — 네비게이션 추가의 의미
파일 변경 목록에 Header.astro가 들어간 건 작은 변경이지만 의미는 크다. 페이지를 만들고 헤더에 링크를 안 달면 사용자가 직접 URL을 쳐야 접근할 수 있다. 당연한 얘기 같아도 피처 완성 정의에 "네비게이션 진입점 추가"를 포함시키지 않으면 PR이 머지되고 나서 "어디서 들어가요?"가 나온다.
커밋 하나에 세 파일이 묶인 건 이런 이유다 — 페이지, 데이터, 진입점이 한 단위로 동작해야 피처가 완성된다. 각각 별도 커밋으로 쪼갰다면 중간 상태에서 배포가 나갈 때 반쪽짜리 피처가 노출되는 리스크가 있다.
회고
통계 기반이라는 수식어를 붙이는 순간 데이터 관리 비용이 생긴다는 걸 처음부터 인식하고 설계한 게 잘한 선택이었다. lotto-freq.json을 분리한 덕분에 나중에 데이터만 갈아끼우는 게 가능해졌다.
한 가지 더 — Astro에서 .astro 파일에 클라이언트 인터랙션을 넣을 때 client:* 디렉티브 선택이 항상 고민 포인트다. 번호 생성 버튼 하나를 위해 어느 수준의 하이드레이션을 줄 것인지는 성능과 개발 편의성의 트레이드오프다. 이건 다음 이터레이션에서 다듬을 여지가 있다.
끝.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.