변화에 뒤쳐지지 않기

2013년 즈음이었다. 그 해 여름날도 여느 때와 다름없이, C++로 게임 서버를 열심히 개발하던 날이었다.

시장은 대격변을 맞이하여 모바일 게임으로 시대가 변해 있었고, 빠른 반응성보다는 결과 저장만 필요한 웹 서버만 있어도 충분한 시대가 되어있었다.

반응성 보장에 조금만 실패해도, 부정적인 게임 플레이 경험을 주기에 ns (나노 세컨드) 단위로 로직에 신경 써야 했던 시기는 지나가고, 어느새 웹 서버 기반의 장점이 극대화되어 몇 년 새 난 뒤쳐진 사람이 되어있었다.

그나마 다행이었다면, ruby on rails로 웹 서버를 접해봤다는것 정도랄까?

내가 잘하고 경쟁력 있는 것들이 “별로 중요하지 않다”는 기조는 내가 해온 것이 부정당하며 뒤쳐졌다는 생각을 지우기 어려웠다.

실제로 다니던 회사가 문을 닫게되어 구직하던 과정에서의 몇몇 면접관에게

이제 소켓 서버 왜 써요?

웹 서버도 아직 안써봤어요?

신기술 공부 잘 안하시나봐요?

같은 비아냥을 꽤나 여러 차례 들어야했다.

꽤나 긴 시간 동안 실제로 그랬다.

모바일로 시장이 넘어간 2013년부터 2016년 리니지2 레볼루션 이전의 대다수의 게임은 소켓 서버가 필요하지 않았다.

웹서버를 통한 DB 저장만 해도 되는 싱글 플레이 게임이 다수였기에 가능했다.

나도 그래서 소켓 서버를 제쳐두고 웹 서버를 더 파고들었다.

그들이 그걸 원한다면, 그 것도 잘하고 싶었다.

그럼에도 나는 꽤 이단아였는데, ruby on rails를 쓰는 결정 때문이었다. 해외에서의 많은 레퍼런스와 달리 국내에서 ruby on rails 매우 비주류 였다. 특히 게임용 웹 서버로는.

그렇게 내가 웹서버에 익숙해지다보니, 다시금 소켓 서버가 필요해졌다.

모바일에서도 상호 작용이 필요한 게임 들이 늘기 시작한 것이다.

그렇지만 나는 다시 비동기 네트웍 엔진 및 게임 프레임 워크 전문가로 돌아가기를 포기했다.

내가 가장 오래 해왔고 가장 잘 할 수 있는 것이지만, 오픈 소스 문화에서 잘 조립해 쓰는 문화가 나에게 큰 성장의 계기가 되었기 때문이다.

변화에 뒤쳐지지 않기 위한 몸부림이 어떤 의미에선 나에겐 계기가 되었다는 사실을 깨닫고 과거를 돌이켜보았다.

C언어 스타일 마인드 (나노 단위 최적화)에서 개발 효율성에 큰 가치를 두게 변했던 시기도, 객체 지향에서 마이크로 단위 기능 단위로 쪼개기 시작한 것도, 소켓 서버만이 아닌 웹 서버를 사용하게 된 것도 적어도 나에게는 꽤나 큰 편견과 고정 관념을 이겨내고 나서야 가능했다.

그 변화가 긍정적인지, 부정적인지는 별개의 문제다.

다양한 경험을 하고 다양한 변화를 받아들이다보니,무엇이 더 나에게 맞는지, 내가 어떠한 개발 철학을 가지게 됐는지가 확고해지고 단단해졌다.

기술적, 발상의 스펙트럼이 넓어지니 조금 더 나은 판단에 가까워질 수 있었다.

어쩌면 그 경험들이 내가 읽어온 수많은 개발 방법론 서적들의 명언들이 와닿게 되어, 발전의 계기가 되는거라고 생각한다.

나는 변화를 두려워하지 않을 수 있다면, 변화를 선도 할 수 있는 사람으로 성장 할 수 있다고 믿는다.

앞으로 몇단계고 더 넘어야 하는, 그리고 이런 변화에 두려움을 몇번씩 이겨내고자 해온 프로그래머로써 조금씩 더 유연해지자고 말하고 싶다.

나의 업무 기록과 관리

나는 실수가 많은 편이었다.

그리고 한가지 업무만 주어졌을 때와, 여러가지 업무가 주어졌을 때의 편차가 컸다.

실제로 QA나 크런치 모드같은 상황에서 주로 난감했는데, 여러가지 작업을 바쁘게 진행하고 버그가 여럿 발생해 한번에 몰아 닥칠 때는 악몽 같았다

그렇게 몇 번을 고생하고 나니 일을 정리하는 습관이 필요했다.

타인에 의해 강제로 사용했던 일감 관리 시스템 (Redmine 같은)은 나에게 큰 도움이 되지 않았다.

동료 분 따라 사용해본 포스트 잇도 나에겐 그다지… 잘 안 쳐다봤다.

무엇보다 자신이 편한 방식으로 시작하는 것이 가장 중요하다고 본다.

나는 수기로 작성하기 시작한 업무 일지가 그 시작이었다.

나는 수기로 작성하는 속도가 느리다 보니 작성 중에 여러가지 감상이 들었고, 이게 습관이 되니 자연스레 PC나 태블릿 등으로 기록하는 업무일지도 익숙해졌다.

이렇게 업무 일지가 익숙해진다고 이것 만으로 업무 관리를 할 수 없다.

업무 일지를 잘 쓰려다보니 자연스레 Redmine 같은 업무 관리 시스템도 잘 쓰게 됐다.

이 과정에서 업무 일지에 부가적인 notify 기능이 필요했는데, 수기나 다름없이 노트로 작성하는 업무 일지에선 그 기능을 할 수 없었다.

그래서 도입 한 것이 wunderlist다.

wunderlist_01

반복적인 업무 알림을 받기 위한 할 일 반복 기능이 있어서 일일 시간표처럼 쓰기 좋다.

wunderlist_02

기한이 없는 to do 목록을 관리하기에도 매우 적합하다.

여타 무료 to do list 관리 프로그램에 비해 오류 없는 안정적 서비스를 제공한다.

또한 원노트를 통한 여러가지 필기와 메모도 나에겐 큰 도움이 됐다.

원노트에서 작성한 필기와 메모를 주기적으로 문서화 하게 되는데, 이 과정에서 다시한번 내용을 다듬을 수 있게 된다.

정리하면 나는

빠른 기록용 노트 (OneNote)

  • Note 기능과 편리한 Scrap 기능을 통한 최초 기록.
  • 업무 일지, 위키에 정리하기전 선 정리.

To do list 관리 (Wunderlist)

  • 각종 todo, 주기적 반복 작업에 대한 notify.

업무 관리 시스템 (Redmine)

  • 내가 진행할, 진행중인, 진행했던 업무를 여러가지 방면으로 추적하기 위해서 사용.
  • 상황에 따라 mantis나 trac 같은 버그 보고 시스템도 비슷한 용도로써 쓰일 수도 있음.
  • 간단하게는 trello도 나쁘지 않음.

문서화 도구

이렇게 관리하고 있다.

이렇게 하고 나서야 비로소 업무를 놓치는 일이 매우 적어졌다.

모두가 이렇게 여러 단계를 거쳐야 할 필요는 없다고 본다.

하지만 업무 기록을 다양하게 추적하고 회고하고 개선해야 될 필요가 있다면 내가 제안한 업무 관리 방식중 두개 이상을 적용해보는 것이 어떨까?

경험에 의한 편견에서 벗어나기

누구나 편견을 가지고 산다. 나 역시 그렇다.

개발 과정에서 많이 나오는 얘기가, 내가 해봤는데 라는 말이다.

하지만 그게 실제 근거이기에 반박은 나도 해봤는데 가 되는게 대다수다.

내가 해봐서 안된다, 내가 해봐서 된다라는 레퍼런스는 장점이기도 하지만, 단점이 되기도 한다.

여러가지 의견이 모두 설득력 있는 이야기일 경우가 가장 문제다.

누구나 자신의 경험이 훨씬 명확하다. 그 과정에서 얻은 장단점과 고려사항이 큰 확신을 가져다 준다.

그래서 다른 방식으로의 시도를 꺼리게 된다.

나는 이 점에서, 내가 해봤을 때, 이런 점이 장점이고 이런 점이 단점이라, 이런 부분을 고려하고 시도한다면 어떤 시도도 괜찮다고 접근해야 된다고 생각한다.

기존 경험도 물론 무에서 유를 만들긴 했지만, 잘 생각해보자.

지금 만들고자 하는 것이, 이전에 만들었던 것과 같은 것인가?

아니다. 우리는 더 나은 것을 만들어야 한다.

그렇게 하려면 이전 경험에서의 소득을 엄격히 분리해야 한다.

나는 이 과정이 경험에 의한 편견 벗어나기라고 부른다.

기존 경험에 의한 생각을 배제해야 발전 속도가 더 빨라 질 수 있고, 효율적으로, 옳은 방향으로 발전 할 수 있다고 생각한다.

그래서 필요한 것은, 시간적 여유나 기회적 여유가 있다면 여러가지 방향성을 열어놓는 것이 좋다고 본다.

자신의 예상과 다른 방향이라 할지라도 말이다.

그러기 위해선 불필요한 제약이 적어야 하는데, 이 내용은 추후에 다시 다뤄보고자 한다.

다시 한번 강조하자면, 경험은 물론 중요하다. 나도 두 세번 이상 경험해봤을 때, 좀 더 확신도 들고 좋은 결과가 나왔다.

하지만 그 경험이, 새로운 시도나 다른 방향성에 대한 제약이 되어선 안된다.

편견을 줄여보자.

(서평) 핵심 C++ 표준 라이브러리 - 우리 C++이 달라졌어요!

내가 처음 프로그래밍을 시작한 언어는 C언어였다.

아니 정확히는 난 시작부터 C++이었다.

즉,

    #include <stdio.h>
    int main(int argc, char* argv[])
    {
        printf("Hello, World!\n");
        return 0;
    }

이 아닌

    #include <iostream>
    int main(int argc, char* argv[])
    {
        std::cout << "Hello, World!" << std::endl;
        return 0;
    }

이었음을 말하는데, 컴파일러 기준으로 C++이지 나는 꽤나 오랜 기간 C 스타일로 코딩해왔다.

게임 개발 쪽에서 꽤나 긴 시간 당연한 선택은 C++이었다.

그렇다 보니 너도 나도 C++의 높은 허들을 넘어야만 했고, 그걸 넘은 사람만이 프로가 될 수 있었다.

이제와 밝히자면, 내가 툴 작업으로 업계에 알바로 염탐(?)했던 2000년대 초 당시의 게임 개발자 분들중에서는, 나처럼 C스타일 코딩을 고수하신 분들이 꽤 많았다.

실제로 일을 시작한 2005년도…뭐 별반 다르지 않았다 랄까?

물론 나 역시 배움의 깊이가 부족 했음은 당연히 인정한다.

내가 boost를 처음 접하게 된 것은, 2008년 경, 당시 프로그래밍 이사님이 알려주신 boost bind, boost function이 시작이었다.

이후 필요한 기능을 한 두개 씩 찾아서 쓰다가, C++ tr1 (technical report 1) 이라는 게 있다는 것을 알게 됐고, 그 것들이 boost의 기능 일부를 포함했음도 알게 됐다.

C++ 0x라고 해서, 차세대 C++ 기능을 0x (2000~09년) 사이엔 정식 포함될 줄 알았던 계획에서, C++ 11 (2011)로 늦춰지면서 기술 보고서의 부분적 이식이 이뤄졌던 것이다.

boost의 기능들이 순차적으로 표준화 되고 있고, 실질적으로 boost가 차기 C++ 표준의 후보자 였다는 것도 알게 됐다.

나는 꽤나 긴 시간인 7년정도는 C++ 위주로만 사용했는데, 그 과정에서 아쉬움은 포인터, 함수 포인터, 문자열이었다.

Boost는 수 많은 C++ 개발자 사이에서 논란이 되거나, 자주 필요로 하는, 또는 다른 언어가 가진 장점을 흡수하려 노력했다.

심지어 개중에는 타 언어에서는 대부분 구현되지 않은 훌륭한 녀석 (multi_index같은)도 존재한다.

사실 C++ 표준은 레거시를 포함할 뿐, 권장하지 않는다.

Smart pointer (shared_ptr, unique_ptr, weak_ptr)로써 소유권의 의미를 엄격하게 관리하길 바라며, 의도가 드러나는 코드를 원한다. 여러가지 이유로 raw ptr를 허용할 뿐이다.

또한 WIN32를 비롯한 POSIX 라이브러리를 직접 다루는 것이 그다지 직관적이지 않아 기능 하나를 구현할 때도, 수 많은 시행 착오를 겪어야 했던 지난날은 이제 안녕~

Chrono와 Time은 SYSTEM_TIME이나 time_t를 사용해야 했던 지난날의 아픔을 모두 잊어도 되게 해준다.

auto, r-value reference, enum class 등은 C++을 사용하며 아쉬웠던 틈을 빼곡히 채워준다.

멀티 리턴 값이 필요하다고? 그렇다면 tuple!

C++은 표준 라이브러리의 확장과 boost library의 발전으로 생산성과 속도, 표현력 등 많은 부분이 성장하고 있다.

물론 그럼에도 집중력과 노력을 기울여야만 그 장점을 이끌어 낼 수 있는 어려운 언어 임은 분명하다.

레거시를 포함하기에 실수의 여지를 포함하여 위 장점들을 다 놓칠 수 도 있다는 점도 인정한다.

하지만 그럼에도, 같은 포지션에서 경쟁력을 잃고 사라진 수많은 언어들과는 다르게 C++은 발전하고 있다.

C++의 몇가지 단점들을 커버할 수만 있다면, 결국 C++의 수명은 예상보다 훨씬 더 길어 질 수 있지 않을까?

Rust 이야기

최근 Rust를 살펴보고 있다.

새로운 언어 학습을 위한 시도로, 여러가지 글들로 접해본 Rust의 포지션은 Go와 비교되는 일이 많았다.

특히 C++의 대체자로 Go와 Rust가 꼽히는 글을 많이 접했고, 그래서 상대적으로 많은 분들이 추천하셨던 Go를 먼저 시작하게 됐었다.

그러던 중, 즐겨찾기 동기화 오류가 극심하던 엣지를 버리고, 주 사용 브라우저를 Firefox로 갈아타게 됐고, 그 과정에서 모질라 재단에서 만들고 있는 Rust를 다시금 관심을 가지게 됐다.

동시성, 병렬 프로그래밍에 큰 장점이 있다는 것은 두 언어가 비슷했으나, 꽤나 두 언어는 차이점이 명확했다.

Go가 가장 마음에 걸렸던 점은, C++과 Java등의 언어들이 가진 단점에 대한 해결책을 거의 제시하지 못했다는 점이다.

Google이 만든 언어라는 점 말곤 사실상 메리트는 없다고 느껴졌다.

이에 대한 글들도 상당히 많은 상태고. https://github.com/ksimka/go-is-not-good

Rust는 Go와 다르게, 명확한 대안 몇가지를 제시했다.

특히 와닿는 것은 가비지 컬렉션이 없다는 점과, 동시성에 대해서 Mutability로 해결하고자 했다는 점이다.

C++, Java가 겪은 동시성 문제에 대한 해결책으로 Rust또한 베스트라 말하기 어려운 대안을 제시했다. 그렇지만 적어도 어떠한 문제가 있었는지는 확실히 이해한 상태에서, 명확한 장단점이 있지만, 어떠한 판단을 근거로 대안을 마련했는지가 뚜렸한 해결책을 제시했다.

요구 사항이 모호하면 모호할수록 기술적 선택은 어떤 선택이든 별반 차이가 없다.

요구 사항이 명확하다 해도 기술 선택에 영향을 주지 않는 경우도 많은데, 이 경우 작업자 다수가 익숙한 기술 선택이 당위성을 얻는 경우가 많다.

또한 라이브러리 (=패키지, =Gem) 수도 꽤 큰 당위성을 얻는다.

필수 패키지 셋들이 충분하면 (Std계열이라 불리는) 어느정도 커버가 되긴하지만, 편의성을 개선해놓거나 선택의 폭이 넓은 게 단점일리는 없으니 납득도 간다. 실제로 대다수의 상황에서 성능의 문제라거나 사용성의 문제등의 이유로 기본 라이브러리보다는 사용자 라이브러리가 선택되는 일이 꽤 빈번하기 때문이기도 하고.

그런 의미에서 아직 Rust는 시기 상조다. http://www.modulecounts.com/ 기준 9000개를 조금 넘어선 수준인데, 이는 기능 구현에 필요한 기능의 패키지가 없을 가능성이 꽤 높다는 얘기다. 패키지가 존재한다해도 기능이 불완전 할 가능성도 꽤 높다. (.NET CORE용 패키지들의 현상태만 생각해도….)

그럼에도 나는 Rust를 선택했다. Rust가 얻고자 하는 것이 명확 했다는 것은, 학습 이후에도 얻어가는 것이 있고, 그 장점이 서버 언어로 충분한 장점을 가져다 줄 것이라 믿는다. (Rust의 단점은 장점을 확고히 하기 위함이기에 더더욱 마음에 들었다.)

이 것이 내가 Rust를 선택하게 된 이유다. 이어서 Rust로 사용기와 Rust로 만드는 프로그램에 대한 이야기를 조금 더 이어가 보도록 하겠다.