나의 게임 업계 투신기

내 또래 남자 아이들중 안그런 아이들이 몇이나 있었겠냐만은, 나 역시 게임을 무척이나 좋아했다.

초등학교도 들어가기전인 6살때 친척형 손잡고 오락실에 간 이후로, 내 인생에서 게임을 빼놓고 이야기할 수 없을 정도 큰 위치를 차지해 버렸다.

처음 오락실에서 했던 게임은 속칭 탱크라 불리는 배틀시티였다.

배틀시티

나의 첫 게임 배틀 시티. 당시 내가 살던 동내 오락실에는 이 게임만 3대가 있었다.

중앙 하단에 위치한 독수리를 지키며 다른 탱크들을 제압하는 것이 목적인 이 게임은, 생각보다 재밌다.

중간 중간 빨간색으로 번쩍이는 탱크를 없앴때는 아이템이 생성되는데, 방어막, 독수리 보호, 미사일 발사 속도 향상 등의 효과가 있었던걸로 기억한다.

단순히 공격만 하는 것이 아니라 수비도 신경을 써야하고, 독수리를 내가 파괴할 수도 있기에 아군 진영에선 공격에 신중하게 해야 했다.

그렇게 첫 발걸음을 내딪고 나서는 용돈만 생기면 오락실로 달려가곤했다.

이후 세기의 명작 스트리트 파이터2를 비롯해서 파이널 파이트, 용호의 권, 다크 스토커즈, 아랑 전설 등 다양한 격투 게임을 즐겼고, 천지를 먹다2, 파이널 파이트, 캡틴 코만도 등의 횡스크롤 액션 게임도 좋아했다.

스트리트 파이터 2

그냥 게임 하는게 좋았고, 게임을 좋아하는 데에 딱히 이유가 없었던 것 같다.

어쨋든 그렇게 게임을 좋아하던 나에게 있어 중요한 계기가 된 사건이 생겼는데, 컴퓨터 학원에 등록하게 된 것이었다.

 

컴퓨터 학원에서 당시에 배웠던것이 윈도우 3.1, 훈민정음, 아래아 한글이었던 만큼 많은 것을 배우진 못했지만, 프로그래밍이라는 것이 어떤것인지 간단히 알 수 있었던 기회였다. (학원에서 가르쳐준 것이 아니라, 같이 학원을 다닌 친구가 알려줬다. 그 친구는 Q-Basic이라는 언어를 할 수 있어, 프로그래밍에 대해 알려주었었다.)

윈도우3.1

사실상 프로그래밍 적인 목적보다는 컴퓨터를 자주 만지기 위해 컴퓨터 학원을 다니다 중학교 진학을 압둔 겨울에, 친구와 게임을 만들어보기로 결심하게 됐고, C언어 책을 사서 공부하기 시작했다.

그 당시 처음본 책이 아직도 기억난다. 터보 C 길라잡이라는 책이었는데 굉장히 쉬운 책이었다. 글씨도 크고.

내가 프로그래밍을 시작하게 된것은 순전히 게임을 만들기 위해서였고, 만약 내가 그림 실력이 좋았다면 그래픽 디자이너가 됐을 것이다.

주변의 도를 넘어선 만류로 심사숙고한 끝에, 이런 손그림 실력으론 디자이너가 될 수 없다는 한계를 깨닳았고, 어떻게 공부해야 할지 난감했던 (시스템 기획자도 있긴 하지만 당시엔 시스템 기획자란게 있는지도 몰랐다.) 기획자보다, 프로그래머를 선택했다.

중, 고등학교 시기에 아마추어 팀을 결성해 게임 제작을 하기도 했고, 습작을 여럿 만들며 프로그래밍에 매진했다.

나우누리 NGM, 하이텔 GMA, 넷츠고 게제동, 넷츠고 프로머 등의 공개 자료를 보며 많이 배웠고, 그 당시 경험이 지금에 와서도 많은 도움이 됐다. 개인적으론 다른 동호회들에서는 주로 자료를 보고, 질문만하곤 했으나, 넷츠고 프로머에서 열심히 활동했고 당시의 경험이 큰 도움이 되었다.

이후 대학교도 컴퓨터 공학 계열로 진학했고, 졸업 시기가 다가와 취업할 때 쯤 되었을 때 프로그래머로써 취업을 하는 것은 나에게 있어 너무나 당연했다. 웹, 클라이언트, 서버, SI, 임베디드 등 다양한 프로그래머가 존재하기에 그 선택이 필요했을 뿐이었다.

나는 게임을 만들기 위해 프로그래밍을 시작했고, 어린 시절 나에게 설레임을 가져다 주었던 그런 게임을 만들고 싶은 꿈이 있었기에 게임 업계를 선택했고, 지금도 게임 제작을 하고 있다.

그렇게 프로그래밍을 직업으로 삼은지가 엇그제 같은데 벌써 2년 반이나 되었다. 비록 긴 시간은 아니었지만, 그 시간동안 나의 열정을 다해 하는 일이니 만큼 아쉬움도 안타까움도 크고, 기쁨도 컸다.

언제까지나 지금과 같은 맘으로 프로그래밍을 할 수 있었으면 좋겠고, 50살, 60살이 되어도 현역 프로그래머가 되어 프로그래밍을 하고 싶은게 내 바램이다.

코드 읽기

문득 코드를 작성하던 중 이런 생각이 들었다.

“과연 지금 내가 작성한 이 코드가 분석하기 쉬운 코드일까?”

생각해보면 아마추어 일때를 제외하고는 새 코드 작성보다 다른 사람의 코드 분석하는 시간이 더 잦았고, 새 코드를 작성하더라도 다른 코드와 어울려야 했기 때문에 코드 분석은 늘 필요했다.

심지어 내 코드를 분석해야 되는 일도 잦았다. 기억력에는 한계가 있고, 시스템의 전체적인 이해도는 높을 수록 좋겠지만 세세한 코드 하나 하나가 하는 일까지 외울 필요는 없다고 생각한다.

그렇기에 내 코드를 내가 몇달이 지나고, 심지어 몇년 후에 봤을 때도 읽기 쉽고 유지보수하기 쉬운 코드를 만들기 위해 노력해야 한다.

그래서 우리는 디자인 패턴, 리팩토링 등을 통해서 좋은 코드를 만들기 위해 노력하고, 표기 법을 만들었으며, 코딩 규약도 만들었다.

그런데 왜 코드 읽는 법에 대한 논의는 없을까? 코드를 잘 “작성”하는 것과, 코드를 잘 “읽는” 것과는 엄연히 다르다.

그런데 많은 사람들이 코드를 잘 작성하는 사람이 코드를 잘 읽을 것이라고 생각한다. 과연 그럴까?

분명히 좋은 코드가 무엇인지 이해하고 있는 사람은, 그렇지 않은 사람보다 코드를 잘 읽을 것이다.

코드 읽기와, 코드 작성은 별개로 보아야 한다. 또한 코드 읽기를 잘하기 위해선 단순한 코드 작성이 아닌, 유지보수하기 쉬운 코드 작성이 되어야한다.

좋은 코드가 무엇인지 이해하려면 경험이 필요하고, 그런 경험을 해오며 코드 읽기에 대한 노하우도 쌓였을 것이라 이미 코드 읽기에 대한 노하우가 있을 것이다.

그렇지 않은 사람들은 코드 읽기를 어떻게 해야 할까?

내가 생각하는 코드 읽기 방법이다.

  1. 특정 클래스를 따로 떼어내서 사용해본다.  만약 해당 클래스가 다른 클래스와의 결합도가 높다면, 별개의 모듈로 동작할 수 있도록 해체 작업을 해본다. 실패하더라도 그 과정에서 해당 모듈에 대한 이해도가 높아졌을 것이다.

  2. 이미 완성된 프로그램을 돌려본다. 그리고 디버깅을 통해서 해당 코드가, 프로그램에 어떤 영향을 주는지 살펴본다.  이 방법의 단점은, 나무는 볼 수 있지만 숲을 볼 수는 없다는 것이다.

  3. UML등을 이용해서, 클래스 구조도를 그려본다. 그리고 각 클래스 별로 따로 분석한다. 1번과 2번 방법을 적절히 사용하면, 코드 분석이 좀 더 이로울 것이다.

이 글이 이제 갓 프로그래밍을 시작한 초보 개발자나, 코드 작성은 자신 있지만, 아직 다른 사람의 코드를 분석하고 수정하는 것은 어렵기만한 분들에게 코드 읽기에 대한 도움이 될 수 있는 글이 되었으면 좋겠다.

(서평) 린 소프트웨어 개발 - 개발 효율 향상을 위한 애자일 지침서

혼자 개발을 하던 시대는 지나갔다. 게임 업계에서도 1인 개발자는 별바람님을 제외하곤 사라진지 오래다. 그만큼 팀 작업의 중요성은 더 크게 다가 오고 있다.

한 프로젝트를 위해 마케팅, 서비스, 시스템, 개발이라는 각기 다른 업무를 맡고 있는 사람들이 협동해야하며, 한 팀 내에서도 웹, 서버, 클라이언트, 애니메이터, 배경, 원화가, 모델러, 기획자 등의 다양한 사람들이 함께 일하곤 한다.

우리는 하루에 반 이상을 회사에서 보낸다. 회사에서 즐겁지 못하다면, 우리의 인생도 즐겁지 않을 것이다.

어떻게 해야 우리 모두 만족하는 개발 과정을 만들 수 있을까?

사실 나는 알게 모르게 유비무환이라는 사자성어를 교훈삼아, 늘 넘치도록 준비하려 노력했다. 그게 미덕인줄 알았다.

이런 내게 있어 낭비를 제거하라는 충격이었다. 포펜딕 부부는 지금 당장 필요하지 않은 것들은 모두 낭비로 규정하고 있었다.

하지만 곰곰히 생각해보니 언제 다시 쓰일지 모르기 때문에, 조만간 필요하게 될거라 생각해서 남겨두었던 코드들이 다시 쓰인 경우는 사실 별로 없었다.

언젠간 쓰게 될거 같아 미리 만든 코드들은 완성도가 좀 부족했다. 무슨 기능이 필요할지 명확히 이해하지 못하고 작성했기 때문에, 결국엔 코드를 새로 작성하는 것이 되기도 했다.

돌이켜보면 필요할 때 만들게 되면 완성도도 더 높았고, 능률도 좋았다. 자신이 하는 일이 의미가 있는 일이라는 생각이 들기 때문이다.

빠르게 납품하라는 얘기도 와닿았는데, 개발과정에서 빠른 피드백의 중요성을 느꼈기 때문이다. 의사 소통문제로 기획팀에서 원하는 내용이 아닌 다른 내용을 개발한 적도 있었고, 만들어보니 만족스럽지 못한 결과를 낳는 경우가 많았기 때문이다.

사실 처음부터 완벽한 결정을 내리고, 완벽한 결과물을 내는 일은 불가능 하기에, 개발 환경을 경험해보며 개선해 나가는 것이 좋다는 말로 시도에 대한 강박관념을 덜어낼 수 있는 좋은 말이기도 했다.

린 소프트웨어 개발은 다양한 예를 들어가며, 프로젝트에 도움이 되지 않는 편견을 깨도록 도움을 주고 있다. 사실 워낙 경험 많은 분들이고 프로젝트 관리를 하시는 분들의 이야기라 아직 경력이 얼마 되지 않았고, 개발자인 내가 어떻게 할 수 없는 부분들이 많다.

이 책을 관리자에게 권해보기도 하고, 변화를 위해 건의도 해보자. 더 좋은 개발 환경은 만들어 나가는 것이다. 성공적인 프로젝트를 위해 노력해보자!

(서평) 대체 뭐가 문제야?

프로그래머는 자주 개발자라는 이름으로 불리고, 구현이 가장 중요한 듯 생각되기도 한다. 하지만, 개발 과정에서나, 유지보수 과정에서나 문제는 발생하기 마련이다.  능력이 아무리 뛰어나고, 머리 좋은 사람들이라 해도 문제를 만들기 마련이며, 오죽했으면 문제가 없다는 것은 아무 일도 일어나지 않고 있다는 증거다라는 말이 있겠는가?

문제가 발생하는 것을 당연하게 여기게 되었다면 우리가 할 수 있는 것은 크게 두 가지가 있다.

첫번째. 문제가 발생할 여지를 줄이는 것이다.

문제가 발생할 여지를 줄이는 좋은 방법으로는 좋은 습관을 들이는 것인데, 개발 프로세스를 늘 개선함으로써 단점을 보완해나가는 것이다. 반복 작업이 있다면 그 횟수를 줄일 순 없을까? 한번으로 끝낼 순 없을까? 고민하고 보완해나가고, 피드백이 부족하다면 회의를 자주 한다던가, 개발 과정을 사용자와 공유한다던가 하는 방법으로 보완해 나가는 식이다.

문제가 덜 발생한다면, 그로 인한 시간과 노력을 낭비하지 않아도 되기 때문에, 문제를 해결한 것보다 가치있다.

두번째. 문제 해결 능력을 기르는 것이다.

문제가 발생했다면, 무엇이 문제던 간에 해결해야 한다.

문제를 해결했다고 말하기에 앞서 자기 자신에게 다음과 같은 질문을 던져봐야만 한다.

원인이 무엇인가?

간혹 원인 자체를 잘못 파악하는 경우도 있다. 이럴 땐 어떤 해결책이던 간에 실패하기 때문에, 원인 파악의 중요도는 크다고 할 수 있다.

우선 생각나는 모든 원인을 떠올리는 것이 좋다. 검증 과정을 거칠 것이기 때문에, 엉뚱하고, 황당한 방법도 모두 나열해보는 것이 좋다.

원인을 생각 했다면 다음과 같은 질문에 답해보자.

해결 방법으로 무엇이 떠오르는가?

대부분의 문제는, 한가지 해결 방법만 존재하지 않는다. 증상을 해결 할 수 있는 해결책은 모두 떠올려 보는 것이 좋다. 많은 문제가 가장 확률이 높은 원인 때문에 발생되지만, 그렇지 않은 경우도 종종 있기 때문이다. 실제로 적은 확률로 발생하고, 그 상황들이 절묘한 타이밍에 겹쳐야만 발생하는 문제를 겪은 적도 있기 때문에 더더욱 그렇다고 생각한다.

증상을 해결했는지 확인해보고, 해결 방법이 새 문제를 만들거나, 문제를 완벽히 해결했는지 아닌지를 생각해보라.

문제 해결를 겪는 사람들이 어려운 문제를 만났을때 눈에 보이는 증상만 해결하려는 욕구에 사로잡히곤 한다. 하지만 절대 그래선 안된다. 잠시 그 문제를 덮어둘순 있겠지만, 그 문제는 더 큰 문제로 다시 내게로 올 것이다.

프로그래머는 문제 해결사여야 한다. 특히 서버 프로그래머는 그렇다고 생각하고, 어떤 문제에 봉착했을 때 논리적이고, 이성적인 판단을 내릴 수 있어야 한다. 기술적인 문제인지 여부는 상관없다. 단지 프로그래머가 문제 상황을 자주 마주치는 직업이고, 그에 따른 해결책을 생각해야 하는 직업이기 때문에, 문제 해결 능력이 중요하다 할 수 있다.

아직 이 책을 읽어보지 못했거나, 아직 자신이 문제 해결사로써 부족하다 느낀다면, 이 책을 통해 문제 해결 방법과 그 과정에 대해 다시 한번 생각해 볼 수 있는 계기를 가지는건 어떨까?

C++ 오류의 원인들

strcpy 등의 길이제한이 없는 함수는 사용하지 않는다

  • strncpy, memcpy와 같은 함수를 사용하고, 스트링 맨 끝에, 0을 넣어주는 것이 안전하다. 특히나 클라이언트에서 올라온 데이터는 더더욱 그렇다.

포인터 검사는 반드시 하라

  • 포인터 사용시에는 무조건 NULL포인터 검사를 하는 것이 좋다. 바로 쓰고 싶을 경우는 참조자를 사용해서 항상 유효한 데이터임을 알린다.

서식 지정자에 넣는 값에 유의하라.

  • 스트링 안에 %s %d 라는 코드가 있고, 가변 인자가 주어지지 않으면 에러가 발생한다.
  • %s 로 문자열을 입력 받으려 하는데, float형이나, int형을 입력했을 때에도 C는 널을 만나기 전까지 데이터 읽는 것을 멈추지 않는다. 잘못된 메모리를 접근 문제는 언제나 조심하자

포인터를 담는 자료구조에서, 해당 자료를 빼고, 포인터에 동작할당 된 주소를 delete할 때 주의하라

  • 한 곳에서 new한 데이터를, 여러 곳에서 사용할 때 주의하라. new한 객체의 delete는 한 곳에서만 하라. delete된 포인터를 자료구조에서 들고 있으면 dangerous 포인터가 되니 조심하자.

배열 접근 시에는 무조건 범위 검사를 하라

  • 배열 접근 인덱스는 반드시 유효한 값인지 범위 검사를 하라. 가급적이면 배열 접근 인덱스는 unsigned 한 값으로 사용해서, 배열 검사를 한번에 끝내는 것이 좋다.

인수로 넘어오는 문자열이나 배열의 값 복사시, 버퍼 크기에 유념하라.인수로 넘어온 값을 버퍼에 복사할 때, 넘어온 버퍼 크기도 고려하라.

  • 받는 버퍼의 크기 검사도 물론 중요하지만, 넘어오는 값의 크기도 주의해야 한다. 넘어오는 버퍼의 크기를 넘겨 받거나 해서 그 크기만큼만 복사하도록 하자.

재귀적인 동작에 주의하라

  • 재귀적으로 돌다 스택 오버 플로우가 나는 상황이나, 처리 과정이 맞물리다 재귀적으로 처리가 이뤄져 사용하는 메모리를 잃어 버리는 경우를 조심하라.
  • 재귀로 인한 스택 오버 플로우는 말 할 필요도 없고, 재귀적으로 처리가 이뤄지다가 클래스 안이나, 힙에 잡힌 메모리의 주소를 사용하는 경우 프로그램의 비정상 동작이 원인이 될 수 있다.
  • 혹시나 재귀적으로 돌아갈 여지가 생긴 경우에는 반드시 지역 변수로 선언해서 스택에 할당한 메모리를 사용하라.

정수형 값의 오버 플로우(또는 언더 플로우)도 주의하라

  • 정수형 값이 오버 플로우 될 가능성은 언제든 존재한다.
  • 그런 상황에서의 대처방법은 여러가지가 있겠지만 오버 플로우가 되는 상황은 늘 염두에 두어야한다.
  • 생각하는 프로그래밍에서도 나왔듯이 생각보다 많은 프로그래머가 오버 플로우 버그가 있는 프로그램을 작성한다. 정수형도 포인터만큼 조심히 다루자.

memcpy에 주의하라

  • memcpy시에 size가 음수가 되는 상황에 주의하라. 또한 NULL 포인터에서 (또는 NULL 포인터로) 복사되는 것에 주의하라.

참조자는 신중히 사용하라.

  • 참조자는 어떠한 변수를 가리킨다. 포인터와 마찬가지로, 가리키고 있는 대상이 사라지면 문제가 생긴다.
  • 참조자보다 가리키고 있는 대상의 수명이 길어야 한다는 것을 잊지말라.

HeapCorrupt 조심해라!

  • 절대 delete된 곳에 access하거나, 할당한 범위를 넘어서서 접근하지 마라. 무슨일이 일어날지 모른다.

상속을 염두에 두고 있다면, 가상 소멸자를 사용하라.

  • 상속을 받은 상태에서 부모 클래스중에 어느 하나라도 가상 소멸자가 아니라면 pure virutal function call 문제가 생긴다.

소멸자에서 가상함수를 호출하지 말아라.

  • 가상 함수를 가지고 있을 때, 베이스 클래스의 소멸자에서 가상함수를 호출하면 pure virtual function call 문제가 생긴다.

스레드를 멈추는 시점을 베이스 클래스의 소멸자로 잡지 마라.

  • 소멸자에서 스레드를 멈추고 싶다면, 구현 클래스에서 멈추게 하라. 베이스 클래스에서 스레드를 멈추게 할 경우 처리되고 있던 스레드에서 잘못된 가상 함수 호출을 할 여지가 있다.

구분자에 조심하라

  • 일반적으로 데이터의 구분을 길이 + 데이터가 아닌, 스트림 형식으로 전달받을 경우 구분자가 존재한다.
  • 이런 상황에서 데이터 내에 구분자가 존재하는 지를 반드시 검토해야 한다.
  • 또한 구분자만으로 구성된 경우, 구분자가 없는 경우등의 다양한 상황도 테스트 해보고 검토하라.