Skip to content

Latest commit

 

History

History
158 lines (105 loc) · 8.61 KB

File metadata and controls

158 lines (105 loc) · 8.61 KB

럭키드로우 개발 과정 요약 (초보자용)

작성일 2026-06-13 · 프로그래밍을 막 시작한 분도 이해할 수 있도록 풀어쓴 개발 일지입니다. 더 기술적인 문서는 CLAUDE.md, 원본 설계도는 Requirement.md를 보세요.


1. 우리가 만든 것 — 한 문장으로

"참가자 이름과 경품을 입력하면, 돌림판을 돌려서 당첨자를 정해주는 웹페이지"

행사장에서 큰 화면에 띄워놓고 쓰는 추첨기입니다. 서버(중앙 컴퓨터)도, 데이터베이스도 필요 없이 브라우저 하나로 완결되는 앱입니다.


2. 가장 먼저 한 일 — "설계도 읽기"

코드를 짜기 전에 Requirement.md라는 요구사항 문서(건축으로 치면 설계도)를 먼저 읽었습니다. 거기엔 단순한 "돌림판" 이상의 규칙들이 숨어 있었어요. 예를 들면:

  • 돌림판 칸 = 남은 경품 수 + "꽝" 1칸 (경품이 줄수록 꽝이 나올 확률이 자연스럽게 올라감)
  • 한 번 당첨된 사람은 다시 못 뽑힘
  • 경품이 하나 소진되면 돌림판을 다시 섞어서 새로 그림

이런 "눈에 잘 안 띄는 규칙"을 미리 정리한 CLAUDE.md를 만들어 두었습니다.


3. 중요한 갈림길 — "무엇으로 만들까?"

요구사항 문서는 만드는 도구를 정해주지 않았습니다. 그래서 딱 하나, 기술 선택을 질문했고 **"순수 HTML + TypeScript + SVG"**로 결정했습니다. 각각을 쉽게 설명하면:

도구 쉬운 설명
HTML 웹페이지의 뼈대 (글자·버튼이 어디 있는지)
TypeScript 동작을 적는 언어. 자바스크립트에 "오타·실수 검사기"가 붙은 버전
SVG 그림을 그리는 도구. 돌림판의 부채꼴 칸들을 수학으로 정확히 그림

💡 알아두기 TypeScript는 브라우저가 바로 못 읽어서 번역(컴파일) 과정이 필요합니다. 보통은 "번들러"라는 복잡한 도구를 쓰지만, 우리는 tsc라는 기본 번역기만 써서 단순하게 갔습니다. 비결은 코드에서 파일을 부를 때 ./draw.js처럼 .js 확장자를 꼭 붙인 것 — 그래야 번역된 결과를 브라우저가 그대로 읽을 수 있습니다.


4. 만든 순서 — "왜 이 순서였나"

집을 지을 때 기초 → 골조 → 마감 순서로 가듯, 코드도 속(논리)부터 겉(화면)으로 쌓았습니다.

① 뼈대 세우기      → 빈 페이지, 설정 파일, 디자인 색/글꼴
② 데이터 모양 정의  → "참가자·경품·결과가 어떻게 생겼는지" (types.ts)
③ 추첨 두뇌        → 돌림판 칸 만들기·섞기·결과 뽑기 (draw.ts)  ★핵심
④ 상태 관리        → "지금 누가 남았고 경품이 몇 개인지" (state.ts)
⑤ 돌림판 그림      → SVG로 부채꼴 그리고 회전 (wheel.ts)
⑥ 화면과 버튼      → 사람이 보고 누르는 부분 (ui.ts + main.ts)
⑦ 저장·내보내기    → 새로고침 대비, CSV 다운로드 (storage.ts)
⑧ 검사            → 진짜 잘 도는지 확인

화면(겉)을 마지막에 둔 이유는, 두뇌(③④)가 먼저 정확해야 화면이 그걸 그냥 보여주기만 하면 되기 때문입니다.


5. 파일별 역할과 호출관계

7개 파일은 각자 하나의 역할만 맡습니다. 아래 표에서 "참조하는 파일"은 그 파일이 불러다 쓰는(import) 다른 파일입니다.

파일 하는 일 참조(import)하는 파일
src/types.ts 데이터의 "모양"만 정의 (참가자·경품·결과·상태가 어떤 형태인지) 없음
src/draw.ts 추첨 계산: 돌림판 칸 만들기·섞기·결과 뽑기 types
src/state.ts 현황 관리: "누가 남았나·경품 몇 개·끝났나"를 계산 draw, types
src/storage.ts 브라우저에 현재 상태 저장/복원 (새로고침 대비) types
src/wheel.ts 돌림판 그림(SVG)을 그리고 회전시킴 없음 (브라우저 기능만 사용)
src/ui.ts 화면 그리기 + 버튼·입력 연결 draw, state, wheel, types
src/main.ts 전체 지휘: 상태 보관, 회전 흐름 조율, 저장/내보내기 draw, state, storage, ui, wheel, types

호출 방향 — 위에서 아래로만 흐름 (순환 없음)

화살표 ─►는 "왼쪽이 오른쪽을 불러다 쓴다"는 뜻입니다. 항상 위 단계가 아래 단계를 부르고, 그 반대는 없습니다.

지휘   main.ts ─► ui.ts, state.ts, storage.ts, draw.ts, wheel.ts (전부 불러 씀)
화면   ui.ts   ─► draw.ts, state.ts, wheel.ts
현황   state.ts ─► draw.ts
기초   draw.ts ─► types.ts        storage.ts ─► types.ts
재료   types.ts (모양 정의 — 아무것도 안 부름)   wheel.ts (독립 — 우리 파일 안 부름)
  • main.ts 가 유일하게 모든 파일을 부르는 "맨 위" 지휘자입니다.
  • types.ts 는 모두가 갖다 쓰지만 자신은 아무것도 안 부르는 "맨 아래" 토대입니다 (데이터 모양만 정의).
  • wheel.ts 는 우리 파일을 하나도 안 부르는 독립 부품입니다 (브라우저의 SVG 기능만 씀). ui.tsmain.ts가 이걸 갖다 씁니다.

이렇게 나눠서 좋은 점

draw.ts·state.ts는 화면(브라우저)을 전혀 부르지 않습니다. 그래서 추첨 로직만 떼어 따로 테스트할 수 있었습니다(아래 7번).


6. 가장 영리한 두 가지 트릭

초보자에게도 흥미로운, 이 앱의 핵심 아이디어 둘입니다.

① "결과를 먼저 정하고, 돌림판을 거꾸로 맞춘다"

보통 생각하면 "돌림판을 돌려서 → 멈춘 곳이 결과"일 것 같죠. 하지만 우리는 반대로 했습니다.

먼저 컴퓨터가 "3번 칸 당첨!"을 몰래 정함 → 그 다음 3번 칸이 포인터 아래 오도록 회전 각도를 계산해서 돌림.

왜냐? 요구사항이 "애니메이션은 연출일 뿐, 결과는 조작 불가능해야 한다"고 했기 때문입니다. 결과와 보여주기를 분리한 거예요.

② "돌아가는 중에는 화면을 다시 그리지 않는다"

화면을 새로 그리면 돌림판이 처음 위치로 리셋되어 버립니다. 그래서 회전하는 동안에는 버튼만 잠그고, 회전이 완전히 끝난 뒤에야 결과를 반영해 화면을 갱신합니다.


7. "진짜 되는지" 어떻게 확인했나

말로만 "됐다"고 하지 않고 3단계로 검증했습니다:

  1. 문법 검사tsc로 컴파일 → 오류 0개 (오타·타입 실수 없음)
  2. 두뇌 검사 — 주방장(추첨 로직)을 따로 떼어 11가지 상황을 테스트:
    • "경품 3개면 돌림판 칸이 4개(꽝 포함)인가?" ✓
    • "당첨된 사람이 또 당첨되지 않는가?" ✓
    • "경품 다 떨어지면 자동 종료되는가?" ✓
    • 11개 전부 통과
  3. 배달 검사 — 실제 웹서버로 띄워서 페이지·코드·스타일이 정상 응답(200)하는지 확인 ✓

8. 지금 상태와 실행 방법

완성도: 요구사항의 모든 핵심 기능이 구현되고 로직 검증까지 끝난 상태입니다.

npm install      # 처음 한 번 (번역기 설치)
npm run build    # 코드 번역 (TypeScript → 브라우저용 JavaScript)
npm run serve    # 브라우저에서 http://localhost:5173 접속

개발 중에는 npm run watch(자동 번역)와 npm run serve(서버)를 각각 다른 터미널에서 함께 켜두면 편합니다.

아직 안 한 것 두 가지:

  • 실제 화면을 눈으로 확인 — 돌림판이 부드럽게 도는지 브라우저로 직접 보기
  • 글꼴 완전 오프라인화 — 지금은 인터넷에서 글꼴을 받아오고, 없으면 기본 글꼴로 대체됨

용어 미니 사전

용어
컴파일 사람이 쓴 코드(TypeScript)를 브라우저가 읽는 코드(JavaScript)로 번역하는 일
ESM (ES 모듈) 코드 파일을 서로 불러 쓰는 표준 방식 (import)
SVG 도형을 수학 좌표로 그리는 이미지 형식 (확대해도 안 깨짐)
상태(state) "지금 누가 남았고 경품이 몇 개인지" 같은 현재 상황 데이터
순수 함수 같은 입력엔 항상 같은 출력을 주고, 바깥 세상을 안 건드리는 함수 → 테스트하기 쉬움
localStorage 브라우저가 데이터를 저장해두는 작은 공간 (새로고침해도 안 사라짐)