지금 볼 때는 매우 비합리적이거나 이상하게 보이는 과거의 결정이 당시에 쓸 수 있었던 컴퓨팅 자원과 환경의 한계 속에서는 충분히 자연스럽게 귀결 가능한 결론이었다는 것을 이해하게 될 것이다. (21쪽)
코드를 명확하게 작성하고, 지나친 재주를 부리지 말라. (51쪽)
대학교에서 20년간 학생들을 가르친 지금도 다른 사람이 한 일에 비판적인 의견을 내는 일에는 썩 마음이 내키지 않는다. 하지만 그것은 필요한 일이고 때때로 우리는 다른 사람의 삶에 영향을 주는 결정을 내려야만 한다. 예를 들면 누군가를 해고하거나, 학생들을 낙제시키는 일이 그렇다. 벨 연구소의 평가 방식이 좋았던 점은, 연구자의 일을 이해하는 다른 사람들의 공동 판단을 최종 평가의 기초로 두었다는 점이다. 더글러스 매클로이가 말했듯이 "벨 연구소 평가 제도의 특징은 동료 간의 협력 관계를 지향했다는 점이다. 그 누구의 진급도 단 한 명의 상사와의 관계로만 결정되지 않았다." 벨 연구소의 평가 절차가 완벽하지는 않았지만 꽤 훌륭했다. 나는 그보다 훨씬 더 나쁜 인사 고과 절차에 대해 분명히 보고 들은 적이 있다. (68쪽)
컴퓨터는 근본적으로는 계산기와 크게 다르지 않다. 하지만 컴퓨터는 산술 연산을 극도로 빠르게 수행할 수 있다. 요즘은 초당 몇십억 번의 연산을 할 수 있는데, 1970년대에는 초당 백만 번에 크게 못 미쳤다. (72쪽)
프로그램에 아주 심한 문제가 발생하면, 운영체제는 그것을 감지하고 프로그래머가 문제를 해결하는 데 도움을 주고자 주기억장치의 내용(자기 코어에 있던 내용)을 담은 파일을 생성했다. 여기서 '코어 덤프core dump'라는 표현이 나왔는데, 이 단어는 자기 코어가 한참 전에 사라졌음에도 불구하고 여전히 사용되고 있다. 생성되는 파일 이름도 그대로 core다.(114쪽)
유닉스에서 파일은 그저 일련의 바이트다. 파일 내용의 구조나 조직은 그 파일을 처리하는 프로그램에 의해서만 결정되고, 파일 시스템 자체는 파일 내에 뭐가 있는지 신경 쓰지 않는다. 이 말은 어떤 프로그램이든 어떤 파일이라도 읽거나 쓸 수 있음을 의미한다. 지금에 와서야 이 아이디어가 명백해 보이지만, 이전 운영체제에서는 항상 그렇게 인식되지는 않았고, 가끔은 파일 내 정보의 형식과 프로그램이 정보를 처리하는 방식에 임의로 제한을 걸기도 했다. 더글러스 매클로이가 한 가지 예를 설명한다.
"일반적으로 소스 코드는 데이터와는 다른 구별된 타입이었네. 컴파일러는 소스코드를 읽을 수 있었고, 컴파일된 프로그램이 '데이터'를 읽고 쓸 수 있었지. 그래서 포트란 프로그램을 생성하고 검사하는 일은 다른 파일을 생성하고 검사하는 일과는 종종 엄격히 구분됐고, 두 가지를 편집하고 출력하는 데 서로 완전히 다른 방법이 필요했네. 이 때문에 프로그램을 이용해서 포트란 프로그램을 생성하는 것은(또는 그냥 복사하는 것조차) 원천적으로 불가능했다네."
유닉스는 그러한 구분을 두지 않았다. 어떤 프로그램이든 어떤 파일을 처리할 수 있었다. 특정한 파일에 특정한 프로그램을 적용할 수 없다면(예를 들어 포트란 소스 파일을 마치 C 소스 파일인 양 컴파일하려는 것처럼), 이는 운영체제와는 전혀 관계없는 프로그램과 파일 간의 문제다. (125-126쪽)
예전 운영체제에서는 실제 장치의 무수한 복잡성이 사용자에게 그대로 전해졌다. 사용자는 디스크 이름, 트랙과 실린더 수 같은 물리적 구조, 디스크에서 데이터가 조직화된 방식까지 모두 알아야 했다. 스티븐 존슨은 과거에 주로 사용하던 하니웰(Honeywell) 컴퓨터의 시분할 서브시스템에서 파일을 다루기 얼마나 까다로웠는지 알려준 적이 있다.
"하니웰 TSS 시스템에서 디스크 파일을 생성하려면 서브시스템 정보를 입력해야 했죠. 질문이 여덟 개 정도 나왔어요. 파일의 첫 크기, 최대 크기, 파일명, 사용할 디바이스, 누가 읽을 수 있는지, 누가 쓸 수 있는지 등이 있었죠. 질문 각각에 대화식으로 답을 입력해야 했어요. 모든 질문에 답을 하고 나면 운영체제에 정보가 입력되고, 십중팔구 뭔가 타이핑이 잘못되어 파일 생성에 실패하곤 했습니다. 그 말은 서브시스템 정보를 다시 입력하고 모든 질문에 다시 대답해야 했다는 뜻이죠. 파일이 마침내 생성됐을 때 시스템이 '성공적!'이라고 표시하는 것도 놀랄 일이 아니었습니다."
(129-130쪽)
데니스 리치가 1993년에 "The Development of the C Language" 논문에서 다음과 같이 설명한 바 있다.
"B는 타입이 없는 C라고 볼 수 있습니다. 더 정확히 말하자면 B는 8K 바이트 메모리에 맞게 압축되고 켄 톰프슨의 두뇌를 거쳐 필터링된 BCPL이라고 하겠습니다. B라는 이름은 BCPL의 축약형으로 보는 것이 가장 그럴듯하지만, 멀틱스 시절에 켄이 만든 관련 없는 언어인 Bon에서 유래했다는 설도 있습니다. Bon은 그의 아내인 보니(Bonnie)의 이름을 땄거나, (Bon 매뉴얼에서 백과사전을 인용한 내용에 따르면) 주문을 중얼거리는 의식을 치르는 종교의 이름을 가져왔다고 합니다."
(149쪽)
스티븐 자신도 Yacc를 이용해서 새로운 '이식성 있는 C 컴파일러(portable C compiler, PCC)'를 만들었다. PCC는 C언어를 구문 분석하기 위한 공통 전단부front-end와 다양한 컴퓨터 아키텍처용 코드를 생성하기 위해 여러 개로 나누어진 후단부back-end로 구성됐다. (...)
"PCC에서 나온 뜻밖의 부산물은 lint라는 프로그램이었습니다. 린트는 프로그램을 읽어 들여서 이식성이 떨어지는 부분, 혹은 전달 인자 수가 틀리게 함수를 호출하거나 사용된 데이터 크기가 정의된 것과 다른 곳 등 명백히 잘못된 부분을 지적해줬습니다. C 컴파일러는 한 번에 파일 한 개씩만 확인했기 때문에 린트는 파일 여러 개로 이루어진 프로그램을 작성할 때 유용한 도구였습니다. 린트는 유닉스 제 7판을 만들 때 이식성을 판별하는 기준을 적용하는 데도 유용했는데, 에러 반환값이 null(제7판) 대신에 -1(제6판)인 시스템 호출을 찾는 것 같은 경우에 사용했습니다. 이식성 검사를 포함해 이러한 검사 중 많은 부분이 결국 C언어 자체로 흡수됐습니다. 이렇듯 린트는 새로운 기능을 테스트하기에 유용한 시험대였습니다."
린트라는 이름은 옷에서 보풀(lint)을 떼어내는 이미지에서 온 것이다. 린트의 기능은 대부분 C 컴파일러로 흡수됐지만, 린트에 사용된 아이디어는 다른 여러 언어용으로 개발된 유사한 도구에 흔히 나타난다.(176쪽)
만일 프로그램이 당신을 위해 코드를 생성해준다면, 직접 손으로 작성한 것보다 더 정확하고 신뢰도 높은 코드를 얻을 것이다. 그리고 코드 생성기가 더 나은 코드를 만들도록 개선되면 모두가 혜택을 본다. 이와 달리 손으로 작성한 프로그램은 하나를 개선한다고 해서 다른 프로그램에 혜택을 주지는 못한다. Yacc와 Lex같은 도구는 이 법칙을 보여주는 훌륭한 예고, 유닉스에는 다른 좋은 사례도 많다. 프로그램을 생성하는 프로그램을 작성하는 시도는 항상 가치가 있다. 더글러스 매클로이는 이렇게 말했다. "무엇이든 반복적으로 해야만 하는 일이 생겼다면, 자동화하기에 적합한 때가 된 것이다." (181쪽)
Eqn 언어(커니핸이 개발한 수학 표현 조판용 언어)는 박사 출신 물리학자들도 배울 수 있을 정도로 간단했고, 얼마 후에 사람들은 전문 타이피스트에 의존하기보다 스스로 타이핑을 하기 시작했다. Eqn은 도널드 커누스가 개발한 TeX의 수학 모드에 영감을 준 언어 중 하나이며, TeX는 이제 수학 타이포그래피용 표준으로 사용되고 있다. (193쪽)
켄과 데니스가 1983년에 튜링상을 받을 당시 켄은 'Reflections on Trusting Trust'라는 강연을 하며 선견지명을 보여줬다. 이 발표에서 그는 컴파일러에 일련의 수정을 가해서 시스템 로그인 프로그램에 트로이 목마를 설치할 수 있다고 설명했다.
"처음부터 끝까지 스스로 만든 코드가 아니라면 신뢰해서는 안 됩니다(특히 저 같은 사람을 채용하는 회사에서 나온 코드라면요). 소스 레벨 검증이나 정밀 검토를 아무리 한다고 해도 신뢰할 수 없는 코드를 이용하는 것을 막지 못합니다."(227쪽)
세월이 흐르면서 컴퓨팅 하드웨어가 얼마나 저렴해지고 성능이 높아졌는지 보여주는 사례가 있다. 1978년에 테드 돌로타와 존 매시가 쓴 PWB에 대한 논문은 천 명이 넘는 사용자를 지원했던 개발 환경을 묘사한다. "어떤 면에서 보더라도 이것은 전 세계에서 알려진 것 중에 가장 규모가 큰 유닉스 운영 환경입니다." PWB는 7대의 PDP-11로 이루어진 네트워크에서 작동했는데, 전체 주기억장치가 3.3MB, 디스크 용량이 2GB였다. 이는 요즘 흔히 사용도는 노트북의 1/1000 정도에 지나지 않는다. 그렇다고 요즘 노트북이 사용자 백만 명을 지원하지는 않을 것이다. (241쪽)
대부분은 우호적인 관계였지만, 연구와 제품 관리 간의 우선순위 차이가 드러날 때가 있었다. 1988년에 USL 관리자와 벌인 설전은 대략 다음과 같았다.
USL 관리자: C++ 컴파일러에 있는 버그를 모두 고쳐야 하지만, 컴파일러의 동작을 어떤 식으로든 바꿔서는 안 됩니다.
나: 그건 가능하지 않아요. 당연히 버그를 고치면 동작은 달라질 수밖에 없어요.
USL 관리자: 브라이언, 이해를 못 하는군요. 버그를 고쳐야 하지만 컴파일러의 동작은 바뀌면 안 된다니까요.
세세한 것을 따지자면 내가 옳았지만, 실제로 USL 관리자가 무슨 의미로 말한 것인지 나도 이해한다.(259쪽)
어느 날 나는 당시 CIA 국장이었던 윌리엄 콜비에게 시연을 하기로 했고, 그는 명백히 중요한 인물이었다. 이번에도 윌리엄 베이커가 동행할 예정이었는데, 미 대통령 정보 자문위원회 회장이었던 그 또한 국가 정보기관 고위직이었다.
이 시연에서 나는 유닉스가 어떻게 특정 종류의 프로그래밍을 쉽게 해주는지 보여주고 싶었지만, spell 스크립트는 실행 속도가 그리 빠르지 않았고 나는 시연이 너무 오래 끌기를 바라지 않았다. 그래서 스크립트를 미리 실행해서 출력을 파일에 캡처한 다음, 2초 동안 멈추기만 했다가 그 전날 이미 계산된 결과를 출력하는 새 스크립트를 작성했다.
sleep 2
cat "이전에 계산된 결과"
이런 식의 시연 기법은 잘 통했다. 콜비 씨가 조금이라도 이해했다면 철자법 검사가 굉장히 빨리 실행된다고 생각했을 것이 분명하다. 물론 여기에는 시연을 처음부터 끝까지 본 경험이 있는 모두를 위한 교훈이 있다. '보이는 것을 다 믿지 말라!'(265쪽)
하지만 플랜9(벨 연구소에서 개발하던 유닉스의 후신. 별로 인기를 얻지 못했다)은 시대를 뛰어넘은 중요한 한 가지 기술을 세상에 기여했다. 바로 유니코드의 UTF-8 인코딩이다.
유니코드는 인류가 지금까지 사용한 무수한 문자를 일관성 있게 표현하는 방식을 제공하기 위한 표준으로, 지금도 개발이 진행되고 있다. 유니코드로 표현 가능한 문자에는 서양 언어 대부분에서 사용하는 알파벳, 중국 문자 같은 표의 문자, 쐐기 문자 같은 고대 문자, 특수 문자와 모든 유형의 기호, 최근에 만들어진 이모티콘까지 포함된다. 유니코드에는 현재 14만 개에 가까운 문자가 있고, 그 수는 꾸준히 늘고 있다.
원래 유니코드는 16비트 문자 집합이었고, 모든 알파벳 문자와 약 3만개의 중국 문자, 일본 문자를 담을 수 있었다. 하지만 대부분의 컴퓨터 텍스트가 7비트 문자 집합인 아스키 포맷인 상태에서 온 세상의 텍스트를 16비트 문자 집합으로 변환하는 것은 실현 가능한 일이 아니었다.
켄 톰프슨과 롭 파이크는 플랜 9 개발 과정에서 이 문제를 해결하려고 애썼다. 플랜 9에서 아스키가 아닌 유니코드를 운영체제 코드 전반에 걸쳐 사용하기로 결심했기 때문이다. 1992년 8월에 그들은 UTF-8이라는 기발한 유니코드의 가변 길이 인코딩 방식을 만들어냈다. UTF-8은 공간과 처리 시간 면에서 효율적이다. UTF-8은 각 아스키 문자를 1바이트로 표현하고, 다른 문자 대부분은 문자 한 개에 2바이트나 3바이트만 사용하며, 최대 4바이트를 사용한다. 인코딩된 데이터의 크기는 작고, 아스키 문자는 그 자체로 유효한 UTF-8 인코딩이 된다. UTF-8로 된 데이터는 읽으면서 바로 디코딩할 수 있는데, 어떤 유효한 문자도 다른 문자의 앞에 붙어나오지 않고, 다른 문자 또는 문자 시퀀스의 일부가 되지 않기 때문이다. 오늘날 인터넷상에 있는 대부분의 텍스트는 UTF-8로 인코딩된다. 다시 말해 UTF-8은 모든 곳에서 모든 사람이 사용한다. (284쪽)
제라드 홀즈먼이 1127 센터 출신 멤버들과 그들이 어디 있는지 보여주는 목록을 관리하고 있다.(http://spinroot.com/gerard/1127_alumni.html) 애석하게도 너무 많은 이들이 세상을 떠났다. 남은 사람들이 가장 많이 옮겨간 곳은 구글이다. 다른 이들은 다른 회사에서 일하거나, 학교에서 학생들을 가르치거나, 은퇴했다. 정말 몇 안 되는 사람만 벨 연구소에 남아 있다. (287쪽)
사람들은 소프트웨어 생산성을 이야기할 때 작성된 코드 행의 수를 기준으로 삼는 경우가 있다. 유닉스 세상에서는 특수한 경우를 제거한 개수나 줄어든 코드 행의 수로 생산성을 판단하곤 했다. (293쪽)
유닉스 철학
(1) 각 프로그램이 한 가지 일을 잘 하게 만들라. 새로운 일을 하려면 오래된 프로그램에 새로운 '기능'을 추가함으로써 복잡하게 만드는 대신 프로그램을 새로 만들라.
(2) 모든 프로그램의 출력이 다른(아직 알려지지 않은) 프로그램의 입력이 될 것을 예상하라. 프로그램의 출력에 관련 없는 정보를 집어넣지 말라. 엄격히 열로 구분되거나 바이너리 형식으로 된 입력을 피하라. 대화식 입력 방식을 고집하지 말라.
(3) 소프트웨어를(심지어 운영체제라도) 일찍, 이상적으로는 수주 이내에 사용해볼 수 있게 설계하고 구축하라. 어설픈 부분을 버리고 다시 구축하는 것을 망설이지 말라.
(4) 프로그래밍 과제의 부담을 덜고자 할 때 비숙련자의 도움보다는 도구를 우선적으로 사용하라. 도구를 구축하기 위해 시간이 더 걸리고 도구를 사용한 다음에 일부는 버려야 할 것으로 예상하더라도 그렇게 하라. (299쪽)
좋은 연구를 하는 큰 비결은 훌륭한 사람들을 채용하고, 그들이 연구할 흥미로운 주제가 있는지 확인한 다음, 장기적인 안목을 취하고, 방해가 되지 않게 비켜주는 것이다. 물론 완벽하지는 않았지만, 벨 연구소 연구 부문은 이 일을 전반적으로 잘했다. (314쪽)
"우리가 지키고자 했던 것은 그저 프로그래밍을 하기에 좋은 환경이 아니라 유대감을 형성할 수 있는 시스템이었습니다. 우리는 경험을 통해 공동 컴퓨팅의 본질이 단지 천공기 대신에 터미널로 프로그램을 입력하는 것이 아니라 밀접한 소통을 북돋우는 것이라는 점을 알았습니다."
(315쪽)