Extremely Agile/General2009.02.18 13:24
순서는 아무 의미가 없으므로 개의치 마시길. CVS가 자주 언급되긴 하지만, Subversion 사용자라면 CVS를 Subversion으로 바꾸어 읽으시기만 하면 OK.

1. CVS에 남겨진 변경 로그에 아무 메시지도 적혀있지 않다

변경 로그에 아무 메시지도 남기지 않는 것은 프로그래머들 사이에는 널리 만연된 관습 가운데 하나로, 보통 '자신이 만든 코드상의 변경이 로그를 적을 만큼 중요한 것이 아니'라고 보기 때문에 저질러지는 실수이다.

어떤 종류의 변경이건, 로그는 남겨져야 한다. 그래야 다른 프로그래머들이 CI 서버로부터 유용한 정보를 얻을 수 있을 것이기 때문이다. 로그를 볼수 없다면 프로그래머는 다른 프로그래머가 자신의 모듈을 사용하면서 저지른 실수를 추적할 수 없다. 물론 그런 문제를 해결하는 가장 좋은 방법은 자신의 코드를 최대한 robust하게 만들고 타입 검사를 명확히 하고 인자 검사를 엄격히 하도록 하여 단위 테스트 단계에서 문제가 드러나도록 하는 것이다.

2. 자동 빌드를 위해 추가한 CVS 사용자 계정을 프로그래머들이 돌려쓴다

CVS 사용자 계정은 프로그래머들마다 하나씩 만들어져야 한다. 계정을 만드는 데 오랜 시간이 걸리는 것도 아니기 때문에, 하나의 계정을 돌려쓰고 있다면 그것은 CI 프로젝트 관리자가 되기에는 너무 게으르다는 뜻 밖에 되지 않는다.

3. CI 관리자가 프로그래머들과 대화를 하지 않는다

이슈 추적 시스템을 맹신하거나 CI 관리자가 본인의 능력을 너무 과대평가할 경우 흔히 벌어지는 일이다. CI 관리자는 그저 관리자일 따름이지 신이 아니기 때문에, 빌드 상에서 발생하는 문제를 스스로 해결하려고 해서는 안된다. 프로그래머들과 대화한 후에 프로그래머들이 직접 문제를 해결하도록 두는 편이 좋다. 그 편이 팀 전체의 능력 향상이나 화합에도 도움이 된다.

4. 단위 테스트 결과가 fail로 나온 이후에도 오랫동안 방치된다

이 문제의 원인은 다음과 같다.
1. 개발자가 CI 서버의 보고서를 보지 않는다.
2. 보았더라도 자기 문제가 아니라고 생각한다.

'보았더라도 자기 문제가 아니라고 생각하'는 이유는 다음과 같다.
1. 개발 서버의 문제라고 생각한다.
2. 다른 프로그래머의 문제라고 생각한다.

개발 서버의 문제가 아니라는 점을 알려주는 건 ci관리자의 몫이다. 자신이 commit한 소스로 인해 발생하는 빌드 문제는 해당 프로그래머의 문제이다. 해당 프로그래머는 자신의 소스가 필요로하는 라이브러리나 설정 파일을 지정된 디렉터리에 commit하여 빌드가 정상적으로 이루어지도록 할 의무가 있다. 그러므로 console output을 주의깊게 살펴야 한다. CI 관리자와 프로그래머간의 의사소통이 원활하지 않으면, fail된 단위 테스트나 망가진 build 프로세스는 오래 방치된다.

자신이 올린 소스가 다른 사람이 만든 테스트 케이스를 망가뜨리는 경우도 종종 있다. 이런 경우 테스트 케이스를 설계한 프로그래머와 새로운 소스 코드를 올린 프로그래머는 의사소통을 통해 문제를 해결하여야 한다. 의사소통이 되지 않으면 '서로 상대방 책임이라고 주장'하면서 fail된 단위 테스트가 방치되는 일이 생긴다.

5. 의미있는 빌드에 tag를 부여하지 않는다

CVS를 쓰건 Subversion을 쓰건 의미있는 빌드가 만들어졌다는 판단이 서면, 그 상태에 태깅을 해 주는 것이 좋다. 태깅을 하지 않는다는 것은 시스템 복원 지점을 설정하지 않고 Windows XP를 사용하는 것과 비슷한 일이다. 어떻게든 사용은 할 수 있겠지만, 비상시에 해야 하는 삽질의 양이 늘어난다는 점에서 그렇다.

6. CI 서버가 보여주는 빌드 리포트가 너무 건조하다

건조하다는 이야기는 재미가 없다는 이야기이고, 재미가 없다는 것은 빌드가 너무 평온하게 발전해 나가고 있다는 뜻이다. 빌드가 평온하게 발전해 나가고 있다는 것은 좋은 일이긴 하지만, 좀 나쁘게 해석하자면 '문제가 감춰진채로 드러나지 않고 있다'는 뜻일 수도 있다. 이럴 때는 테스트의 커버리지를 재점검하고, 테스트가 너무 말랑말랑하게 작성되어 있지는 않은지 점검해보는 것이 좋다. 테스트는 가급적 공격적인 것이 바람직하다.

[계속 수정됨...]


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. dhyi123

    CI 라는 것이 무엇의 약자인지요? CI 서버라는 것은 cvs 서버이면서 테스트도 같이 해서 리포트도 보내는 등 여러가지 역할이 있는 거 같네요. 개발자가 신규로 개발하는 경우는 해당 단위 테스트를 새로 추가해야 CI 서버도 자종으로 동작하겠죠? (제가 좀 무식해서.. ^ ^)

    2009.02.18 14:46 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • Continuous Integration의 약자입니다. Hudson, CruiseControl 등의 제품이 있는데 저는 Hudson을 사용합니다. ^^

      2009.02.18 14:53 신고 [ ADDR : EDIT/ DEL ]
  2. 이병준 선배님, 저 조영일입니다.
    오래간만에 인터넷에서 뵙네요.
    메타블로그에서 이것저것 찾다가 우연히 발견해서 들어오게 되었습니다.
    OO 전문가에 소설도 쓰시니 딱 알아보겠더라구요.
    잘 지내시죠? 식구들 모두 건강하시구요?
    둘째가 아주 귀엽던데, 건강하게 잘 크는지 궁금합니다.

    2009.02.23 18:30 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. 100% 공감합니다. 특히 3번 항목은 제가 얼마전까지도 잘못 하고 있던 내용이군요.
    '불확실성과 화해하는..'책을 읽기 시작하면서 블로그 방문해 보았습니다.
    좋은 글들 많이 부탁드립니다.

    2009.03.24 13:11 신고 [ ADDR : EDIT/ DEL : REPLY ]
  4. 좋은 글 잘 봤습니다. 다 공감합니다.
    1번 같은 경우는 예전에 써놓은 글이 있어서 트랙백으로 겁니다.

    2011.06.20 09:47 신고 [ ADDR : EDIT/ DEL : REPLY ]

Extremely Agile/General2009.01.21 23:51
보통 프로그래머들에게는 한가지씩의 무용담이 있습니다. 그 중 가장 흔한 것이 바로 "내가 만났던 가장 개같은 버그" 류의 무용담입니다.

이런 이야기는 왜 하는 것일까요? 뭐 다들 잘 아시겠습니다만, (1) 이런 무용담이 많으면 어디가서 분위기를 띄우기 좋고 (2) 자기가 경력이 꽤 된다는 걸 간단하게 입증해 보여줄 수 있으며 (3) 다른 프로그래머에게 유용한 정보를 전해줄 수 있다는 장점이 있습니다. 물론 이런 이야기는 '군대에서 축구한 이야기'랑 비슷하기 때문에, 프로그래머들이 둘 이상만 모이면 저절로 튀어나오게 되는 경향도 있긴 합니다. ^^;

프로그래밍 심리학이라는 책에도 나옵니다만, 천공 카드를 통해 프로그래밍을 했던 중세시대에도(ㅋㅋ) 소위 '개발자 커뮤니티'라는 것이 있었습니다. 천공 카드를 컴퓨터에 입력하려면 순번을 기다려야 하니까, 기다리면서 노가리들을 깠던 것이죠. 인터넷이 없었으니 당연했겠죠? 그 시대의 개발자들은 아마 지금 개발자들에 비해 백배는 수다스러웠을 겁니다.

각설하고... 그런데 버그에 관한 그런 무용담들을 들어보면, 보통 '버그를 잡았다'에서 스토리가 끝나버려요. 그 뒤의 이야기들은 좀체로 하질 않습니다. 오늘도 커피를 마시러 휴게실로 가다가 같이 일하는 분들하고 잠시 이야기를 할 기회가 있었는데요. 개발자를 한달간 애먹인 버그에 대해서 들려주시더군요. 관련된 모든 사람들의 영혼을 한달동안이나 잠식했던, 정말 가공할만한 버그였습니다. (가장 큰 문제는 그 버그가 그분들이 개발한 시스템에서 나온게 아니라는 점이었죠.) 듣는 제가 다 소름돋을 정도였으니....

보통은 거기까지 듣고 마는데, 오늘은 제가 이런 질문을 한번 해봤습니다.

"그런 버그를 한 번 겪고 나면 본인이 어떻게 달라졌다고 느끼나요?"

질문을 좀 뜨악하게 들으시는 것 같아서 좀 다르게 물어봤습니다.

"그런 버그가 (프로그래머로서의) 자신의 인생을 바꿔 놓았다고 느낄 때가 있나요?"

생뚱맞게 들리실수도 있겠습니다만, 저는 이런 질문을 한번쯤은 던져 보아야 하지 않나 합니다. 제가 이 직장에 처음 들어왔을때 처음 맞닥뜨린 가장 심각했던 'UNDETERMINISTIC' 버그[각주:1]는 시그널 핸들링 관한 것이었습니다. 시스템이 죽긴 죽는데, 진짜 어쩌다 한번 죽는 겁니다. 그리고 그 상황 사이의 일관성을 찾기가 정말 힘들었어요.

이 문제의 해결책을 찾기 위해 정말 많은 삽질을 했습니다. (지금 생각하면 삽질이 아니라 당연하게 해야 하는 일들이지만요.) 첫 번째로 했던 일은 메모리 누수가 시스템의 crash로 이어지는 시점을 정확하게 동기화시키기 위해 MALLOC_CHECK_ 환경 변수의 값을 설정하는 것이었습니다. (Linux라면 man malloc하시면 관련 자료가 나올 겁니다.) 처음에는 시스템이 죽는 이유가 메모리 누수 때문이 아니었을까 하고 추측했거든요. (그당시에는 valgrind에 대해서 몰랐습니다.)

물론 그래도 문제가 해결이 안되었습니다. 한달 뒤에야 겨우 문제의 실마리를 찾을 수 있었죠. (쪽팔립니다ㅎㅎ) 문제인즉슨 이런거였습니다. write를 할 때 리턴 값으로 '파이프가 깨졌다'는 오류 메시지를 받을 수 있을 것으로 기대했었는데 (write를 하는 중에 서버가 죽을 경우를 대비하려던 거였죠) 문제는 그게 SIGPIPE 시그널을 block 하지 않으면 제대로 동작하지 않고 프로세스가 죽는다는 거였습니다. (그것도 꼭 항상 죽는건 아니었죠. ㅋㅋ)

이 문제의 교훈은 이런 거였습니다. 매뉴얼에 의존해서 그대로 몇 줄 코드를 구현했습니다. ('상대 프로세스가 죽을 경우 내 프로세스는 파이프가 깨졌다는 오류 메시지를 받는다'는 것이 매뉴얼 내용이었습니다.) 그런데 그 코드가 정말로 제대로 동작하는지는 확인을 하지 않았던 겁니다. '몇 줄'에 불과하고, '매뉴얼 대로' 구현했기 때문에, 거기 버그가 숨어들어갈 거라고는 생각을 못했던 것이죠.

이 문제를 '기계적'으로 해결하려면, 작은 수정을 가할 때 마다 그 수정이 정말로 올바른지 확인을 하고 넘어가야 했습니다. TDD 수준으로 보폭을 좁게 가져가는 것이 필요하다는 결론을 그 때 얻은 거죠. 이 결론을 실천해 볼 기회는 2년 뒤에 찾아왔습니다. 일단 모든 코드의 구현을 마친 뒤 (테스트 과정에서 설계가 변경될 수 있다는 가정은 일단 배재했기 때문에 그럴 수 있었습니다. 코드에 확신이 있기도 했고, 사실 무식할 때 가장 용감해지는 법이니까요), 시스템의 아주 작은 부분부터 차례로 테스트를 해 나기가 시작했습니다. 테스트를 마친 코드만을 조금씩 시스템에 포함시켜서 빌드를 해 나가기 시작했고, 그 부분이 제대로 시험되었다는 확신이 들 때메만 다음 코드로 넘어갔습니다. 이런 식으로 해서 결국 연동시험 때 발견된 버그 수를 0으로 낮출 수 있었습니다. 테스트에 CppUnit을 도입한 것, TDD를 공부한 것, '한 걸음을 뗄 때 마다 뒤돌아보기'에 대한 확신이 생긴 것 등이 그 시기에 했고 느꼈던 것들입니다. (지금 생각하면 '책 한 권만 잘 읽었어도 더 잘 할 수 있었을텐데' 하긴 합니다만.)

결국, '그 자그마한 버그 하나'가 저를 바꿔놓은 것이죠. 이 블로그도 그 덕에 생겼습니다. ^^;

많은 개발자들이 Continuous Integration이나 Issue Tracking의 필요성에 대해 공감은 하면서도 실제 도입을 망설이는 이면에는 '버그는 부끄러운 것'이라는 개발자적 자존심이 어느 정도 깔려 있다고 저는 생각합니다. 그런 부분을 해소할 수 있으려면, 버그 자체도 지식으로 대우하는 자세가 필요합니다. Bug Tracking이라는 말 대신 Issue Tracking이라는 다소 점잖은 용어가 널리 쓰이는 것도, 어쩌면 그래서일지도 모르겠어요.

버그가 나를 더 좋은 곳으로 데려갈 수 있다는 확신을 가지는 것은, 그런 의미에서 중요하다고 생각합니다. 여러분도 저처럼, '나를 바꾼 버그'를 하나씩 가지고 계신가요?

  1. reproduce하기 굉장히 난감한, 발현 시점을 도무지 정확히 알 수 없는 버그. [본문으로]
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 공감하고 갑니다. ^^

    2009.01.29 02:40 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 아. 안녕하세요? 제가 블로그 첨 열었을 때 A2님 블로그에서 X-note에 리눅스 설치하는 방법을 참고했던 기억이 나네요. 새해 복은 많이 받으셨는지? 올해도 건승하시길~

      2009.01.29 09:11 신고 [ ADDR : EDIT/ DEL ]
  2. 정말 공감가는 글입니다. 저는 아직 인생까지 걸어보진 못했지만 잡아내는 버그 한두개로 소프트웨어 자체를 fail 시켜야 한다는 점에서는 거의 매일 누구에겐가는 운명적인(?) 버그를 잡아낸다고 해야하나요. 하지만 더 열심히 한다면 언젠가는 저도 제 인생을 바꿀만한 버그를 잡아내는 날이 오겠죠? ^^; 어쨌든 이젠 돌다리를 두들겨만보고 건너는 버릇은 아예 없앴습니다. 뛰어보고 엎어보고 발로 차보고 긁어보고 맛도 본 후에나 건너게 되더군요.

    2009.03.26 13:00 신고 [ ADDR : EDIT/ DEL : REPLY ]