Head First Debugging :: 2008/06/19 14:25


신입 개발자를 위한 조언
Head First Debugging
신영진 codewiz@gmail.com 

소프트웨어 출시를 지연시키는 가장 큰 원인 중의 하나는 버그다. 그 중에도 몇몇 복잡한 버그들은 개발자들을 지독하게 괴롭힌다. 심지어는 그런 버그 때문에 개발된 제품이 폐기되기도 한다. 또한 회사는 출시 지연이 심각한 단계에 놓이면 유능한 버그 사냥꾼을 따로 고용하기도 한다. 그런 복잡한 버그에 대항하는 초보 버그 파이터들이 저지르는 실수에 대해서 살펴보고 그런 버그들을 효과적으로 디버깅하는 방법에 대해서 알아보도록 하자.

대부분의 초보 버그 파이터들이 자주 범하는 실수는 버그가 발생한 지점에 집착하는 것이다. 그들은 끊임없이 ‘도대체 버그가 어디서 발생했을까?’란 질문을 던진다. 그와 동시에 그곳을 찾기 위해서 다양한 방법을 동원한다. 가장 애용하는 방법 중에 하나는 분할 정복법이다. 마치 바이너리 서치를 하는 것처럼 그들은 프로그램을 두 조각으로 나누고 어느 부분에서 버그가 발생하는지를 찾아나간다. 물론 좀 똑똑한 버그 파이터들은 크래시 덤프나 맵 파일등을 활용하기도 한다.

어쨌든 재현할 수 있는 버그라면 그들은 버그가 발생하는 바로 그 지점을 찾아내는데 성공한다. 하지만 문제는 지금부터 시작이다. 초보 버그 파이터가 찾아낸 바로 그곳은 십중팔구 다음과 갈은 어처구니 없는 라인일 것이기 때문이다.

*dst = *src;

물론 위와 같은 라인은 똑똑한 개발자에게는 몇 가지 암시를 던져주기는 한다. src가 읽을 수 없는 메모리 영역을 가리키고 있다거나, dst가 기록할 수 없는 메모리를 가리키고 있다면 이 코드는 분명히 실패한다는 것이다. 물론 그들은 저런 가정을 디버거의 추적 기능을 활용해서 확인할 수 있다. 그런 가정이 들어맞았다고 하더라도 그들은 속수무책이다. 왜냐하면 왜 그렇게 됐는지는 모르기 때문이다. SEH와 같은 방법들을 동원하더라도 그들은 예외 부분에 무엇을 넣어야 할지를 모른다. 만약 빈 예외처리 문장을 넣는다면 그건 단지 폭탄이 터지는 시점을 연장시킬 뿐이다. 그 폭탄은 언젠가 다른 곳에서 다른 형태로 다시 터질 것이기 때문이다.

때로는 정말 어처구니 없는 OutputDebugString(“some debug msg.”) 같은 부분이 문제가 되기도 한다. 그들은 이렇게 말한다. 이 디버그 메시지를 넣으면 잘 동작하는데 이걸 빼면 잘 동작하지를 않아요. 그러면서 원인도 모른 체 이 디버그 메시지를 릴리즈될 제품에 포함시킨다.

초보 버그 파이터들이 저지르는 이러한 실수는 버그에 대한 잘못된 이해에서 비롯된다. 복잡한 프로그램에 숨어있는 잡기 힘든 버그는 대부분 두 가지 특성을 가지고 있다. 첫째는 문제의 원인이 한 곳에 있지 않다는 것이고, 둘째는 버그를 관찰하는 행동 자체가 피드백이 되어서 버그에 영향을 미친다는 것이다. 이런 기준에서 보면 그들이 그토록 집착했던 버그가 발생한 지점은 중요하지 않은 요소에 불과하다는 것을 알 수 있다. 그 곳은 단지 폭탄이 터진 장소일 뿐, 실제로 폭탄은 다른 곳에서 다른 원인에 의해서 만들어졌기 때문이다. 중요한 것은 바로 그 폭탄이 생겨난 원인이고, 완전한 디버깅은 그런 원인 요소를 제거하는 것이기 때문이다.

프로그램은 데이터에 가공을 하는 절차들의 집합이다. 이렇게 가공을 하는 개별 절차들은 일정한 흐름을 만들어낸다. 순차적이기도 하고 중첩되기도 하고, 다른 절차를 기다리기도 하는 식으로 말이다. 대부분의 복잡한 버그는 이러한 흐름이 미묘하게 변경될 때 발생한다. 따라서 그런 복잡한 버그를 효과적으로 디버깅 하기 위해서는 프로그램의 흐름에 집중하는 것이 바람직하다. 흐름에 집중한다는 것은 머릿속으로 그런 과정을 재현해 보는 것을 의미한다. 정상적인 흐름을 다르게 만들어서 재생시켜 보면 아마도 버그의 증상과 일치하는 결과를 가져오는 흐름이 있을 것이다. 그 다음은 그 틀어진 흐름이 틀어지지 않도록 바로 잡아주면 된다. 이 과정이 숙달되면 마치 일류 정비공이 엔진 소리를 듣고 문제를 판단하는 것처럼 증상만 보고도 그 원인을 알 수 있게 될 것이다.


스폰서
글타래

  • 2주간 인기 글
  • 2주간 인기글이 없습니다.
Trackback Address :: http://jiniya.net/tt/trackback/701
  • 디버깅의 어려움과 즐거움

    Tracked from 사진찍는 프로그래머 | 2008/06/24 08:36 | DEL

    Visual Studio 2005 로 개발/운영 되어 오던 프로덕트를 Visual Studio 2008로 전환하는 작업을 얼마 전부터 진행 중에 있습니다. 2005 와 2008 은 내부 기반 구조에 있어 큰 차이가 없어서 금방 컨버젼이 끝..

  • Gravatar Image.
    개꿈닷넷 | 2008/06/19 22:07 | PERMALINK | EDIT/DEL | REPLY

    옳은 말씀입니다 ㅋ

    문제는 아무리 생각해도 잘 모르겠다는것에 있지요 ㅎㅎ orz

  • Gravatar Image.
    Eminency | 2008/06/23 00:57 | PERMALINK | EDIT/DEL | REPLY

    초보 개발자들은 물론 위의 사실들을 잘 모르고, 숙련된 개발자들은 위의 사실을 알겁니다만...
    숙련된 개발자라고 해도 저런 버그를 만들어 내는 것이 문제이며, 결국 위의 내용은 별로 도움이 안된다는 거지요.
    왜냐구요? 그런 정상적인 흐름을 머릿속으로 생각해보고 고쳐서 재생해보고 할 수 있을 정도를 이미 지나쳤기 때문에 버그는 발생하는 것입니다. 복잡한 버그는 추적하기에도 복잡하고 머릿속으로 흐름을 생각하기에도 복잡한 버그입니다.
    위의 내용은 상당히 이상적인 관점으로만 씌어진 글인 것 같군요.

    • Gravatar Image.
      codewiz | 2008/06/23 20:35 | PERMALINK | EDIT/DEL

      좋은 의견 감사합니다. 조금 곡해하신 부분이 있으신 것 같습니다. 저는 버그를 추적한다는 이야기를 한 적은 없습니다. 프로그램의 흐름을 바꾸어 재생해 보라고 한 것이죠. 제 경우에는 이러한 방법이 복잡한 버그를 잡는데 굉장히 많은 도움이 되었습니다. 사무실에 앉아서 디버깅 툴을 가지고 버그를 추적하는 과정보다 말이죠. *^^*

      이상적인 관점에서 쓴 글은 아닙니다. 단지 전 제가 아는 한 가지 방법을 알려주려고 한 것 뿐이니까요. 글을 쓰고 제가 느낀 점은 다소 추상적이라는 점이었습니다. 흐름을 실제로 어떻게 틀어서 재생하는지 그런 것들이 어떤 효과를 가지고 디버깅에 도움이 되는지에 대한 내용이 부족하기 때문에 그렇게 느꼈죠. 이러한 맥락을 이상적이라고 표현하셨는지도 모르겠습니다. 하지만 그러한 내용을 담기란 생각보다 쉽지 않습니다. 실제 현업에서 일하신다면 아시겠지만 그러한 버그를 잡는 과정에서는 굉장히 고무적으로 느껴지지만 지나고 나면 멍청해서 생긴 버그인 경우가 많이 때문이죠. 고치고 나서 그 과정을 쭈욱 적어놓고 보면 '왜 당연한걸 몰랐을까?'라는 생각이 든다는 거죠. 그래서 진짜 디버깅 이야기를 쓰는게 좀 힘든것 같습니다.

      글 중에서 숙련된 개발자라고해도 저런 버그를 만들어 내는 것이 문제라고 하셨는데, 전 조금 다르게 생각합니다. 어떠한 프로그램을 만들더라도 버그가 없을 수는 없습니다. 또한 버그가 없는 상태의 프로그램도 버전업이나 수정을 가하면서 새로운 버그가 생겨나죠. 단지 유능한 개발자는 끊임없이 에너지를 투입해서 그것들을 바로 잡는 것이라고 생각합니다.

    • Gravatar Image.
      Eminency | 2008/06/24 22:13 | PERMALINK | EDIT/DEL

      숙련된 개발자도 버그를 만들어낸다는 말의 의미는 사실 제 나름대로는 codewiz님이 쓰신 것과 동일한 뜻으로(버그는 늘 있다는) 쓴 건데 전달이 제대로 안 되었나봅니다.
      하지만 글의 마지막 단락의 의미는 여전히 안 와닿네요.
      흐름을 바꾸어서 재생해 본다는 것도 사실 한두 군데 바꿔서 찾을 수 있는 버그가 아닌 경우도 많고요...ㅡㅡ
      아직 제 내공이 부족해서 제대로 이해를 못하나 봅니다. 써 주신 답글을 보면 더욱 그런 생각이 드네요 -_-; 답글 감사합니다.

  • Gravatar Image.
    eslife | 2008/06/24 08:37 | PERMALINK | EDIT/DEL | REPLY

    얼마전에도 희한한 비정상종료 때문에 며칠을 허비한 적이 있었습니다. 다행히 큰 수확도 얻기는 했지만,
    늘 실수는 어처구니 없는 곳에 있더군요.
    무엇보다 디버깅을 하는 마음자세가 가장 중요한 거 같습니다. 죽기 살기로 잡아야죠 ^^;

  • Gravatar Image.
    bellfive | 2008/06/25 14:35 | PERMALINK | EDIT/DEL | REPLY

    제 사수가 가르쳐 주신 가르침과도 어느정도 맞는데요..

    모든 문제 해결에는 디바이드 앤 퀀커라고 하셨는데..

    일단 가정을 하고 (몇가지 가정을 해야 하는데)..
    이 경우 가지고 있는 지식이 넓을 수록 가정이 많아지고 확률도 높아지죠..
    그리고 그 가정이 맞다는 것을 증명해가면서 해결을 해가죠..

    그리고, 항상 문제가 일어남 직한 곳은 나눠서 해결하는 방식으로 증명해가죠..가장 쉬운 방법은 그 루틴을 아예 막아버리는 것이죠~ 항상 1로 리턴하게 한다던가..~

    Codewiz님 말씀도 아마 의심나는 곳을 한번 틀어보고 증명해보란 의미같아요..

    좋은 글 잘 읽었습니다~

  • Gravatar Image.
    window31 | 2008/06/26 13:30 | PERMALINK | EDIT/DEL | REPLY

    때로는 정말 어처구니 없는 OutputDebugString(“some debug msg.”) 같은 부분이 문제가 되기도 한다. 그들은 이렇게 말한다. 이 디버그 메시지를 넣으면 잘 동작하는데 이걸 빼면 잘 동작하지를 않아요. 그러면서 원인도 모른 체 이 디버그 메시지를 릴리즈될 제품에 포함시킨다.

    -> 아아 공감 백만개 ;;; 제 경우 디버그스트링은 아니었지만 암튼 ;;
    이런건 문제를 "수정"한 게 아니고 "회피"한 거죠..
    좋지 못한 방법이지만 릴리즈 시간에 쫓기다보면 저런코드가 점점 많아지는 OTL
    영진씨글은 항상 재밌어요 ㅎㅎ

  • Gravatar Image.
    zelon | 2008/07/03 13:59 | PERMALINK | EDIT/DEL | REPLY

    "틀어진 흐름이 틀어지지 않도록 바로 잡아주면 된다" 이 부분에서 왠지 한의사들이 침을 놓아서 몸에 흐르는 기운을 바로 잡아준다는 생각이 든다는;;

    재미있는 글 잘 읽었습니다 :)

  • Gravatar Image.
    랄라 | 2008/08/03 22:26 | PERMALINK | EDIT/DEL | REPLY

    간만에 들린 일류 정비공이고픈 초보 버그 파이터(?) 입니다..ㅎㅎ
    글 잘 보고 갑니다.

Name
Password
Homepage
Secret
< PREV | 1| ... 67|68|69|70|71|72|73|74|75| ... 604| NEXT >