• 2004-11-24

    어떻게 우리 팀의 XP가 실패했는가?

    붐붐차차 프로젝트는 처음부터 "XP를 한번 연습해본다"라는 기치를 내걸고 시작했다. 개발 초기 3-4개월동안은 별 문제없이 흘러갔지만, 7-8 개월이 지난 이후부터 지금까지, 테스트 코드는 더이상 유지보수되지 않고 있다. 과연 무엇이 문제였을까? 그리고 다음번 프로젝트에서도 XP 를 성공적으로 도입할 수 있을까?

    잘못된 테스트 프로젝트 설정

    • 요약 : unittest 의 링킹 시간이 너무 길었다.
    • 해결책 : DLL(?)

    unittest 라는 프로젝트에서 다른 모든 라이브러리를 테스팅하도록 프로젝트를 구성했다. 테스팅 코드가 적을 때에는 unittest 만 통과하면 OK 이었기 때문에 편리했지만, 점차 테스팅 코드가 많아지면서 링킹해야 할 라이브러리의 개수와 크기가 늘어나게 되었고, 결국 컴퓨터가 버벅거리며 링킹할 동안 인터넷 서핑하는 습관이 생겨버렸다. 작업 효율이 떨어진 것은 당연지사.

    중복 코드의 미제거

    • 요약 : TestingCode 의 중복이 너무 심해서 컴파일 시간이 너무 길어졌고, 리팩토링을 할 때에는 죽어났다
    • 해결책 : 중복 코드가 제거되기 전까지는 테스트가 완료된 것이 아니다.

    어느 날 소스를 조사해보니, (2만라인이 채 안되는) ProductionCode 보다 TestingCode 가 8배 정도 더 많다는 사실을 발견했다. 물론 이게 문제라는 것은 깨달았지만 아무도 이 부분을 고치지 않고 그냥 지나가버렸다. 시간이 나면 고치겠다는 프로그래머의 전형적인 회피술과 함께. 그리고, 언젠가부터 ''시스템 사양이 좀 떨어지는'' 한 개발자가 점점 UnitTest 를 회피하기 시작했으며, 그다음 체크아웃을 한 개발자가 깨진 UnitTest 를 복구해야 하는 일이 종종 발생하게 되었다. 덕분에 서로가 서로에게 짜증을 내게 되었는데... 그 개발자는 시스템 업그레이드 타령과 함께, 굳이 간단한 건 하지 않아도 무방하지 않느냐..라고 하고, UnitTest 를 복구해야 했던 개발자는 왜 자신이 그걸 대신 복구해야 되느냐고 화를 냈기 때문이다. (물론 이때가 팀웍이 흐트러지고 사기가 저하된 타이밍이기도 했다)

    그러다가 대규모 리팩토링이 필요해진 시점이 있었다. 그러나, 이미 테스트 코드들이 더이상 손쓸수 없이 거대해졌기 때문에, ProductionCode 를 수정을 하는 시간에 비해 TestingCode 를 리팩토링해나가는 시간이 훨씬 더 많이 들게 되었다. 리팩토링을 완료하고 나자, 다들 UnitTest 라면 손사래를 치며 도망가버렸다.

    웃긴 것은, Kent Beck 의 TestDrivenDevelopmentByExample 책에서는 '''중복 코드의 제거'''가 Iteration 의 필수 요소로 자리잡고 있었다. 왜 ExtremeProgrammingInstalled 번역서에서는, 이걸 더 강조해주지 않았을까? 쳇!

    UnitTest 라이브러리의 기능 부족

    • 요약 : 특정 테스트를 선택하기 위해서는 항상 재컴파일이 필요했다. 결국, 테스트 시간을 더 길어졌고, 개발자들은 UnitTest 와 더 멀어졌다.
    • 해결책 : 선택적인 테스트가 편리한 라이브러리를 사용할 것

    CppUnit 과 BoostTest 중, BoostTest 를 선택한 이유는 Visual Studio 7.1 과의 호환성 문제였다. (당시 CppUnit 의 경우 VC 7.1 과 호환되지 않았다) 그러나, 이넘은 내가 원하는 코드만을 테스트한다는 것을, 즉 GUI 방식의 테스트를 지원하지 않았기 때문에, 결국 매 테스트마다 코드를 수정해야 했다. 문제는 특정 테스트를 수동으로 추가/삭제하는 파일이 다른 헤더 파일을 모두 include 하는 main 이라서, 약간만 수정하더라도 컴파일 -> 링킹을 다시 해야 했다는 데 있다.

    PairProgramming 의 실패

    • 요약 : 관용의 부족으로 인한 불화(?)
    • 해결책 : 정신을 뜯어고쳐야지!

    이 부분은 솔직히 [레이옷]에게 원인이 있다. [레이옷]의 후배이자 동료인 프로그래머와 Pair를 할 때마다 티격태격 했던 것 때문이다. 조금씩 서로의 코드에 대한 관용의 마인드를 키워나가기도 했고, 관계 개선 - 후배에서 동료로 생각을 고쳐먹기 - 을 해보려고 했지만, 잘 되지 않았다. 여전히 지금도 반말 90% 존대말 10% 에다가 틈만 나면 큰소리치고 강압적으로 밀어붙이기를 해대고 있다. ㅡㅡ;

    귀차니즘

    • 요약 : 4-5개월 이후부터 CRC 카드라든지 스토리, 일정 추정, 기립 회의 같은 걸 하지 않았다
    • 해결책 : XP 관리자의 마인드가 중요하다.

    이 부분 역시 XP 관리자였던 [레이옷]에게 원인이 있다. 처음에는 다들 열정적으로 해나갔지만, 프로젝트가 길어지면서 XP의 핵심 요소들을 하나 둘씩 빠져나가고 마지막까지 남았단 UnitTest 마저도 어쩌다보니 개발자들로부터 폐기처분 당해버렸다. 중간에 문제가 있을 때마다 추스리고 나가야 했지만, 그러질 못했다.

    see also:

  • 2004-11-24

    내맘대로 쓰는 게임 개발 방법론

    Extreme Game Development

    레이옷이 처음 온라인 게임을 만들 때에는, 최신 기술을 얼마나 잘 사용할 것인가? 라든지, 오픈후 폭주할 사용자들의 접속과 그에 따른 불만들을 생각하면서 서버를 디자인할 때에나, 코딩을 할 때 아예 처음부터 이런 부분을 모두 고려해서 잘 짜보자..라는 환상에 빠져 있었다.

    그러나, 실제로 이렇게 하다 보면 작업 기간이 두배 세배로 늘어났으며, 그에 따라서 능률이라든지 효율이 많이 떨어졌던 적이 많았다. 이러다보니 개인 생활도 점차 피폐해져가고, 원래부터 얼마 없던 인간미도 스트레스로 인해 점점 희미해져가게 되고, 일은 일대로 진척되지 않고, 유저들은 불만을 느끼고... 재미없게 만든 게임 치고 히트를 칠 이유가 없지 않은가...

    요즘 들어 느끼는 것은, 서버의 안정성은 경력이 쌓여갈수록 점점 높아지며, 확장성은 프로그램을 짜면 짤수록 자연스럽게 얻어진다는 점이다. 속도는 실행해보고 느리면 프로파일링을 통해서 그 부분만 최적화해나가면 되는 법. 결국 우리가 여기서 얻을 수 있는 교훈은, 필요한 기능은 필요할 때 구현하면 된다. 대신, 현시점에서 가장 간결한 코드를 유지하라! 미래의 요구사항을 걱정하지 말라! 라는 것일까? 이는 Extreme Programming의 가치와 매우 유사하다.

    즉, 불필요한 확장성과 최신 기술로 고민하는 시간을 부족한 게임성을 높이는데 주력하라는 말씀! 근데 말은 이렇게 해도 나 역시 언행일치가 잘 안될 때가 많다.

    헤일로2 개발자들에게 배우는 상위 법칙

    아직도 헤일로2 보너스 DVD 를 보지 않았다면, 꼭 동료들을 불러서 함께 봐라. 30% 정도의 과장과 연출을 무시하더라도 그들은 정말 강하다. 팀원 개개인이 게임 개발의 주체가 되어 더 나은 게임성을 만들어나가는 모습은 정말 감동적이다. 그들에게서 배울 수 있는 2가지 핵심 법칙은 다음과 같다.

    • 30초 플레이의 법칙 : 30초의 게임 플레이가 즐거우면, 모든 것이 즐겁다. (이 플레이를 계속 유지시키면 되니까...)
    • 5분 플레이의 법칙 : 플레이어는 5분 동안 플레이해서 재미가 없으면 접는다. 즉, 5분 동안 플레이어를 잡아 둘 수 있다면 성공!!

    잦은 릴리즈

    적정 기간의 마일스톤은 개발팀이 하나의 목표를 향해 흔들리지 않고 달릴 수 있게 해준다. 또한 투자자들에게 일이 잘 흘러간다는 것, 내 돈이 제대로 쓰이고 있다는 것을 알게 해준다.

    매 2-3개월마다 개발된 내용을 릴리즈하고 사내에서 시연하라. 시연은 잘못된 과거를 반성할 수 있게 해주며, 부족한 시간과 자금, 맨파워를 느낄 수 있게 해준다. 잘 되든 잘못되든 시연은 좋은 것이다. 아무리 적어도 일년에 4-6회의 내부 시연을 가져야 한다. 결과가 좋을 경우 개발팀에게 보너스를 지급하라. 나쁠 경우에는 왜 잘못되었는지에 대해서 보고서를 쓰게 하고, 보너스는 다음번 시연으로 연기하라.

    모든 작업은 2주를 단위로 개발자들에게 할당되어야 한다. 주5일이 확산되고 있는 시점에서, 1주는 너무 짧고 3주는 너무 길다.

    퀄리티 > 일정

    퀄리티는 절대 양보될 수 없다. 버그 1개를 출시할 바에는 기능 2개를 제거하는 것이 옳다. 그러나 이미 윗사람들이나 마케터가 유저들에게 약속해버린 경우에는 어떻게 해야 할 것인가? (종종 개발팀을 압박하기 위해서 저질러지는 일들이다.) 이 기능이 빼고 출시할 바엔 차라리 포기하는 게 낫다. 그러나 이걸 포기하면 잠재적인 손해가 수천수백만원에 회사 이미지가 손상되므로 무조건 구현해라!라고 나오면 어떻게 하는 것이 옳은가?

    중요한건 그들은 책임지지 않는다는 것이다. 최종적으로 책임지는 자는 개발팀이며 결과적으로 회사는 더욱 막심한 손해를 입는다. 주가 관리를 위해 마그나카르타를 출시했다가 치명적인 손상을 입은 소프트맥스의 케이스를 보라. 끝까지 설득하라. 그래도 안된다면 그들로 하여금 퀄리티와 스케줄 둘 중 하나를 선택케 하라.

    실제로 불가능한 스케줄을 accept 하게 되면, 원죄를 짊어지고 시작하게 되는 것이다. 어떻게 열심히 야근하면 되지 않을까 하는 낙관적인 접근은 결국 팀을 와해시킨다. 전통적인 SE 에서 디자인 시간이 오래 걸리는 것은 이와 같은 스케줄 관리에서 소모되는 시간을 포함한 것이라고 보면 옳을 것이다. 일단 작업계획서에 서명을 하고 나면 모든 것은 끝이 난다. 그렇더라도 불가능을 확인하게 되면 즉시 상부에게 알려라. 그것이 피해를 최소화하는 것이다.

  • 2004-11-24

    XML RPC

    XML RPC는 HTTP 프로토콜 위에 XML 로 RPC(Remote Procedure Call. 원격지의 어플리케이션에 정의된 함수를 로컬인 것처럼 호출할 수 있게 해주는 기법)을 구현한 것이다. 특히 Python을 이용하면 정말 쉽게 XML RPC 를 사용할 수 있다. 레이옷은 MoinMoin 위키의 매크로에서 XML RPC 로 원격지의 시스템에 설치된 게임 서버 WindowsService를 제어하는 에이전트를 구현중이다

    see also:

  • 2004-11-24

    Using Xerces C++

    Xerces는 XML 파싱을 위한 C++/Java 공개 라이브러리다. 기존의 Microsoft XML SDK를 이용한 XML 파싱 라이브러리가 있음에도 불구하고, Xerces를 이용한 파서를 새로 만들게 된 것은 Microsoft XML SDK가 Visual C++에서만 컴파일이 정상적으로 되었기 때문이다. Borland C++ Builder를 이용해서 기존의 라이브러리를 컴파일하기 위해 몇가지 시도를 해보았지만, 정상적으로 되지가 않았다. 결국 포기하고 다른 방편으로 Xerces를 이용하게 되었다.

    파싱 클래스나 함수 등은 W3C에서 이미 규정한 것이기 때문에 Xerces나 Microsoft나 별반 다르지 않다. 차이점은 함수의 프로토타입이나, 내부적으로 사용하는 유틸리티 클래스들인데, 이는 쉽게 넘어갈 수 있는 문제였다. 게다가 나중에 유닉스 계열로 가도 이 라이브러리를 그대로 이용할 수 있으니 이 어찌 즐겁지 않으리요.

    Install For Microsoft Visual C++

    • http://xml.apache.org 에서 Xerces 바이너리를 다운받는다. 소스를 다운받아도 상관없으나 컴파일하는 수고를 덜려면 바이너리를 받는 게 낫다.
    • 인스톨하고, Visual C++에서 PATH를 잡아준다.
    • 프로젝트 링크 탭에다가 xerces-c_2.lib 또는 xerces-c_2D.lib 라이브러리를 집어넣는다.
    • xerces-c_2.lib라면 xerces-c_2_2_0.dll을, xerces-c_2D.lib라면 xerces-c_2_2_0D.dll을 PATH로 잡혀있는 디렉토리 어디엔가 복사해둔다.
    • 컴파일하고 실행한다.

    주의해야할 점

    Xerces를 사용해서 XML 문서를 다룰 때, 한글을 사용하기 위해서는

    < ?xml version="1.0" encoding="Windows-1252"?>
    

    과 같은 헤더를 붙여줘야한다. 인터넷 익스플로러에서 보면 한글이 깨져서 보이지만, 실제로 프로그램에서 돌릴 때는 괜찮다.

    < ?xml version="1.0" encoding="euc-kr"?>
    

    로 하는 경우에는 인터넷 익스플로러에서는 보면 괜찮지만, 프로그램 돌릴 때는 한글 문자가 깨지게 된다.

    see also:

  • 2004-11-24

    SAX 이벤트 처리하기

    XML 프로세싱에는 두 가지 모델이 있다. DOM(Document Object Model)과 SAX(Simple API for XML)다.

    • DOM은 XML 문서를 파싱해서 트리 형식의 객체를 만들어낸다. 클라이언트, 즉 DOM을 사용하는 프로그래머는 이 트리에 붙어서 문제를 해결해 나가야한다.
    • SAX는 이벤트 기반이다. XML 문서를 처음부터 파싱해 나가면서, ''새로운 element가 나왔다'', ''element의 끝이 나왔다'' 등등의 이벤트가 발생될 때마다 사용자가 지정한 함수를 호출하는 형식으로 파싱이 이루어진다.

    현재 만들어져 있는 라이브러리는 SAX를 이용한 라이브러리다. 마이크로소프트에서 지원하는 XML SDK를 이용해서, element들의 집합으로 이루어진 트리를 구성하거나, 리스트를 생성할 수 있도록 만들어져 있다. 아직까지는 DTD 관련 처리는 되어있지 않다.

    SAX 이벤트 처리

    SAX를 이용한 애플리케이션을 만들때 처리해줘야하는 이벤트를 설명하자면 다음과 같다.

    • startDocument : 문서의 처음을 읽을 때 호출된다.
    • endDocument : 문서의 마지막을 읽을 때 호출된다.
    • startPrefixMapping : 모르겠다.
    • endPrefixMapping : 모르겠다.
    • startElement : 엘리먼트의 시작점을 만났을 때 호출된다. 위의 예제에서는 이 부분이나 같은 엘리먼트를 만났을 때 호출된다.
    • endElement : 엘리먼트의 끝점을 만났을 때 호출된다. startElement와 대칭되는 쌍으로서 항상 불리게 된다. 물론 문서에 문법 오류가 있을 때에는 안 불린다.
    • characters : 엘리먼트의 시작과 끝 사이의 글자를 만났을 때 호출된다. 위의 예에서는 test 태그 사이의 hey를 만났을 때 호출된다.
    • ignorableWhitespace : 모르겠다. 공백 문자를 만났을 때 호출되는 것 같은데 사용하지 않는다.
    • processingInstruction : 모르겠다.
    • skippedEntity : 역시 모르겠다.

    각각의 이벤트 핸들링 함수에는 인자로 노드의 이름과 길이 등이 따라오기 때문에 이를 이용해서 트리나 리스트를 만들어내는 것은 매우 쉽다. 다만 기본적인 처리가 2바이트 문자이고, 유니코드 로케일 문제 때문에 문자열 변환이 약간 귀찮다.