기계어로 코드를 쓰고 드럼 메모리 컴퓨터를 극한까지 최적화했던 진짜 프로그래머 멜의 전설적인 이야기.
프로그래밍의 _마초_적인 면을 다룬 최근 글에는
다음과 같은 꾸밈없고 단도직입적인 주장이 있었다:
진짜 프로그래머는 FORTRAN으로 작성한다.
아마 지금은 그럴지도 모른다,
Lite 맥주, 휴대용 계산기, 그리고 “사용자 친화적” 소프트웨어가 있는
이 퇴폐적인 시대에는 말이다.
하지만 “소프트웨어”라는 말이 우습게 들렸고
진짜 컴퓨터가 드럼과 진공관으로 만들어지던
그 좋았던 옛날에는,
진짜 프로그래머는 기계어로 작성했다.
FORTRAN도 아니고. RATFOR도 아니고. 심지어 어셈블리 언어도 아니었다.
기계어였다.
꾸밈없는, 난해한 16진수 숫자 그대로였다.
직접.
완전히 새로운 세대의 프로그래머가
이 영광스러운 과거를 모른 채 자라지 않도록,
나는 세대 차이를 넘어 가능한 한 잘,
진짜 프로그래머가 어떻게 코드를 작성했는지 설명해야 할 의무를 느낀다.
그를 멜이라고 부르겠다,
그것이 그의 이름이었기 때문이다.
나는 지금은 없어진 타자기 회사의 자회사였던 Royal McBee Computer Corp.에 취직했을 때
처음 멜을 만났다.
그 회사는 당대 기준으로 작고 저렴한
드럼 메모리 컴퓨터인 LGP-30을 제조했고,
막 RPC-4000도 생산하기 시작한 참이었다. 그것은 훨씬 개선된,
더 크고, 더 좋고, 더 빠른 드럼 메모리 컴퓨터였다.
코어는 너무 비쌌고,
어차피 오래가지도 않을 터였다.
(그래서 그 회사나
그 컴퓨터 이야기를 들어본 적이 없는 것이다.)
나는 이 새로운 경이로운 기계를 위한 FORTRAN 컴파일러를 작성하도록 고용되었고, 멜은 그 경이로움들을 안내해 주는 사람이었다.
멜은 컴파일러를 좋게 보지 않았다.
“프로그램이 자기 코드를 다시 쓸 수 없다면”,
그는 물었다. “무슨 쓸모가 있지?”
멜은
16진수로,
회사가 보유한 컴퓨터 프로그램 중 가장 인기 있는 것을 작성했다.
그것은 LGP-30에서 실행되었고
컴퓨터 전시회에서 잠재 고객들과 블랙잭을 했다.
그 효과는 언제나 극적이었다.
LGP-30 부스는 전시회마다 사람들로 가득 찼고,
IBM 영업사원들은 서서
서로 이야기를 나누었다.
그것이 실제로 컴퓨터를 팔았는지는
우리가 결코 논의하지 않은 문제였다.
멜의 일은
블랙잭 프로그램을 RPC-4000용으로 다시 작성하는 것이었다.
(포팅? 그게 무슨 뜻이지?)
새 컴퓨터에는 일 더하기 일
주소 지정 방식이 있었는데,
각 기계 명령어에는
연산 코드와 필요한 피연산자의 주소뿐 아니라
회전하는 드럼 위에서 다음 명령어가 있는 위치를 나타내는 두 번째 주소도 있었다.
현대적인 표현으로 말하면,
명령어 하나하나 뒤에는 모두 GO TO가 붙어 있었다!
그걸 Pascal의 파이프에 넣고 피워 보라.
멜은 RPC-4000을 사랑했다.
코드를 최적화할 수 있었기 때문이다.
즉, 드럼 위에 명령어를 배치하여
하나가 일을 막 마칠 때
다음 명령어가 “읽기 헤드”에 막 도착해
즉시 실행될 수 있게 하는 것이었다.
그 일을 하는 프로그램,
“최적화 어셈블러”가 있었지만,
멜은 그것을 쓰지 않았다.
“어디에 배치할지 절대 알 수 없잖아”,
그는 설명했다. “그러면 별도의 상수를 써야 하니까.”
그 말을 이해하기까지 오랜 시간이 걸렸다.
멜은 모든 연산 코드의 수치 값을 알고 있었고
드럼 주소도 직접 정했으므로,
그가 작성한 모든 명령어는
수치 상수로도 볼 수 있었다.
가령 앞에 있던 “더하기” 명령어를 가져와
수치 값이 맞는다면 그것을 곱하는 데 쓸 수 있었다.
그의 코드는 다른 사람이 수정하기 쉽지 않았다.
나는 멜이 손으로 최적화한 프로그램들을
최적화 어셈블러 프로그램으로 같은 코드를 다듬은 결과와 비교했고,
멜의 것은 언제나 더 빨랐다.
그것은 프로그램 설계의 “하향식” 방법이
아직 발명되지 않았기 때문이었고,
발명되었더라도 멜은 쓰지 않았을 것이다.
그는 프로그램 루프의 가장 안쪽 부분부터 먼저 작성했으므로,
그 부분들이 드럼에서 최적의 주소 위치를
먼저 선택할 수 있었다.
최적화 어셈블러는 그렇게 할 만큼 영리하지 못했다.
멜은 시간 지연 루프도 결코 작성하지 않았다.
말썽 많은 Flexowriter가 제대로 작동하려면 출력 문자 사이에 지연이 필요했을 때조차 그랬다.
그는 그저 드럼 위에 명령어를 배치해
필요할 때 연속된 각각의 명령어가 읽기 헤드를 막 지나간 상태가 되게 했다.
그러면 드럼은 다음 명령어를 찾기 위해 한 바퀴를 완전히 더 회전해야 했다.
그는 이 절차를 위해 잊을 수 없는 용어를 만들었다.
“최적”은 “유일한”처럼 절대적인 말인데도,
“완전히 최적은 아닌” 또는 “덜 최적인”
혹은 “그다지 최적이지 않은”처럼
상대적인 말로 쓰는 것이 흔한 관행이 되었다.
멜은 최대 시간 지연 위치를
“가장 비최적”이라고 불렀다.
그가 블랙잭 프로그램을 끝내고
실행되게 만들었을 때
(“초기화 루틴마저 최적화되어 있어”,
그는 자랑스럽게 말했다),
영업 부서에서 변경 요청이 왔다.
그 프로그램은 “카드”를 섞고 “덱”에서 나눠 주기 위해
우아한(최적화된)
난수 생성기를 사용했는데,
고객이 지는 경우가 있었기에 일부 영업사원은 그것이 너무 공정하다고 느꼈다.
그들은 콘솔의 감지 스위치를 설정하면
확률을 바꾸어 고객이 이기게 할 수 있도록
멜이 프로그램을 수정하기 원했다.
멜은 거부했다.
그것은 명백히 부정직한 일이었고,
실제로 그랬으며,
프로그래머로서 자신의 개인적 진실성을 침해한다고 느꼈고,
실제로 그랬으므로,
그는 하기를 거부했다.
영업 책임자가 멜과 이야기했고,
큰 사장도 이야기했으며, 사장의 권유로
몇몇 동료 프로그래머도 이야기했다.
마침내 멜은 굴복하여 코드를 작성했지만,
검사를 반대로 만들었다. 그래서 감지 스위치를 켜면
프로그램은 매번 이기도록 부정행위를 했다.
멜은 이것을 무척 기뻐하며,
자신의 잠재의식은 통제할 수 없을 만큼 윤리적이라고 주장했고,
고치기를 단호히 거부했다.
멜이 더 푸른 목장으로 회사를 떠난 뒤,
큰 사장은 나에게 코드를 살펴보고
그 검사를 찾아 반대로 바꿀 수 있는지 알아보라고 했다.
다소 마지못해, 나는 살펴보겠다고 했다.
멜의 코드를 추적하는 것은 진정한 모험이었다.
나는 종종 프로그래밍이 예술 형식이라고 느꼈다.
그 진정한 가치는 같은 비전의 예술에 정통한 다른 사람만이
감상할 수 있다.
과정의 본질상,
때로는 영원히 인간의 시야와 찬탄에서 숨겨지는
아름다운 보석과 눈부신 묘수가 있다.
16진수로 되어 있더라도 그의 코드를 읽어 보는 것만으로
한 개인에 대해 많은 것을 알 수 있다.
내 생각에 멜은 알려지지 않은 천재였다.
아마 가장 큰 충격은
검사가 전혀 없는 무고한 루프를 발견했을 때 왔다.
검사가 없었다. 전혀 없었다.
상식적으로는 프로그램이 영원히, 끝없이 순환하는
닫힌 루프일 수밖에 없었다.
하지만 프로그램 제어는 그것을 그대로 통과해
반대편으로 안전하게 빠져나갔다.
그것을 알아내는 데 2주가 걸렸다.
RPC-4000 컴퓨터에는 인덱스 레지스터라는
정말 현대적인 기능이 있었다.
프로그래머는 내부에 인덱스된 명령어를 사용하는
프로그램 루프를 작성할 수 있었다.
매번 루프를 돌 때마다
인덱스 레지스터의 숫자가
그 명령어의 주소에 더해졌으므로,
연속된 데이터 중
다음 데이터를 가리키게 되었다.
그는 매번 인덱스 레지스터를 증가시키기만 하면 되었다.
멜은 결코 그것을 쓰지 않았다.
대신 그는 명령어를 기계 레지스터로 가져와,
그 주소에 하나를 더하고,
다시 저장했다.
그런 다음 수정된 명령어를
레지스터에서 바로 실행했다.
루프는 이 추가 실행 시간이 고려되도록 작성되어 있었다.
이 명령어가 막 끝나는 순간,
다음 명령어가 드럼의 읽기 헤드 바로 아래에 있어
실행할 준비가 되어 있었다.
하지만 루프에는 검사가 없었다.
결정적인 실마리는
명령어 워드에서 주소와 연산 코드 사이에 놓인 비트,
인덱스 레지스터 비트가
켜져 있음을 알아차렸을 때 나왔다.
그런데 멜은 인덱스 레지스터를 한 번도 쓰지 않아,
항상 0으로 남겨 두었다.
깨달음이 왔을 때 그것은 거의 나를 눈멀게 할 뻔했다.
그는 자신이 다루는 데이터를
메모리의 꼭대기 근처,
명령어가 주소로 지정할 수 있는 가장 큰 위치에 배치해 두었다.
그래서 마지막 데이터를 처리한 뒤
명령어 주소를 증가시키면
오버플로가 발생했다.
캐리는 연산 코드에 하나를 더해,
명령어 집합의 다음 코드인 점프 명령어로 바꾸었다.
과연 다음 프로그램 명령어는
주소 위치 0에 있었고,
프로그램은 즐겁게 제 갈 길을 계속 갔다.
나는 멜과 연락을 유지하지 않았으므로,
그 오래전에 사라진 시절 이래 프로그래밍 기법 위로 밀려온
변화의 홍수에 그가 결국 굴복했는지는 모른다.
나는 그가 그러지 않았다고 생각하고 싶다.
어쨌든,
나는 충분히 감명받았기에 그 문제의 검사를 더 찾지 않았고,
큰 사장에게 찾을 수 없었다고 말했다.
그는 놀란 기색이 아니었다.
내가 회사를 떠났을 때,
블랙잭 프로그램은 여전히 올바른 감지 스위치를 켜면
부정행위를 했다.
그리고 나는 그것이 그래야 한다고 생각한다.
진짜 프로그래머의 코드를
함부로 뜯어고치는 일은 편하게 느껴지지 않았다.
이것은 자유시 여부와 상관없이 해커 세계의 위대한 영웅 서사시 중 하나다. 몇 개의 절제된 이미지로, 이 글은 해킹의 미학과 심리에 관해 이 주제의 모든 학술 저작을 합친 것보다 더 많은 것을 포착한다. (그러나 반대 관점은 진짜 프로그래머 항목을 보라.)
[1992년 추신 — 저자는 이렇게 쓴다: “네트에 처음 올린 글은 자유시도, 그에 가까운 어떤 것도 아니었다. 양쪽 맞춤을 하지 않은 문단으로 된 평범한 산문체였다. 네트를 떠돌아다니는 동안, 지금 널리 퍼진 ‘자유시’ 형식으로 바뀐 듯하다. 다시 말해, 네트에서 해킹된 것이다. 어쩐지 그것이 어울리는 듯하다.” 저자는 자신의 원래 산문보다 ‘자유시’ 판을 더 좋아한다고 덧붙인다...]
[1999년 갱신: 이제 멜의 성이 알려졌다. LGP-30 매뉴얼은 “ACT 1 시스템의 프로그래밍 대부분을 수행한 Royal McBee의 Mel Kaye”를 언급한다.]
[2001년: Royal McBee LPG-30에는 또 다른 유명한 일화가 있었음이 밝혀졌다. 기상학자 Edward Lorenz는 1961년에 LGP-30에서 날씨 시뮬레이션을 수행하던 중 “나비 효과”와 계산적 카오스를 발견했다. 이것도 어쩐지 잘 어울리는 듯하다.]