- 15년 경력의 소프트웨어 엔지니어가 어린 시절 카드 게임을 Go 언어로 개발하는 경험을 공유
- LLM(대형언어모델) 없이 “Truco”를 개발할 때는 UI 설계와 서버리스 배포 등 모든 문제를 수작업으로 해결하며 3개월 소요
- “Escoba”를 만들 때는 LLM을 활용해 백엔드 코드 변환 및 구현 속도를 크게 단축, 프롬프트 1회 만에 대부분 동작 성공
- 글 후반에서는 Tic-Tac-Toe 예제와 함께 Go 백엔드, WASM 변환, React 연동을 통해 누구나 게임을 만들 수 있는 단계별 가이드를 제공
- 하지만 React 프런트엔드 및 WASM 기반의 게임 상태 관리는 여전히 직접 디버깅 및 구현 필요
소개
- 15년 경력의 소프트웨어 엔지니어가 자신이 실제로 게임을 만들어 배포해본 적이 없음을 깨달음
- 어린 시절 아르헨티나에서 친구들과 즐겼던 카드 게임 중 하나를 Go 언어로 개발하기로 결심
Truco: LLM 없이 3개월
- 2024년 6월 18일부터 Truco라는 카드 게임을 Go 백엔드로 개발 시작. React는 최소한의 지식만으로 프론트엔드를 작성
- UI 구현이 가장 큰 도전이었고, 서버를 제공하지 않기 위해 TinyGo를 활용해 WASM(WebAssembly)로 트랜스파일 후, 정적 파일을 GitHub Pages에 배포함
- LLM이 없던 시기라, 모든 세부 사항을 직접 찾아내고 시행착오를 반복하며 약 3개월 동안 완성함
- 광고나 수익 목적 없이 오로지 게임을 완성하려는 목적이었으며, 출시 1년이 지난 후에도 꾸준히 플레이되고 있음
- Truco 플레이: https://marianogappa.github.io/truco-argentino
- 백엔드(Golang): https://github.com/marianogappa/truco
- 프런트엔드(React): https://github.com/marianogappa/truco-argentino
Escoba: LLM과 함께 3일
- 1년 후, 가족을 만나러 아르헨티나를 방문하는 도중 조카에게 Escoba라는 두 번째로 인기 많은 카드 게임을 가르쳐줌
- 이번에는 LLM(Claude) 을 활용하여, Truco의 백엔드를 복제한 뒤 Escoba의 규칙을 프롬프트로 설명, 코드 리팩터링을 요청함
- 첫 프롬프트만에 거의 완벽하게 구현되었으며, 약간의 사소한 버그와 추가 기능만 수동으로 보완함
- 프론트엔드는 여러 날 직접 구현/디버깅이 필요했음. LLM의 한계와 React 스킬, 게임 상태를 WASM에서 관리하는 특이한 환경 모두 도전 요소였음
- Escoba 플레이: https://marianogappa.github.io/escoba-de-15
- 백엔드(Golang): https://github.com/marianogappa/escoba
- 프런트엔드(React): https://github.com/marianogappa/escoba-de-15
단계별: 자신의 게임 만드는 방법
- 누군가가 직접 게임 개발을 시도할 수 있도록 최소한의 실습 가이드와 예제 코드를 소개함
- Tic-Tac-Toe(틱택토) 예시 리포지토리를 제공, 이를 포크해서 시작 가능함
백엔드 개발
- 턴 기반 백엔드는 명확하게 기능을 설계 가능함
- 서버리스 구조 유지, 사람이 서로 플레이하는 구조는 상용 서버가 없다면 피하는 것이 현실적인 선택임
프론트엔드 개발
- 프런트엔드는 다음과 같은 작업이 필요함
- 백엔드에 신규
GameState생성 요청 - UI에서 상태 표시
- 유효한 행동 선택 인터페이스 제공
- 행동 적용 시 백엔드에 커맨드 전송
- 봇 차례일 경우 백엔드에게 요청
- 백엔드에 신규
백엔드 WASM 전환
- Go 코드를 WASM으로 빌드하려면
GOARCH=wasm GOOS=js go build사용 - 바이너리 크기가 큰 문제가 있을 수 있으므로, TinyGo를 활용해 사이즈를 줄임
- 프런트엔드와 연결할 함수들을 내보내기 위해 Go에서 별도의 엔트리포인트(ex:
main_wasm.go)를 작성해 빌드시 분기 처리함 - 메인 함수에서
select {}로 블록킹하여 프로그램이 즉시 종료되지 않게 처리 필요
백엔드-프런트 데이터 연동
- Go의 자유형 struct인
GameState등은 WASM에서 직접 serialize/deserialize 불가 - 모든 데이터는 JSON 포맷으로 교환하는 방식이 필요
- TinyGo에서 제공하는 문서 참고하여, 입력/출력 모두 JSON 직렬화로 주고받음
프런트엔드-백엔드 인터페이스
- 프런트엔드에서는 backend 함수들을 직접 호출
GameState는 WASM 내에서만 관리되고 프런트엔드는 뮤테이션 불가, 항상 backend가 진실의 소스임- WASM 재컴파일 후 파일 교체 필요, Makefile를 통해 자동화 예시 제공
WASM 실행 환경
- 실행을 위해서
wasm_exec.js를 head에 포함해야 하고, 해당 스크립트 활용해 인스턴스 생성 후 실행함
결론
- 게임 제작은 즐거운 경험이었으며, Go와 WASM, React 조합으로 누구나 시도할 수 있는 접근법임
- LLM의 도움으로 생산성이 크게 향상되었지만, 프론트엔드 역량과 디버깅 경험이 여전히 중요함
- 누구나 이러한 구조로 직접 게임 개발에 도전할 수 있으니 시도해 볼 것