저번 주말에 최초로 해커톤 CalHacks 2.0에 다녀왔다. 규모가 커서 그런지 해외라 문화가 달라서 그런지 지금까지 보고 들어왔던 해커톤이랑은 약간 달랐지만 재밌게 즐겼다. 평상시였으면 귀찮다고 안 했을 삽질을 많이 하면서 새로운 흑마법들을 배워서 돌아왔다. 처음 가 보는 해커톤이라 뭘 해가야 하는지 몰라서 우왕좌왕 하다가 지난 겨울방학 때 건드려보다가 의욕감퇴로 폐기한 socket.io에다가 HTML 5 얹어서 게임 만들기에 다시 도전해 보았다.

해커톤 일정은 금요일 오후 7시부터 시작해 일요일 오후 4시쯤 끝났다. 보통 해커톤이 1박 2일로 진행되는걸 생각하면 빡센 일정이라고 느꼈다. UCB 캠퍼스 내였지만 가 보지 못했던 건물이라 버스에서 내려서 주변을 두리번 거리고 있다가 체크 무늬 셔츠 또는 IT 회사 티셔츠를 입고 노트북 가방을 매고 있는 사람들이 향하는 곳을 따라갔더니 역시나 도착할 수 있었다. 어디서 비슷한 경험을 한 것 같은데

도착해서는 기업 부스들을 돌면서 전리품을 챙겼다. 머그컵, 프리스비, 티셔츠, 스티커 등 다양한 상품을 나눠주었고 채용 상담을 진행하는 부스도 있었다. MS가 최대 스폰서였고 나머지는 다 비슷비슷했다. Facebook이나 Uber 정도가 참가한 회사 중에 좀 큰 회사였던 것 같은데 MS처럼 적극적으로 부스 운영을 하지는 않았다. MS 부스에서는 후드에 베게가 달려 있는 신개념 기념품을 나눠 줘서 쪽잠을 잘 때 유용하게 사용했다. 참가 기업들은 부스 운영을 하면서 회사 이미지를 관리도 하고, 각 회사별로 자기들의 API를 가장 잘 활용한 팀을 뽑아서 상금 또는 상품을 줬다.

슬랙과 주변 분위기를 보니 미리 팀을 짜서 나오는 경우가 대부분이었다. 10시부터 실제 팀매칭 및 해커톤 시작이었는데 일정표에 팀매칭 시간이 있으니 아마 괜찮겠지 싶어서 그냥 기다렸는데 팀을 미리 찾고 자리를 잡는 편이 더 나았을 것 같다. Your Best Match를 찾아준다고 했는데 진행자가 관심분야별로 잘 나누지도 못했고, 특정한 관심 분야 없이 아무거나 다 재밌게 할 거라고 말하는 사람들이 많아서 팀매칭이 그리 효율적으로 진행되지는 않았다. 게임 만들고 싶다고 했더니 참가자 중에 의욕적인 미국인 한 명이 “우왕, 님 게임 만듦? 재밌어 보임! 혹시 웹 하시는 분 없나요!” 하면서 팀원을 모아줘서 어찌저찌 시작할 수 있었다. NEXT에서 온 한국인 두 분과도 같은 팀이 되었다. 해커톤이 주 목적은 아니고 여행 중에 해커톤에 오셨다고 들었던 것 같다.

팀을 구하고 나서는 자리를 찾아 헤맸는데 본 건물에 해당하는 스타디움에 자리가 없어서 별관에 해당하는 SDH로 이동했다. SDH에서는 초심자들을 위한 워크샵을 진행하기도 하고, 하드웨어 관련 팀들을 위한 하드웨어 랩이 준비되어 있었다. 하지만 여기도 자리가 없어서 처음에는 불쌍하게 복도에서 멀티탭 하나에 조그만 책상을 놓고 개발을 하다가, 워크샵이 끝나고 워크샵이 진행되던 교실로 장소를 옮겼다. 3일 내내 여기서 작업했는데, 식사는 다행히도 예정이 변경되어 스타디움까지 가서 먹지 않아도 되도록 SDH까지 배달이 되었지만 스타디움에 있던 친구 말로는 다른 참가자와의 상호작용이나 기업 부스 견학, 기념품 증정 등 해커톤의 분위기는 스타디움 쪽이 압도적으로 좋았다고 해서 아쉬움이 남는다.

첫째날 밤에는 우선 무엇을 만들지에 대해 이야기했다. 나는 PICO PARK 영상을 소개하며 이 게임과 유사한 방식으로 캐릭터끼리 상호작용하는 게임을 만들고 싶다고 아이디어를 냈고, 다른 팀원들이 마리오 파티처럼 다양한 미니게임들이 있는 방식으로 만들자는 의견을 냈다. 그래서 PICO PARK의 요소를 따와서 캐릭터들끼리 밀거나 밟고 올라갈 수 있는 기능 등을 넣되, 경쟁 방식으로 빠르게 미니게임들이 회전하는 게임을 만들자고 기획을 했다. 시간이 많이 없기 때문에 미니 게임의 수를 제한해서 “줄어드는 플랫폼에서 살아남기”, “위에서 떨어지는 장애물 피하기”, “마리오 스타일로 밟고 밟히는 서바이벌” 총 세 가지 미니게임을 기획했고, 최종 제출 때는 두 개를 구현했다.

개발을 시작한 직후에 나는 처음부터 백엔드를 작업하고 싶다고 얘기했기 때문에 socket.io 기본 튜토리얼을 따라하면서 기억을 되살리고 있었고, 다른 팀원들은 HTML 5 게임 엔진 목록에서 쓸만한 라이브러리를 골라서 작업을 시작했다. 적당히 상위권이고 무료인 EaselJS, Phaser, pixi.js가 후보로 올랐고 사이트 메인을 제일 잘 만든 Phaser를 골랐다. 그러니까 우리는 프로그래밍만 잘 하면 안되고 사이트 메인이랑 문서도 잘 꾸며야 합니다.

개발 과정을 요약해보면 다음과 같다.

  • 1일차 밤 ~ 2일차 새벽: 기획
  • 2일차 새벽 ~ 2일차 아침: 뼈대 코드 작성
  • 2일차 낮 ~ 밤: 물리엔진
  • 2일차 밤 ~ 3일차 새벽: 리팩토링
  • 3일차 아침: 스테이지 시스템 구현

이번 프로젝트에서 가장 삽질을 많이 한 부분은 물리엔진이다. 원래 온라인 게임이라면 동기화 문제 및 치팅 방지를 위해 모든 처리를 서버에서 하는게 정석이다. 하지만 처음에는 굳이 그 정도의 엄밀함을 추구할 필요는 없을 것 같고 Phaser 자체 물리엔진 API가 굉장히 편리해서, 클라이언트 쪽에서 상대방의 정보를 서버에서 받아 ‘자기 자신에 대한 물리’만 계산하면 되지 않을까 추측해서 그렇게 짜봤다. 결과는 대실패. 캐릭터끼리 밀어내는 것도 제대로 동작하지 않았고, 충돌하고 나서 물리 엔진이 꼬여서 공중에서 캐릭터가 덜덜 떨고 있더라.

결국 서버에서 물리 처리를 짜기로 하고, 처음 시도해 본 방법은 플래시 게임을 만들던 경험을 살려 직접 구현하는 것이었다. 오랜만에 짜는 코드였지만 2차원 플랫포머는 많이 짜 봐서 금방 완성할 수 있었다. 하지만 점프를 구현하고 나서 캐릭터 충돌을 구현할 때가 되니 너무 막막하더라. 강체 충돌을 직접 구현하느니 지금까지 짠 게 조금 아깝지만 차라리 물리엔진을 가져다 붙이는게 편하겠다 싶어서 엎었다.

서버사이드에 Node.js를 쓰고 있었기 때문에 JS 물리엔진을 조사해 봤는데, 구현체도 별로 없고 브라우저 대상으로만 구현된 것들이 많아 찾는데 고생을 했다. 일단 여기를 기초로 조사를 했고, 후보로 남은 두 가지 선택은 box2dnode랑 Phaser를 마개조해서 서버에 붙이기였다. ChipmunkJS도 괜찮아 보였지만 시간이 제한된 해커톤 특성을 생각했을 때 학습 곡선이 짧은 것을 선택하는 편이 좋다고 판단해 다른 물리엔진에 비해 조금 더 익숙했던 box2d와 서버와 클라이언트간에 코드 재사용이 쉬운 Phaser를 남겼다.

Phaser 내장 아케이드 물리엔진이 box2d에 비해 훨씬 사용하기 쉬웠기 때문에 처음에는 Phaser 기반으로 구현하려고 했다. Phaser가 Headless 렌더링을 지원하긴 하지만, 게임 엔진 초기화 과정에 HTML5 캔버스가 필요해 Phaser를 붙이기 위해 jsdom과 node-canvas 모듈을 이용하는 튜토리얼을 참고해 따라해 보았다. 하지만 빌드 오류를 해결하지 못해 실패했는데, 우선 나는 파이썬 3 버전을 사용하는데 요구 버전이 2.7이었다. 열심히 검색해가며 파이썬을 2랑 3을 둘 다 쓸 수 있게 설정했더니 이번에는 윈도 커맨드라인 환경 문제로 추정되는 컴파일 에러를 뱉으며 또다시 빌드에 실패했다. 결국 포기하고 box2dnode로 방향을 다시 선회했다.

box2dnode는 정말 최후의 수단으로 남겨 두고 있었는데 가장 큰 이유는 문서가 없었다. 결국 C++ box2d 튜토리얼을 보면서 따라하면서, 같은 메서드랑 클래스가 box2dnode에서 어떻게 구현됐는지 열심히 소스코드를 읽어가면서 해독해야 했다. 말로는 별로 안 어려워 보이지만 몇천 줄 짜리 파일을 Ctrl+F로 열심히 찾아가면서 읽어야 했고 메서드나 클래스 이름이 다른 경우에는 상위 클래스에서 추적해서 찾거나 클래스 이름을 추측해서 때려 맞추는 경우도 있었다. Body가 월드 경계를 넘어가면 런타임 에러를 뱉으며 월드 갱신이 안 되는 문제도 있었는데 이건 라이브러리 문제인지 아니면 box2d 설계가 원래 이렇게 돼 있는건지 밝혀 내지 못했고, box2d가 미터 단위를 사용하도록 설계된 물리엔진이라는 걸 몰라서 픽셀 단위로 계산해서 생기는 오류를 코드 문제인 줄 알고 계속 찾기도 했다. 프로그래밍을 하면서 했던 삽질 중 손에 꼽을 정도였는데 그냥 집에서 취미로 짜는 거였으면 결국 삽질을 하다가 때려치웠겠지만 해커톤이라서 끝까지 할 수 있었다고 생각한다.

물리엔진 쪽을 손보고 나서 스테이지 시스템을 구현하기 전에 리팩토링을 했다. 화면 전환을 짜려면 일단 지금 화면에 있는 객체들을 다 지우고 새로운 스테이지에 있는 객체들을 배치해야 하는데, 이게 가능할만큼 구조화가 돼 있지 않아서 코드 구조를 전부 뒤엎고 난 다음 스테이지를 짰다. 리팩토링은 할 때마다 ‘잘못 건드렸다가 안 돌면 어떡하지’라고 걱정하면서 이것저것 뜯어고치기 시작하고, 끝내고 나서는 ‘내가 이걸 어떻게 했지’라는 생각을 한다. 그러고보니 Node.js 모듈 시스템 사용법도 배웠다. JS 모듈 시스템이 CommonJS, RequireJS 등 이것저것 있어서 뭐가 어떻게 다른 건지는 아직 잘 모르겠지만 Node.js 모듈 시스템이 브라우저보다 낫긴 하더라.

디플로이 서버로는 MS 애저를 사용했다. 꼭 애저를 쓸 필요는 없었지만 MS 부스에서 열심히 홍보하고 있기도 했고, 드림스파크 계정 있으면 낮은 티어 서버는 무료로 사용할 수 있어서 애저를 골랐다. MS API를 잘 사용한 작품을 대상으로 하는 MS 챌린지를 찔러 보기 위한 흑심도 있었지만, 사실 애저에 디플로이 한 정도로는 많이 부족하기 때문에 안 될걸 알면서 냈다. 애저를 직접 써 보는 건 처음인데 디플로이가 미친듯이 편했다. GitHub 리포지토리에 푸시하기만 하면 알아서 업데이트하고 자동으로 프로세스를 띄워준다. 무료 서버에서 트래픽을 너무 많이 써서 그런지 중간부터 오류가 발생했는데, MS 부스에 가서 도움을 요청하니 애저 100달러 크레딧을 주면서 유료 서버로 돌리라고 해서 그렇게 했더니 잘 됐다. 어차피 한 달 짜리 크레딧이라 고사양 서버에서 마구 돌리고 있다. 그런데 후기를 너무 천천히 써서 지금은 크레딧을 다 쓰고 다시 무료 서버에서 돌리고 있다.

둘째 날 오후에는 HackerRank 코드스프린트가 있었다. 이름을 보니 알고리즘 대회라는 감이 와서 기대하고 있었는데, 마침 물리엔진으로 고통 받고 있다가 잠깐 쉬는데 도움이 됐다. HackerRank 사이트에서 비공개 콘테스트 형식으로 진행됐고 총 6문제가 나왔고 그 중 B와 F를 가장 마지막에 풀었다. B는 쉬운 문제였지만 규칙성을 찾는데 시간이 걸렸고, F는 DP식을 분해해서 O(N^2)을 O(N lg N)으로 줄이는 문제였다. 오랜만에 문제를 푸는 것치곤 상당히 컨디션이 좋아서 3번째로 만점을 받았다. 10위까지는 티셔츠를 주는 대회였는데 여성용 티셔츠밖에 없어서 티셔츠를 받지 못했다. HackerRank가 전국에서 진행되는 Girls Cup이랑 해커톤 내부에서만 하는 코드스프린트 두 개를 동시에 진행하던데 여기서 운영이 꼬인 것으로 추측된다. 사이즈만 맞으면 그냥 입고 다니려고 했는데 등에 “Code like a girl!”이라고 써 있어서 그냥 해커랭크 티셔츠 말고 다른 티셔츠를 받아왔다.

해커톤의 마지막에는 팀별로 자리를 배정받아 프로젝트를 설명하는 시간을 가졌다. 부스 운영하면 흔히 생각하는 방식인 과학전람회 형식(Science-Fair Style이라고 하더라)으로 진행됐다. 지나가는 사람한테 체험 시키고, 프로젝트 기술 스택 설명하는 등 이매진컵이랑 비슷한 느낌으로 진행됐다. 신기했던 점은 역시 다들 개발자라 그런지 프레임워크 이름만 말하면 다들 “음, 그렇군!” 하면서 납득했던 것. 나도 열심히 설명하기는 했지만 다른 팀원 한 명이 나보다 뛰어난 영어 실력으로 열심히 설명해줘서 편했다.

기억에 남는 프로젝트를 세 개 정도 꼽자면 4인용 체커, 뇌파로 하는 카트 조종, 글로브 뉴스였다. 4인용 체커는 우리 프로젝트랑 비슷하게 온라인 멀티플레이어였는데 UI가 깔끔했던 게 기억에 남는다. 무슨 회사였는지 잘 기억은 안 나지만 백엔드 데이터 관리에 그 API를 잘 끌어다 써서 상을 받아갔다. 뇌파로 하는 카트 조종은 하드웨어 분야였다. 스타디움 근처에서 스태프들 이동에 쓰던 미니 카트를 빌려서 액셀이랑 브레이크를 원격으로 조종할 수 있게 액추에이터를 설치하고, 핸들로 방향 전환만 하면 운전을 뇌파로 할 수 있다고 주장하는 작품이었다. 작년 수상작 중에 있었던 뇌파로 조종하는 드론에서 영감을 받은 것 같았다. 글로브 뉴스는 검색어를 입력하면 그 검색어와 연관된 이슈를 지구본에 3D 그래프로 띄워 주는데 아이디어도 괜찮고 정말 깔끔하게 잘 만들었더라. ArmsGlobe의 뉴스 버전이라고 생각하면 된다. 이 프로젝트는 Best Visualization 상을 수상했다.

보통 해커톤은 주제를 하나 주고 그에 맞는 개발을 한다고 알고 있었는데, CalHacks는 미리 상당 부분을 만들어 오는 팀도 있었고 수상 분야도 하나가 아니라 다양한 회사들이 각자의 API 잘 끌어다 쓰면 알아서 상을 주는 방식이라 자유도가 굉장히 높았고, Uber API라든지 Bitcoin API 등 흥미로워 보이는 API도 많았다. 각 회사별 시상이 끝나고 나서 진행자들이 열심히 폼을 잡고 발표할 준비를 하더니 “CalHacks에 참가한 여러분 모두가 승자입니다!”라면서 해커톤이 공식적으로 종료됐는데, 확실히 한국보다 경쟁이 덜한 사회라고 느꼈다.

열심히 쓰다 보니 후기보다는 일기가 된 느낌이다. 3일동안 코딩만 하면서 살아보니 이게 부질이 있는 삶인지 없는 삶인지 헷갈리지만 확실히 이전에 하지 못한 새로운 경험이기는 했다. 평소에 배워야지 생각하던 기술들을 이번 기회를 살려 배울 수 있었고, 내 능력을 바탕으로 정해진 시간 내에 어디까지 할 수 있을지를 계획하고 실행했던 몇 안 되는 경험 중 하나였다. 아쉬웠던 부분도 몇 가지 있는데 위치를 잘못 잡아 서드파티 부스 이벤트에 많이 참가하지 못했던 점과, 팀을 구할 때 제대로 팀 빌딩 시간이 적어 서로 담당 분야를 제대로 맞추지 못해 업무 분담이 제대로 되지 않은 점이다. 이번 해커톤에서 아쉬웠던 점들을 개선해 다음 해커톤 때도 흥미롭고 재밌는 프로젝트를 만들어야지.

+
그래서 만든 게임은 여기에서 하실 수 있습니다. 위에서 서술했듯이 무료 티어에서 돌리고 있는데다가 해커톤 특성상 최적화도 제대로 못한 상태라 상당히 끊길 거예요 다 제가 못난 탓입니다 ㅜㅜ 방향키로 이동하고 스페이스 바로 점프합니다.

사건은 오늘 저녁으로 먹을 피자를 시키면서 발생했다. 피자헛 홈페이지에서 페이스북 연동 기능을 통해 주문을 하려고 했지만 로그인이 되지 않았다. ‘아이디 찾기’ 기능을 통해 확인해 보니 내가 예전에 쓰던 페이스북의 로그인용 메일 주소(primary email)와 지금 사용하는 로그인용 메일 주소가 달라서인 것으로 추측되었다. 피자헛 홈페이지 아이디가 이전 메일과 연동이 되어 있었고, 유저 로그인 체크를 페이스북 고유 id로 해야 하는데 페이스북 메일 주소로 체크를 하는 것이다.

그래서 홈페이지 아래쪽에 있는 ‘온라인 주문 전용 상담 번호’로 전화를 걸어 이런 문제가 있다고 말했는데 이해를 못 하더라. 나도 설명을 횡설수설 하기는 했지만, 상담원이 홈페이지 기술 담당이 아닌 그냥 주문 상담원이어서 그랬던 점도 있다. 통화를 통해 ‘홈페이지가 잠깐 이상한 것일 수도 있으니 다음에 다시 시도해보시고, 오늘은 전화로 주문을 도와주겠다’는 답변을 얻은 것이 고작이었다.

어쩔 수 없이 전화로 주문을 하고, 다시 이전 메일 주소로 로그인용 메일 주소를 되돌린 후 피자헛 로그인을 시도해보았다. 예상대로 로그인이 원활하게 잘 됐다. 그래서 지금 사용하는 메일 주소로 변경하기 위해 이전 계정을 탈퇴시키고 재가입을 하는데, 알 수 없는 오류가 발생했다면서 회원가입에 실패했다. 사이트는 예쁘게 잘 만들었던데 백엔드가 개판인듯 하다.

문득 피자헛만 그런건지 다른 사이트들도 그런건지 궁금해서 예전 이메일로 로그인 연동해 놓은 다른 해외 사이트들에도 들어가 봤다. 5개 정도를 체크해 봤는데 로그인에 실패하는 사이트는 하나도 없었고, 일부 사이트는 ‘야 너 메일 주소 바뀌었네? 이걸로 갱신할거야?’라고 물어보기까지 하더라.

프로그래밍을 해 온 경험들 덕에, 오늘 겪었던 사건처럼 서비스들을 이용하며 문제 상황이 발생했을 때 어디를 잘못 짰을지 예상되는 경우가 종종 있다. 그래서 이런 문제를 리포팅 하려고 해도 제대로 된 소통 창구가 존재하지 않는 경우도 많고, 열심히 정리해서 보내주더라도 동문서답을 하거나 자기들 잘못이 아니라 내가 서비스 이용을 잘못 했다고 책임을 돌리는 경우도 있었다.

통계를 내 본건 아니지만 이와 유사한 상황을 겪었던 경험들은 해외 서비스보다 국내 서비스에서 훨씬 많았다. 물론 내가 한국인이다보니 한국 서비스를 해외 서비스보다 더 많이 이용할 것이고, 한국에서까지 이용할만한 해외 서비스라면 어느 정도의 규모와 안정적인 기반이 있을 것이기 때문에 문제가 덜 발생할 것이다. 하지만 이런 점을 고려하더라도 비슷하거나 더 큰 규모의 국내 서비스들에서 찾은 문제가 더 많았다고 생각한다. 오늘 겪었던 피자헛 문제를 포함해 알송과 신한은행, 한국정보화진흥원(NIA)의 서비스에서도 문제를 겪고 리포팅을 했었고, 이 중 건의한 문제가 고쳐진 건 NIA밖에 없었다.

이러한 문제점은 대한민국의 IT 업종 대우가 영 좋지 않은 것과 무관하지 않을 것이다. 내가 아직 사회에 나가 본 것이 아니라서 어디까지 우스갯소리인지 판단하지는 못하겠지만 개발자 그룹에서 가장 큰 유머 코드 두 가지가 ‘야근/밤샘’과 ‘여자친구 없음’이다. 사이트를 관리하는 프로그래머를 고용하는 것이 아니라 외주를 통해 싸게 해결하려는 문화도 전반적인 온라인 서비스 품질 하락에 영향을 미쳤을 것이라 생각한다.

흔히들 ‘IT 강국 대한민국’이라고 말하곤 한다. 높은 인터넷 보급률과 빠른 인터넷 속도, 그리고 2000년대 초 IT 붐의 흐름을 잘 타서 지금까지는 선두의 자리를 지킬 수 있었다. 하지만 아직도 없어질 줄을 모르는 Active X와 웹표준을 지키지 않는 플래시 메뉴들, 검색 엔진을 차단하는 공공기관 사이트들을 보면 IT 강국의 자리를 탈환 당하는 건 먼 미래의 일이 아닐 것이라 생각한다. 지금은 자아 도취에 빠져 있을 때가 아니며, 위기 의식을 느끼고 잘못된 관습을 바꿔 나가야만 진정한 ‘IT 강국 대한민국’으로 계속 남을 수 있을 것이라 생각한다.

+
피자헛 배달원은 피자가 ‘뜨거우시니’ 조심하라고 말했다. 이건 또 언제쯤 고쳐지려나 ㅠㅠ