getpass라는 unix library function이 있다. 이 함수는 /dev/tty를 열어 echo를 끈상태로 입력을 받아 버퍼에 읽어 들인 데이터를 돌려주는 함수인데,
쉬운말로 해서, 암호를 입력받는 함수이다.

이 함수가 apr(Apache Portable Runtime) project에서 사용되며, 웹서버에 쿼리하기전 인증(Basic auth)을 하기 위해 암호열을 받는 행동을 한다.

그런데, 문제는 Apache가 관리하는 암호열이 getpass의 제약사항과는 상관없다는 것인데, getpass는 고전적으로 8자만 받아서 넘겨주는 고리타분한 행동을 한다. 리눅스의 경우 255자까지 되어 있지만, HPUX에서는 그렇지 않다는 것이다.

Subversion이 apr을 이용하여 코드 저장소를 접근하는 일이 있는데, 아무리 내 암호를 입력해도 잘못되었다는 것이다. 아... 된장.

결국, subversion 안에 배포되고 있는 apr의 getpass에 대한 autoconfiguration 결과를 발견되지 않음으로 강제적으로 수정한 다음 다시 컴파일하여 svn을 만들었다.

성공.
테스트가 드라이브하는(주도하는) 프로그래밍

쉽게 생각하기에는 테스트 코드를 반드시 작성해야한다고 생각하기 쉽지만, 이 방법은 다음과 같은 극단적인 프로그래밍 습관의 변화를 내포한다.


  1. 어떻게 사용할지 사용 형태의 샘플을 먼저 작성한다.

  2. 어떤 환경설정 파일을 사용할지 샘플 환경을 작성한다.

  3. 테스트해야할 함수와 테스트하지 않아도될 함수를 적절히 나누어 작성하게 된다.

  4. 자동화된 테스트를 위한 로그를 작성한다.



어떻게 사용할지 사용 형태의 샘플을 먼저 작성한다.
사용되는 곳에 쓰일 샘플을 먼저 작성하지 않으면, 설계의 정확한 의도를 파악하지 못한 채 작성하기 쉽다. 만약 직접 설계한 코드를 만든다고 할 지라도, 전체적인 방향이 주먹구구일 수 있다. 즉, 필요하지도 않은 인자를 함수에 전달 할 수도 있고, 필요한 인자가 빠질 수도 있으며, 두개로 만들어야할 함수를 하나로 만들기도하고, 하나로 만들어야할 함수를 두 개로 만들 수 있기 마련이다. 코드의 주요부분은 설계를 반영하겠지만, 섬세한 부분들은 테스트 코드가 지시해야한다.

어떤 환경설정 파일을 사용할지 샘플 환경을 작성한다.
환경설정 파일에 대한 샘플은 추후에 샘플을 바꾸어 가며 다양한 환경에 대한 커버리지를 테스트할 수 있는 틀이 된다. 당신의 코드는 대부분 돌아가는데 집중하기 쉽겠지만, 테스트 샘플은 돌아갈 수 없는 상황을 재현하고, 앞으로 모든 빌드이후 테스트 되면서, 과거에 대한 확신을 심어 줄 것이다.

테스트해야할 함수와 테스트하지 않아도될 함수를 적절히 나누어 작성하게 된다.
테스트해야하는 함수는 대개 외부로 노출되는 함수이다. C언어에서는 static으로 선언된 것들은 노출되지 않으므로, 직접적인 테스트 대상이 아니다. 테스트 해야할 것이 library라면, static 함수는 .c에 전방선언으로만, 외부로 내보내야할 함수들은 .h 파일에 등록하는 습관을 기를 수 있다. 즉, 무엇보다 깔끔한 인터페이스가 만들어진다.

자동화된 테스트를 위한 로그를 작성한다.
Unit test에서는 함수의 return 값이나 referenced된 인자를 가지고 테스트하겠지만, Interface test 혹은 통합 테스트 등에서는 각 단계별로 확인할 방법이 로그를 이용한 것이다. 그저 작성된 로그는 아무렇게나 남기겠지만, 테스트 로봇을 위해 작성된 로그는 일관성이 있게 되어야하며, 쉽게 그 포맷을 수정하지 못하게 되므로 로그에 신중함과 꽉짜여진 값을 남기게 된다.
검색엔진들은 검색결과를 통해서 사용자들이 링크를 누르는 순간
자신이 먼저 받고, 실제 사이트로의 재전환(Redirection)해주는 기능으로 동작하기도 한다.
라이코스의 경우

http://r.lycos.com/r/XXXXX/http://originalsite.com/

과 같은 형식으로 내려보내주고, r.lycos.com에서 r 이라는 cgi가 받아서 사용자 통계를 내는 것인지
아니면 죽어 있는 링크를 조사하기 위한 것인지 아뭏든 위와 같은 방법을 사용할 수 있다.

야후의 경우

http://rds.yahoo.com/XXXXXXX/*-http://originalsite.com/

과 같은 형식으로 보내준다.


http://r.lycos.com/r/jflskdajkflasijefiwoa89kdjsalkfjslka/http://pynoos.byus.net/

이렇게 하면 실제로 http://pynoos.byus.net/ 이라는 사이트에 연결된다!

스패머들이 하는 일 중에 가장 흔한 것이 스팸 필터의 스트링 DB에 등록되지 않도록 연구하는 것인데,
저런 링크야말로 중간에 임의의 문자열도 가능할 뿐더러 맨앞이 lycos로 시작하는데, 얼마나 좋으랴.
  1. parkboo 2005.05.03 08:52 신고

    스팸들이 갈수록 교묘해지는구만.. 근데 요즘은 안티스팸쪽 연구하나봐?

  2. 2005.05.03 10:31 신고

    오래됐는데?

스팸을 걸러내는 방법중에 몇년전부터 유행인 RBL (Realtime Blackhole List; Relay Block List)이라는 것이 있다. 이 서비스는 DNS 서비스 즉, 영문 이름을 IP 주소로 변환시켜주는 도메인 네임 서비스를 기반으로 만들어지는데, 그 개념이야말로 상당히 깜찍하다.

메일서버 입장에서 보면, 지금 접속해 들어온 IP 주소가 혹시 스패머가 이용하는 설정이 제대로 안되어 아무나 메일 서버로 사용되는 서버이거나, 아니면 실제 메일 발송기가 장착된 스팸 발송 머신이 아닐까 확인할 수 있는 방법이 있다면 참 좋은 것이 아니겠는가?

이를 위해서 별도의 연동 라이브러리가 필요없이 DNS를 기반으로 그 서비스를 한다니 참 신통방통한 방법이다. 그 원리는 다음과 같다.

만약 외부에서 접속해 들어온 IP가 172.17.122.20 이라하고, "172.16.122.20.rbl-service.net" 라는 호스트 명에 해당하는 IP 주소를 찾아보는 일상적인 행위(?)를 자신의 DNS 서버에게 물어 본다고 가정하자. 그러면 그 DNS 서버는 최상위 도메인 net을 주관하는 서버에게 rbl-service.net 의 DNS 서버를 알아낼것이고, 그 서버에게 저런 장황한 영문 호스트가 있는지 물어 보게 된다. 그러면, 그 호스트에 만약 172.16.122.20이 확실히 스패머인지 알고 있다면 "127.0.0.2" 라는 IP 주소를 돌려준다고 하자

이런 시나리오에서 "127.0.0.2" 라는 IP는 결코 사용되지 않는 IP 주소 이지만, (실제 127.0.0.x 는 localhost를 나타내는 127.0.0.1 외에는 존재하지 않는다!) DNS 서비스상 그 내용에는 아무 하자가 없는 패킷이므로 처음 도메인 네임을 찾아본 녀석에게까지 전달된다. 여기서 어떻게 그 IP가 스팸이었는지 아는 방법은 그 회사만의 노하우라고 하자. 우리의 관심사는 어떻게 하나의 IP에 대한 질의/응답 채널을 만들것이냐이고, 위와같이 DNS는 훌륭한 솔루션이 될 수 있다는 것을 알 수 있다.

실제 상황으로 돌아와서 생각해보자. 위에서는 IP 주소를 그대로 사용하였지만, 실제 RBL 서비스 규칙은 IP를 거꾸로 사용한다. 위의 예에서 rbl-service.net에 해당하는 것을 RBL base라하면,

http://www.uceprotect.net/ 에서 제공하는 RBL base로 dnsbl-2.uceprotect.net 이라는 것을 사용해보자. ( http://www.uceprotect.net/en/index.php?m=6&s=11 ) 위의 예에서 사용된 IP를 거꾸로 하면 20.122.17.172 가 되고 여기에 RBL base를 붙이면

20.122.17.172.dnsbl-2.uceprotect.net

과 같이 된다. 이 호스트를 nslookup 명령으로 찾아 보자.

> 20.122.17.172.dnsbl-2.uceprotect.net
Server: 172.16.11.25
Address: 172.16.11.25#53
 ** server can't find 20.122.17.172.dnsbl-2.uceprotect.net: NXDOMAIN

NXDOMAIN! 이것은 DNS에 타임아웃이 아니라 DNS로부터 온 정상적인 응답이며, Non-eXistent DOMAIN 이라는 뜻이다.

222.111.22.33 이라는 호스트를 질의한다면,
33.22.111.222.dnsbl-2.uceprotect.net과 같이 될 것이다. 이 IP주소는 몇번의 추측으로 찾아낸것이므로, 별 생각하지 마시라.

> 33.22.111.222.dnsbl-2.uceprotect.net 
Server: 172.16.11.25
Address: 172.16.11.25#53
Name: 33.22.111.222.dnsbl-2.uceprotect.net
Address: 127.0.0.2


이게 왠일이냐. 127.0.0.2 랜다. 아! 요놈은 스팸 전력이 있는 놈이구나! 하~ 이거 신기하지 않은가?

IP를 DNS에 질의할 때는 위와 같이 IP 주소를 거꾸로 하여 질의하는 경향이 있다. 그 이유는 관리상 편의 때문인데, 위의 예를 가지고 설명하자면, 만약 222.111.22.x 전체가 유동 IP 주소대역이라, 결코 메일을 직접 보낼일이 없는 주소공간이라는 것이 확실하다면, 굳이 255개의 IP 정보를 다 가지고 있을 필요가 없다. 즉,
22.111.222.dnsbl-2.uceprotect.net 이라는 도메인에 맨 앞에 어떤 추가적인 호스트 이름이 오던지 모두 127.0.0.2로 돌려줄 수 있다. 이를 DNS 쪽 용어로는 Wild card 지원이라하는데, 실제 DNS에
*.22.111.222 라는 호스트 명을 127.0.0.2 로 등록하여 놓으면 위 설명과 같은 응답이 가능하다.

아뭏든 위와 같이 DNS 를 기반으로하는 IP 검사방법에 대한 좋은 예가 있으니 뒤져서 머리를 건강하게 해보시라.

  1. june8th 2005.05.01 22:41 신고

    제품 간접 광고 이므로 유효.. ;-)

  2. 2005.05.02 01:56 신고

    그것이... 크..

  3. benant 2016.06.15 11:53 신고

    오 ... 상세 설명 감사드립니다. 혹시 http://korea.services.net 에 대한 정보도 있으면 부탁드립니다.

    • Coolen 2016.06.28 21:36 신고

      요즘엔 제가 이 분야에 있지 않아서요. 별 정보가 없네요.

문서화 되지 않은 키 몇가지를 경험상 쓰고자한다.
나야 유닉스 쟁이이긴 하지만, 하도 오랫동안 OE를 써와서, 다른 것보다 친근하다.

문서화 되지 않은 바로가기 키

Ctrl+F3: 메시지 MIME 원문을 보는 키로써, 나 같은 개발자에게는 아주 도움이 되는 키이다.
Ctrl+F2: 메시지가 HTML일 경우 HTML 소스를 보여주는 것으로, MIME 원문이 대개 Base64 로 인코딩된 경우에도 보여주는 기능을 한다.

Ctrl+H : 메시지를 주제별로 쓰레드를 만들어 주는 기능을 한다. 물론 메뉴에 있지만, Alt+VVG 를 차례로 누르는 것 보다는 빠르다.

가장많이 쓰이는 바로가기 키
뭐니 뭐니해도
Ctrl+R: 답장을 하는 것
Ctrl+Shift+R: 전체 답장을 하는 것
Ctrl+F: 전달하는 것
이고,

유용한 바로가기키
Ctrl+D: Del키를 누른 것과 같이 삭제
Ctrl+J: 읽지 않은 다음 폴더로 이동
Ctrl+U: 읽지 않은 다음 메시지
Ctrl+I: 받은 편지함으로 이동
Ctrl+K: 주소록을 뒤져서 수신자 완성
Ctrl+, (< 키):메인 화면에서 현재 보고 있는 메일의 위 메일로 이동
Ctrl+. (> 키):메인 화면에서 현재 보고 있는 메일의 아래 메일로 이동
Ctrl+Shift+, (< 키):팝업으로 뜬 메일 창에서 위 메일로 이동
Ctrl+Shift+. (> 키):팝업으로 뜬 메일 창에서 아래 메일로 이동

다른 것들은 보기만해도 머리가 아프다.
indent라는 C 소스의 들여쓰기, 띄어쓰기 괄호 위치 등을 정리해주는 프로그램은 의외로 오래된 프로그램 중의 하나이다.

1988년의 오래된 이메일
http://www.pell.portland.or.us/~orc/Code/bsd/bsd-current/indent/
를 보면, 원작은 David Willcox가 일리노이 대학교에서 어떤 프로젝트로 인해 필요해서 만들었고, 그 이후 여기 저기 떠돌다가 4.2 BSD에 처음 들어왔다고 한다.

그러나, linux에는 그 소스의 최신(?) 수정본이 들어 있다. 최신이래봐야 2002년 버전인데, 지금쯤 C++이 적절히 반영된 최신버전이 들어옴직한데, 뭘 고민하는지 그간 업데이트가 없다.

indent는 여러 옵션을 가지고(실로 엄청난 옵션이다.) 수행되는데 이 옵션들은 $HOME/.indent.pro 라는 파일에 미리 정의해 놓을 수 있다. 따라서 같은 개발팀이라면 이 파일을 공유하고, 코드들이 코드 저장소(repository)에 반영(commit)되기 전에, 한 번씩 수행하도록하면, 많은 사람들이 동일한 들여쓰기를 사용하게 되어 코드 가독성이 높어지게 된다.

이 시점에서 짚고 넘어 가야할 일이 있다. 코드 가독성을 말할 때, 항상 자신만의 코딩스타일이 가독성이 높으리라는 생각이다. 그러나, 코드 가독성은 많이 보아온 스타일에 대해 가독성이 높을 뿐, 그것이 항상 자신의 코드이기 때문만은 아니다. 오히려 전문성을 발휘한다면, 모든 형태의 들여쓰기에 대해 코드 흐름을 놓치지 않을 수 있는 다양한 경험이 있어야할 것 아닌가.

또 다른 한가지는 들여쓰기같은 사소한 문제로 인해 코드리뷰의 지적 대상을 삼지 말자는 것이다. 이 말은 너무 많이 자신의 습관을 반영했기 때문에 들여쓰기 지적을 하지 말라는 것이 아니라, 그런 정도는 indent 같은 코드 화장품을 좀 도입하자는 것이다. 그리고, 수시로 indent를 돌리는 습관을 기르는 것이 팀을 위해서 좋은 것이다.

indent의 한가지 문제라면, 이미 성숙해 있는 코드에 들여쓰기를 흩어놓는다면, 그것은 코드의 변화상을 추적하기 어려워지는 단점이 있다. 코드의 변화상을 추적하는 것(annotate)은 한 줄 단위로 누가 어떤 리비전에서 작성하였는지를 보고자하는 것인데, indent 라는 놈은 모든 행에 대해 뒤집어 놓기 때문에, 정작 필요한 경우 곤란한 상황에 직면할 수 도 있는 것이다.

따라서, 소스 코드 초기에 진압하지 않으면, indent의 유용성은 단점을 안고 가게 된다. 만약 코드 변화를 추적하는 일도 하지 않았던 팀이라면 중간에 사용해도 크게 어려움이 없다 할 수 있다.

인간이란 규칙을 세우기는 하여도 항상 실수가 있기 마련이고, 그것을 지적하는 것 또한 귀찮은 일이 된다. 문제는 팀 구성원의 개발하는 습관이다. 이 문제는 다음 글에서 다룰일이 있을지 모르겠다.
  1. 졸곰 2005.05.18 22:14 신고

    전에 KLDP에 쓰신 글중에 cvs와 indent연동해서 commit시에 indent하도록 하시지 않으셨나요?
    http://bbs.kldp.org/viewtopic.php?t=24241
    제 경우에는 실제 사용해보고 싶었는데 부서내에 도입은 못했는데 결과가 어떤가요?

  2. 2005.05.19 13:55 신고

    저희는 잘 썼었지요. 제가 강제하였기 때문에 가능했었습니다.
    지금은 더이상 cvs를 사용하지 않고 svn을 사용하므로 그런 기능을 사용하지 못하고 있습니다.

아래는 Cascading Style Sheet - The Designer's Edge (Holzschlag) 라는 책의 한 부분을 인용한 것이다.
저자에게는 허락을 받지 않았으나, 미안하긴 하지만 게재한다.아래는 의역입니다.

So why should you follow standards? A lot of people say, “Hey, I can use nonstandard markup that works just fine.”

그러면 왜 표준을 지켜야하는가. 많은 사람들이 말하길 "뭐, 난 표준이 아닌 태그를 이용해도 잘 돌아가."라고들 말한다.

There are several reasons why understanding and following standards makes sense. Here are a few:

왜 표준을 이해하고 따라야하는지 납득할 만한것을 예로 들자면,

You will save time. If your documents follow standards, you achieve a level of efficient work practices. Troubleshooting becomes easier because of document consistency. Team members will work more efficiently in an environment where documents follow structure and logic.

시간을 절약할 수 있습니다, 작성한 HTML이 표준을 따르게 된다면, 효율성을 충분히 경험한 수준을 달성하게 되고, 다른 것들과 일관성 있기 때문에 문제를 찾는것도 쉽게 됩니다. 팀구성원이 문서를 구조적이고 논리적으로 맞추며 작업하는 환경이라면 보다 효율적으로 일할 수 있게 됩니다.

Saving time means saving money. If you are able to save time by ensuring that your documents are standards compliant, stable, and use CSS for style, you will be able to both profit from the process and pass the resulting savings on to your clients.

시간을 절약한다는 것은 돈을 절약한다는 것입니다. 만약 작성하는 HTML 문서들이 표준에 준하게 되고 안정적이고 스타일을 일치시키는데 CSS를 사용하는 것이 확실하다면 시간을 절약하게됩니다. 따라서 개발절차상 이득이며, 이것은 고객을 만족시키게 됩니다.

You’ll reduce complicated pages so browsers will interpret and display a page quickly and accessibility concerns will be addressed. This means a happier end user.

복잡한 페이지들을 간단하게 만들어 브라우져로 하여금 페이지를 해석하고 화면에 나타내는데 빠르게하며, 접근성 문제를 대두시키게 합니다. 고객은 더 행복하겠지요.

You’ll have better job opportunities. If you are still creating web pages in a visual editor without understanding the underlying markup and have not spent any time studying standards, you are restricting yourself in terms of advancement within the profession.

더 좋은 취업 기회를 갖게 됩니다. 만약 여전히 비주얼 에디터를 사용하며, 태그가 가지는 뜻을 이해하지 못하고, 표준을 공부하는데 시간을 들이지 않는다면, 전문성있는 일과는 거리가 멀어지게 될 것입니다.

You will become part of the solution, not the problem, as the infrastructure of the web becomes increasingly more complex.

문제 덩이에서 문제 해결사로 변신하게됩니다. 만약 복잡도가 상당한 웹에서는 더욱 더 그러하겠지요.

Standards set the stage for extending content beyond the limits of the Web to wireless devices such as smart phones, pagers, and PDAs; alternative devices such as MSNTV (formerly WebTV); and a range of devices yet to come.

표준은 웹이라는 제한적인 것을 확장할 수 있는 발판이 되게합니다. 스마트 폰이나 호출기, PDA등의 무선 장치나 웹TV로 알려진 MSNTV같은 대안 장치, 그리고 아직 나타나지도 않은 많은 장비들에게까지 확장은 무한합니다.

-----

웹에서 뿐아니라 어디에서든 표준.. 지켜야겠죠?
온갖 상상이 난무하고, 추측과 확신이 교차하는 작업이 디버깅이라고해도 과언이 아니다. 디버깅은 아는 것 만큼 혹은 조금 더 상상한 것 만큼만 해결 가능하고, 그 외의 것들은 모두 우연한 실수일 뿐이다. 어쩌다 문제를 해결했어도 그것은 실수로 해결한 것이리라. 잔인한가?

디버깅이야말로 책으로 보아왔던 지식이 살아나는 현장이고, 디버깅이야말로 책을 들여다보게 만드는 작업이다. 디버깅을 하면서 가장 중요한 자세 하나를 생각해보고자 한다.

디버깅의 가장 큰 적은 "그 부분은 문제없을텐데"라고 믿게되는 근거를 알 수 없는 자기확신이다. 만일 디버깅을 잘하고자한다면, 지금까지 확실하다고 생각했던 부분을 다시 한 번 보라.

프로그래머가 가져야할 가장 중요한 덕목 중에 하나는 논리적인 무결성과 실제 데이터의 무결성에 대한 차이를 알고 그것을 상황에 따라 적절히 펼치는 것이다. 누구나 프로그래머라면 프로그램의 무결성을 추구한다. 즉, 오류에 적절히 처리하는 루틴이 삽입된다. 그런데, 가끔 명령한 동작의 결과가 성공일 것이라는 맹신을 할 때가 있고, 그것은 논리적으로 아무 오류가 없을 것이라는 생각으로 슬쩍 넘어가게 된다. 그러나 실행시간에 실제 데이터가 그 동작을 보장할 수 없는 값으로 넘어 왔고, 여기에는 논리적으로 있을 수 없다는 것에서 오류처리를 하지 않았고, 이것 때문에 버그가 생기는 것이다.

물론 디버깅을 획일화할 생각은 없지만, 가장 도움이 되는 버그 퇴치자세를 논하기 위해 다른 상황은 잠시 무시하자. 그렇다면, 논리적 무결성과 실데이터의 무결성에 대한 차이는 무엇일까?

논리적으로 무결한 예는 이렇다.
정수를 입력받고, 이 값을 2로 나누면 짝수 아니면 홀수임을 알 수 있다.

하지만 다음은 논리적으로 무결하지 않다.
내가 지금 300바이트를 TCP/IP를 통해서 한번에 전송하였다. 그러면 수신쪽에서도 한 번 읽을 때 300바이트가 읽혀질것이다.

다음은 어떠한가?
두 개의 쓰레드가 돌아가는데, 한 쓰레드에서 스택에 생성된 자동변수 두개의 값을 바꾸기 위해 하나를 더 잡아서 임시 보관용으로 사용하면 두 개의 값을 바꿀 수 있다
스택은 쓰레드마다 고유한 것이고, 따라서 위 말은 아무런 문제가 없다. 논리적으로 아무런 문제가 없으니 이런 루틴은 설마 버그가 있었으랴하고 지나치는 것이 우리의 상식이다. 하지만, 좀더 염세적으로 생각해보자, 쓰레드는 다른 쓰레드의 스택에 접근할 수 있는 권한이 있다. 혹시 이전 작업이 같은 함수내의 자동변수에 대한 포인터가 다른 쓰레드에 넘어 갔고 그쪽에서 오버플로라도 일어났다면? 심각한 문제이다.

인생은 디버깅이다. 적절히 assert 뿌려가면서 사는 것이지.
요즘에야 프로젝트의 시작부분에 설치본을 만드는 것이 당연하다 생각되나, 나 자신도 몇년전에는 그러하다 생각지 못하였는데, 그 이유는 "설치할 것이 있어야 설치본을 만들지!"라는 생각에서였다.

하지만, 제일 쉬우면서도 가장 오래, 배포되는 프로그램의 끝까지 애를 먹이는 것이 바로 배포를 위한 설치본, 또는 부분패치 설치본이며, 이것은 릴리즈 엔지니어링의 마지막 결과물에 해당한다.

강조를 백번해도 모자랄 정도로 프로젝트의 시작부분에서의 설치본인데, 이것은 개발조직이 분화되기 위한 첫걸음이된다. 개발초기부터 테스팅 및 릴리즈를 위한 얘기를 할 수 있고, 중간 단계쯤에서 그간 진행된 기능에 대한 다양한 피드백을 받을 수도 있고, 나중에 고생할만한 일을 초기에 잡을 수 있는 아주 필수적인 것이 개발팀이 설치본을 만들어 배포하는 것이다. 그것이 비록 불완전하게 동작한다할 지라도, 설치본이 대화의 중심에 있어야한다.

다양한 계층의 테스터, 성능이나 UI에 대한 피드백을 프로그래머들이 오너십을 가지고 진행한다는 것은 얼마나 피곤한 일인가? 그것은 전문성도 떨어지려니와 프로그래머에게 설계/구현/디버깅이라는 행위에서 의견 수집/분석/조율이라는 행위간의 문맥전환을 수시로 일으키기란 참으로 어려운 일이다.

설치본을 어떻게 만들것이냐는 것은, 초기에는 대~~충 설치본을 만드는 한이 있더라도 초안을 생각해두고 진행해야한다. 설치 및 삭제 그리고 부분 업그레이드에 대한 것이 나중에 버그를 잡는데도 도움이 된다. 그 이유는 한 번 개발팀을 떠난 것은 어떤 식으로든, 부메랑을 타고 돌아오게 되어 있다. 그런데, 문제는 개발팀의 손을 한두번 떠난것이 아닌 상황이 오게되면, 부메랑에 맞아 쓰러지는 상황이 발생하게 된다.

몇가지 정리하자면, 설치본을 만들때는 다음과 같은 상황을 고려해야한다.

1. 매일매일 최신소스로 설치본이 자동으로 만들어지는가?
2. 임의의 바이너리가 어느 빌드에서 생성되었는지 알 수 있는가?
3. 바이너리들이 의존하고 있는 라이브러리들은 모두 알고 있는가?
4. 바이너리안에 들어 있는 global symbol(nm 명령을 통해)들은 관리가 되고 있는가?
5. 이전 설치본과 지금 설치본에서 변경사항은 자동으로 뽑혀 릴리즈 노트를 구성할 수 있는가?
6. 부분 테스트를 위한 정보들은 버그트래킹시스템과 연결되어 꼭 필요한 인수 테스트를 할 수 있는가?

매일매일 최신소스로 설치본이 자동으로 만들어지는가?
아마 이 부분이 다른 다섯가지보다 가장 재미있고, 쉽고, 뿌듯한 부분이 아닐까 한다. 왜냐하면, 자동으로 만드는 스크립트에는 나머지 것들에 대한 모든 것이 포함되기 때문이다. 그 끝은 관련자들에게 따끈따끈한 설치본의 URL과 빌드로그 및 릴리즈 노트를 메일로 전송하는 것이 될 것이다. 이렇게 기쁜 일은 프로젝트가 시작할 때 얼른 담당하고 남주지 말자. 만약 당신이 닥치는대로 공부하는 열정이 있는 사람이라면 이 일은 정말 남주면 안될 것이다.

적절히 crontab 을 운영할 것이고, 빌드 로그중에서 warning만을 추려내어 따로 보고해야할 지도 모르며, 하나의 소스로 여러 OS에서 동시에 빌드할 수 있어야하고, apache의 fancy indexing도 사용해야할 수도 있고, 가장 빨리 빌드하는 방법을 위한 여러 안건을 만들 수도 있고, cvs나 subversion 등의 tag, diff, merge 등에 대해 일가견이 생기게 되고 하여간 도무지 말로 할 수 없는 수 많은 것들을 빌드 시스템을 구축하면서 찾고 공부하게 된다.

임의의 바이너리가 어느 빌드에서 생성되었는지 알 수 있는가?
바이너리 안에는 대개 "static char []"형으로 된 $Id$가 들어가게 된다. 이것은 소스 정보만을 나타내게 되지만, ident라는 좋은 툴은 $String ...$ 형태로 되어 있는 모두 뽑아주므로 거기에 팀의 독특한 스트링을 버전 및 빌드 번호를 표시하는데 사용할 수 있다. 예를 들면
$Version: doorscan 2.2.1.1224 $
와 같이 Version 이라는 것을 사용할 수 있겠다. 만약 2.2.1.1224 와 같은 이름으로 소스 트리를 태깅을 해놓는 다면, 바이너리를 만드는데 들어간 소스들의 버전을 쉽게 뽑아낼 수 있게된다.

또는 반대로, 바이너리를 출시한 뒤 MD5 해시 값을 구해놓고 빌드시점에 모든 파일의 MD5 해시를 저장해 놓은 뒤 비교하여 구할 수도 있다.

바이너리들이 의존하고 있는 라이브러리들은 모두 알고 있는가?
ldd 를 이용한 검사인데, 개발도중 어느새 모르게 개발팀이 모르는 라이브러리가 들어갈 수 있다. 이것은 설치가 개발 장비에서만 제대로 될 수 있고, 정작 다른 곳에는 해당 바이너리가 없는 것으로 인해 설치후에 수행이 되지 않을 수 있다. 어딘가에 그 프로젝트 전체적으로 외부 라이브러리를 사용한다면 모든 배포되는 바이너리가 어떤 의존관계를 가지고 있고, 그 의존 관계에 대한 것은 선행작업이 필요함을 설치본 배포시에 적절히 명시해야한다.

바이너리안에 들어 있는 global symbol(nm 명령을 통해)들은 관리가 되고 있는가?
바이너리가 특히나 shared object(so) 파일이라면, 흔히 저지르기 쉬운 것이 단지 어떤 실행파일이 사용한다정도의 정보만을 가지기 쉽다. 즉, ldd에 의한 의존성만 확인하는 경우가 발생할 수 있는데, nm 을 통해서 정확히 외부에 노출시킬 것이 노출되고 있는지, 이전과 다르게 추가되거나 삭제된 것이 없는지 확인해야한다. shared object 의 생명은 global symbol(defined, undefined)l과 의존성이다. 이것이 적절히 빌드시점에 생성되거나 관리되지 않는다면, 나중에 업그레드시에 모든 바이너리가 배포되어야하는 상황이 발생할 수 있다. 그러면 왜 so로 분리했느냐!라는 소릴 듣게 될 수도 있다. 무작적 so로 쪼게는 것은 정말 삼갈일이며, 그것은 신발에 껌을 잔뜩 붙이고 줄넘기하는 것과 똑같다.

이전 설치본과 지금 설치본에서 변경사항은 자동으로 뽑혀 릴리즈 노트를 구성할 수 있는가?
릴리즈 노트라는 것은 새로운 버전을 출시할 때, 개발자들이 그간의 기억을 미루어 적어 내거나, 그동안 처리했던 버그 리스트를 정리하는 것이 아니다. 그것은 버그를 처리할 때마다 적어 놓은 간단한 노트들이 있어야하고, 그 노트들을 각 버전별로 뽑을 수 있는 상태로 관리되어야하는 것이다.

간단히는 cvs나 subversion을 쓸 때, 커밋로그를 이용해서 릴리즈 노트용을 적절한 규칙에 의해 적게되면, 태깅한 기간별로 구별하여 뽑아 낼 수 있다. 로그는 한 번 올리면 다시 수정못하는 것으로 아는데, cvs의 경우 cvs admin 명령으로 subversion의 경우 svn ps svn:log 조합으로 다시 고칠 수 있다. 로그는 커밋하는 시점외에는 다시 자세히 적을일이 없게된다. 대략 간단한 어플리케이션을 개발하는데, 5000 번 정도의 커밋이 되면 알파 릴리즈가 만들어지는데, 5000번에 대한 것을 누가 이후에 관리할 것인가.

부분 테스트를 위한 정보들은 버그트래킹시스템과 연결되어 꼭 필요한 인수 테스트를 할 수 있는가?
SCM(Software Configuration Management)이라는 영역이 있다. 검색을 하게 되면 개발 관련된 각종 도우미 툴들이 소개되는데, 가장 중요한 것은 소스를 소스만으로 두는 것이 아니라, 제기된 이슈나 버그, 그리고 고친 내역등을 유기적으로 결합하는 방법을 어떻게 구성할 것인가에 있다.
학교에서 갓 나온 수준으로 기업형 프로그램을 만들어야할 경우, 프로그램이란 몇달하고 마는 것이 아니라 계속 살아서 발목을 잡아 당기는 실로 무시무시한 존재와 같은 것을 느끼게 된다. 이런 문제를 해결하기 위해 버전 컨트롤 시스템을 도입하게되는데, 그 이후에도 문제는 또 발생한다. 버전 컨트롤 시스템이 단지 코드의 변화에 대한 것은 알려주지만, 코드가 변하는데는 이유가 있어야 하며, 그 이유의 근원에 대한 것은 동시에 수십 수백개가 관리되어야하고, 릴리즈 이후 코드에 변형을 가하는 모든 커밋에 대한 것이 테스트 대상으로 연결되어 문제를 재발하지 않고, 원하는 방향으로 적절한 계획을 가지고 나갈 수 있어야한다.

이상으로 간단히 빌드와 관련된 것을 살펴보았는데, 소스가 공개되어 개발되는 프로그램들을 잘 살펴보면, 빌드 및 그 관리와 관련된 상당히 많은 노하우들이 그 프로젝트안에 녹아 있고, 그 과정들이 단지 프로그래밍 실력으로만 시작하여 진행되는 것이 아니라는 것을 알 수 있다. 그들은 끊임없이 고객의 요구를 수용하고 있고, 버그를 찾고 있으며, 새로운 기능을 추가하고 있다. 이것이 모두 릴리즈를 어떻게 관리할지에 대한 것에 대한 것이 모두 오픈되어 진행된다.

어디서 개발을 하던지, 이상과 같은 빌드관리가 선행되지 않는다면, 조만간 누구도 손댈 수 없는 코드로 변신하고 말것이다.
  1. june8th 2005.04.04 09:46 신고

    잘 정리했네요.. 근데 이 문서의 버전은 어디에? ㅎㅎ

  2. 2005.04.04 10:38 신고

    ㅋㅋ.. 요건 버전관리 대상이 아닌 릴리즈지...
    설치해서 배포할까? ^^;

  3. 석영 2005.04.17 14:21 신고

    이 쪽은 정말 관심이 많은데, Windows 환경에서 소스 자동 빌드와 버전 배포를 위해 사용할 수 있는 툴들 또는 관련 리소스들이 있는 사이트가 있으면 알려주겠어요?

  4. 2005.04.18 07:42 신고

    아하.. 그것참.. 저는 윈도우쪽 환경에서는 많이 고민하지 못해서, 저도 찾아봐야해요..

Subversion : http://subversion.tigris.org/
TortoiseSVN: http://tortoisesvn.tigris.org/
poedit: http://www.poedit.org/translations.php

나는 요 세가지의 한국어 문자열을 관리하고 있는데, 어떤 소프트웨어가 맘에 들면 번역을 시도해보는 것은 그 프로그램을 깊이 이해하는데 더 도움이 된 것 같다. 가장 활발히 하는 것은 TortoiseSVN인데, 그 이유는 일주일에 한 번 씩 번역 상태가 메일로 오고 각 언어별 번역율이 그래프로 나오는 것이 약간의 경쟁을 유도하게한다.

subversion은 일주일에 한 번정도 모든 언어들의 번역상태가 메일링리스트로 전송되어 온다.
Translation status report for revision 13587 (trunk/)

============================================================================
Status for 'de.po': in repository
Passes GNU msgfmt --check-format
Statistics:
0 obsolete
82 untranslated
1238 translated, of which
48 fuzzy
----------------------------------------------------------------------------
Status for 'es.po': in repository
Passes GNU msgfmt --check-format
Statistics:
0 obsolete
94 untranslated
1226 translated, of which
106 fuzzy
----------------------------------------------------------------------------
Status for 'ja.po': in repository
Passes GNU msgfmt --check-format
Statistics:
0 obsolete
75 untranslated
1245 translated, of which
121 fuzzy
----------------------------------------------------------------------------
Status for 'ko.po': in repository
Passes GNU msgfmt --check-format
Statistics:
0 obsolete
79 untranslated
1241 translated, of which
134 fuzzy

poedit도 번역 상태가(tortoise svn처럼) 웹에는 계속 올라오는데, 메일을 안보다 보니 내가 들어가서 보기전까지는 잘 모르게 된다.(실로 지금까지 한 번 보내고 말았는데, 이 놈의 게으름..)

(내가 관심있는 요 세 프로그램에 대한 독일어버전도 TortoiseSVN의 번역관리담당인 뤼베 옹켄이라는 한 사람이 한다.)

사실 개인적으로 svn을 사용하면서 cvs의 사용이 극도로 줄어들게 되었고, 그에 따라 관심의 영역이 줄어 든 것도 사실이다. (cvs 프로젝트도 observer로 등록되어 있기는 하다마는) 번역하면서 위세를 떨칠것도 아니고, 관심의 끊임없는 표현인데, 그에 따른 적절한 책임감이 소프트웨어를 빛나게하는 것 같다.

난 일주일에 한 번, 번역에 시간을 들여 커밋 또는 메일링 리스트에 올리는데, 대개 주말에 한다. 번역을 하게 되면서, 프로그램을 작성할 때 번역자를 고려하는 설계와 누구나 번역을 쉽게 할 수 있도록 하는 방법에 대한 고민을 많이 하게 되었고, 나와 같이 패키지 작업을 하는 것이라면 더욱 도움이 많이 된다.

po 포맷이라는 전통적인 Unix 기반 다국어 처리용 포맷이 있는데, 요놈의 구조가 간단하고 그 editor들 또한 훌륭하여 프로그램을 모르는 사람을 번역하는데 고용할 수 있으므로 더욱 그 활용도가 높다.

Subversion과 poEdit 프로젝트는 전통적인 방식 그대로 po를 compile한 mo 파일을 어플리케이션에서 핸들링한다. 즉 gettext라는 라이브러리에서 최적화되어 메모리 맵된 파일 입출력을 통하여 사용되는데, 요 Tortoise SVN이라는 녀석은 gettext library를 사용하지 않고, po 포맷을 단지 우리같은 지역화하는 사람들과의 통신도구로만 사용하는데 그 재미가 있다. 그 개발팀은 restext.exe 라는 MS 윈도우용 프로그램을 이용하여 po 파일을 dll로 만들어준다. 마치 mo 파일 만들듯이 Tortoise SVN용 리소스 DLL을 만들며, 현재 아무 문제 없이 Tortoise SVN의 언어 확장팩으로 배포되고 있다.

난, 여기에 힌트를 얻어 회사에서의 프로젝트에 po 포맷을 도입했는데, 이로써 사내에서는 po 포맷을 이용하여 다국어 기반의 업무 프로세스를 만들었다는데 그 의의가 있다. 즉, 소스와 전혀 상관없이 po 파일로 기술문서팀과 이야기하고 개발팀에서는 po 포맷을 자바스크립트의 연관 배열로 바꾸는 스크립트를 간단히 제작하여 웹관리툴의 다국어 지원을 꾀하였다.

약 1000개의 문자열로 된 웹관리툴이 po 기반의 다국어 지원을 한다는것이 신선하지 않은가? strings.js 라는 그 자바 스크립트는 모든 웹페이지가 link하는 형태로 load하므로 네트웍 트래픽은 한 번만 일어나게되며, 화면에 약 30개 정도의 문자열이 그려지게 되는데, 1000개정도의 연관배열을 뒤지는데는 그다지 많은 컴퓨팅 파워를 소모하지 않는다.

다국어를 지원하는 방법은 여러가지겠지만, 될 수 있으면 많이 사용하는 방법을 최대한 이용하는 것이 생산성과 직결된다는 생각을 상기하며 이만.

+ Recent posts