성당과 시장
리눅스의 역사에 의해 제시된 소프트웨어 엔지니어링의 놀라운 이론의 신중한 테스트로 실행된 성공적인 오픈소스 프로젝트, fetchmail을 분석한다. 이 이론들을 두 개의 근본적으로 다른 개발 스타일의 용어들로 논할 것이다. 두가지 스타일이란 상업용 소프트웨어의 “성당” 모델과 리눅스 세계의 “시장” 모델이다. 이 모델들은 소프트웨어 디버깅 작업의 본질에 대한 서로 대립되는 가설들로부터 파생되었다는 것을 보일 것이다. 그리고 나서 리눅스의 경험으로부터 “충분히 많은 사람이 있다면, 찾을 수 없는 버그란 없다” 는 일관된 주장을 펴고, 다른 이기적인 에이전트들의 자가수정 시스템과의 생산적인 비유를 제시한 다음, 소프트웨어의 미래를 위해 이 통찰이 가지는 의미에 대한 탐구로 마무리짓는다.
순서
- 성당과 시장
- 메일은 배달되어야만 한다
- 사용자가 있다는 것의 중요성
- 일찍 발표하고, 자주 발표하라
- 장미가 장미다우려면
- Popclient 가 Fetchmail 이 되다
- Fetchmail 의 성장
- Fetchmail에서 배울 점
- 시장 스타일의 개발에 필요한 선행조건들
- 오픈소스 소프트웨어의 사회적 문맥
- 감사의 말
- 읽어볼 만한 글들
- 후기 : 넷스케입이 시장스타일을 받아들이다!
- 버전과 변천사
1. 성당과 시장
리눅스는 파괴적이다. 파트타임으로 해킹을 하면서 인터넷이라는 가느다란 선만으로 연결되어 있는 전세계 수천명의 개발자들에 의해 세계적인 수준의 운영체제가, 마치 마술로 된 것처럼 만들어질 수 있었으리라고 5년 전에 누가 상상이나 할 수 있었을까? 나는 분명 상상하지 못했다. 1993년 초, 리눅스가 내 레이다 화면에 잡혔을 때 나는 이미 유닉스와 오픈소스 개발을 10년 동안 해오고 있었다. 1980년대 중반에 GNU 에 공헌한 첫 번째 사람들 중 한명이었다. 나는 네트워크 상에 꽤 많은 오픈소스 소프트웨어를 발표했고, 지금도 널리 사용되고 있는 몇몇 프로그램을 개발중이거나 공동개발하고 있었다. (네트핵, Emacs VC 와 GUD 모드, xlife, 등등) 나는 프로그램이 어떻게 개발되어야 하는지 알고 있다고 생각했다.
리눅스는 내가 알고 있다고 생각한 것을 많은 부분 뒤집어 버렸다. 몇 년 동안이나 나는 작은 도구, 빠른 프로토타이핑, 그리고 진화적인 프로그래밍을 여러 해 동안 유닉스의 복음으로 설교해 오고 있었다. 하지만 나는 어떤 종류의 매우 중요한 복잡성이 있어서 거기에는 더 집중되고 선험적인 접근방법이 필요하다고 믿고 있었다. 가장 중요한 소프트웨어 (운영체제나 Emacs 같이 대단히 커다란 커다란 도구들) 은 성당을 건축하듯이, 즉 찬란한 고독 속에서 일하는 몇 명의 도사 프로그래머나 작은 그룹의 뛰어난 프로그래머들에 의해 조심스럽게 만들어지고 베타버전도 필요없이 발표되어야 한다고 생각했던 것이다.
리누스 토발즈의 개발 스타일은 – 일찍, 그리고 자주 발표하며 다른 사람들에게 위임할 수 있는 것은 모두 위임하고, 뒤범벅이 된 부분까지 공개하는 그런 스타일 – 나에게 놀라움으로 다가왔다. 고요하고 신성한 성당의 건축방식은 여기에서 찾아볼 수 없었다. 대신, 리눅스 공동체는 서로다른 의견과 접근방법이 난무하는 매우 소란스러운 시장같았다. (리눅스 아카이브 사이트가 이것을 적절히 상징하고 있다. 이곳에는 누/구/나/ 파일을 올릴 수 있다) 이런 시장바닥에서 조리있고 안정적인 시스템이 나온다는 것은 연속된 기적으로만 가능한 것처럼 보였다.
시장 스타일이 매우 효과적이라는 사실은 분명히 충격이었다. 리눅스 공동체에 익숙해 가면서 나는 개개의 프로젝트에만 열심이었던 것이 아니라 왜 리눅스 세계가 혼란속에 갈라지지 않을 뿐 아니라 성당건축가들이 간신히 상상만 할 수 있는 속도로 갈수록 강해지는지 이해하려고 애썼다.
1996년 중반에야 이해가 되기 시작했다. 내 이론을 시험해 볼 수 있는 완벽한 기회가 오픈소스 프로젝트의 형태로 찾아왔다. 여기에서 나는 의식적으로 시장 스타일을 시도해 볼 수 있었고, 큰 성공을 거두었다.
이 글의 나머지 부분에서는 그 프로젝트에 대해 이야기하고 효과적인 오픈소스 개발에 대한 격언들을 제시할 것이다. 내가 이 모든 것을 리눅스 세계에서 배운 것은 아니지만 리눅스 세계가 이 격언들에게 특별한 요점을 가질 수 있게 해주었다. 만일 내가 옳다면, 독자들은 이 격언들로부터 리눅스 공동체가 훌륭한 소프트웨어를 만들어내는 원천이 될 수 있었던 이유를 이해할 수 있을 것이며, 독자 자신들도 더 생산적으로 될 수 있을 것이다.
2. 메일은 배달되어야만 한다.
1993년에 서 펜실베니아 주, 서 체스터(West Chester) 시의 자그마한 무료 ISP 인 체스터 카운티 인터링크 (Chester County InterLink : CCIL) 에서 기술적인 측면을 담당하고 있었다. (나는 CCIL 의 공동설립자였으며 우리만의 멀티유저 게시판 소프트웨어를 작성했다 – locke.ccil.org 에 telnet 으로 접속하면 볼 수 있다. 지금은 19 회선으로 3000 여명의 사용자를 지원한다) 이 일 덕분에 나는 하루 24시간 내내 CCIL 의 56K 회선을 통해 네트워크에 접근할 수 있었다. 사실, 그렇게 해야만 하는 상황이었다.
그래서 나는 즉시 배달되는 인터넷 이메일에 매우 익숙해졌다. 복잡한 이유로 인해 내 집의 컴퓨터 (snark.thyrsus.com) 과 CCIL 사이에 SLIP 연결을 하기가 힘들었다. 마침내 성공하고 나자, 주기적으로 locke 에 접속해 메일이 왔는지 체크해 보는 것이 매우 귀찮은 일이라는 것을 알게 되었다. 나는 내 메일이 snark 로 배달되었을 때 바로 알 수 있고, 내 도구들을 가지고 메일을 다룰 수 있게 되는 것을 원했다.
sendmail을 이용해 단순히 포워드시키는 것은 소용이 없었다. 내 개인 컴퓨터가 항상 네트워크에 연결되어 있는 것도 아니고 고정적인 IP 어드레스를 가지고 있지도 않았다. SLIP 연결이 되면 내 메일을 배달해주는 프로그램이 필요했다.
그런 프로그램이 몇 개 있었고, 대부분은 프로토콜로 POP (Post Office Protocol)을 사용했다. 물론, locke 의 BSD/OS 운영체제에는POP3 서버가 포함되어 있었다. 내게 필요한 것은 POP3 클라이언트였다. 그래서 네트워크를 뒤져 하나를 찾아냈다. 사실은 서너개를 찾아내긴 했다. 잠시동안은 pop-perl을 사용했지만 기본적인 기능이 빠져있었다. 가져온 메일에서 발신인의 주소를 제대로 처리하지 못해 답장을 보낼 수가 없었다. locke 의 사용자 중에 joe 라는 사람이 나에게 메일을 보냈다고 해보자. snark 로 메일을 가져와서 그 메일에 답장을 하려고 하면 메일 프로그램은 snark 에는 있지도 않은 joe 에게 답장을 보내려고 시도한다. 그래서 손으로 ‘@ccil.org’를 뒤에 붙여주어야 했는데, 곧 매우 성가시게 느껴졌다.
이것은 분명히 컴퓨터가 해주어야 하는 일이었다. 하지만 이미 있는 POP 클라이언트들 중 어느것도 이 일을 해주지 못했다. 여기에서 첫 번째 교훈을 얻을 수 있다.
1) 모든 좋은 소프트웨어는 개발자 개인의 가려운 곳을 긁는 것으로부터 시작된다. (Every good work of software starts by scratching a developer’s personal itch)
명확해 보이는 교훈이긴 하지만 (“필요는 발명의 어머니” 라는 오래된 속담이 있지 않은가)소프트웨어 개발자들은 너무나자주, 단지 돈 때문에 그들이 필요로 하지도 않고 좋아하지도 않는 프로그램을 만들어 내는데 시간을 쓰고 있다. 하지만 리눅스 세계에서는 그렇지 않다 – 아마도 이것이 리눅스 공동체에서 만들어진 소프트웨어들의 평균적이 품질이 그렇게나 좋은지를 설명해줄 것이다.
그래서 내가 이미 있는 POP3 클라이언트들과 경쟁하는 새로운 프로그램을 곧바로 코딩하기 시작했을까? 천만에. 나는 이미 가지고 있는 POP 유틸리티들을 조심스럽게 살피면서 스스로에게 물었다. “내가 원하는 것과 가장 가까운 프로그램이 어느 것일까?” 그 이유는
2) 좋은 프로그래머는 어떤 프로그램을 만들어야 할 지 안다. 위대한 프로그래머는 어떤 프로그램을 다시 만들어야 할 지 (그리고 재사용해야 할 지) 안다. (Good programmers know what to write. Great ones know what to rewrite(and reuse))
내가 위대한 프로그래머라는 말은 아니지만 흉내내려고는 했다. 위대한 프로그래머의 중요한 특징 중 하나는 건설적인 게으름이다. 그들은 들인 노력으로가 아니라 결과로 평가받는다는 것을 알고 있으며 완전한 무에서 시작하는 것보다는 부분적으로나마 좋은 해결책에서 시작하는 것이 거의 항상 더 쉽다는 것을 알고 있다.
리누스 토발즈 (http://www.earthspace.net/~esr/faqs/linus)를 예로 들자면 그는 맨바닥에서 Linux를 써내려고 하지 않았다. 대신 그는 386 기계를 위한 Unix 비슷한 OS, Minix 의 코드와 아이디어를 재사용하는 것으로부터 시작했다. 결국 모든 Minix 코드는 사라지거나 새로 쓰여졌다 — 하지만 Minix 의 코드가 남아있을 동안 그 코드는 나중에 Linux 가 될 어린 아기의 발판 역할을 했다.
똑같은 생각으로 나는 이미 있는 POP 유틸리티 중 코딩이 잘 되어있는 것을 찾아 개발의 기초로 사용하려 했다. Unix 세계의 소스를 공유하는 전통은 언제나 코드를 재사용하는데 호의적이었다. (GNU 프로젝트가 Unix 자체에 대한 심각한 의혹에도 불구하고 Unix 를 기본 OS 로 선택한 것도 바로 이런 이유에서였다) 리눅스 세계는 거의 기술적인 한계에 다다를때까지 이 전통을 받아들였다. 일반적으로 찾아볼 수 있는 오픈된 소스가 수 테라바이트에 달하는 것이다. 그래서 누군가의 거의 완성된 소스를 찾아보는데 시간을 들이는 것이 다른 어느 곳에서보다 리눅스 세계에서는 좋은 결과를 가져다 줄 가능성이 높다. 나에게도 역시 그랬다. 예전에 찾아놓은 것에다가 두 번째 검색결과를 더하니 모두 아홉 개의 후보가 생겼다. fetchpop, PopTart, get-amil, gwpop, pimp, pop-perl, popc, popmail, 그리고 upop 이었다. 내가 제일 먼저 신경을 집중한 것은 오승홍 씨의 fetchpop 이었다. 헤더 재작성 기능과 더불어 몇몇 개선사항을 그 안에 추가했고, 저자가 릴리즈 1.9 에 그것을 수용했다.
몇 주 후에 나는 Carl Harris 가 만든 popclient 의 코드를 들여다 보다가 문제점을 발견했다. fetchpop 에는 훌륭한 독창적인 아이디어가 들어 있었지만 (daemon 모드 같은 것) POP3 만을 처리할 수 있었고, 아마추어 티가 나는 코딩이었다. (오승홍 씨는 똑똑하기는 하지만 경험이 부족한 프로그래머였으며 그 두 가지 특징 모두를 코딩에서 볼 수 있었다) Carl 의 코드는 탄탄한 프로페셔널의 더 나은 코드였으나 몇가지 중요하면서도 구현하기 위해서는 약간의 잔머리가 필요한 fetchpop 의 기능들이 (내가 추가한 기능들을 포함해서) 빠져 있었다.
머물러 있을 것인가, 옮겨갈 것인가? 옮겨간다면 더 나은 개발기반을 위해 이미 해놓은 코딩을 포기해야만 했다. 옮겨가는데 실질적인 동기가 되었던 것은 다중프로토콜 지원 여부였다. POP3 가 우체국 서버 프로토콜 중에서 가장 널리 쓰이는 것이긴 했지만 유일한 프로토콜은 아니었다. fetchpop을 비롯하여 다른 경쟁자들은 POP2, RPOP, 또는 APOP를 지원하지 않았고, 나는 당시에 재미삼아서 IMAP (Internet Message Access Protocol; http://www.imap.org; 가장 최근에 고안되었으면 가장 강력한 우체국 프로토콜) 을 지원해볼까 하는 생각을 가지고 있었다.
하지만 옮겨가는 것이 좋은 생각이라는 좀 더 이론적인 이유도 가지고 있었다. 오래전에 리눅스에서 배운 교훈이었다.
3) “가지고 있는 것을 버릴 계획을 세우라 ; 언젠가는 버리게 될 것이다 (Plan to throw one away; youu will anyhow)” (Fred Brooks, “The Mythical Man-Month”, Chapter 11)
다른 말로 하자면, 첫 번째 해결책을 구현할 때까지도 진짜 문제가 무엇인지 이해하지 못하는 경우가 종종 있다는 것이다. 두 번째가 되어서야 어떻게 하는 것이 옳은 것인지 충분히 알게 될 수 있다. 따라서 만일 올바른 방법을 찾고 싶다면 최/소/한 한 번은 처음부터 다시 시작할 준비를 해 두어야 한다. 그래, fetchpop을 고친 것은 내 첫 번째 시도였어, 하고 스스로에게 말하고 나서 나는 popclient 로 옮겨갔다.
1996년 6월 25일에 Carl Harris 에게 내 첫 번째 popclient 패치를 보낸 후, 나는 그가 popclient 에 대한 흥미를 이미 잃었다는 것을 알게 되었다. 코딩이 좀 지저분했고, 자잘한 버그들이 널려있었다. 수정을 많이 가했고, Carl 과 나는 곧 내가 프로그램을 넘겨받는 것이 합리적이라는 데에 동의하게 되었다. 내가 알아차리지 못하는 새에 프로젝트가 차츰 궤도에 오르기 시작했다. 나는 이미 존재하고 있는 POP 클라이언트의 마이너 패치를 생각하는 것이 아니었다. 클라이언트 하나를 통채로 관리하고 있었으며 내 머리에서는 커다란 변화가 될 아이디어들이 솟아나고 있었다.
코드공유를 장려하는 소프트웨어 문화에서는 이런 방식으로 프로젝트가 진화하기 마련이다. 이렇게 말할 수 있다.
4) 적절한 태도를 가지고 있으면 흥미로운 문제가 당신을 찾아갈 것이다. (If you have the right attitude, interesting problems will find you)
하지만 Carl Harris 의 태도가 훨씬 더 중요했다. 그의 태도는
5) 프로그램에 흥미를 잃었다면 프로그램에 대한 당신의 마지막 의무는 능력있는 후임자에게 프로그램을 넘겨주는 것이다. (When you lose interest in a program, your last duty to it is to hand it off to a competent successor)
토론할 필요도 없이 Carl 과 나는 가장 좋은 해결책을 찾아낸다는 목표를 가지게 되었다. 우리에게 남아있는 한가지 문제는 내가 적임자라는 것을 입증할 수 있느냐 하는 것이었다. 내가 그것을 증명하자 그는 기꺼이, 그리고 신속하게 행동했다. 내가 그렇게 행동할 차례가 되었을 때 나도 그만큼 잘 할 수 있기를 바란다.
3. 사용자가 있다는 것의 중요성
그래서 내가 popclient를 넘겨받았다. 내가 popclient 의 사용자들을 넘겨받았다는 것도 그에 못지않게 중요하다. 사용자들이 있다는 것은 매우 좋은 일이다. 당신이 누군가의 필요를 충족시켜주고 있으며 일을 잘 해나가고 있다는 것을 보여주기 때문만은 아니다. 적절하게 유도해 준다면 사용자들을 공동개발자가 될 수 있다.
유닉스의 전통이 가지고 있는 또하나의 강점, 즉 많은 수의 사용자들이 동시에 해커이기도 하다는 것을 리눅스는 좋은 의미로서의 극단까지 밀어붙였다. 소스코드가 공개되어 있기 때문에 그들은 효/과/적/인/ 해커가 될 수 있었다. 이것은 디버깅 시간을 줄이는 데 엄청난 도움이 되었다. 조금만 격려해주면 사용자들은 문제를 분석하고 해결책을 제시하며, 도움없이 혼자 일할 때보다 훨씬 빨리 코드를 개선시키도록 해준다.
6) 사용자들을 공동개발자로 생각하면 코드가 다른 어떤 방법보다도 빠른 속도로 개선되며 효율적으로 디버깅할 수 있다. (Treating your users as co-developers is your least-hassle route to rapid code improvement and effective debugging)
이 효과의 위력은 과소평가되기 쉽다. 사실, 오픈소스의 세계의 우리들조차 시스템의 복잡도에 대항하여 많은 수의 사용자가 얼마나 힘이 되는지를 리누스 토발즈가 보여주기 전까지 과소평가하고 있었다. 실제로 나는 리누스의 가장 영리하고 가장 중요한 해킹은 리눅스 커널을 만들었다는 점이 아니라 리눅스 개발모델을 만들었다는 점이라고 생각한다. 리누스에게 이 의견을 말해 주었더니 그는 씨익 웃고서 조용히 여러번 하던 말을 되풀이했다. “난 기본적으로 매우 게으른 사람이라서 실제로는 다른 사람들이 해놓은 일을 가지고 공로라고 인정받곤 해요.” 여우처럼 게으르군. 로버트 하인라인이라면 실패하기에는 너무 게으르다고 말했을 것이다.
되돌아 보면, 리눅스의 성공과 방법론은 GNU Emacs Lisp 라이브러리와 Lisp 코드 아카이브에서 그 선례를 찾아볼 수 있다. Emacs C 코어와 다른 대부분의 FSF 도구들의 성당건축 스타일과는 대조적으로 Lisp 코드 풀의 진화는 유동적이었고, 사용자가 주도한 것이었다. 아이디어와 프로토타입 모드들은 안정적인 최종형태를 갖추기까지 종종 서너번씩 다시 쓰여졌다. 느슨하게 묶인 공동작업이 인터넷으로 인해 가능해졌고, 리눅스에서는 매우 자주 일어나는 일이 되었다. 사실 fetchmail 이전에 내 자신의 가장 성공적인 해킹은 아마 Emacs VC 모드였을 것이다. 세 명의 사람들과 email을 통해 리눅스와 비슷한 협동작업을 했고, 그 셋 중의 한 명 (리차드 스톨만:Richard Stallman. Emacs 의 저자이면서 FSF 의 설립자) 만을 지금까지 만나고 있다. VC 모드는 SCCS, RCV 와 CVS 를 위한 Emacs 내의 프론트엔드였고, “원터치” 버전컨트롤 기능을 제공했고, 누군가 만들어 놓은 작고 조악한 sccs.el 모드로부터 진화한 것이었다. VC 의 개발은 Emacs 와는 다르게 Emacs List 코드가 발표/테스트/개선의 주기를 매우 빨리 반복할 수 있었기 때문에 성공했다. 코드를 GPL 에 법적으로 묶어두려던 FSF 의 정책은 한가지 예기치 못한 부작용을 가져왔다. FSF 는 20줄 이상의 개인적인 공헌에 대해서 저작권을 받아야 한다고 생각하기 때문에 시장모드를 사용하는 절차가 어려워졌다는 것이다. 이것은 GPL 의 코드가 저작권법 하에서 도전받는 것을 방지하기 위한 정책이다. BSD 와 MIT 의 X 콘소시엄 라이센스를 사용하여 저작권을 얻는사람은 이런 문제를 겪지 않는다. 그들은 누군가가 도전할 동기를 가질만한 권리를 가지려 하지 않는다.
4. 일찍, 그리고 자주 발표하라
일찍, 그리고 자주 발표하는 것은 리눅스 개발모델의 중요한 부분이다. 대부분의 개발자들은 (필자를 포함하여) 아주 사소한 프로젝트가 아니라면 이런 정책은 나쁜 것이라고 생각한다. 초기버전들은 예외없이 버그가 많고, 개발자라면 사용자들의 인내심을 시험하고 싶어하지 않기 때문이다. 이런 믿음이 성당건축 스타일의 개발을 더 선호하게 만들었다. 만일 가장 중요한 목표가 사용자들로 하여간 가능한 한 적은 버그를 발견하게 만드는 것이라면 6 개월에 한 번씩, 혹은 그보다 더 늦게 발표하면서 그동안 죽어라고 일하는 편이 나을 것이다. Emacs C 코어는 이런 식으로 개발되었다. Lisp 라이브러리는 그렇지 않았다. Emacs 의 발표주기와 관계없이 언제든 새로운 개발 코드 버전을 찾을 수 있으며, FSF 의 통제권 밖에 있는 Lisp 라이브러리들이 있었기 때문이다. 이들 중 가장 중요한 아카이브는 오늘날 대형 리눅스 아카이브들의 정신과 많은 기능들을 이미 가지고 있었던 오하이오 주 elisp 아카이브였다. 하지만 우리가 하고 있는 일에 대해, FSF 의 성당건축 개발모델의 문제점들에 대해 그 아카이브의 존제가 무엇을 제시하는지에 대해 우리들 중 소수만이 진지하게 생각하고 있었다. 나는 1992년에 오하이오 코드를 모다 공식적인 Emacs Lisp 라이브러리로 만들려는 시도를 했으나 정치적인 문제에 부딪쳤고, 큰 실패를 겪었다.
1년 후에, 리눅스가 널리 알려지기 시작했고, 무언가 다르면서도 훨씬 바람직한 일이 일어나고 있다는 것이 확실해 보였다. 리누스의 열린 개발정책은 성당건축과 완전히 반대되는 것이었다. 선사이트와 tsx-11 아카이브가 싹트고 있었고, 다중배포방식이 퍼지기 시작했다. 그리고 이 모든 것이 이전의 어느 소프트웨어보다 자주 릴리즈되는 코어시스템에 의해 주도되고 있었다. 리누스는 가장 효과적인 방식으로 사용자들을 공동개발자라고 여겼던 것이다.
7) 일찍 발표하고 자주 발표하라. 그리고 사용자들의 소리에 귀를 기울이라. (Release early. Release often. And listen to your customers)
리누스의 혁신은 그가 이렇게 했다는 점 보다는 (오랫동안 유닉스 세계의 전통이었던 것처럼) 그가 개발하고 있던 리눅스 커널의 복잡성에 비견될만한 수준으로까지 끌어올렸다는 데 있다. 초기에 (1991년 경에) 그는 하/루/에 한 번 이상 새로운 커널을 발표하기까지 했다. 리누스가 공동개발자들이라는 자신의 기반을 잘 만들었고, 인터넷이라는 지렛대를 이용하여 누구보다도 열심히 협동작업에 몰두했기 때문에 이런 방식은 성공했다. 하지만 어/떤 과정을 거쳐 성공했을까? 내가 재현할 수 있는 것일까, 아니면 리누스 토발즈만의 천재성이 필요한 것일까?
그렇게 생각되지는 않았다. 리누스가 매우 뛰어난 해커라는 점은 인정한다. (우리중에 상업용 제품 못지 않은 운영체제의 커널을 만들어낼 수 있는 사람이 몇이나 될까?) 하지만 리눅스는 놀랄만한 개념적 전진을 이루어내지는 않았다. 리누스는 리차드 스톨먼이나 제임스 고슬링 (NeWS 와 자바를 만든) 과 같은 혁신적인 설계를 이루어내는 천재는 (적어도 지금까지는) 아니없다. 대신 리누스는 공학의 천재인 것으로 보인다. 버그와 개발의 막다른 골목을 피하는 육감, 그리고 A 점에서 B 점까지 가는데 최소노력경로를 찾아내는 요령을 갖추고 있었다. 실제로 리눅스의 전반적인 설계는 이런 특성을 바탕으로 하고 있으며 리누스의 본질적으로 보수적이고 단순한 설계 방식을 반영하고 있다. 따라서 빠른 릴리즈와 인터넷을 매체로 사용하는 것은 우연히 이루어진 것이 아니라 리누스의 공학에 대한 천재성의 일부분으로 최소노력경로에 대한 통찰력으로 된 것이라면 그가 최대화 하고 있는 것은 무엇이었을까? 기계에서 무엇을 뽑아내었던 것일까?
해답은 질문 안에 있다. 리누스는 그의 해커/유저들에게 지속적인 자극과 보답을 제공했다. 리눅스 개발에 참여함으로써 자기만족을 얻으리라는 전망에 자극받았고, 그들이 하는 일이 계속해서 (어떤 때는 날/마/다) 향상되고 있다는 것이 보답이 되었다. 리누스는 코드의불안정성과 만일 처리하기 곤란한 심각한 버그가 발견되면 사용자들이 떨어져 나갈 것을 무릅쓰고 디버깅과 개발에 투입되는 공수(the number of person-hours)를 최대화 하는 것에 목표를 두었다. 리누스는 다음과 같은 신념을 가지고 있는 것처럼 행동했다.
8) 충분히 많은 베타테스터와 공동개발자가 있으면 거의 모든 문제들은 빨리 파악될 것이고 쉽게 고치는 사람이 있게 마련이다. (Given a large enough beta-tester and co-developer base, almost every problem will be characterized quickly and the fix obvious to someone)
덜 형식적으로 말하자면, “눈알이 충분히 많으면 찾지 못할 버그는 없다”. 나는 이것을 “리누스의 법칙” 이라고 부른다.
내 원래의 공식적인 서술은 모든 문제는 “누군가에게는 간단할 것이다” 였다. 리누스가 문제를 이해하고 고치는 사람이 그 문제를 처음 파악한 사람과 항상 같은 것이 아니라 오히려 다를 경우가 더 많다고 이의를 제기했다. 리누스 말로는 “누군가 문제를 발견합니다. 그리고 또/다/른 누군가가 그 문제를 이해하지요. 문제를 발견해 내는 것이 더 중요한 일이라고 분명히 말할 수 있습니다.” 하지만 가장 중요한 점은사람이 충분히 많을 경우 이 두 가지가 모두 매우 빨리 일어나는 경향이 있다는 것이다.
내 생각에는 여기에 성당건축과 시장 스타일의 핵심적인 차이점이 있다. 프로그래밍의 성당건축가의 관점에서 보자면 버그와 개발 문제는 어렵고, 까다로우며 심오한 현상이다. 문제를 해결하려면 헌신된 소수의 사람이 몇 달이고 정밀한 검사를 수행해야 모두 끝났다는 확신을 가질 수 있다. 따라서 발표 사이의 기간이 길어지고, 오랫동안 기다린 릴리즈가 완벽하지 않을 때는 필연적으로 실망이 따른다. 반면, 시장의 관점에서는 버그가 보통 쉽게 해결할 수 있는 것이라고 본다 – 최소한 새로운 릴리즈가 나올때마다 그것과 씨름하는 수천의 열정적인 공동개발자들에게 알려진다면 금방 쉽게 해결할 수 있는 문제로 바뀐다. 따라서 더 많이 교정을 받고 싶다면 자주 발표해야 하며 덤으로 서투른 부분이 드러나더라도 덜 창피하게 되는 이점이 있다.
바로 이것이다. 이것으로 충분하다. “리누스의 법칙” 이 틀렸다면 리눅스 커널과 같이 복잡한 시스템은 어떤 것이라도 수많은 손들에 의해 해킹되면서 일찍이 볼 수 없었던 나쁜 상호작용과 발견되지 못한 “심오한’ 버그들에 의해 어느 시점에선가 붕괴되고 말았을 것이다. 반면에, 만일 그 법칙이 옳다면 그 법칙만으로도 리눅스의 상대적으로 적은 버그를 설명할 수 있다.
그리고 이 법칙이 옳다는 점에 대해서는 너무 놀라지 않았어야 할 것이다. 수년 전, 사회학자들은 비슷하게 전문적인 (혹은 비슷하게 무지한) 관찰자들로 이루어진 대중의 평균적인 의견이 그 관찰자 중 무작위로 뽑은 한 명의 의견보다 더 신뢰할 만하다는 점을 발견했다. 사회학자들은 이것을 “델파이 효과” 라고 부른다. 리누스가 보여준 것은 이 효과가 운영체제를 디버깅하는 데에도 적용될 수 있다는 점이다. 델파이 효과는 OS 커널만큼 복잡한 개발까지도 다룰 수 있는 것이다.
고맙게도 제프 덧키(Jeff Dutck) 는 리누스의 법칙을 “디버깅은 병렬처리가 가능하다” 는 말로 표현할 수 있음을 지적해 주었다. 제프는 디버거들이 디버깅을 하려면 의사소통을 조정해주는 개발자가 필요하지만 디버거들 사이에는 그다지 조정이 필요하지 않다고 진술한다. 따라서 개발자를 추가하는데서 생기는 기하급수적인 복잡성과 관리의 어려움이 디버깅에는 짐이 되지 않는다.
실제로 리눅스 세계에서는 디버거의 작업이 중복됨으로써 생기는 이론적인 효율의 저하가 거의 문제되었던 적이 없는 것으로 보인다. “빨리, 그리고 자주 발표하는 정책” 의 효과 중 하나는 피드백 되어오는 수정사항을 빨리 전파함으로써 중복이 최소화된다는 것이다. 브룩스(Brooks)는 제프의 진술과 관련하여 즉석에서 다음과 같은 말을 했다. “널리 사용되는 프로그램의 유지보수에 들어가는 비용은 보통 개발시 드는 비용의 40 퍼센트나 그 이상입니다. 놀랍게도 이 비용은 사용자의 수에 큰 영향을 받습니다. 더/많/은 사/용/자/들/이 더/많/은 버/그/들/을 찾/아/냅/니/다.” (필자의 강조) 사용자들이 많아지면 프로그램을 시험해보는 방법이 더 늘어나기 때문에 버그를 더 많이 잡아낼 수 있다. 이 효과는 사용자들이 공동개발자들일 때 더욱 커진다. 각 사람들이 버그를 찾아낼 때 조금씩 다른 개념의 집합과 분석 도구들을 사용하여 문제의 다른 각도에서 접근하기 때문이다. “델파이 효과” 는 바로 이런 편차에서 비롯되는 것으로 보인다. 또한 디버깅이라는 특정한 환경에서 이 편차는 노력의 중복을 줄여주는 경향이 있다.
따라서 더 많은 베타테스터를 가지는 것은 개/발/자/의 관점에서 현재의 “가장 심오한” 버그의 복잡성을 줄여주지는 않을 테지만, 누군가의 도구가 문제에 딱 들어맞아 그 버그가 그/사/람/에/게/는 쉽게 잡을 수 있는 것이 될 가능성을 높여준다. 리누스도 물론 할 일이 있었다. 심각한 버그가 있/을 경우에 대비해 리눅스 커널 버전은 잠재 사용자들이 최종적으로 “안정된” 버전을 사용할 수도 있고 새로운 기능을 사용하기 위해 최신의 버그가 있을 수 있는 버전을 사용할 수도 있게 번호가 붙여졌다. 이 전술은 아직까지 대부분의 리눅스 해커들이 따라하지는 않고 있지만 아마도 따라하게 될 것이다. 두 가지 선택이 가능하다는 사실이 양쪽 모두를 더 매력적으로 보이게 한다.
5. 장미가 장미다우려면
리누스의 행동을 연구하고 그것이 왜 성공적이었는지에 대한 이론을 만든 후, 나는 이 이론을 내 새로운 프로젝트 (물론 훨씬 덜 복잡하고 덜 야심적인 프로젝트) 에 적용해 보기로 했다.
그러나 내가 가장먼저 한 일은 popclient를 더 재조직화하고 단순화한 것이었다. 칼 해리스 (Carl Harris) 의 구현방식은 매우 건강한 것이었지만 많은 C 프로그래머들에게서 볼 수 있었던 것처럼 일종의 불필요한 복잡성을 보여주고 있었다. 그는 코드를 중심적인 것으로, 자료구조는 코드를 받쳐주는 것으로 취급했다. 그 결과 코드는 아름답지만 자료구조는 임시변통으로 설계되었고, 보기에 좋지 않았다. (최소한 옛 LISP 해커의 높은 기준에서 보자면 말이다) 그리고 코드와 자료구조를 개선하는 것 말고도 나는 또다른 목적을 하지고 있었다. popmail을 내가 완전히 이해하는 무엇인가로 진화시키고 싶었다.
이해하지 못하는 프로그램의 버그수정책임을 맡는 것은 괴로운 일이다. 처음 한달 정도가 지날 동안 나는 그저 칼의 기본적인 설계가 어떤 의미를 가지고 있는지 따라다니기만 했다. 내가 처음으로 중요한 수정을 가한 것은 IMAP 지원이었다. 프로토콜 머신을 일반적인 드라이버와 세가지 메소드 테이블 (POP2, POP3, IMAP을 지원하는) 로 재조직했다. 이것과 그 이전의 변경들은 프로그래머들이 기억해 둘만한 일반적인 원리를 보여준다. 특히 C 와 같이 즉흥적으로 프로그램하기 힘든 언어에서는.
9) 자료구조를 훌륭하게 만들고 코드를 멍청하게 만드는 것이 그 반대의 경우보다 훨씬 잘 작동한다. (Smart data structures and dumb code works a lot better than the other way around)
브룩스의 책 9 장(Chapter 9) 에 이렇게 쓰여있다. “내게 [코드]를 보여주고 [자료구조]를 숨긴다면 나는 계속 어리둥절할 것이다. 자료구조를 보여준다면 코드는 볼 필요도 없이 뻔한 것이다.” 사실 브룩스는 “흐름도” 와 “테이블” 이라고 이야기했다. 하지만 30년간 변해온 용어들과 문화를 고려한다면 거의 똑같은 말이라고 할 수 있다.
이 시점에서 (1996년 9월 초, 일을 시작하고 6 주가 지난 후) 나는 이름을 바꿀 때가 되었다고 생각하기 시작했다. 이 프로그램은 더 이상 POP 클라이언트만이 아니었다. 하지만 설계상에 정말 새로운 것이 들어가 있지 않았기 때문에 머뭇거리고 있었다. 내가 만든 popclient 는 아직 스스로의 정체성을 확립하지 못하고 있었다.
fetchmail 이 어떻게 SMTP 포트로 가져온 메일을 포워드 시켜야 하는지 알고 난 후에는 상황이 급변할 것이었다. 잠시 후면 그렇게 될 것이 분명했다. 하지만 그보다 먼저, 앞서 나는 리누스 토발즈가 옳은 방법으로 일을 해냈다는 내 이론을 시험하기 위해 이 프로젝트를 수행하기로 했다고 말했다. 어떻게 시험을 했을까? 다음과 같은 방법을 사용했다.
(1) 일찍, 자주 발표했다. (발표간격이 10일을 넘는 경우는 거의 없었으며 개발에 몰두해 있을 때는 하루에 한번씩 발표했다)
(2) fetchmail 에 대한 일로 나와 접촉하는 사람은 누구든지 베타테스터 목록에 올렸다.
(3) 새로 발표할 때마다 베타테스터들에게 떠들썩하게 발표를 알리며 사람들이 참여하도록 격려했다.
(4) 그리고 그들의 이야기를 들었다. 설계 결정에 대해 투표를 하기도 했고 패치나 피드백을 보내올 때마다 베타테스터들을 구슬렀다.
이 단순한 방법들은 즉각 효력을 나타냈다. 프로젝트를 시작할 때부터 개발자들이라면 학수고대할 만한 버그 리포트를, 때로는 훌륭하게 수정된 코드를 받을 수 있었다. 사려깊은 비판과 팬 메일, 기능제안들을 받았다. 이것은
10) 베타테스터들을 가장 중요한 자원으로 여긴다면 그들은 정말 가장 중요한 자원이 되어준다. (If you treat your beta-testers as if the’re your most valuable resource, they will respond by becoming your most valuable resource)
fetchmail 의 성공을 재는 재미있는 척도 중 하나는 프로젝트 베타테스터 메일링리스트인 fetchmail-friends 의 크기이다. fetchmail을 개발하고 있을 때 목록에는 249 명이 있었고 1주일에 2-3 명이 추가되었다. 1997 년 5월말 경에 수정을 했을 때 목록은 300명 가까이 되었고, 멤버들이 흥미로운 이유 때문에 조금씩 줄기 시작했다. 몇몇 사람들이 구독을 중단하면서 fetchmail 이 잘 작동하기 때문에 더 이상 메일링리스트를 보고 있을 이유가 없다고 말했다. 아마 이것이 성숙한 시장 스타일의 프로젝트가 가지는 일반적인 라이프사이클 중 하나일 것이다.
6. Popclient가 Fetchmail이 되다
fetchmail 프로젝트에서 큰 전환이 일어났던 것은 해리 호흐하이저(Harry Hochheiser) 가 클라이언트 머신의 SMTP 포트로 메일을 포워딩하는 대략적인 코드를 보내준 때였다. 보자마자 이 기능을 안정적으로 구현한다면 다른 모든 배달 방법은 구식이 되리라는 것을 깨달았다. 여러 주 동안 나는 fetchmail을 조금씩 뜯어고치고 있었는데, 인터페이스 설계가 작동하긴 하지만 지저분하다고 느끼고 있었다. 우아하지도 않고 몇 안되는 옵션들이 너무 여기저기 흩어져 있었다. 가져온 메일을 메일박스 파일에 부어놓을 것인지, 표준출력으로 내보낼 것인지 결정하는 옵션이 특히 골치거리였지만 왜 그런지 확실히 깨닫지는 못했다.
SMTP 포워딩을 생각하자 그동안 popclient 가 너무 많은 것을 해내려고 했다는 것을 알게 되었다. poopclient 는 MTA (Mail Transport Agent) 와 MDA (Mail Delivery Agent) 기능을 모두 가지도록 설계되었다. SMTP 포워딩만 할 수 있다면 MDA 기능을 없애 순수한 MTA 가 될 수 있었다. sendmail 과 마찬가지로 최종적인 메일 배달은 다른 프로그램에게 맡기면 되는 것이다.
TCP/IP를 지원하는 플랫폼이라면 거의 어디에나 25번 포트가 기다리고 있는데 무엇 때문에 복잡한 MDA 기능을 설정하거나 메일박스를 잠그고 덧붙이는 (lock-and-append) 문제를 가지고 고생을 하는가? 더구나 포워딩을 사용하면 가져온 메일이 평범한 SMTP 메일처럼 보일 것이고, 우리가 원하는 것이 바로 그것이었는데 말이다.
몇가지 배울 점이 있었다. 먼저, SMTP 포워딩에 대한 아이디어는 내가 리누스의 방법을 모방하려고 의식적으로 노력한 것에 대한 가장 큰 보답이었다. 사용자 한 명이 내게 끝내주는 아이디어를 주었다. 내가 해야했던 일은 그 의미를 이해하는 것 뿐이었다.
11) 좋은 아이디어를 생각해내는 것 다음으로 중요한 일은 사용자들이 알려준 좋은 아이디어를 깨닫는 것이다. 때로는 이편이 더 나을 수도 있다. (The next best thing to having good ideas is recognizing good ideas from your users. Sometimes the latter is better )
흥미롭게도 만일 당신이 얼마나 다른사람에게 빚을 많이 지고 있는지를 자기비하라고 느껴질 정도로까지 솔직하게 털어놓는다면 대개의 사람들은 당신이 혼자서 거의 모든 일을 해내고서 천재성에 대해서 겸손해 하는 것처럼 대한다는 것을 곧바로 알게 될 것이다. 리누스의 경우를 보라! (1997년 8월, Perl 컨퍼런스에서 이 글을 발표할 때 래리 월이 첫 번째 줄에 앉아 있었다. 바로 윗 줄에 도달했을 때 그는 부흥사라도 된 것처럼 외쳤다. “형제여, 이야기 하시오, 이야기를!” 청중들 모두가 이것이 Perl을 만든 래리에게도 적용된다는 것을 알았기 때문에 웃음을 터뜨렸다)
똑같은 정신으로 프로젝트를 몇 주 진행해 나가자 나는 사용자들 뿐 아니라 이야기를 전해들은 다른 사람들로부터 비슷한 칭송을 받기 시작했다. 나는 그런 email 중 몇몇을 따로 보관해 두었다. 나중에 내 삶이 가치있는 것이었는지 의심스러워질 때 그 메일들을 다시 꺼내볼 생각이다. 🙂
모든 종류의 설계에 대해서 적용될 수 있는 두가지 더 기본적이며 비정치적인 교훈이 있다.
12) 종종 가장 충격적이고 혁신적인 해결책은 당신 자신이 문제에 대해서 가지고 있는 개념이 잘못되어 있다는 것을 깨닫는 것에서 나온다. (Often, the most striking and innovative solutions come from realizing that your concept of the problem was wrong)
나는 popclient를 MTA/MDA 기능을 다 갖추고 복잡한 지역배달모드들까지 (local delivery modes) 갖춘 것으로 개발해 나가면서 틀린 문제를 풀려고 노력하고 있었다. fetchmail 의 설계는 가장 기초적인 것부터 재고하여 SMTP 포트로 메일을 배달하는 인터넷 메일 경로의 한 부분인 순수 MTA 가 되어야 했다. 개발도중에 벽에 부딪친다면 – 다음번 패치 후에 무엇을 해야 할 지 모르겠다면 – 그때는 정답을 가지고 있는지 생각할 것이 아니라 질문이 올바른 것인지 의문을 가져보아야 하는 경우가 종종 있다. 아마도 문제의 틀을 다시 잡아야 할 것이다.
그래서, 나도 내 문제의 틀을 다시 잡았다. 분명히 제대로 일을 진행하려면 (1) SMTP 포워딩 지원 기능을 일반 드라이버에 포함시키고, (2) SMTP 포워딩을 기본모드로 만들고 (3) 최종적으로는 다른 배달모드들, 특히 ‘파일로 배달하기’ 와 ‘표준출력으로 배달하기’를 제거해야 했다.
나는 단계 (3)에서 조금 머뭇거렸는데, 이유는 오랫동안 popclient를 써오면서 다른 배달모드에 의존하고 있을 사용자들의 심기를 불편하게 만들고 싶지 않았기 때문이다. 이론적으로는 그들 모두 즉시 .forward 파일이나 sendmail 외의 비슷한 프로그램으로 전환하여 동일한 결과를 얻을 수 있었다. 실제로는 전환 자체가 큰 일이 될 것이었다.
하지만 단계 (3)을 실행하고 나자 이점이 매우 큰 것으로 나타났다. 드라이버 코드 중 가장 힘든 부분이 사라졌다. 설정이 엄청나게 간단해졌다 – 시스템의 MDA 와 사용자의 메일박스를 찾아다니며 굽실거릴 필요도 없어졌고, OS 가 파일 잠금을 지원하는지 걱정할 필요도 없어졌다.
게다가 메일을 잃어버릴 한가지 가능성도 사라졌다. ‘파일로 배달하기’를 선택했을 때 디스크가 꽉 차 있으면 메일이 사라져 버렸던 것이다. SMTP 포워딩에서는 SMTP 리스너가 메시지 배달이 가능하거나 나중에 대발할 수 있도록 스풀해 놓기 전에는 OK를 돌려주지 않을 것이기 때문에 이런 일이 일어날 수가 없다.
성능도 향상되었다(한두번 실행시켜서는 느끼지 못하겠지만). 변경에 따르는 그다지 중요하지않은 이익이라면 매뉴얼 페이지가 훨씬 간단해 졌다는 것이다. 나중에 나는 사용자가 지정한 지역 MDA를 통해 배달하는 기능을 다시 넣어야 했다. 동적인 SLIP를 포함하여 몇몇 애매한 상황을 다루어야 했기 때문이다. 하지만 처음보다 훨씬 간단한 방법을 찾아낼 수 있었다.
교훈이라면?낡아서 사용할 수 없는 기능이라면 효율을 떨어뜨리지 않고 할 수 있을 때는 망설이지 말고 제거해 버리라. 앙뜨완 드 생떽쥐뻬리는 (아동서적 작가였으며 남는 시간에는 비행기 조종과 설계를 했던) 이렇게 말했다.
13) “(설계에 있어서) 완벽함이란 더 이상 추가할 것이 없을 때 이루어지는 것이 아니라 더 이상 버릴 것이 없을 때 이루어진다. (Perfection (in design) is achieved not when there is nothing more to add, but rather when there is nothing more to take away)”
코드가 더 나아지고 간단해 지고 있을 때가 바로 일이 제대로 되어가고 있다는 것을 “알게 되는” 때다. 그리고 그 과정에서 fetchmail 의 설계는 조상격인 popclient 와 다른, 자신만의 정체성을 획득했다. 이름을 바꿀 때가 된 것이다. 새로운 설계는 예전의 popclient 보다는 sendmail 과 비슷해 보였다. 둘다 MTA 였으나 sendmail 은 푸시(push) 후에 메일을 배달했고 새로운 Popclient 는 풀(pull) 후에 메일을 배달했다. 해서 두 달 후에 나는 Popclient 의 이름을 fetchmail 로 변경했다.
7. Fetchmail 의 성장
이제는 깔끔하고 혁신적인 설계, 매일 사용하므로 잘 작동하는 것을 알고 있는 코드, 발전하고 있는 베타테스터의 목록을 가지고 있었다. 더이상 내가 하고 있는 일이 몇몇의 사람에게 유용할 수도 있는 사소하고 개인적인 해킹은 아니라는 생각이 서서히 들기 시작했다. 내가 가지고 있는 것은 유닉스 박스와 SLIP/PPP 메일 연결을 가지고 있는 모든 해커들이 정말로 필요로 하는 프로그램이었다.
SMTP 포워딩 기능으로 fetchmail 은 경쟁에서 멀찍이 앞서나와 “카테고리 킬러,” 그러니까 해당분야의 다른 프로그램들은 아예 잊혀져 버릴 만한 경쟁력을 갖추고 자신의 지위를 확고하게 하는 고전적인 프로그램이 될 수 있는 능력을 갖추었다.
이런 결과를 계획하거나 목표로 가질 수는 없으리라고 생각한다. 아주 강력한 설계상의 아이디어로 그런 결과가 불가피하고, 자연스러우며 운명적인 것으로 보이게 함으로써 그런 결과에 도달해야 한다. 그런 아이디어를 구체화해 볼 수 있는 유일한 방법은 수많은 아이디어를 가지는 것이다. 아니면 다른 사람들의 좋은 아이디어를, 원래 생각되었던 것보다 더 멀리 이끌고 가서 구체화 시켜보는 방법이다.
앤드류 타넨바움 (Andrew Tanenbaum) 은 교습도구로 사용하기 위해 386용으로 간단한 네이티브 유닉스를 만들려는 원래의 아이디어를 가지고 있었다. 리누스 토발즈는 이 미닉스의 개념을 앤드류가 생각했던 것보다 더 멀리 밀고 나갔다. 그래서 리눅스는 굉장한 것이 되었다. 똑같은 방식으로 (더 작은 스케일이었지만) 나는 칼 해리스와 해리 호흐하이저의 아이디어들을 가져와 강하게 밀어붙였다. 리누스나 나나 사람들이 천재들이 그러하리라고 생각하는 낭만적인 의미에서 ‘독창적’ 인 것은 아니었다. 하지만 통념과는 반대로 대부분의 과학과 공학과 소프트웨어 개발은 독창적인 천재, 해커의 전설에 의해서 이루어지지 않는다.
결과물은 똑같이 매우 사람을 흥분시키는 것들이다 — 사실, 모든 해커들은 이런 종류의 성공을 얻기 위해 살아간다! 거기에는 내가 기준을 더 높이 잡아야 한다는 의미도 들어있다. fetchmail을 최상의 것으로 만들기 위해 나는 내자신의 필요뿐 아니라 나와는 상관없지만 다른 사람들에게는 필수적인 기능을 포함시키고 지원해야했다. 게다가 프로그램을 단순하고 튼튼하게 유지시키면서 그런 일을 해야 했다.
이것을 깨닫고 나서 내가 추가한 매우 중요한 첫 번째 기능은 멀티드롭(multidrop) 기능이었다. 그룹이나 사용자들의 메일을 한꺼번에 가지고 있는 메일박스에서 메일을 가져와 각 메일들을 개인 수신자에게 라우트(route) 시켜주는 기능이었다.
멀티드롭 기능을 추가하기로 한 데는 몇몇 사용자들이 원한다는 것도 있었지만 가장 큰 이유는 어드레싱을 완전히 구현함으로써 싱글드롭 코드에 있는 버그들을 잡아낼 수 있으리라고 생각했기 때문이다. 그리고 그렇게 되었다. RFC822(http://www.internic.net/rfc/rfc822.txt) 의 파싱을 제대로 구현하는 것에 매우 오랜 시간이 걸렸는데, 각각의 조각이 어려웠기 때문이 아니라 각각이 서로 의존하고 있으며 세심하게 신경을 써야 하는 사항들이었기 때문이다. 하지만 멀티드롭 어드레싱 역시 매우 훌륭한 설계상의 결정이었던 것으로 드러났다. 다음과 같은 교훈을 얻을 수 있었다.
14) 어떤 도구든지 기대하는 방법으로 쓸모가 있어야 하지만 정말 위대한 도구는 사용자가 전혀 기대하지 않았던 용도에 알맞게 된다. (Any tool should be useful in the expected way, but a truly great tool lends itself to uses you never expected)
미처 생각하지 못했던 멀티드롭 fetchmail 의 용도는 메일링리스트를 그대로 유지한 채, 알리아스 확장이 된 채로 SLIP/PPP로 연결된 클/라/이/언/트 쪽에서 메일링리스트를 운영하는 것이었다. 개인의 컴퓨터로 ISP 계정을 통해 접속하는 사람이 ISP 의 알리아스 파일에 지속적으로 접근하지 않고도 메일링리스트를 운영할 수 있다는 것을 의미한다.
베타테스터들이 요구한 중요한 변경사항중 또 하나는 8비트 MIME 오퍼레이션이었다. 이것은 내가 코드를 8비트에 대비하여 계속 유지시켜왔기 때문에 매우 쉬운 일이었다. 이런 기능에 대한 요구를 미리 예측해서 그랬던 것은 아니다. 다음과 같은 규칙을 따르려고 해서였다.
15) 어떤 종류든 게이트웨이 소프트웨어를 만들려고 한다면 데이터스트림에 가능한 한 최소한의 조작만 가하라 — 그리고 수신자가 강제로 하게 하지 않는다면 정보를 *절대로* 잘라버리지 말라. (… the data stream as little as possible — and *never* throw away informtion unless the recipient forces you to!)
이 규칙을 따르지 않았다면 8비트 MIME 지원은 매우 어려웠을 것이며 많은 버그를 만들어 냈으리라. 규칙을 따랐기 때문에 내가 해야 할 일은 RFC 1652 (http://www.internit.net/rfc/rfc1652.txt)를 읽고 헤더생성 로직을 약간 수정하는 것 뿐이었다.
유럽의 몇몇 사용자들은 한 세션에서 가져올 수 있는 메시지의 수를 제한하도록 옵션을 추가해달라고 요구해왔다. (전화 네트워크의 비싼 비용을 조절할 수 있도록 해달라는 말이다) 오랫동안 여기에 저항했고, 아직도 완전히 수긍하지 못했다. 하지만 세계를 상대로 프로그램을 만든다면 고객들의 소리에 귀를 기울여야 한다 — 그들이 돈을 지불하지 않는다고 해도 마찬가지다.
8. Fetchmail에서 배울 점
일반적인 소프트웨어공학의 주제로 돌아가기 전에 fetchmail 의 경험으로부터 배울 점이 몇 가지 더 있다. rc 파일의 구문은 선택사항으로 ‘noise’ 라는 키워드를 포함하는데 이것은 파서에 의해 무시된다. rc 파일에서 허용하는 영어와 비슷한 구문은 잘라낼 것을 모두 잘라낸 후에 얻는 전통적이고 간명한 키워드-밸류 짝에 비해 훨씬 알아보기 쉽다.
이것은 내가 rc 파일의 선언들이 명령형 소언어 (imperative minilanguage)를 얼마나 많이 닮아가기 시작했는지 알아차리고 나서 한밤중의 실험으로 시작되었다. (popclient 의 ‘server’ 라는 키워드를 ‘poll’ 로 바꾼 이유도 이것이다)
명령형 소언어를 더 영어처럼 만들면 사용하기 쉬울 것으로 보였다. 지금은 내가 비록 Emacs 나 HTML, 그리고 많은 데이터베이스 엔진에서 볼 수 있듯이 설계를 할 때 “언어처럼 만드는” 파의 일원이긴 하지만 “영어와 비슷한” 구분을 가지는 것에 대해서는 그다지 달가와 하지 않는다.
전통적인 프로그래머들은 정확하고 짧으며 중복을 허용하지 않는 제어구문을 선호하는 경향이 있다. 이것은 컴퓨팅 자원이 비싸서 파싱하는 단계가 최대한 싸고 간단해야 했을 때부터 내려온 문화적 유산이다. 영어는 대략 50% 정도의 중복을 허용하므로 대단히 부적절한 모델인 것으로 보인다.
이것이 내가 영어와 비슷한 구문을 보통 피하는 이유는 아니다. 이 문제를 언급한 이유는 그런 관습을 없애기 위해서다. 사이클과 코어의 값이 싸졌는데도 간명함은 저절로 없어지지는 않았다. 최근에는 언어가 컴퓨터의 관점에서 싼 가격이라는 점 보다는 사람에게 편리한가 하는 점이 더 중요하다.
물론 조심해야 할 충분한 이유는 있다. 한가지는 파싱하는 단계의 복잡성에 대한 비용이다 — 파싱하는 단계를 버그가 우글거리는 데다가 사용자로 하여금 그 자체만으로 혼란을 일으키게 만들고 싶지는 않을 것이다. 또 하나의 이유는 언어의 구문을 영어와 비슷하게 만들려고 노력하면 그 “영어” 가 심각하게 왜곡되어 자연어와의 피상적인 유사점이 전통적인 구문만큼이나 혼란스럽게 되는 경우가 많다는 점이다. (소위 “4세대” 언어와 상업용 데이터베이스 질의어에서 이런 경우를 많이 볼 수 있다)
fetchmail 제어구문은 이런 문제를 피하려고 했다. 언어의 영역이 매우 제한되어 있었기 때문이다. 일반적인 목적의 언어와는 거리가 멀었다. 언어가 표현하는 것이 별로 복잡하지 않았기 때문에 영어의 일부분에서 실제 제어언어로 옮겨가는데 혼란을 일으킬 가능성이 적었다. 더 넓은 의미의 교훈을 여기에서 얻었다.
16) 언어가 튜링-컴플리트하지 않다면 구문상의 유연성이 필요하다. (When your language is nowhere near Turing-complete, syntactic sugar can be your friend)
또하나의 교훈은 불투명함에 의한 보안에 대해서이다. fetchmail 의 사용자 중에는 스누퍼들이 우연히 패스워드를 보지 못하도록 rc 파일에 있는 패스워드를 암호화하여 가지고 있게 하자고 이야기하는 사람들이 있었다.
나는 그 이야기를 받아들이지 않았는데, 그렇게 한다고 해서 보안이 강화되는 것이 아니기 때문이다. rc 파일의 읽기 퍼미션을 얻은 사람이라면 사용자와 마찬가지로 fetchmail을 실행시킬 수도 있는 것이다 — 그리고 그들이 패스워드를 원하는 것이라면 패스워드를 얻기 위해 fetchmail 코드에서 디코딩하는 코드를 뽑아낼 수도 있다.
fetchmail 의 패스워드를 암호화 했다면 사람들은 그리 심각하게 생각하지도 않고 보안에 대해 잘못된 관념을 가지게 되었을 것이다. 여기서 알 수 있는 일반적인 규칙은 다음과 같다.
17) 보안시스템은 그것이 보호하려고 하는 비밀만큼만 안전하다. 가짜 비밀들에 주의할 것. (A security system is only as secure as its secret. Beware of pseudo-secrets)
9. 시장 스타일의 개발에 필요한 선행조건들
이 글을 초기에 검토해준 사람들과 시험적으로 청중이 되었던 사람들은 계속해서 성공적인 시장 스타일의 개발을 위한 선행조건이 무엇인지 물었다. 여기에는 공동개발자의 공동체를 만들기 위해 프로젝트가 공개되는 시점에 리더의 자질과 코드가 어떤 상태인지가 포함된다.
아예 처음부터 시장스타일로 개발할 수 없다는 것은 자명하다. 테스트, 디버그, 그리고 개선은 시장 스타일로 할 수 있다. 하지만 프로젝트를 시/작/할/때/ 시장 스타일로 시작하기는 매우 어렵다. 리누스는 그렇게 하지 않았다. 나도 마찬가지. 개발자들의 공동체는 초기에 실행시키면서 테스트할 수 있는 장난감이 필요하다.
공동체를 만들기 시작할 때 제시할 수 있어야 하는 것은 그럴듯한 장래성이다. 프로그램이 특별히 잘 작동할 필요는 없다. 조잡하거나, 버그투성이여도 되고, 완성되지 않고 문서가 형편없어도 상관없다. 하지만 한가지 확실하게 해야할 것은 잠재적인 공동개발자들에게 이것이 머지 않은 미래에 정말 괜찮은 무언가로 진화할 수 있다는 것을 납득시키는 일이다.
리눅스와 fetchmail 둘 다 강력하고 매력적인 기본설계를 가지고 공개되었다. 내가 시장모델에 대해 이야기하자 많은 사람들이 이것을 중요하다고 생각했고, 높은 수준의 설계에 대한 직관과 영리함이 프로젝트의 리더에게는 필수적인 것이라고 지레짐작으로 결론을 내려버렸다.
하지만 리누스는 그의 설계를 유닉스에서 따왔고 나는 기본적으로 popclient에서 가져왔다. (물론 나중에 많은 것이 바뀌긴 했지만 리눅스는 그보다 훨씬 더 바뀌었다). 그렇다면 시장스타일의 리더/조정자에게 정말 특별한 설계의 재능이 필요한 것일까, 아니면 다른 사람들이 가진 설계의 재능을 이끌어 내는 것이 필요한 것일까?
나는 조정자가 특별하게 영리해서 독창적인 설계를 만들어낼 수 있는지의 여부가 중요하다고 생각하지 않는다. 하지만 조정자가 다/른/사/람/의 좋/은/ 설/계/를 알/아/볼 수 있는지는 절대적으로 중요하다.
리눅스와 fetchmail 프로젝트는 이에 대한 증거를 보여주고 있다. 리누스는 (앞서 논했듯이) 대단히 독창적인 설계자라고는 할 수 없으나 좋은 설계를 알아보는 대단한 요령을 보여주었고, 그것을 리눅스 커널에 통합해 넣었다. 앞서 fetchmail에서 가장 강력한 설계상의 아이디어 하나 (SMTP 포워딩) 가 다른 누군가로부터 온 것이라고 설명한 바 있다.
이 글의 초기 청중들은 내가 설계상의 독창성을 과소평가하는데 내가 그런 독창성을 가지고 있기 때문에 당연한 일로 생각한다고 주장하며 내게 경의를 표시했다. 어느 정도는 사실이다. 설계는 분명히 (코딩이나 디버깅에 비해서) 내가 가장 잘하는 일이다.
하지만 소프트웨어 설계에 있어서 똑똑하고 독창적이라는 것의 문제점은 그게 버릇이 되어버린다는 점이다 — 설계를 강력하고 단순하게 유지해야 할 때 그렇게 하지 않고 계속해서 일을 멋지고 복잡하게 만들기 시작한다. 이전의 프로젝트에서 나는 그런 성향 때문에 실패한 적이 있었다. fetchmail 에서는 간신히 그것을 이겨냈다.
그래서 나는 fetchmail에서