[NDC2015] 토크방식으로 풀어보는 마비노기 듀얼 서버 개발 이야기

게임뉴스 | 이동연 기자 | 댓글: 8개 |



20일 판교에서 열린 NDC 2015에서 ‘모바일 게임 개발자로의 변신! 마비노기 듀얼 서버 개발 이야기’ 주제로 강연이 열렸다. 이번 강연은 PC게임 10년 차의 서버 프로그래머가 어떻게 모바일 게임 서버를 개발하게 되었는지 토크 형식으로 진행되었다.

사실 받아적을 때만 해도 몰랐다. 이렇게 길어질 줄은. 50분 동안 진행된 임태현, 이승재 두 강연자의 토크를 요약하지 않고 그대로 풀어보았다.




▲ 임태현(좌), 이승재(우)

임태현 : 원래 저는 이 시간이 오후 3시에 시작하는 줄 알았는데 1시에 점심 끝나자마자라는걸 알게 된 후, 상당히 긴장하고 있습니다. 느껴지실지 모르겠지만 원래 목소리를 라디오처럼 낮게 내고 그러는데 그러면 다들 주무실 것 같아서 약간 경쾌하게 진행을 해보겠습니다.

마비노기 듀얼은 일단 클로즈 베타까지 진행된 상태이고 지금 런칭이 코앞으로 알고 있는데요. 아마 잘 알고 계실 거라 생각되지만, 간단히 소개를 해보겠습니다. 제가 소개할 문구를 찾기가 힘들어서 웹페이지 있는 것을 따왔습니다.

‘드로우가 없는 정통 모바일 TCG 열두 장의 카드를 이용해 다양한 전략을 펼쳐나가라. 상대 체력을 0으로 만들어서 듀얼에서 승리하세요!’ 대충 무슨 게임인지 아시겠죠? 흐름은 대충 이렇고요.




카드가 정말 예쁩니다. 아트 전시한 곳에 마비노기 듀얼의 이미지들이 있는데 매우 예쁘니 한번 지나가면서 보시고요. 그런 거 보고 나니 저도 한번 해보고 싶은 생각이 드네요? 정식출시를 곧 한다 하니 많은 관심을 부탁드립니다. 이제 본격적으로 시작을 해보도록 하겠습니다. 이승재 님은 프로젝트에서 무슨 역할을 맡으셨죠?

이승재 : 아아. 들리세요? 저는 전체 개발 기간 중에서 절반 정도 지점에서 합류했습니다. 그 시점에 게임의 핵심적인 부분들은 다 결정이 돼서 만들어져 있는 상태였고요.

임태현 : 제가 미리 주제를 전달받았는데요. 주제의 느낌이 좋습니다. ‘좋은 설계는 좋은 결정으로부터 만들어진다.’ 일단 설계에 대한 이야기가 메인이 될 것 같은 느낌이네요. 이 주제에 대해서 질문을 간단히 해보겠습니다. 어떤 의미로 이 주제를 선택하시게 되었나요?




이승재 : 오늘 하게 될 이야기는 마비노기 듀얼의 서버 구조가 어떻게 되어 있는지, 제가 그 구조를 선택하게 된 이야기입니다.

설계라는 것이 수많은 공학적인 의사결정이 모인 것인데 대부분 정답이 하나로 정해진 것이 없습니다. 이걸 고르면 장·단점이 다른 것을 고르면 또 다른 장단점이 있는 식입니다.

설계 과정에서 이 것을 만나게 되는데요. 어떤 설계를 참고할 때 결과물만 보는 게 아니라, 과정을 따라갈 때 의도를 파악하면서 절차를 밟아보면 이 이야기를 듣는 사람이 설계하는데 도움이 되지 않을까 해서 선택하게 되었습니다.

임태현 : 말씀해주신 걸 정리하면 마비노기 듀얼 서버 구조와 설계과정이 주제 메인이 되는군요. 그러면 우선 간단하게 서버 구조를 요약해 주실 수 있을까요?

이승재 : 간단하게 얘기하면 C++로된 서버 엔진에서 루아(Lua)로 작성하고 있습니다. 네트워크 라이브는 웹서버 크로우를 사용하고 있고요.




임태현 : 핵심단어들이 몇 개 나왔는데요. C++이 우선 나왔고요. 루아, 그리고 웹서버 크로우가 나왔습니다. 제가 나머진 들어본 것이 있는데 크로우가 무엇인가요?

이승재 : 크로우란 나온 지 얼마 안됐는데요. C++된 웹서버 프레임워크입니다. 성능이 매우 좋아서 선택하게 됐습니다.

임태현 : C++은 크게 설명 안 해도 될 것 같고, 그럼 루아는 어떻게 사용하게 됐나요?

이승재 : 서버 로직 전체를 루아로 만든 이유는 클라이언트에서 루아를 쓰고 있기 때문입니다.

임태현 : 클라이언트가 루아를 쓰고 있다? 좀 더 자세한 설명 부탁합니다.

이승재 : 제가 합류한 시점이 프로젝트 절반이 된 시점이었고, 그때 게임의 중요한 대부분이 만들어지고 결정지어진 상태라고 말씀드렸었잖아요? 이미 클라이언트가 많이 완성되어 있었던 상태고 이것까지 다시 새로 만들 여유가 없었습니다.

마비노기 듀얼 클라이언트가 기대로스라는 엔진을 사용하고 있습니다. 이 엔진이 많이 알려진 엔진은 아닌데요. 기데로스가 게임 로직을 만들 때 루아로 만드는 거로 되어 있습니다. 예를 들면 유니티를 쓸 때 대부분 C#으로 만들잖아요? 그 부분이랑 같다고 생각하시면 됩니다. 서버랑 클라이언트가 장기적으로 봤을 때 같은 언어를 쓰는 게 생산성이 좋을 것 같아서 서버를 루아로 채택했습니다.

임태현 : 생산성이 좋아서 루아를 선택했다? 어떻게 생산성과 루아가 연결이 될 수 있을까요?

이승재 : 공통 코드가 생기는 경우에 유지하기가 쉽습니다. 서버랑 클라이언트가 같이 사용하면 되니까요. 마비노기 듀얼의 공통 코드가 MMORPG처럼 많은 건 아니지만, 조금이라도 있으면 같은 데이터를 읽어들이는 시간이 줄어들고, 두 번째로 언어가 같으면 학습능력이 높아집니다.

클라이언트랑 서버팀이 서로 칼같이 나뉘어 있는 게 아니라 서버 작업을 하다가도 어떤 작업을 맡으면 클라이언트 코드를 봐야 되고 클라이언트 담당분도 서버 쪽 코드 수정이 필요하다면 서버 쪽 소스를 봐야 하는데 언어가 다르면 서로 보기가 힘들거든요. 공통코드를 유지함에 있어서 클라이언트에서 프로토타입 코드를 쓰다가 쓸만하다고 판단되면 그걸 그대로 서버로 옮겨서 심어놓은 기억이 있습니다.

임태현 : 그렇지만 웹서버와의 루아의 콜라보는 생소합니다. 저희가 흔히 사용하는 PHP나 Node.js의 프레임워크가 더 유명한 걸로 알고 있는데요. 그런데도 루아를 사용하게 된 좀 더 핵심적인 이유가 있을까요?

이승재 : 프로젝트 경험상 제가 잘 알고 직접 수정할 수 있는 도구 외에 다른 것을 고르면 게임 로직을 만들면서 지속해서 비용을 계속 소모합니다. 무언가를 하고 싶은데 못하게 되고 하부구조를 바꾸고 싶은데 못 바꾸게 되는 경우도 많고요. 근데 Node.js나 PHP를 선택하는 장점을 생각해보면 초기 투자 비용을 아낄 수 있습니다. 오늘 당장 설치하고 당일부터 바로 개발을 시작할 수도 있고요. 가져다 쓸 수 있는 것도 많고, 라이브러리 구하기도 쉽습니다.

그러면 두 가지 경우 중에 선택해야 합니다. 초기 투자 비용을 아낄 것인가, 아니면 내가 안에까지 다 파헤칠 수 있는 장기적으로 비용을 아낄 수 있는 것을 선택할 것인가. 저는 장기적으로 비용을 아끼는 걸 택했습니다. 그리고 이번 마비노기 듀얼 서버를 만들 때 부담이 크지 않았던 이유가 예전 프로젝트에서 루아를 많이 활용해본 것도 있고, 합류하기 직전 프로젝트에서도 클라이언트를 루아로 뼈대까지는 이미 만들어 놓은 상태였기 때문에 수월한 부분도 있었습니다.




임태현 : 초기비용과 지속적인 비용. 생산성 향상. 그전에 이미 사용을 해봤기 때문에, 이 시점에서는 코스트가 낮은 편에 속했다. 이렇게 정리가 되는군요. 루아는 알겠습니다. 그러면 HTTP를 프레임 워크로 사용하고 있는데 그 이유는 무엇인가요?

이승재 : 저는 게임 상태 동기화를 만들 때 두 개 중에 하나라고 봤습니다. 스트리밍 방식으로 만들지. 아니면 요청 응답 방식으로 만들 것인지.




임태현 : 요청 응답…. 이제 슬슬 어려워지기 시작합니다. 요청 응답 방식에 대해서 설명 부탁합니다.

이승재 : MMORPG를 예를 들어 볼게요. MMORPG의 경우 캐릭터가 아무런 행동을 하지 않아도 보고 있는 세계의 변화가 생기잖아요. 유저가 지나간다든지. 이렇게 실시간으로 변화를 받아와야 합니다. 이것을 스트리밍 방식이라고 합니다…. 그런데 요청 응답 방식을 채택하면 이런 걸 만들 수가 없습니다.

임태현 : 그러면 스트리밍이 좋은 것 아닌가요?

이승재 : 스트리밍이 PC에서 구현하기 좋은데, 모바일에서는 스트리밍 방식을 선택하기가 어렵습니다. Wifi에서 LTE로 바뀌면서 끊길 때 아이피가 바뀌잖아요. 그때 TCP 소켓이 스트리밍 방식을 계속 이어나갈 수 없습니다.

임태현 : 요청 응답 방식이 자주 끊기는 방식에서 유리하다는 이야기인데, 결과적으로 요청 응답도 끊기면 응답 못 받는 것은 마찬가지 아닌가요?

이승재 : 요청 응답 방식은 클라이언트가 요청을 보냈을 때, 제한시간 동안 응답이 오지 않으면 '아 끊겨나' 하고 다시 보내면 됩니다.

임태현 : 다시보낸다… 다른 장점은 없을까요?

이승재 : 요청 응답을 만들면 서버의 상태를 없게 만들 수 있어요.

임태현 : 이제 서서히 철학적인 질문이 나옵니다. 상태가 없다? 자세한 설명을 부탁합니다.

이승재 : 상태가 우리가 좀 받아들이기 어려운 단어인데요. MMORPG로 예를 들면 유저가 서버에 붙어 있으면 PC 접속을 계속 유지하고 있는 상태가 되잖아요? 로그인하면 로그아웃 할 때까지 소켓이 붙어있고. 이게 서버의 상태가 됩니다. 유저의 HP가 얼마인지, 위치가 어딘지, 계속 메모리가 붙들고 있는데 이것이 서버에서의 상태입니다.

임태현 : 상태가 뭔지 알겠습니다. 상태가 없는 게 장점이라고 했는데 이거에 대한 설명도 부탁합니다.




이승재 : 마찬가지로 MMORPG로 예를 들면 서버 프로세스가 죽으면 유저가 소켓이 끊기면서 게임에서 나가게 됩니다. 이것을 막겠다고 소켓을 추상화해서 잘 죽지 않는 상태로 붙여놓는다 해도 의미가 없습니다. 몬스터 위치 같은 것도 서버에 붙어있기 때문에, 서버가 죽으면 날아가기 때문이죠. 아이템이나 경험치 같은 중요한 것은 DB에 저장하기 때문에 서버가 끊겨도 살아남을 수 있습니다.

그런데 아예 서버 상태가 없는 상태로 메모리를 유지하지 않으면 서버가 죽어버리게 되면 요청을 다시 보내면 됩니다.

임태현 : 잠깐만요. 그럼 몬스터나 이런 정보들이 다 DB에 있다는 이야기인가요?

이승재 : 몬스터가 없죠. 마비노기듀얼은 MMORPG가 아니므로 이런 방식이 가능합니다. MMORPG는 1초 미만 단위로 정보를 처리하기 때문에, 매번 DB에 갔다 오면 못 만듭니다. 마비노기 듀얼의 경우 실시간 유저간 대전을 하는 경우에도 몇 초 이상 걸리거든요. 생각을 오래 하면 10초 이상 걸리고… MMORPG는 이렇게 못 만들죠.

임태현 : 그럼 마비노기 듀얼의 특성이 카드 게임이잖아요? MMORPG처럼 전투가 없고 템포가 없으므로 가능한 방법이었다… 게임의 특성이기 때문에 생긴 결과라고 볼 수 있겠네요? 좀 더 이야기가 있을 것 같은데 다른 이점은 없을까요?

이승재 : 서버의 상태가 유지되지 않기 때문에 패치를 점검 없이 할 수 있습니다. MMORPG는 서버의 버전을 올리려면 프로세스를 끈 다음에 해야 되잖아요? 우리는 유저의 정보가 DB에 들어있고 게임 서버에는 없기 때문에 서버 패치를 점검 없이 할 수 있습니다.

어떻게 하느냐면 서버를 한 대씩 끈 후, 버전을 올리고 다시 붙이면 됩니다. 그렇게 하면 유저는 전혀 느끼지 못하는 상태에서 패치를 할 수 있습니다. 물론 클라이언트 프로토콜이나 데이터에 영향을 주는 것은 그렇게 할 수도 없고, 해서도 안 되죠. 이런 패치는 유저에게 알리고 점검을 진행하면 됩니다. 다만 사소한 버그 패치는 이런 방식으로 할 수 있습니다.




임태현 : 중간정리를 해보겠습니다. 일단 루아를 채택한 건 클라이언트 엔진인 기데로스가 루아를 쓰기 때문에 같은 것을 쓰고 싶었고, 생산성에서 좋아서 사용했다. 초기비용은 경험해봤기 때문에 낮출 수 있어서 선택한 것이고, 요청/응답 방식을 선택한 것은 모바일+카드게임이라는 장르적인 특성을 살려 택한 거라고 요약해도 될까요?

이승재 : 네

임태현 : 요약은 했는데, 사실 잘 모르겠어요. 뭔가 변화가 생기고 스트리밍 방식을 써야 되지만, 우리는 카드게임이기 때문에 그럴 필요가 없어서 요청 응답으로 충분했다… 제가 마비노기 듀얼 CBT 때 방송하는 걸 봤어요. 아리따운 여자분이 유저하고 배틀하는 것을 봤는데, 내가 카드는 내면 상대가 그걸 바로 받잖아요? 그걸 다시 말하면 서버에서 변화가 생기고 요청 응답으로는 이 방식이 안 되는 것 아닌가요?

이승재 : 네 기본적으로는 그런데요. 롱 폴링(Long Polling) 방식을 사용하면 됩니다. HTTP 서버에서 발생한 사건을 전송할 때, 그쪽으로 연구가 많이 됐는데요. 그 다양한 방법 중에 제일 직관적인 폴링(Polling)이란 방법이 있습니다. 클라이언트가 서버에 계속 물어보는 방식인데요.

상대편이 턴을 실행했는지. 한 번 더 했는지. 이렇게 계속 물어보는 방식입니다. 그런데 이 방식을 사용하면 네트워크와 배터리 사용량이 많고 부하도 많이 갑니다. 이때, 폴링 방식을 조금만 틀면 쓸만한 것이 나오는데요. 새로운 사건이 일어나지 않았을 때 서버가 즉시 응답을 하지 않고, 새로운 사건이 일어날 때까지 기다리게 하는 거예요. 그 기법을 롱 폴링이라고 합니다.

임태현 : 복잡하네요. 그럼 단도직입적으로 물으면 꼭 그런 걸 써야 되나요? 편하게 유저간 통신에 한정해서 스트리밍. 그러니까 우리가 잘 아는 TCP 방식을 쓰면 안 되나요?

이승재 : 그 지점에서 고민을 많이 했어요. 둘 중 하나를 써야 하는데 그중에서 요청 응답 방식을 고른 이유가 빨리 만들려고 했기 때문에 사용했어요. 스트리밍 방식을 쓰면 서버가 끊길 때 재전송을 해주는 버퍼링/재전송 레이어를 만들어야 했고요. 요청 응답을 쓰면 서버 응답 부분을 만들어야 합니다.

그러면 '서버 응답 부분인 롱 폴링을 만드는 게 버퍼링/재전송을 만드는거보다 시간이 빨리 걸리는가?'라는 질문을 해볼 수가 있는데요. 사실 그건 아닙니다. 제가 롱 폴링을 선택한 것은 만들어 본 적이 있기 때문에 탄탄하게 만들 수 있고 개발 기간을 예측할 수 있어서 선택했습니다.




임태현 : 답이 나왔네요. 이전에 해봤기 때문에 잘할 수 있어서 선택했다. 그러면 의문점은 해결됐는데 롱 폴링 기법이 뭔지 구체적으로 설명 부탁합니다.

이승재 : 마비노기 듀얼에서 롱 폴링을 어떻게 사용하고 있는지 유저간 대전을 예로 말씀드리면 이걸 스트림 방식으로 구현했을 때, 같은 방에서 상대방이 턴을 선택하면 스트림 방식으로 전달할 것입니다.

그런데 마비노기 듀얼은 방이란 게 서버에 있지 않습니다. 아까 서버에 상태가 없다고 했잖아요? 방도 일종의 상태인데요. 방은 DB에 있습니다. 실제로 실시간 듀얼을 할 때 어떤 일이 벌어지느냐면 유저가 내턴이 아닐 때 서버에 상대편이 무슨 행동을 할지 물어봅니다. 상대방이 실행을 안 하면 기다리고 있다가 실행하면 그때야 보내는 방식입니다.

임태현 : 서버 안에서 기다리는 거 맞죠? 제가 왜 고민이 드느냐 하면 일단 서버 안에서 기다리는 게 제 상식과 안 맞아서 그런데요. 말을 풀어보면 서버 안에서 기다리려면 서버가 멈춰야 하잖아요? 기다린다는 게 아무것도 안 한다는 것으로 알고 있습니다.

근데 서버는 멈추면 안 되잖아요. 서버는 비싼데 기다릴 동안 아무것도 안 하고 있으면 리소스 크기나 예측이 안 되잖아요? 그렇게 만들면 혼난다고 알고 있는데 자세히 설명 좀 부탁합니다.

이승재 : 지적하신 게 맞습니다. 스레드 라는 건 하나당 적게는 몇 메가바이트부터 많게는 몇십 메가바이트까지 갖고 있어야 하는 비싼 자원입니다. 그래서 스레드가 유저가 보낸 요청을 계속해서 기다리게 하면 동시 접속을 많이 받을 수 없어요. 스레드 하나당 걸리는 부하를 줄여야 합니다.

임태현 : Node.js와 파이썬은 그렇게 하겠죠? 마비노기 듀얼은요?

이승재 : 마비노기 듀얼은 요청을 할 때 롱폴링 응답을 해야겠다 생각을 하면, 변수를 한 곳에 저장해놓고 다른 걸 실행합니다. 그것을 계속하다가 대기하는 게 여러 개 생기면 대기하는 것 들 중에 새롭게 보내줄 이벤트나 타임아웃이 생기면 그거에 대한 응답을 보냅니다. 그런데 스레드가 여러 개고 웹 서버도 여러 개잖아요? 그래서 이 부분에서는 'redis' 서버 채널을 쓰고 있습니다.






▲ 클라이언트가 서버에 요청을 보내면



▲ 일단 대기



▲ 다른 클라이언트 쪽에서 요청을 보내면



▲ redis에서 서버로 응답을 보낸다



▲ 응답을 받은 서버는 클라이언트에 응답을 보낸다.

임태현 : 정리를 해보면 롱 폴링이라는 녀석은 우선 모바일 환경에서 요청 응답 방식으로 스트리밍을 구현하기 위해서 사용하고 있습니다. 그런데 이것은 말 그대로 롱 폴링이니까 오래 기다려야 하잖아요? 이걸 서버에 전가하면 부담이 많이 되니까 그 안에 VM에서 대기를 하고 있습니다. 근데 VM에서 대기한다고 되는 것이 아니라 무언가를 받아야 하는데 redis에서 메시지를 전달을 받고 있고, 거기서 제가 상대방에게 요청을 보내면 HTTP - VM - redis를 차례로 통과해서 메시지가 오게 되는 거죠.

화제를 돌려보면 루아는 기본적으로 파이썬이라는게 없잖아요. 함수의 인자를 받는데 이 인자가 숫자인지 문자인지 모르거든요. 그러면 다루는 사람 입장에서 실수할 여지가 매우 많지 않을까요?

이승재 : 불안한 점이 확실히 있죠. 사실은 파이썬이 없는 것은 그렇게 심각한 문제가 아닙니다. 이름을 바꿔주거나 리팩토링을 할 때 훨씬 심각한 문제가 발생합니다. 루아의 어두운 구석이라고 생각하는 게 내가 선언하지 않는 지역변수를 가지고 그 이름을 어떻게 사용해 버리면 전역변수로 선언되거든요. 그런 규칙이 있는데 매우 자주 하는 실수 중 하나입니다.

변수명을 고쳤는데, 실수로 다른 한곳을 고치지 않으면, 컴파일에서 잡히지 않거든요. 이게 굉장히 짜증이 나는데 바로 테스트할 때 잡히는 게 아니라 며칠이 지나고 QA한테 가서 이런 버그가 있어요. 한 두 시간 디버깅했는데 저 사람이 이름 안 바꿔서 두 시간 동안 디버깅하게 만들었어! 이러면 열 받잖아요?

이 문제에서 루아의 파서를 없는 지역변수를 전역으로 바꿔줄 때 특별한 규칙이 없는 전역을 아예 만들지 못하게 한다거나 방식으로 고칠 수 있습니다. 그것보다 뾰족한 해답이 존재하지 않는 것이 있는데 루아의 테이블 같은 구조를 객체처럼 사용할 수 있거든요. 그런데 객체에서 없는 멤버함수나 변수를 부르면 컴파일 에러가 뜨는데 루아는 그걸 막을 방법이 없습니다.

그것 때문에 생산성을 많이 깎아 먹죠. 사실 이것은 해결을 못 하는 문제입니다. 온라인게임을 루아로 만든 적도 있었는데 그때는 정말 고통스러웠습니다. 적은 프로그래머로 생각보다 짧은 시간에 게임을 출시할 수 있다는 것은 좋았는데, 어이없는 실수를 하고 그 실수는 기계가 잡아주지 않아서 디버깅하는데 시간을 많이 잡아먹는 게 고통스러웠고요.

그래서 다시 루아로 큰 프로그램을 만들지 않겠다고 결심을 했습니다. 그래서 마비노기2 할 때 스크립트 언어가 필요할 때 그건 새로 만들었습니다.




근데 마비노기 듀얼에 합류하고 보니까 클라이언트 언어가 루아였습니다. 제가 루아를 짜고 싶지 않다고 해도 저 혼자 프로그래밍 하는 게 아니고 같이 만들기 때문에 어떤 방향으로 가야 할지 머리를 아무리 굴려봐도 루아가 좋겠더라고요. 그래서 루아를 골랐습니다. 정리해보면 루아는 어두운 구석이 있고, 다시는 안 하기로 했는데 어쩔 수 없이 하게 된 겁니다.

그런데 지금 와서는 조금 다릅니다. 클라이언트는 모르겠는데 서버는 괜찮습니다. 할만합니다. 왜냐하면, 컴파일에 잡아주는 게 적더라도 우리가 유닛 테스트와 클라이언트를 제대로 짜서 서버의 코드가 모두 한 번씩은 실행된다고 가정을 하면 런타임에서 잡을 수 있습니다. 물론 유닛테스트를 일일이 만들어야 한다는 단점이 있지만, 어차피 유닛 테스트는 짜야 되기 때문이죠.

임태현 : 유닛테스트를 하니까 괜찮다. 속마음을 말하겠습니다. '말 너무 쉽게 하는 거 아냐?' 유닛테스트 안 되잖아요? 하면 좋은 거 모르는 사람은 없어요. 하지만 안되지 않습니까. 가르침을 주세요. 어떻게 하면 유닛 테스트를 잘할 수 있나요?




이승재 : 유닛테스트… 사실 어렵습니다. 근데 이게 일반적인 모든 유닛테스트가 어려운 것이 아니라 기존에 유닛테스트 없이 작성된 코드를 유닛테스트를 나중에 들어가서 적용하려고 할 때 지옥이 따로 없습니다.

제가 경험해봤던 MMORPG 개발순서를 생각해볼 때 맨 처음 만드는 게 이동, 시야 처리, 그다음 전투를 만듭니다. 근데 이것들은 입, 출력을 코드로 표현하기가 쉽지 않아 유닛테스트를 하기가 힘든 부분이 있습니다.

그래서 이 시점에서 유닛테스트를 거치지 않고 쭉 개발하다 보면, 코드가 한 덩이가 됩니다. 이때 유닛테스트를 하려면 코드를 다 잘라서 해야 하는데 그게 나중에는 하기가 쉽지 않은 거죠. 그런데 MMORPG가 아니고 마비노기 듀얼같이 상태가 없는 서버는 유닛테스트가 상대적으로 쉬운 편입니다.

임태현 : 상태가 없어서 유닛테스트를 더 쉽게 할 수 있다. 무슨 의미죠?

이승재 : MMORPG 같은 경우에는 유닛테스트 없이 만들다가 나중에 테스트를 만들려면 힘들다. 배보다 배꼽이 더 커질 수 있다. 그래서 포함을 못 시킨 것이라는 의미입니다.

임태현 : 결국은 모바일게임+TCG라는 장르적인 콜라보레이션이 유닛테스트에서 혜택을 봤다는 건가요?




이승재 : 결과적으로는 맞습니다. 그런데 제가 과거에 기존 코드에서 유닛테스트를 점점 늘려간 기억을 돌아보면 처음부터 MMORPG도 유닛테스트 하면서 만들 수 있을 것 같습니다. 왜냐하면, 새 코드를 짤 때 기존 통합된 상태에서 테스트하거든요.

기능상태에서 하기보단 새로운 코드를 짤 때 기존코드랑 격리해놓은 상태에서 유닛테스트를 먼저 통과하게 하고 그다음에 기존코드랑 통합해서 테스트하면 버그가 적은 상태에서 만들 수 있을 것 같습니다. 코드 자체의 양은 많아지지만 만드는 시간은 줄어들고. 설계도 개선되는 부분도 있고요.

응집성이 좋고, 의존성이 적은 코드가 좋은 거라고 하잖아요? 유닛테스트를 통과하고 난 후에 통합하게 되면 인터페이스를 훨씬 더 가다듬을 수 있고. 결과적으로는 설계가 개선되는 경우가 많습니다

임태현 : 제가 이 주제를 포함해서 정리하면 처음으로 돌아가서 '좋은 설계는 좋은 결정에서 나온다'에서부터 시작을 했습니다.

그리고 웹서버, 루아, 롱폴, 유닛테스트까지 이야기가 쭉 흘러 지나왔고요. 얘기의 핵심은 이런 설계들이 마비노기 듀얼이라는 특성. 즉, 모바일 TCG, 그밖에 등등 비용과 성능을 만족하는 그 안의 범위에서의 결정으로 탄생한 거군요. 쉽게 말해서 여러 가지 가능성 중에서 비용과 성능을 모두 만족하는 것을 선택 한 거군요?




이승재 : 결과를 놓고 보면 저랑 프로그래머 3분이 중간에 투입돼서 기존 코드를 버리고 서버를 새로 코딩을 하기까지 두 달이 걸렸습니다. 테스트 기간까지.

임태현 : 두 달 만에 CBT? 오늘 들은 얘기 중에서 가장 황당한 얘기 같습니다. 두 달 만에 CBT를 한 비결은 무엇인가요?

이승재 : 오늘 발표에서 말씀드린 내용을 쭉 돌이켜보면 공통점이 있는데 다 해본 것 위주로 구성했다는 것입니다. 그래서 시행착오를 하지 않았다는 것이죠. 루아는 예전 회사에서 일하면서 직접 해봤고, 롱 폴링도 파이썬으로 해봤고, 이때 redis도 써봤습니다. 시간이 너무 타이트해서 시행착오를 할 여유가 없었습니다. 완전히 익어서 삽질할 여지가 전혀 없는 걸 선택했습니다.

임태현 : 그러면 마무리를 해보겠습니다. 좋은 설계는 경험으로부터 나온다. 경험은 기회가 있을 때 해봐야 한다. 새로운 경험과 시도를 해봐야 한다. 하다 보면 언젠가 보답으로 돌아온다는 거죠?

이승재 : 좀 더 설명해 드리면 우리가 새로운 기술을 도입하려고 할 때 언제나 위험이 있습니다. 도구가 문제가 있을 수도 있고, 사용하는 도구가 충분히 알지 못하면 시간을 많이 날리게 되는데, 그런 위험을 애초에 알고 싶지 않기 때문에 업무에 사용하는 경우가 적습니다.

언제나 늘 하던 대로 일하게 되는데 저 같은 경우 직업도 프로그래밍, 취미도 프로그래밍이에요. 그래서 업무에서 하는 거 말고 취미에서 다른 기술을 종종 만들어보는 경우가 있었습니다. 취미생활 때 모험적인 시도를 해볼 수 있었고, 이때 해본 성공이나 실패 둘 다 자산으로 남을 수 있었습니다. 회사에선 MMORPG만 계속 개발을 해왔지만, 취미로 이것저것 해보지 않았으면 두 달 만에 온라인에서 모바일 게임 개발자로 전향은 불가능했을 것으로 생각하고 있습니다.

이승재 : 예. 말씀 감사합니다. 수고하셨습니다. 이상으로 강연 마무리 하겠습니다.



댓글

새로고침
새로고침

기사 목록

1 2 3 4