코드에 얹어지는 삶

2년전 이었나.
한비야씨의 책을 읽으며 "생활이 묻어나는 문장" 의 맛을 알았다.
맛깔스런 글을 읽는 만족감. 그러한 문장에 대한 부러움.
그런 문장을 낳은 한비야씨의 삶에대한 존경심.
그러나 그것들은 내 머리와 가슴속에 길게 살아남지 못했다.

프로그램코드도 글인데, 코드 위에도 삶이 얹어질까.
공학. 수학적인 통찰이 아닌 일상적인 것의 영향력은 없을까.
낙엽처럼 차곡차곡 쌓인 시인의 일상이 시에 알알이 들어차듯
엔지니어의 삶과 작업물도 그러할 수는 없을까.

삶이 기술을 타고 뻗어나갈 수 없다면
어떠 일상도 기술자의 관점에서는 동일한 것이 된다.
반대로 기술을 얻기위해 혼신의 힘을 다해 공부하는 사이
기술을 사용하는 인간인 나는 퇴보하는 느낌도 참기 힘들다.

이 질문 하나만 살아남아 나를 공부하게 하고 또 절망케 했다.
그리고 이제는 거의 잊었다 싶었다.

대학원에 들어와 처음 프랑스와 덴마크사람들의 논문을 읽었고
독일유학을 다녀오신 교수님을 모신 세미나에도 참석했다.
각 나라마다 참 다른 방식으로 엔지니어링을 하고 있음에 놀랐다.
 
국민성이란 그 나라국민의 매일매일의 삶의 경험에서 형성될게다.
그리고 국민성은 생각하는 방법을 다르게 함으로서 프로그래머에게 지대한 영향을 준다.
경험이 생각의 틀을 결정하고 프로그램은 생각의 한가지 표현형이다.
엔지니어의 삶은 결국 그의 작업물속에서 다시 피어난다.
 
늦기는 했지만 너무 늦지는 않게 한가지 증거물을 얻은셈이다.
이런 별것 아닌 깨닳음에 세상이 달라질리 없다.
단지 나 하나는 조금더 가벼운워진 마음으로
공부하고 또 일상을 살 수 있을 것이다.

p.s 그런 의미에서 요즘 내가 짠 프로그램을 보면 삶이 부끄러워진다.

Posted by 발당


Leave a comment

Solver Generator


문제 분석

휴대폰 키 입력 시스템은 외부 입력에 반응하는 스택머신으로 모델링 가능하다.
삼성 천지인 시스템을 살펴보자. 다음은 천지인에서 입력 1에 대응하는 상태전이를 나열한 것이다.

종성ㄹ::나머지,1 -> 종성ㄹㄱ::나머지
종성ㄹㄱ::나머지,1 -> 초성ㅋ::종성ㄹ::나머지
초성ㄲ:종성ㄹ::나머지,1 -> 종성ㄹㄱ::나머지
초성ㄱ::나머지, 1 -> 초성ㄲ::나머지
초성ㄲ::나머지, 1 -> 초성ㅋ::나머지
초성ㅋ::나머지, 1 -> 초성ㄱ::나머지
중성_::나머지, 1 -> 종성ㄱ::중성_::나머지
종성ㄱ::나머지, 1-> 종성ㅋ::나머지
종성ㅋ::나머지, 1 -> 종성ㄲ::나머지
종성ㄲ::나머지, 1 -> 종성ㄱ::나머지

특정 문자열을 휴대폰으로 입력하기 위해 필요한 키 입력 순서를 찾는 문제는 결국 어떤 순서로 상태전이가 일어나야 하는지 찾는 문제와 동일하다.

Prolog가 Mercury같은 언어 익숙하다면 이 대목에서 "Inference Rule Backward Chaining" 가 떠오를지 모른다. 또한 문맥민감언어를 파싱하는 문제와 거의 흡사하다. (사실 문맥민감 언어와 내리누름 오토마타는 동등하다)  그러나 Yaccd으로 파서를 짜고 Prolog로 직접 휴대폰입력기의 작동을 기술하자면 인생이 고달퍼진다. (휴대폰 자판 종류가 바뀔 때 마다 전체 프로그램을 새로 작성해야 한다) 상태전기 규칙만 기술하면 그에 상응하는 Prolog나 Yacc(혹은 제3의 언어) 코드를 생성해주는 무언가가 필요하다. 그런 변환기가 있다면 삶이 조금더 행복해질 것 같다.


트랜지션 기술 언어
우선 상태전이 규칙을 기술하는 간단한 언어를 고안했다. 예를 들어 초성ㄹ::나머지,1 -> 중성ㄹㄱ::나머지 의 규칙은

1<리턴키>
0 ㄹ<리턴키>
1 ㄹㄱ<리턴키>

이렇게 인코딩 한다. 이런 구조의 텍스트파일은 쉽게 처리할 수 있다. Solver Generator를 만들기 전에 미리 6개의 휴대폰 시스템의 상태전이 규칙을 기술해 보았다. 규칙만으로도 분량이 2000줄 정도 되었다. Yacc이나 Prolog (혹은 제 3의 언어)를 써서 직접 작성했을 생각을 하니 확실히 삶이 행복하게 느껴졌다.


Solver Generator작업
이렇게 간단하게 인코딩된 파일을 읽어들여 Solver 코드를 뱉어내는 Solver Generator 를 자바로 작성하였다. 자바를 선택한 이유는 언어수준에서 유니코드를 지원하고 문자열 처리가 용이하기 때문이다.
우선은 삼성 휴대폰의 상태전이 규칙을 작성한뒤 그것을 토대로 Ocaml 로된 Solver를 직접 만들었다. Solver를 최대한 튜닝한 다음 이 코드를 바탕으로 Generator를 작성하기 시작했다.
Solver는 BFS를 써서 가능한 모든 상태전이를 시도해보며 해답을 찾아간다. 최적화를 위해서 적합도 평가함수을 만들었다. 적합도 값은 "목표 스트링과 현재 만든 스트링의 공통 접두사의 길이"로 정의한다. 적합도가 작아지거나, 세번의 상태전이 이후에도 적합도가 증가하지 않으면 그 경로는 버린다. 적합도가 증가하는 경로가 단 하나 존재하는 경우, 나머지 경로를 모든 버린다. 이렇게 하면 스트링의 길이가 길어도 경우의 수가 폭발하지 않고 솔루션을 찾아나갈 수 있다. GLR parsing algorithm과 비슷하다.

DFS를 쓸 수 있으면 Solver의 구조가 더 단순해 질 것 같은데 생각하기 귀찮아서 포기했다.

Solver Generator의 출력 언어 선택
Solver Generator에는 세가지 대안이 있었다.

첫 번째는 Solver Generator가 Parser Code 를 Generate하는 것이다. 그러나 Parser Generator를 위한 문법을 만들어 내는 알고리즘을 고안하기가 수작업으로 Solver 전체를 코딩하기 보다 어려워 보였다. 게다가 Parser Generator가 만들어 주는 Parser는 DFS 기반이라 Solver와는 어울리지 않는다.

두 번째로 엄청난 Library 를 제공하는 C++가 있다. 포인터와 라이브러리의 기능이 빠방하지만 내가 익숙하지 않다. 게다가 모든 로직을 언어의 도움 없이 직접 짜야 해서 머리가 고달퍼진다.

마지막은 패턴매칭을 제공하는 Ocaml이다. 라이브러리도 빈약하고 글로벌이나 포인터를 명시적으로 사용할 수 없어 큰 프로그램을 짜기에는 답답하다. 그러나 "현재 스택에 적용 가능한 상태전이" 를 찾는 문제를 Ocaml에서 지원하는 "리스트에 대한 패턴매칭" 으로 표현하면 컴파일러가 알아서 처리해어 귀찮은 작업을 덜 수 있다.

문자입력시스템에 따라 달라지는 부분은 "가능한 상태전이"를 찾아주는 함수 뿐이므로, Ocaml을 선택하게 되었다.

작업 당시에는 Prolog나 Mercury에 대한 지식이 없었다. 주어진 규칙을 사용하여 목표를 만드는 적용순서를 찾는 문제는 Prolog가 아주 잘 처리하는 "Inference" 유형의 문제로 인코딩할 수 있을 것 같다. Ocaml이라 C정도로 Prolog를 쓸 수 있었더라면 Prolog를 택했을지도 모른다.
-to be continue

Posted by 발당


Leave a comment
지난 가을학기에 대학국어수업에 쓸 목적으로 휴대폰 입력기 시뮬레이터를 만들었습니다. 나름 학부에서 가장 고생하면서 만든 프로그램이고 자신에게 기념이 될만한 작업인 만큼 정리해야할 필요성도 느끼고 있었는데 한 후배가 내용을 설명해 달라고 하여 프로그램에 대한 리포트를 포스팅하게 되었습니다. 별것 아닌 프로그램이지만 워낙 떠벌이고 다녀서 그런지 대단한게 있어 보인 모양입니다. 그저 고마울 따름이죠.

도입



학부 졸업학기에 미루던 대학국어를 들었다.  파릇파릇파릇파릇한 전기과 07학번들과 함께하는 강좌에서 나는 가장 나이가 많았다. 소논문 주제로 "어떤 휴대폰 입력 시스템이 좋은가?" 를 다루게 되었는데 입력 시스템의 성능을 어떻게 평가할 것인지를 놓고 이야기하던 중에 조원 하나가 "시뮬레이션으로 하면 안되요?" 라고 물었다. [시뮬레이션을 사용하면 검증은 가능하다] 는 의미에서 할 수 있다고 가볍게 답을 했다. 그런데 이 녀석들은 [시뮬레이션 정도 짜줄 수 있지] 로 이해를 한 듯 했다. "앗! 너희들이 뭔가 잘못생각하고 있는데.." 라고 발뺌을 하기에는 4학년의 자존심이 허락하지 않아 시뮬레이션 프로그램을 짜게 되었다. 학부시절 만든 가장 복잡한 프로그램을 교양필수수업 과제로 인하여 만들게 될줄 누가 알았으랴. 삶은 예측할 수 없는 것이다.



소개


문자를 입력하는 현장에서는 두 가지 "번역" 작업이 벌어진다. 첫 번째 단계는 생각한 문자를 자판시스템에 맞는 입력순서로 번역하는 일이다. 예를 들어 "감"을 삼성 천지인에서 입력한다면 [4 1 2 0] 순으로 번호키를 눌러야 한다. 두 번째로는 번역된 키입력 순서를 손가락으로 실행하는 작업이다. 휴대폰 문자입력기로 문자를 입력하는 작업을 제대로 시뮬레이션 하려면 이 두 단계를 정확히 모델링할 필요가 있다.

입력순서 생성기

휴대폰에 입력 하고 싶은 문자열을 주고 어떤 입력순서가 필요한지를 구하는 작업은 사실상 입력기라는 함수의 역함수를 구하는 작업이다. 역함수를 만드느 방법은 다양하게 생각해볼 수 있다. 가장 간단하게 방법은 빈 문자열에서 시작하여 원하는 출력이 나올 때 까지 모든 가능한 입력을 다 적용해 보는 것이다. 무식해 보이지만 가지치는 방법만 잘 고안한다면 백트랙킹 알고리즘만으로도 충분히 효율적이다.

그러나 "가능한 모든 입력을 다" 에 문제가 있다. 휴대폰 입력기를 스테이트 머신으로 생각해보면 스테이트와 전이의 수가 100개를 가볍게 넘어간다. 100개가 넘는 룰을 올바로 하드코딩할 자신이 있는가? 이 질문에 나는 자신이 없었다. 게다가 우리의 목표는 "여러 입력 시스템을 비교하는 것"이기에 최소한 6개의 입력기에 대해 "입력순서 생성기"를 작성해야 한다.  방법은 한가지. 반복되는 작업을 제거하자!

입력순서 생성기 생성기

입력순서 생성기를 만드는 과정을 살펴보자.

1단계. 입력기를 스테이트 머신(정확하게는 내리누름 오토마타)의 형태로 기술한다.
2단계. 오토마타의 가능한 전이를 시도하며 답을 찾아가는 Solver를 작성한다.

1단계의 작업은 피할 수 없다. 그에 비해 1단계에서 2단계로 넘어가는 작업은 기계적이다. 변환작업을 훌륭히 수행하는 변환기(입력순서 생성기 생성기) 가 존재하기만 한다면, 작엽량은 훨씬 줄어들 것이다. 물론, 입력순서 생성기 생성기를 쉽게 만들 수 는 없겠지만, 생성기 여섯개를 하드코딩 하는데 비하면 용이한 작업이다.

손가락 시뮬레이터

키입력순서만 해도 휴대폰 입력기에 대해 여러가지를 말해준다. 예를 들어 동일한 문자를 입력하는데 필요한 키입력회수는 입력속도를 비교하는 한가지 척도로 슬 수 있다. 그렇지만, 키입력 회수만으로 비교하는 것이 의미가 있을까? 실제의 입력속도나 어려움은 [손가락]으로 키입력순서를 실행되어야만 측정될 수 있다. 입력회수는 적지만 실제로는 느린 입력기가 있을지도 모른다. 정확한 결과를 원한다면 손가락의 움직임을 시뮬레이션 하는 시뮬레이터는 필수적이다. 시뮬레이터에게는 두가지가 요구된다. "물리적인 손가락의 움직임"을 믿을 수 있는 수준으로 재연해야하며 사용자의 특징(예컨데 사람마다 왼손 엄지와 오른손 엄지가 담당하는 키가 다르다) 을 인자로 받아서 시뮬레이션에 반영할 수 있어야 한다.

인터페이스

입력순서 생성기와 손가락 시뮬레이터가 있으면 하나의 입력기를 시뮬레이션 할 수 있다. 그러나, 우리의 목표는 여러개의 입력기 평가하는 것이므로 평가를 위한 테스트셋과 평가대상만 입력하면 자동으로 시뮬레이션을 수행하여 결과를 요약해주는 수준의 인터페이스를 제공해야 한다. 즉, 사용자는 "실험설계"에만 집중할 수 있어야 한다.

-To be continue

Posted by 발당


Comments List

  1. erniea 2008/03/28 16:08 # M/D Reply Permalink

    오오 재밌는거다! 개인적인 평가는

    싸이언>모토로라>>넘사벽>>>>다른거

Leave a comment

세미나를 어떻게 이끌어야 할 것인가?

개발동아리의 세미나는 최소한의 이론적 설명과 가능한 많은 실습과 삽질로 구성해야 한다.

배워야 하는 내용을 두 가지 카테고리로 나눠서 생각해 보자.

<type a> :  개념의 순수한 의미가 문제가 되는 경우 (수학)
강의 : 개념 자체를 이해시키기위해 타이트하게 짜여짐
실습 : 개념이 보다 큰 관점에서 어떤 식으로 다른 개념들과 소통하는지 알 수 있는 Reading
수단 : 정의, 예시, 비유, 비교, 증명, 산파법
목표 : 개념의 Clearance

<type b> :  개념이 사용되는 방식을 숙달해야 하는 경우 (산수)
강의 :  개념에 대한 간단한 정의와 예제에 대한 설명
실습 :  다양한 예제를 직접 풀어봄으로서 개념이 어떻게 작용하는지를 알게하는 문제풀이
수단 :  예제, 과제, 프로젝트, 삽질
목표 :  용법이 뼈에 새겨지는 것

두가지 경우에 대한 접근방식은 명백히 달라야 한다. 컴퓨터를 다루는데 있어서 <type a>에 속하는 문제는 알고리즘이나 컴퓨터 구조등의 이론적인 부분이 될 것이고 C언어로 UNIX환경에서 프로그래밍하기는 후자가 될 것이다.

<type a>에 해당되는 내용은 컴퓨터공학부 교육 커리큘럼에서 잘 커버하고 있으며 학생인 내가 교수보다 잘 설명하는 것은 힘든 일이다. UPnL에서는 <type b>의 교육에 전념하는 것이 좋다고 생각한다. (최소한의 설명과 풍부한 실습) 학생들마다 선행학습양의 차이가 있지만, 다량의 실습을 통해서 극복할 수 있을 것이다.

강의안 #-1 : Opening

환영합니다.오늘은 컴퓨터공학에 대해 조망하고 UPnL 을 소개합니다.

컴퓨터는 계산기다

계산기 (수식과 메모리를 입력으로 받아 값과 메모리를 돌려주는 계산기) + 주변기기

계산기로 어떻게 우리가 쓰는 프로그램을 만들지?
계산 결과를 주변장치가 읽어서 작동 + 계산결과가 다시 입력으로 들어감

그 복잡한것을 어떻게 다루나?

컴퓨터공학 : 추상화의 예술

복잡한 것을 단순하게
(1)언어의 추상화
0110010 -> mov $a 0 -> a = 0
이름붙이고 덩어리만들기

(2)시스템의 추상화
CPU + Memory + 주변기기
CPU + Memory + 드라이버(주변기기)
OS(CPU + Memory +  드라이버(주변기기))
UI(OS(CPU + Memory + 드라이버(주변기기)))

컴퓨터공학부에서 배우는 것
추상화
전체추상구조를 조망(점을 배우고 점 사이의 연결을 배운다)
추상구조를 고안하는 방법
각 추상계층에서의 충분한 경험
미리 잘 정의된 추상구조들(Tool Box)
아주 복잡한 대상을 간단하게 만들어서 처리하는 지적인 능력

UPnL이걸 다 배워야 프로그램 짜나요?

UPnL이 추구하는 바

공부하는 과정중에 있는 사람들이 모여서 하고싶은 일을 하자
과정중에도 얼마든지 좋은 프로그램을 만들 수 있다


UPnL에서 하지 않는 것

추상적으로 생각하는 능력과 생각하는데 필요한 부속을 주지 않는다.
구현하기 위해 필요한 기술을 가르쳐주지 않는다.

UPnL에서 얻을 수 있는 것 : 혼자 삽질하는 것과 무엇이 다른가?
동료
같이 달릴 사람들
자신이 얻은 것을 공유할 사람들


강의안 #0 : 언어일반론

Definition of Program : 컴퓨터에게 일을 시키는 작업 명세서

프로그래밍 : 어떻게 생각을 컴퓨터가 알아먹게 쓸 것인가?

프로그래밍 방법론 : "일"을 어떻게 명세서로 만들것인지
맥도날드예제
절차적(베이직)
재료를 준비한다
재료를 포갠다.
포장지를 준비한다
포장한다.
손님에게 준다.

OOP관점(자바)
관계자 : 재료담당자, 조리담당자, 카운터아가씨, 포장담당자, 손님
나 -> 카운터아가씨 : 햄버거주세요
카운터 -> 재료담당 : 햄버거 만들어줘요
재료담당 -> 조리담당 : 재료 줄테니까 햄버거 만들어줘요
조리담당 -> 포장담당 : 햄버거 줄테니까 포장해줘요
포장담당-> 카운터 : 햄버거 다 됬어요
카운터아가씨 -> 나 : 햄버거 여기있습니다

선언적관점( SQL, 프롤로그)
주문서 :
"통깨가 듬뿍붙어있는 호밀빵 사이에 순쇠고기 퍼티와 토마토 두 슬라이스, 양파, 양상치를 넣은 햄버거를 원해요. 피클은 넣으면 안되요"

주방에서는 이런 결과물이 나올 수 있는 조리법중 아무거나 한가지를 택하여 조리한다.

함수형 (스킴, ML)
(포장 (햄버거조립 (원료준비)), 포장지)

재료준비: Null -> 원료
햄버거조립 : 원료 -> 햄버거
포장 : 햄버거 * 포장지 -> 포장된 햄버거
전체실행결과 : 포장된 햄버거

일을 머리속에서 모델링하는 수 많은 방법
그 중에서 컴퓨터가 알아듣게 옮기기 쉬운 방법 => 프로그래밍 언어화
다양한 언어를 안다는 것 : 다양한 방식으로 생각할 수 있다는 것
생각을 언어로 한다 vs  언어로 생각을 표현한다 (선후관계는 불분명)
하지만 프로그래머의 경우에는, 언어가 있기전에 생각이 있다.

--
이때는 빨리 뭔가 이루고 싶다는 생각이 머리속에 가득했었나보다.
2006년 1학기 신입생 세미나를 준비하면서 작성한 수기노트를 옮겨놓음

Posted by 발당


Leave a comment

겸손

항상 리눅스에서만 작업하다가 아르바이트로 윈속 프로그래밍을 하게 되었다. 이론적으로야 소켓프로그래밍이 어떻게 이루어지는지 알고있지만, 실제 부르는 함수를 모르면 말장 꽝이라, 서버 코드를 몇개 구해서 읽었다. 대체로 마음에 들지 않았다. MSDN에 있는 예제코드가 그럭저럭 읽어줄만 했고, 나머지 구글링해서 나온 코드는 도무지 구조적인 깔끔함을 찾아볼 수 없었다. 그런건 생각하지도 않고 작성한 듯 했다. 도움을 구하고 있는 처지에 분수에 맞지 않게 투덜거리다가 문뜩 생각했다.

이 세상에 존재하는 인간활동의 수 만큼 많은 "보는눈" (감식안)이 존재할 것이다. 우리가 SE를 공부하지 않은 사람의 코드를 읽으며 웃음짓듯 다른 영역에 눈을 가진 사람들도 우리가 그네들의 전공영역을 기웃거릴 때 웃겠지.

음.. 겸손하게 살아야지.

Posted by 발당


Comments List

  1. 유키 2007/04/26 01:17 # M/D Reply Permalink

    난 오늘 현대대수 시간에 수강생들을 웃겼지.. 젠장 -_-;

Leave a comment
이 글은 최근 있었던 제6회 자바 개발자 컨퍼런스에서 필자가 발표했던 ‘테스트 주도 개발 수련법’의 내용 중 몇 가지에 대해 상술하고 추가한 것이다. 총 2회에 걸쳐 연재될 예정인데, 첫 번째의 무게 중심이 무술 쪽에 가깝다면 두 번째는 프로그래밍 쪽에 가깝다고 할 수 있다. 그리고 무술과 프로그래밍의 관계를 설명함에 있어 필자가 수련하는 기천이라는 무술에 대한 언급이 몇 번 있는데, 이는 특정 무술을 선전하거나 혹은 그 무술이 다른 무술에 비해 월등하다는 주장을 하거나 신비화하려는 의도는 전혀 없음을 미리 밝혀둔다. 특정 무술에 대한 언급이 약간 눈에 거슬리더라도 마소는 무술 잡지가 아니라 프로그래밍 잡지라는 맥락을 상기하고 가볍게 읽어 주길 바란다.

필자는 무술을 수련해 오고 있다. 처음 무술의 ‘武’자를 몸으로 접한 것은 초등학교 입학 전후로 기억하는데, 당시 대한민국 남아의 필수 교양 스쿨이었던 태권도 도장을 통해서였다. 고등학교는 태권도 수업 시간이 있는 좀 독특한 학교였는데, 그 때 단증과 함께 명예의 검은 띠를 얻었다. 대학에 들어와서는 손이 그리는 태극 모양에 매료되어 기천이라는 전통무예를 배우기 시작했다. 군대에서는 고참의 눈을 피해 날마다 저녁 자유시간에 창고에서 몰래 수련을 하기도 했다. 현재까지 계속하고 있는 이 기천이라는 무술은 시작한지 벌써 10년이 넘었다. 프로그래머로서 무술을 한다는 것이 무슨 상관이 있냐고 혹자는 반문할 지도 모르겠지만, 경험에 의하면 무술은 음으로 양으로 프로그래밍에 도움을 주고 있다. 먼저 간접적으로 얻는 깨달음에 대해 이야기해보자.

무술에서 얻는 영감
무술에서 얻는 부차적인 이득이 하나 있다. 필자는 마소 2003년 1월호에서 개발자에게 『훈민정음 해례본』을 추천한 바 있다. 당시 기사의 일부분을 인용해본다.

한글은 하나의 시스템이다. 기능과 모양새가 한 박자에 맞춰간다. 다양한 상징과 은유가 일관된 체계를 구축하며 들어 있다. 필자는 이제까지 한글처럼 완벽한 시스템을 본 적이 없다. 디자인을 하는 사람이나 어떤 시스템을 만들려는 사람에게 이 책이 큰 계발이 되리라 생각한다. 무형의 것을 어떻게 자연스럽게 유형화해서 표현할 것인가, 추상적인 개념들을 어떻게 규칙적으로 체계화할 것인가 하는 데에 큰 공부가 된다.

당시 담당 기자로부터 몇 번 확인을 받아야 했다. 정말 이 책을 추천하는 게 맞느냐. 다른 책으로 바꿔줄 수는 없겠냐. 하지만 필자는 무술을 하면서 훈민정음 해례본에서 느꼈던 치밀함을 다시 맛볼 수 있었다. 다음은 공부론에 대해 도올고신에 연재를 했던, 필자의 선배 윤종권 씨의 글이다. 윤종권 씨는 무술과 음악에 대해 퍽이나 깊은 수준을 갖고 있다.

여기서 우리가 의외로 명확하게 인식하지 못하는 인체의 상식 하나를 소개하고자 한다. 그것은 우리가 사지를 몸통에서 멀리 뻗을 때(伸)는 숨을 내쉬고(呼息), 몸 쪽으로 당기거나 굽히는(屈) 동작을 수행할 때에는 숨을 들이쉰다(吸息)는 사실이다. 이는 다음과 같은 단순한 실험을 해보면 단번에 이해될 것이다. 두 사람이 서로 악수한 상태에서 손을 서로 잡아당길 때, 한쪽이 숨을 내쉬면 그는 곧 상대방 쪽으로 끌려가고 만다. 팔을 접으면서 잡아끄는 행위는 屈의 움직임이며, 이 때는 들숨이 필요하기 때문이다. 반대로 서로 손을 맞잡고 밀어내는 경우, 한쪽이 숨을 들이키면 그는 뒤로 밀리게 된다. 팔을 앞으로 내미는 신장(伸張) 동작은 날숨과 연동되어 있기 때문이다. 참고로 숨과 신근(伸筋)의 연동은, 권투에든 야구에든 첼로 연주자의 활 긋는 동작에든 모두 동일하게 적용된다.



조던은 결국 다음과 같은 이유에서 혀를 내미는 것이다: 그는 돌파시에 혀를 내밀고 달림으로 인해서 “날숨”의 상태(정확하게는 숨을 내쉰 직후의 호흡정지 상태)를 인위적으로 지속시켜서, 伸筋(등 부분, 다리의 앞면, 팔의 뒷면 등의 근육)의 퍼포먼스를 최대한으로 높인다. 이 시점에서 주력(走力)이 향상된다. 점프할 때 혀를 빼무는 것은, 전신의 脫力(불필요한 屈筋의)을 촉진하고 몸통 내부에 일정한 상태를 조성하여 -- 이 부분은 구체적으로 기술할 수 없으나, 소위 “浮身”이라고 불리우는 무술의 한 테크닉과 거의 일치한다 -- 더 높고 멀리 점프할 수 있도록 도와준다. (윤종권, 마이클 조던이 혀를 내민 까닭은?, 도올고신 27신)

윤종권 씨는 이 글에서 조던이 혀를 내미는 이유를 운동역학적인 면에서 분석하면서, 몸의 특성과 그것을 운용하는 방식 등을 하나의 디렉트 시스템으로 통합하여 보고 있다. 그런데 본인은 기천 운동을 하면서 기천의 수들이 이런 체계적이고 치밀한 시스템 원리를 따르고 있다는 것을 점점 더 절감하고 있다. 기천의 수는 일종의 부트스트랩핑과 비슷하다. 부트스트랩(boot-strap)은 신발 뒷축의 가죽 끈을 말하는데, 부트스트랩핑은 스스로 자기의 신발끈을 당겨서 자신을 공중에 띄워야 하는 것과 같은 모순적 상황을 일컫는다.

기천은, 나아가서 모든 무술은 어떻게 하면 조직이 스스로를 개선할 수 있을까 하는 질문과 마찬가지로 어떻게 하면 자신의 몸으로 더 많은 힘을 낼까 하는 부트스트래핑적인 고민을 담고 있다. 기천의 수는 땅을 박차는 반작용의 힘을 많이 이용한다. 동시에 자신의 몸을 여러 개의 부분들이 연결된 것처럼 다루면서 회전력과 비트는 힘을 이용해서 힘을 배가시킨다. 마치 수영선수가 출발할 때 속도를 얻기 위해 벽면을 박찰 때에 벽면이라는 외부요소를 이용하듯이, 기천에서는 자신의 팔이나 다리, 허리 등을 일시적으로 마치 외부요소인 것처럼 이용해서 자신의 힘을 불리는 것이다. 그 치밀함은 정말 놀라울 정도이다. 그래서 기천 수를 연습하면서 많은 계발과 영감을 얻고 있다. 그런 영감의 몇 가지를 소개한다.

무술과 프로그래밍은 모두 시간의 예술이다. 무술에서 고정된 동작이란 그 자체로 의미가 없다. 주먹은 앞으로 나가야 타격을 할 수 있는 것이다. 프로그램 역시 시간의 흐름 속에서만 의미가 있다. 프로그램 실행이란 공간적 배치를 시간적 배치로 바꾸는 것이다. 한 동작을 거듭 수련하면 할수록 더 복잡해지는 것이 아니라 더 소박하고 단순해진다. 필요없는 잔 동작이 없어지고 핵심만 남는다. 전설의 검객 미야모토 무사시는 자신의 오륜서에서 “필요없는 것을 하지 마라”고 했다. 프로그램도 계속 다듬으면 오히려 단순해지는 것 같다.

무술은 허실, 음양의 양태의 조합과 반복이다. 주먹을 뻗으면 실을 만들면서 나의 허리 쪽에는 허가 생긴다. 오른손이 올라가면 왼손이 내려간다. 왼손이 올라가면 왼발은 뒤로 간다. 왼발이 뒤로 가면 오른발은 앞으로 간다. 컴퓨터 시스템에도 이런 허실과 음양의 관계 양상이 존재한다. 전체 시스템에서 특정 컴포넌트가 실하다면 나머지 부분 중 허한 부분이 생기게 되고 그 부분을 보충해줘야 한다. 공수가 어울려야 한다.

범사(기천에서는 사범 대신 범사라고 호칭한다)가 시범을 보이면 그걸 따라한다. 하지만 뭔가 다르다. 양념이 빠진 느낌이랄까, 2% 부족한 느낌이다. 그러다가 문득 깨달은 것이 있다. 범사의 동작에는 흥과 리듬감이 있었다. 기천의 동작(특히 동공)은 ‘흥’이 나야 한다. 이것을 알고 나서 하는 동작은 훨씬 더 자연스럽고 쉬우면서도 힘이 난다. 흥이 나려면 리듬을 타야 한다. 흥을 내다보면 탈춤을 하는 느낌이 들기도 한다. 생명의 느낌에는 리듬이 있다. 이처럼 뛰어난 프로그래머를 관찰하면 흥이 난다. 리듬감이 있다. 옆에서 “얼쑤!”라고 추임새를 해주고 싶을 때도 있다. 필자도 프로그래밍이 잘 될 때에는 박자가 잘 맞고 흥이 난다. 하지만 그렇지 않을 때에는 박자가 어긋나고 흥이 없고 살아 있는 느낌이 나질 않는다.

프로그래머의 스트레스
이번에는 무술에서 얻는 직접적인 효과에 대해 이야기해보자. 지식 노동자들은 스트레스가 많다. 특히 프로그래머라는 직업은 나날이 늘어가는 신기술의 홍수 속에서 가만히 있으면 뒤쳐지는 붉은 여왕의 스트레스(루이스 캐럴의 『이상한 나라의 앨리스』에 등장하는 붉은 여왕에서 유래. 그 나라에서는 있는 힘을 다해 달려야만 제 자리에 머물 수 있다)가 이만저만이 아니다. 어디에선가 프로그래머는 5년에 한 번씩 자기가 아는 지식의 절반을 완전히 갈아엎어야 한다는 이야기를 본 것 같다. 그래서 이런 스트레스를 해소하는 방법은 꼭 필요하다.

필자는 몸으로 하는 무언가가 좋은 처방이라고 생각한다. 본인은 그 중에서도 특히 무술을 통해 스트레스를 해소하고 있다. 운동을 한 날은 마치 정신의 샤워를 한 느낌이 든다. 가장 좋은 아이디어는 샤워를 할 때 떠오른다는 유명 프로그래머들이 꽤 있는데, 정신의 샤워 역시 비슷한, 혹은 더 높은 효과가 있다.

세상에는 인과관계가 역으로도 성립하는 듯 보이는 경우가 종종 있다. 우리는 기분이 좋으면 웃는다. 상식적 견지에서 보면, ‘기분이 좋다’가 원인이면 ‘웃는다’가 결과가 될 것이다. 하지만 최근의 연구에 따르면 웃는 표정을 지으면 기분도 좋아진다고 말한다. 우리는 기분이 좋으면 육체적 활동을 한다. 하지만 반대로 육체적 활동을 하면 기분이 좋아지기도 한다. 우울증 치료의 가장 효과적 처방 중 하나가 바로 운동이다. 매일 계속하는 운동은 우울증 예방과 치료에 큰 도움이 된다. 스트레스 해소라는 정신적 측면뿐만 아니라 육체적인 측면에서도 큰 도움이 된다. 하루 종일 의자에 앉아서 일해야 하는 직업의 특성상 허리, 눈, 다리, 팔, 손목 등에 병이 걸리기 쉽다. 꾸준히 하는 운동이 있으면 그런 병 걱정이 없다. 또 몸이 조금 피곤해도 쉽게 풀린다.

알파파와 집중력
며칠 전 필자를 지도해 주는 범사님과 함께 집중력 검사를 받았다. 필자의 지우 중에 지상은 박사라고 계신데, 한의사 출신으로 다양한 공부를 하신 분으로 지금은 서울 근방에서 학습 클리닉을 운영하고 있다. 일전에 지 박사와 함께 기천 수련과 관련해 심박 측정을 했었는데 이번에는 뇌파 측정을 해보기로 했다. 머리에 전극을 연결하고 뇌파를 측정해서 집중력을 검사(혹은 트레이닝)하는 것인데(소위 바이오피드백이라고 알려져 있다) 스트리트파이터 류의 게임을 머리로 했다. 상대는 컴퓨터가 조종한다. 좌뇌, 우뇌 활성화 여부(알파파와 베타, 쎄타파의 비율)에 따라 캐릭터가 움직이고 공격을 한다. 뇌에서 어떤 패턴으로 알파파가 얼마나 강하게 나오느냐에 따라 공격의 종류가 달라진다. 복잡한 공격 기술일수록 만들어 내기가 어렵다. 꽤나 힘들긴 했지만 컴퓨터 상대를 이길 수 있었다. 꼭 영화 ‘매트릭스’의 한 장면 같았다.

이 게임이 어려운 이유는 자연스러움을 거스르기 때문이다. 일반적으로 이러한 종류의 대전 격투 게임을 할 때에는 뇌에서 알파파가 나오는 차분하고 평정한 상태를 잃기 쉽다고 한다. 하지만 그런 흥분되는, 혹은 몽환적 상황에서도 차분하게 집중을 하고 있는(보통 알파파 상태를 영어로 calm and focused attention이라고 한다) 상태를 유지해야 하기 때문에 어떻게 보면 모순이다. 필자의 생각으로는 무술의 고수는 실제 겨루기를 할 때에도 알파파가 나오지 않을까 한다.

이 알파파라고 하는 것은 우리가 보통 공부를 할 때 필요한 집중력과 직접적 관련이 있다고 한다. 학습장애 클리닉에 집중력 장애를 가진 학생이 부모와 함께 왔을 경우, 부모는 대부분 부인한다. “우리 애가 집중력이 부족하다고요? 말도 안돼요. 게임할 때 보면 누가 업어가도 모를 정도로 얼마나 집중을 잘하는데요.” 그래서 국내의 연구자가 프로 게이머 대상으로 실험을 했다. 게임을 할 때 어떤 뇌파가 많이 나오는가. 쎄타파였다. 쎄타파 상태는 깨어 있는 것과 잠든 것의 중간 상태와 비슷하다. 그런데 이 쎄타파는 공부할 때 필요한 알파파와는 전혀 차원이 다르기 때문에 아무 도움도 되지 않는다는 것이 그 연구자의 말이다.

지 박사는 이런 몇 가지 실험 후, 필자와 범사님 두 사람 모두 상당한 집중 능력을 보여줬다고 말했다. 이는 기천 수련의 영향이라고 생각한다. 집중력이 높다는 것은 원하는 시점에, 심지어 주변에 방해요소(앞선 실험에서는 화면에서 번쩍이는 현란한 그래픽과 폭력성)가 있어도 알파파를 내도록 스스로 조절할 수 있다는 이야기이다. 프로그래밍에 몰입한 때에도 알파파가 나온다고 생각하는데, 그렇다면 당연히 이런 능력이 프로그래밍을 비롯한 대다수의 지적 활동에 많은 도움이 될 것이다.

건강과 프로그래밍
정신 건강이나 육체 건강이 프로그래밍과 얼마나 관련이 있을까? 필자는 그 관계가 무척 깊다고 생각한다. 예컨대 동일한 사람을 극심한 스트레스 아래에 놓고 일을 시킬 때와 그렇지 않을 때를 비교하면 그 사람의 퍼포먼스는 많은 차이가 난다. 본인이 주변을 관찰한 바로는 몸 상태에 따라 한 프로그래머의 성과가 서너배 이상 차이가 났다. 주지해야 할 것은, 이런 효과가 개인이 아니고 조직에 영향을 끼치게 되면 파급효과는 제곱수가 된다는 것이다. 짜증이 극도에 이른 개발자나 몸살로 헤롱거리는 개발자와 함께 일해 본 경험이 있는 사람이라면 쉽게 고개를 끄덕일 수 있을 것이다.

궁금한 독자는 다음 실험을 해보시라. 주변 동료에게 간단한 프로그래밍 문제를 풀게 한다. 같은 시간을 주되, 한 번은 일요일 오후 편안한 시간에 풀게 하고 다른 한 번은 업무를 마치고 스트레스가 높고 피곤한 상태에서 풀도록 한다. 양자의 결과는 놀라우리만큼 차이가 크다. 후자의 경우, 프로그래머는 실수를 자주 하게 되며 그 실수가 되먹임되어 더 큰 실수가 생기고, 더군다나 아주 어처구니없는 실수를 잡아내지 못해 고생을 하고, 그래서 시간은 부족하고 스트레스는 더 늘어나며 그로 인해 다시 실수를 하는 악순환에 빠지게 된다. 세미콜론 하나를 빠트려서 두 시간 삽질해 본 경험을 한번쯤은 해보지 않는가. 길을 걷다가 발을 헛디디는 순간 우리는 숨을 들어 마시게 되고 몸의 균형이 깨어진다. 이 때 누군가가 그 사람을 타격하면 이건 정말 치명타가 될 수 있다. 기의 균형이 깨어진 상태, 정말 무방비의 시점이다. 한 번 발을 헛디뎌 헉하는 순간 주먹을 맞으면 그냥 KO당하는 수가 있다. 그렇게 센 주먹일 필요도 없다. 정신 활동도 이와 비슷하다.

고수가 되는 것이란
앞서 살펴본 바와 같이 무술을 꾸준히 하면 육체와 정신에 여러모로 긍정적인 영향을 준다. 그렇다면 이런 무술의 고수는 어떤 사람들일까? 질문을 조금 일반화해 보자. 고수는 어떤 사람들일까? 현대 한국어에서 고수는 한 방면에 매우 뛰어난 사람을 일컫는 비유적 표현으로 많이 쓰이고 있다. 간단히 말하자면 전문가인 셈이다.

필자가 만든 말 중에 ‘메리 분석하기(Analyze Mary)’라는 게 있다(메리에겐 뭔가 특별한 것이 있다라는 영화에서 따온 말이다). 우리 주변에는 메리처럼 뭔가 특별한 사람들이 있다. 남들과 비슷하게 일을 하는 듯하면서 늘 더 나은 성과를 보이는 사람들이다. 그런 사람을 볼 때 대다수의 사람들은 그 사람은 특별하다는 감탄사를 외치고 나는 왜 그들처럼 될 수 없을까 한탄하고, 곧 까맣게 잊는다. 다음은 필자가 노스모크에 썼던 글이다.

그들을 주의 깊게 관찰하고, 분석하라. 그리고 무엇이 그들을 그렇게 ‘특별하게’ 하는지 알아내고 그걸 배워라. 또 그들이 어떻게 그렇게 특별해질 수 있었는지 배워라. 조만간 당신도 그들이 하는 것을 할 수 있을 것이다.

……

나는 지하철에서 물건을 파는 사람들을 매일 본다. 그러나 부산에서 봤던 구두솔(구두약이 나오는) 파는 아저씨를 도무지 잊을 수가 없다. 그 아저씨는 내가 타고 있던 칸에서만 50개를 넘게 팔았다. 아주 경이로운 장면이었다(영화의 한 장면 같았다). 도대체 어떻게 하길래 저 사람은 물건을 이렇게 잘 파는 것일까. 내게는 그 사람이 세일즈의 달인으로 보였다. 나는 세일즈를 하는 사람이 아니다. 하지만 세일즈의 기본은 설득과 유혹이다. 설득과 유혹은 내가 나날이 사용하는 기본적인 삶의 도구들이다. 그래서 그 사람을 ‘Analyze Mary’ 해보았고 거기서 많은 통찰과 영감을 얻었다. 그 사람은 좌석에 앉은 사람들의 신발을 일일이 자신의 구두솔로 닦아주었다 -- 한 사람도 빼놓지 않고(아 물론 운동화와 샌들은 빼고). 그걸 싫어하는 사람들이 대부분이지 않겠냐고 생각하겠지만 상황은 정반대였다. 저마다 반짝거리는 자신의 신발을 이리 저리 돌려 보면서 신기해했다. 그 사람이 신발을 닦아준 사람의 90%는 모두 구입을 했다. 상품과 세일즈 기술이 잘 결합된 좋은 예였다.

나는 여기 등장한 구두솔 아저씨를 고수로 생각한다. 그 아저씨의 고수됨은 이소룡의 고수됨과, 또 베토벤의 고수됨과, 다익스트라의 고수됨과 크게 다르지 않다.

공부와 쿵후
여기에서 잠깐 공부와 쿵후의 관계에 대해 짚고 넘어가도록 하자. 이에 관해서는 도올 김용옥의 『태권도철학의 구성원리』라는 책이 무척 탁월하다. 그 책의 설명을 인용한다.

“To study”의 번역술어로서 우리현대어에 자리잡은 이 “공부”(工夫)라는 말의 원뜻은 “德의 得함을 지향하는 모든 디시플린(훈련)”을 의미하는 것으로 그 원의는 사실 중국말의 “쿵후”에 더 잘 보존되어 있다. 우리 말의 “工夫”의 중국발음이 “kung-fu”이며 이것을 우리말로 簡化하여 표기한 것이 곧 “쿵후”다. (工夫=功夫=功扶). “쿵후”는 공부다. ...... 중국말(혹은 우리 옛한문)에 있어서 쿵후는 인간의 몸의 達人的 경지에 대하여 광범위하게 두루두루 쓰이는 표현으로서 우리가 지금 “쿵후”라고 부르는 무술의 한 형태는 쿵후라는 일반명사의 개념에 포섭되는 광범위한 개념중의 한 하위개념일 뿐이다. 지게를 잘 지는 노인의 지팽이질도 쿵후요, 호리병에 한방울도 흘리지않고 기름을 떠넣는 기름장수의 손놀림도 쿵후다. ...... 이러한 인간의 몸의 동작의 장난에 있어서 高手와 下手의 차이를 “쿵후”라고 표현하며, 이 쿵후는 오랜 시간의 축적을 통하여 高手의 몸이 얻은(得) 德인 것이다.

관심있는 독자들은 꼭 일독하기를 권한다. 도올은 여기에서 우리가 일상어에서 공부라고 부르는 뇌의 기호 조작(symbol manipulation) 능력과 무술의 쿵후 능력, 더 나아가 빨래터의 아낙이 능숙하게 방망이질을 하는 것을 모두 몸(Mom)의 수련이 이룬 경지라는 동등한 차원에서 볼 수 있다고 하는 것이다.

수련의 필요성
고수가 되려면 어떻게 해야 하는가. 필자가 노스모크에 썼던 글을 인용하겠다.

고수가 하는 것을 배우거나 따라하려고 하지 말고, 그들이 어떻게 고수가 되었는지를 배우고 따라하라. 대부분의 사람들은 어떤 분야의 전문가가 되기 위해 현재의 전문가들이 하고 있는 행동을 따라하려고 한다. 우선은 따라하기가 힘들 뿐만 아니라, 설령 똑같이 따라하게 되더라도 그것은 전문가 흉내내기일 뿐 전혀 전문가적이지 못하다. 행동 하나하나의 맥락을 이해하지 못하기 때문이다. 문제의 해결법만 달달 외운 사람은 세상의 모든 문제가 그 해결법을 적용할 대상으로 보인다. 또 새로운 문제에 직면했을 때 창의적이고 상황에 맞는 전문가적 해결안을 제시하지 못한다. 컴퓨터 프로그래밍에서 좋은 해결안들만 사전처럼 모아둔 디자인 패턴을 공부하는 사람들의 병폐가 대부분 여기에서 온다.

인공지능에서 전문가 시스템(Expert System)이라는 것이 초기의 장밋빛 기대와는 달리 별 신통한 결과를 주지 못한 이유가 이것이기도 하다. 전문가 시스템 구축을 위해 특정 분야의 전문가 수백 명을 몇 년에 걸쳐 인터뷰와 관찰을 계속한다. 그 전문가들은 자신이 일을 하는 원칙과 법칙을 서술해야 한다.

즉, 영어 전문가라면 어떤 문장에서 어느 경우에 무관사인지, 정관사인지 부정관사인지 등을 법칙으로 설명해야 한다(우리는 이런 것들을 달달 외우려고 노력한다). 이미 많은 연구에서 밝혀졌지만 의외로 전문가들은 전혀 법칙에 의해 행동하지 않는다. 우리가 질문을 했을 때 전문가들은 법칙을 즉석에서 자신의 평소 상황에서 유추, 만들어내어 설명해주고 있다. 우리가 이 법칙을 모두 외운다고 해도 전문가의 행동을 할 리 만무하다. 전문가의 머리 속에는 그런 법칙들은 물론 이제까지 그가 축적해온 엄청난 영어 경험이 각 상황성과 함께 적절히 정리되어 있기 때문에 그들의 머리와 법칙만 외운 우리의 머리에는 큰 간극이 존재한다. 아마도 우리가 배워야 할 것은 그들이 전문가에 도달하기 위해 밟았던 과정일지도 모른다. 우리의 목표는 몇몇 특정 시점에서 전문가를 흉내내는 것이 아니고 스스로 전문가가 되는 것이기 때문에.

고수가 되려면 수련이 필요하다. 단순히 현재 고수가 하는 것을 따라하는 것으로는 부족하다. 사실 제대로 따라하기가 거의 불가능하다. 하지만 고수가 현재 무엇을 하는가에 대한 정보도 매우 귀중하다. 등대가 되어줄 것이기 때문이다.

무술처럼 프로그래밍에도 수련이 필요하다. 이 생각을 갖게 된 계기는 무술을 수련하면서, 그리고 인지심리학을 공부하면서였다. 인지심리학에서는 전문가에 대한 연구(전문성, expertise에 대한 연구라고 한다)를 몇십 년 전부터 해오고 있다. 이 때 연구 대상은 주로 전문직이라고 할 수 있는 음악 연주자, 의사, 판사, 운동선수, 체스선수, 프로그래머 등에 해당한다. 그렇다. 프로그래머! 인지심리학 분야에서는 꽤 오래전부터 고수 프로그래머에 대해 연구해 오고 있다. 이런 전문성 연구의 목표는 크게 잡아 두 가지이다. 전문가와 비전문가가 그 사고 과정과 문제 해결, 행동 방식에 있어 어떻게 다른가. 어떻게 비전문가를 전문가로 만들 수 있을 것인가.

의도적 수련
필자는 전문성 연구 중에서 특히 앤더스 에릭슨(Anders Ericsson)이라는 사람의 연구결과에 주목한다. 그는 퍼포먼스와 수련 시간 간에 밀접한 관계가 있다고 말한다. 아니, 좀 더 극단적으로 한 영역에서의 경험은 일, 놀이, 수련 세 가지로 나눌 수 있는데, 이 중 수련에 투자된 시간만이 퍼포먼스 향상과 관련이 있다고 한다. 프로그래밍 쪽으로 말한다면, 회사에서 프로그래밍하는 시간이나 심심풀이로 프로그래밍하는 시간은 내가 고수가 되는 데에 직접적 공헌을 하지 못한다는 이야기가 된다(사실 일, 놀이, 수련의 구분은 엄격할 수 없고, 겹쳐진 영역이 존재할 수 있다). 특정 영역에서 개인이 다다를 수 있는 최고 수준의 퍼포먼스는 경험을 많이 한다고 자동으로 획득되지 않으며 심지어 많은 경험을 했던 사람일지라도 개선하려는 의도적인 노력의 결과로서 퍼포먼스 수준이 향상될 수 있다고 에릭슨은 말한다. 피터 드러커는 이노베이터의 조건에서 다음과 같이 말한다.

세상에 음계(etude-연습곡)를 연습하는 것보다 더 지루한 일은 없다. 그러나 위대한 연주자일수록 하루도 빠짐없이 성실하게 음계를 연습한다. 마찬가지로 유능한 외과 의사일수록 한층 더 성실하게 봉합술을 연마한다.

피아니스트는 연주 능력 향상에 크게 도움이 될 것 같지 않은 음계를 여러 달 동안 계속 연습하기도 한다. 그러나 그 연습이 피아니스트로 하여금 원하는 음악적 성취를 이룰 수 있도록 해준다. 외과 의사는 능숙한 수술 실력 향상에 크게 도움이 될 것 같지 않은 작은 손놀림을 익히기 위해 여러 달 동안 계속해서 봉합용 실과 씨름을 한다. 외과 의사는 그 꾸준한 연습 덕분에 수술을 빠르고 정확하게 하게 되고, 그 결과 소중한 인명을 구하기도 한다. 무언가를 성취하는 것은 반복적인 연습에 의해서만 가능하다.

하지만 단순한 음계 연습은 무엇도 이루어주지 않는다. 에릭슨은 바이올린 전문가들에 대해 막대한 조사를 해보았는데, 그들의 실력은 자신이 바이올린 연습에 투자한 시간과 거의 비례했다. 하지만 그는 여기에 전제를 단다. 단순한 반복 연습은 아무 도움이 안된다고 강조한다. 자기 자신을 관찰하는 것, 그리고 피드백을 통해 재조정하는 것, 특별히 현재의 기량 증진을 위해 설계된 훈련 등이 중요하다. 에릭슨은 이런 수련을 특별히 의도적 수련(deliberate practice)이라고 부른다.

에릭슨의 연구에 따르면, 고수와 하수를 가르는 가장 효과적인 인자는 의도적 수련의 양이었다. 예컨대 IQ와는 별 상관이 없다. 실제로 프로그래머의 퍼포먼스에 대한 연구를 봐도 그 사람이 얼마나 일을 잘 하는가와 그 사람의 학력, 경력년수, IQ 간에는 별 관련이 없었다. 필자의 경험으로도 크게 틀리지 않는 것 같다. 경력이 많은 개발자가 꼭 경력이 짧은 개발자보다 능력이 더 뛰어나진 않았다. 설사 처음에는 큰 차이가 있더라도 금새 따라잡을 수 있었다.

에릭슨의 연구는 우리의 뒷통수를 칠만큼 허를 찌른다. 우리의 커리어 모델에 대한 심각한 재고가 요구된다. 전문성 연구에 따르면 한 분야의 세계적 수준의 고수가 되려면 10년의 수련, 혹은 도합 일만시간 이상의 의도적 수련이 필요하다고 한다. 재즈 기타리스트에 대한 전문성 연구에 따르면, 실제 공연 시간은 전문가와 비전문가를 가리는 데에 별 도움이 되지 않았고 혼자서 연습한 시간이 더 의미가 있었는데, 전문가와 준전문가(semi-expert)의 경우 수련 시간이 일주일에 최소 두 배 이상(43시간 대 17시간)의 차이가 있었다. 나는 일주일에 몇 시간을 의도적 수련에 할애하는가? 이건 정말 무서운 질문이다.

무술 쪽에 이런 의도적 수련이 많이 개발되어 있는 것 같다. 실제로 무술인의 의도적 수련에 대한 연구도 있다. 본인은 의도적 수련을 다른 말로 ‘특수 훈련’이라고 옮기기도 한다. 세계적인 전문가와 비전문가 혹은 ‘나름대로 전문가’의 차이 중 하나는 자신의 기량을 향상시키기 위해 자신만의 특수 훈련을 직접 설계, 시행하느냐에 있다. 전문가가 되기 위해서는 많은 특수 훈련이 필요하다. 특수 훈련에는 여러 가지 종류가 있다. 그중에 스캐폴딩(scaffolding)이라는 방법이 있다. 우리말로는 지지대인데, 두발 자전거 뒷바퀴 양옆에 보조 바퀴를 달고 타다가 나중에 떼어 버리는 것과 유사하다.

수영선수들이 받는 특수 훈련 중에 이런 게 있다고 한다. 선수의 몸에 밧줄을 묶는다. 그리고 풀장 밖에서 트랙터를 이용 선수의 몸을 빠른 속도로 끌어당긴다. 그러면 선수는 평소 자신의 속도보다 훨씬 높은 속도로 물속을 가로지르게 된다. 이 때 그 선수는 빠르게 수영할 때의 느낌을 맛볼 수 있다. 물의 저항, 몸의 느낌 등. 이런 특수 훈련을 하고 나면 더 이상 트랙터로 당기지 않더라도 그 사람의 기량이 향상된다.

기천의 수중에 이런 것도 있다. 정면을 보고 선 자세에서 한 발자국(예컨대 오른발) 크게 내딛는다. 발 뒷꿈치가 닫는 순간 뒷꿈치를 축으로 몸을 반 시계 방향으로 비튼다. 주먹은 이 때 허리에 있다가 정면으로 내어지른다. 주먹이 완전히 나간 상태에서는 몸은 왼쪽을 바라보고 있고 주먹은 원래의 정면 쪽으로 나와 있는 상태이다. 그리고 다리는 기마자세이다. 처음 이 동작을 배우고 계속 연습을 했다. 그런데 범사님이 뭔가 제대로 되고 있지 않다고 말을 했다. 하지만 동작은 수정되지 않았다. 그러다가 다시 한 번 앞발을 내딛으려는 순간 뒤에서 범사님이 내 허리춤을 잡고 몸을 획 돌려버렸다. 마치 애들이 손바닥 사이에 끼고 막대기를 비비면 윗부분의 자그만 북에 실로 연결된 구슬이 북을 쳐서 소리를 내는 장난감처럼. 그러자 내 주먹이 마치 허리춤에서 총알 발사되듯이 앞으로 튕겨 나갔다. 바로 이 느낌이었다. 엄청난 파워. 그러나 힘은 들지 않았다. 이 경험을 한 번 했더니, 한 마디로 말해 ‘감이 왔다’. 당연히 기량에도 발전이 있었다.

왜 이런 훈련이 효과가 있을까? 몸이 기억하기 때문이다. 몸은 그 당시의 느낌을 기억한다. 그래서 그 이후 같은 수련을 해도 그 때의 그 완벽한 느낌에 가깝게 가기 위해 노력하고 몸을 컨트롤한다. 이번에는 그 느낌이랑 좀 비슷했네. 아니야, 이번에는 영 아니었어. 미감이 생기는 것과 비슷하다. 피드백이 더 구체적으로 어떤 방향을 제시해 주게 되는 것이다.

이런 이야기를 ‘테스트 주도 개발 수련’에 적용하면 어떨까? 나는 애자일 언어(파이썬, 루비 등 동적인 성질이 강한 언어)로 TDD를 하는 것이 이런 특수 훈련의 효과를 낼 수 있다고 본다. 그러고 나서 비-애자일 언어로 돌아가는 것이, 차라리 처음부터 비-애자일 언어와 씨름하는 것보다 빠른 기량 향상을 가능하게 할 것이다. 이런 자기보다 한 단계 높은 경험을 하는 특수 훈련도 있는가 하면 발목에 모래주머니를 차고 다니는 한 단계 낮은 경험을 하는 특수 훈련도 가능하다. 프로그래머를 위한 다양한 특수 훈련의 소개는 다음 연재를 기대하시라. 다음 연재에서는 구체적으로 프로그래밍의 고수와 하수의 차이점, 프로그래밍의 고수가 되기 위해 어떤 수련이 필요한지 등에 대해 살펴보겠다. [MASO]

Posted by 발당


Comments List

  1. 양치 2005/12/03 10:42 # M/D Reply Permalink

    찬찬히 보고있었는데...
    어느샌가 깨달았다.

    길어! [...;]

  2. WinNie 2005/12/03 12:47 # M/D Reply Permalink

    미안하다 걍내렸다

  3. 족발당 2005/12/07 08:34 # M/D Reply Permalink

    사실 나도 아직 안읽어본겨....

Leave a comment
우리 프로그래머들은 항상 공부해야 합니다. 우리는 지식을 중요하게 여깁니다. 하지만 지식에 대한 지식, 즉 내가 그 지식을 얻은 과정이나 방법 같은 것은 소홀히 여기기 쉽습니다. 따라서 지식의 축적과 공유는 있어도 방법론의 축적과 공유는 매우 드문 편입니다. 저는 평소에 이런 생각에서 학교 후배들을 위해 제 자신의 공부 경험을 짬짬이 글로 옮겨놓았고, 이번 기회에 그 글들을 취합, 정리하게 되었습니다. 그 결실이 바로 이 글입니다.

김창준 (마이크로소프트웨어)  2002/06/02

이 글은 공부하는 방법과 과정에 관한 글입니다. 이 글은 제가 공부한 성공/실패 경험을 기본 토대로 했고, 지난 몇 년간 주변에서 저보다 먼저 공부한 사람들의 경험을 관찰, 분석한 것에 제가 다시 직접 실험한 것과 그밖에 오랫동안 꾸준히 모아온 자료들을 더했습니다. '만약 다시 공부한다면' 저는 이렇게 공부할 것입니다.부디 독자 제현께서 이 글을 씨앗으로 삼아 자신만의 나무를 키우고 거기서 열매를 얻고, 또 그 열매의 씨앗이 다시 누군가에게 전해질 수 있다면 더 이상 바랄 것이 없겠습니다.
이 글은 특정 주제들의 학습/교수법에 대한 문제점과 제가 경험한 좋은 공부법을 소개하는 식으로 구성됐습니다. 여기에 선택된 과목은 리팩토링, 알고리즘?자료구조, 디자인패턴, 익스트림 프로그래밍(ExtremeProgramming 혹은 XP) 네 가지입니다. 이 네 가지가 선택된 이유는 필자가 관심있게 공부했던 것이기 때문만은 아니고, 모든 프로그래머에게 어떻게든 널리 도움이 될만한 교양과목이라 생각하여 선택한 것입니다. 그런데 이 네 가지의 순서가 겉보기와는 달리 어떤 단계적 발전을 함의하는 것은 아닙니다. 수신(修身)이 끝나면 더 이상 수신은 하지 않고 제가(齊家)를 한다는 것이 어불성설인 것과 같습니다.
원래는 글 후미에 일반론으로서의 공부 패턴들을 쓰려고 했습니다. 하지만 지면의 제약도 있고, 독자 스스로 이글에서 그런 패턴을 추출하는 것도 의미가 있을 것이기에 생략했습니다. 그런 일반론이 여기 저기 숨어있기 때문에 알고리즘 공부에 나온 방법 대부분이 리팩토링 공부에도 적용할 수 있고, 적용되어야 한다는 점을 꼭 기억해 주셨으면 합니다. 다음에 기회가 닿는다면 제가 평소 사용하는 (컴퓨터) 공부패턴들을 소개하겠습니다.

@알고리즘?자료구조 학습에서의 문제

우리는 알고리즘 카탈로그를 배웁니다. 이미 그러한 해법이 존재하고, 그것이 최고이며, 따라서 그것을 달달 외우고 이해해야 합니다. 좀 똑똑한 친구들은 종종 "이야 이거 정말 기가 막힌 해법이군!"하고 감탄할지도 모릅니다. 대부분의 나머지 학생들은 그 해법을 이해하려고 머리를 쥐어짜고 한참을 씨름한 후에야 어렴풋이 왜 이 해법이 그 문제를 해결하는지 납득하게 됩니다. 그리고는 그 '증명'은 책 속에 덮어두고 까맣게 사라져버립니다. 앞으로는 그냥 '사용'하면 되는 것입니다. 더 많은 대다수의 학생은 이 과정이 무의미하다는 것을 알기 때문에 왜 이 해법이 이 문제를 문제없이 해결하는지의 증명은 간단히 건너뜁니다.
이런 학생들은 이미 주어진 알고리즘을 사용하는 일종의 객관식 혹은 문제 출제자가 존재하는 시험장 상황에서는 뛰어난 성적을 보일 것임은 자명합니다. 하지만 스스로가 문제와 해답을 모두 만들어내야 하는 상황이라면, 또는 해답이 존재하지 않을 가능성이 있는 상황이라면, 혹은 최적해를 구하는 것이 불가능에 가깝다면, 혹은 알고리즘을 완전히 새로 고안해내야 하거나 기존 알고리즘을 변형해야 하는 상황이라면 어떨까요?
교육은 물고기를 잡는 방법을 가르쳐야 합니다. 어떤 알고리즘을 배운다면 그 알고리즘을 고안해낸 사람이 어떤사고 과정을 거쳐 그 해법에 도달했는지를 구경할 수 있어야 하고, 학생은 각자 스스로만의 해법을 차근차근 '구성'(construct)할 수 있어야 합니다(이를 교육철학에서 구성주의라고 합니다. 교육철학자 삐아제(Jean Piaget)의 제자이자, 마빈 민스키와 함께 MIT 미디어랩의 선구자인 세이머 페퍼트 박사가 주창했습니다). 전문가가 하는 것을 배우지 말고, 그들이 어떻게 전문가가 되었는지를 배우고 흉내 내야 합니다.
결국은 소크라테스적인 대화법입니다. 해답을 가르쳐 주지 않으면서도 초등학교 학생이 자신이 가진 지식만으로 스스로 퀵소트를 유도할 수 있도록 옆에서 도와줄 수 있습니까? 이것이 우리 스스로와 교사들에게 물어야 할질문입니다. 왜 우리는 학교에서 '프로그래밍을 하는 과정'이나 '디자인 과정'(소프트웨어 공학에서 말하는 개발 프로세스가 아니라 몇 시간이나 몇 십 분 단위의, 개인적인 차원의 사고 과정 등을 일컫습니다)을 명시적으로 배운 적이 없을까요? 왜 해답에 이르는 과정을 가르쳐주는 사람이 없나요? 우리가 보는 것은 모조리 이미 훌륭히 완성된, 종적 상태의 결과물로서의 프로그램뿐입니다. 어느 날 문득 하늘에서 완성된 프로그램이 뚝 떨어지는 경우는 없는데 말입니다.
교수가 어떤 알고리즘 문제의 해답을 가르칠 때, "교수님, 교수님께서는 어떤 사고 과정을 거쳐, 그리고 어떤 디자인 과정과 프로그래밍 과정을 거쳐서 그 프로그램을 만드셨습니까?"하고 물어봅시다. 만약 여기에 어떤 체계적인 답변도 할 수 없는 분이라면 그 분은 자신의 사고에 대해 '사고'해 본 적이 없거나 문제 해결에 어떤 효율적체계를 갖추지 못한 분이며, 따라서 아직 남을 가르칠 준비가 되어있지 않은 분일 것입니다. 만약 정말 그렇다면 우리는 어떻게 해야 할까요?

@자료구조와 알고리즘 공부

제가 생각건대, 교육적인 목적에서는 자료구조나 알고리즘을 처음 공부할 때 우선은 특정 언어로 구현된 것을 보지 않는 것이 좋을 때가 많습니다. 대신 말로 된 설명이나 의사코드(pseudo-code) 등으로 그 개념까지만 이해하는 것이죠. 그 아이디어를 절차형(C, 어셈블리어)이나 함수형(LISP, Scheme, Haskell), 객체지향(자바, 스몰토크) 언어 등으로 직접 구현해 보는 겁니다. 그 다음에는 다른 사람이나 다른 책의 코드와 비교합니다. 이 경험을 애초에 박탈당한 사람은 귀중한 배움과 깨달음의 기회를 잃은 셈입니다.
만약 여러 사람이 함께 공부한다면 각자 동일한 아이디어를 같은 언어로 혹은 다른 언어로 어떻게 다르게 표현했는지를 서로 비교해 보면 배우는 것이 무척 많습니다. 우리가 자료구조나 알고리즘을 공부하는 이유는, 특정 '실세계의 문제'를 어떠한 '수학적 아이디어'로 매핑시켜 해결할 수 있는지, 그것이 효율적인지, 또 이를 컴퓨터에 어떻게 효율적으로 구현할 수 있는지 따지고, 그것을 실제로 구현하기 위해서입니다. 따라서 이 과정에 있어 실세계의 문제를 수학 문제로, 그리고 수학적 개념을 프로그래밍 언어로 효율적으로 표현해내는 것은 아주 중요한 능력이 됩니다.

@알고리즘 공부에서 중요한 것

개별 알고리즘의 목록을 이해, 암기하며 익히는 것도 중요하지만 더 중요한 것은 다음 네 가지입니다.
①알고리즘을 스스로 생각해낼 수 있는 능력
②다른 알고리즘과 효율을 비교할 수 있는 능력
③알고리즘을 컴퓨터와 다른 사람이 이해할 수 있는 언어로 표현해낼 수 있는 능력
④이것의 정상작동(correctness) 여부를 검증해 내는 능력
첫 번째가 제대로 훈련되지 못한 사람은 알고리즘 목록의 스테레오 타입에만 길들여져 있어서 모든 문제를 자신이 아는 알고리즘 목록에 끼워 맞추려고 합니다. 디자인패턴을 잘못 공부한 사람과 비슷합니다. 이런 사람들은 마치 과거에 수학 정석만 수십 번 공부해 문제를 하나 던져주기만 하면, 생각해보지도 않고 자신이 풀었던 문제들의 패턴 중 가장 비슷한 것 하나를 기계적?무의식적으로 풀어제끼는 문제풀이기계와 비슷합니다. 그들에게 도중에 물어보십시오. "너 지금 무슨 문제 풀고 있는 거니?" 열심히 연습장에 뭔가 풀어나가고는 있지만 그들은 자신이 뭘 풀고 있는지도 제대로 인식하지 못 하는 경우가 많습니다. 머리가 푸는 게 아니고 손이 푸는 것이죠. 이렇게 되면 도구에 종속되는 '망치의 오류'에 빠지기 쉽습니다. 새로운 알고리즘을 고안해야 하는 상황에서도 기존 알고리즘에 계속 매달릴 뿐입니다. 알고리즘을 새로 고안해 내건 혹은 기존의 것을 조합하건 스스로 생각해 내는 훈련이 필요합니다.
두 번째가 제대로 훈련되지 못한 사람은 일일이 구현해 보고 실험해 봐야만 알고리즘 간의 효율을 비교할 수 있습니다. 특히 자신이 가진 카탈로그를 벗어난 알고리즘을 만나면 이 문제가 생깁니다. 이건 상당한 대가를 치르게 합니다.
세 번째가 제대로 훈련되지 못한 사람은, 문제를 보면 "아, 이건 이렇게 저렇게 해결하면 됩니다"하는 말은 곧잘할 수 있지만 막상 컴퓨터 앞에 앉혀 놓으면 아무 것도 하지 못합니다. 심지어 자신이 생각해낸 그 구체적 알고리즘을 남에게 설명해 줄 수는 있지만, 그걸 '컴퓨터에게' 설명하는 데는 실패합니다. 뭔가 생각해낼 수 있다는 것과 그걸 컴퓨터가 이해할 수 있게 설명할 수 있다는 것은 다른 차원의 능력을 필요로 합니다.
네 번째가 제대로 훈련되지 못한 사람은, 알고리즘을 특정 언어로 구현해도, 그것이 옳다는 확신을 할 수 없습니다. 임시변통(ad hoc)의 아슬아슬한 코드가 되거나 이것저것 덧붙인 누더기 코드가 되기 쉽습니다. 이걸 피하려면 두 가지 훈련이 필요합니다. 하나는 수학적?논리학적 증명의 훈련이고, 다른 하나는 테스트 훈련입니다. 전자가 이론적이라면 후자는 실용적인 면이 강합니다. 양자는 상보적인 관계입니다. 특수한 경우들을 개별적으로 테스트해서는 검증해야 할 것이 너무 많고, 또 모든 경우에 대해 확신할 수 없습니다. 테스트가 버그의 부재를 보장할 수는 없습니다. 하지만 수학적 증명을 통하면 그것이 가능합니다. 또, 어떤 경우에는 수학적 증명을 굳이 할 필요 없이 단순히 테스트 케이스 몇 개만으로도 충분히 안정성이 보장되는 경우가 있습니다. 이럴 때는 그냥 테스트만으로 만족할 수 있습니다.

@실질적이고 구체적인 문제를 함께 다루라

자료구조와 알고리즘 공부를 할 때에는 가능하면 실질적이고 구체적인 실세계의 문제를 함께 다루는 것이 큰 도움이 됩니다. 모든 학습에 있어 이는 똑같이 적용됩니다. 인류의 지성사를 봐도, 구상(concrete) 다음에 추상(abstract)이 옵니다. 인간 개체 하나의 성장을 봐도 그러합니다. 'be-동사 더하기 to-부정사'가 예정으로 해석될 수 있다는 룰만 외우는 것보다 다양한 예문을 실제 문맥 속에서 여러 번 보는 것이 훨씬 나을 것은 자명합니다. 알고리즘과 자료구조를 공부할 때 여러 친구들과 함께 연습문제(특히 우리가 경험하는 실세계의 대상들과관련이 있는 것)를 풀어보기도 하고, ACM의 ICPC(International Collegiate Programming Contest: 세계 대학
생 프로그래밍 경진 대회) 등의 프로그래밍 경진 대회 문제 중 해당 알고리즘?자료구조가 사용될 수 있는 문제를 같이 풀어보는 것도 아주 좋습니다. 이게 가능하려면 "이 알고리즘이 쓰이는 문제는 이거다"하고 가이드를 해줄 사람이 있으면 좋겠죠. 이것은 그 구체적 알고리즘?자료구조를 훈련하는 것이고, 이와 동시에 어떤 알고리즘을 써야할지 선택, 조합하는 것과 새로운 알고리즘을 만들어내는 훈련도 무척 중요합니다.

@알고리즘 디자인 과정의 중요성

알고리즘을 좀더 수월하게, 또 잘 만들려면 알고리즘 디자인 과정에 대해 생각해 봐야 합니다. 그냥 밑도 끝도없이 문제를 쳐다본다고 해서 알고리즘이 튀어나오진 않습니다. 체계적이고 효율적인 접근법을 사용해야 합니다. 대표적인 것으로 다익스트라(E. W. Dijkstra)와 워스(N. Wirth)의 '조금씩 개선하기'(Stepwise Refinement)가 있습니다. 워스의 「Program Development by Stepwise Refinement」(1971, CACM 14.4,http://www.acm.org/classics/dec95)를 꼭 읽어보길 바랍니다. 여기 소개된 조금씩 개선하기는 구조적 프로그래밍에서 핵심적 역할을 했습니다(구조적 프로그래밍을 'goto 문 제거' 정도로 생각하면 안 됩니다). 다익스트라의 「Stepwise Program Construction」(Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982, http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD227.PDF)도 추천합니다.
알고리즘 검증은 알고리즘 디자인과 함께 갑니다. 새로운 알고리즘을 고안할 때 검증해 가면서 디자인하기 때문입니다. 물론 가장 큰 역할은 고안이 끝났을 때의 검증입니다. 알고리즘 검증에는 루프 불변식(loop invariant)같은 것이 아주 유용합니다. 아주 막강한 무기입니다. 익혀 두면 두고두고 가치를 발휘할 것입니다. 맨버(UdiManber)의 알고리즘 서적(『Introduction to Algorithms: A Creative Approach』)이 알고리즘 검증과 디자인이 함께 진행해 가는 예로 자주 추천됩니다. 많은 계발을 얻을 것입니다. 고전으로는 다익스트라의 『A Discipline of Programming』과 그라이스(Gries)의 『The Science of Programming』이 있습니다. 특히 전자를 추천합니다. 프로그래밍에 대한 관을 뒤흔들어 놓을 것입니다.

@알고리즘과 패러다임

알고리즘을 공부하면 큰 줄기들을 알아야 합니다. 개별 테크닉도 중요하지만 '패러다임'이라고 할만한 것들을 알아야 합니다. 이것에 대해서는 튜링상을 수상한 로버트 플로이드(Robert Floyd)의 튜링상 수상 강연(The Paradigms of Programming, 1978)을 추천합니다. 패러다임을 알아야 알고리즘을 상황에 맞게 마음대로 변통할 수 있습니다. 그리고 자신만의 분류법을 만들어야 합니다. 구체적인 문제들을 케이스 바이 케이스로 여럿 접하는 동안 그냥 지나쳐 버리면 개별자는 영원히 개별자로 남을 뿐입니다. 비슷한 문제들을 서로 묶어서 일반화해야 합니다.
이런 패러다임을 발견하려면 '다시 하기'가 아주 좋습니다. 다른 것들과 마찬가지로, 이 다시 하기는 알고리즘에서만이 아니고 모든 공부에 적용할 수 있습니다. 같은 것을 다시 해보는 것에서 우리는 얼마나 많은 것을 배울수 있을까요. 대단히 많습니다. 왜 동일한 문제를 여러 번 풀고, 왜 같은 내용의 세미나에 또 다시 참석하고, 같은 프로그램을 거듭 작성할까요? 훨씬 더 많이 배울 수 있기 때문입니다. 화술 교육에서는 같은 주제에 대해 한번 말해본 연사와 두 번 말해본 연사는 천지 차이가 있다고 말합니다. 같은 일에 대해 두 번의 기회가 주어지면두 번째에는 첫 번째보다 잘 할 기회가 있습니다. 게다가 첫 번째 경험했던 것을 '터널을 벗어나서' 다소 객관적으로 볼 수 있게 됩니다. 왜 자신이 저번에 이걸 잘 못 했고, 저걸 잘 했는지 알게 되고, 어떻게 하면 그걸 더 잘할 수 있을는지 깨닫게 됩니다. 저는 똑같은 문제를 여러 번 풀더라도 매번 조금씩 다른 해답을 얻습니다. 그러면서 정말 엄청나게 많은 것을 배웁니다. '비슷한 문제'를 모두 풀 능력이 생깁니다. 제가 개인적으로 존경하는 전산학자 로버트 플로이드(Robert W. Floyd)는 1978년도 튜링상 강연에서 다음과 같은 말을 합니다.

"제가 어려운 알고리즘을 디자인하는 경험을 생각해 볼 때, 제 능력을 넓히는 데 가장 도움이 되는 특정한 테크닉이 있습니다. 어려운 문제를 푼 후에, 저는 그것을 처음부터 완전히 새로 풉니다. 좀 전에 얻은 해법의 통찰(insight)만을 유지하면서 말이죠. 해법이 제가 희망하는 만큼 명료하고 직접적인 것이 될 때까지 반복합니다. 그런 다음, 비슷한 문제들을 공략할 어떤 일반적인 룰을 찾습니다. 아까 주어진 문제를 아예 처음부터 최고로 효율적인 방향에서 접근하도록 이끌어줬을 그런 룰을 찾는 거죠. 많은 경우에 그런 룰은 불변의 가치가 있습니다. … 포트란의 룰은 몇 시간 내에 배울 수 있습니다. 하지만 관련 패러다임은 훨씬 더 많은 시간이 걸립니다. 배우거나(learn) 배운 것을 잊거나(unlearn) 하는 데 모두."

수학자와 프로그래머를 포함한 모든 문제 해결자들의 고전이 된 죠지 폴리야(George Polya)의 『How to Solve it』에는 이런 말이 있습니다: 

“심지어는 꽤나 훌륭한 학생들도, 문제의 해법을 얻고 논증을 깨끗하게 적은 다음에는 책을 덮어버리고 뭔가 다른 것을 찾는다. 그렇게 하는 동안 그들은 그 노력의 중요하고도 교육적인 측면을 잃어버리게 된다. … 훌륭한선생은 어떠한 문제이건 간에 완전히 바닥이 드러나는 경우는 없다는 관점을 스스로 이해하고 또 학생들에게 명심시켜야 한다.”

저는 ACM의 ICPC 문제 중에 어떤 문제를 이제까지 열 번도 넘게 풀었습니다. 대부분 짝 프로그래밍이나 세미나를 통해 프로그래밍 시연을 했던 것인데, 제 세미나에 여러 번 참석한 분이 농담조로 웃으며 물었습니다. "신기해요. 창준 씨는 그 문제를 풀 때마다 다른 프로그램을 짜는 것 같아요. 설마 준비를 안 해 와서 그냥 내키는 대로 하는 건 아니죠?" 저는 카오스 시스템과 비슷하게 초기치 민감도가 프로그래밍에도 작용하는 것 같다고 대답했습니다. 저 스스로 다른 해법을 시도하고 싶은 마음이 있으면 출발이 조금 다르고, 또 거기서 나오는 진행방향도 다르게 됩니다. 그런데 중요한 것은 이렇게 같은 문제를 매번 다르게 풀면서 배우는 것이 엄청나게 많다는 점입니다. 저는 매번, 전보다 개선할 것을 찾아내게 되고, 또 새로운 것을 배웁니다. 마치 마르지 않는 샘물처럼 계속 생각할 거리를 준다는 점이 참 놀랍습니다.
알고리즘 개론 교재로는 CLR(Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest)을 추천합니다. 이와 함께 혹은 이 책을 읽기 전에 존 벤틀리(Jon Bentley)의 『Programming Pearls』도 강력 추천합니다. 세계적인 짱짱한 프로그래머와 전산학자들이 함께 꼽은 위대한 책 목록에서 몇 손가락 안에 드는 책입니다. 아직 이 책을 본 적이 없는 사람은 축하합니다. 아마 몇 주간은 감동 속에 하루하루를 보내게 될 겁니다.

@리팩토링 학습에서의 문제

먼저, 본지 2001년 11월호에 제가 썼던 마틴 파울러의 책을 추천하는 글을 인용하겠습니다.

"OOP를 하건 안 하건 프로그래밍이란 업을 하는 사람이라면 이 책은 자신의 공력을 서너 단계 레벨업시켜줄 수 있다. 자질구레한 술기를 익히는 것이 아니고 기감과 내공을 증강하는 것이다. 혹자는 DP 이전에 RF를 봐야 한다고도 한다. 이 말이 어느 정도 일리가 있는 것이, 효과적인 학습은 문제의식이 선행해야 하기 때문이다. DP는 거시적 차원에서 해결안을 모아놓은 것이다. RF를 보고 나쁜 냄새(Bad Smell)를 맡을 수 있는 후각을 발달시켜야 한다. RF의 목록을 모두 외우는 것은 큰 의미가 없다. 그것보다 냄새나는 코드를 느낄 수 있는 감수성을 키우는 것이 더 중요하다. 필자는 일주일에 한 가지씩 나쁜 냄새를 정해놓고 그 기간 동안에는 자신이 접하는 모든 코드에서 그 냄새만이라도 확실히 맡도록 집중하는 방법을 권한다. 일명 일취집중 후각법. 패턴 개념을 만든 건축가 크리스토퍼 알렉산더나 GoF의 랄프 존슨은 좋은 디자인이란 나쁜 것이 없는 상태라고 한다. 무색 무미 무취의 무위(無爲)적 자연(自然) 코드가 되는 그 날을 위해 오늘도 우리는 리팩토링이라는 유위(有爲)를 익힌다."

주변에서 리팩토링을 잘못 공부하는 경우를 종종 접합니다. 어떤 의미에서 잘못 공부한다고 할까요? '실체화'가 문제입니다. 리팩토링은 도구이고 방편일 뿐인데, 그것에 매달리는 것은 달은 보지 않고 손을 보는 것과 같습니다. 저는 리팩토링 책이 또 하나의 (이미 그 병폐가 많이 드러난) GoF 책이 되는 현상이 매우 걱정됩니다.

@리팩토링 공부

사람들이 일반적으로 생각하는 바와는 달리 리팩토링 학습에 있어 어떤 리팩토링이 있는지, 구체적으로 무엇인지 등의 리팩토링 목록에 대한 지식과 각각에 대한 메카닉스(Mechanics: 해당 리팩토링을 해나가는 구체적 단계)는 오히려 덜 중요할 수 있습니다. 더 기본적이고 유용한 것은 코드 냄새(Code Smell)와 짧은 테스트-코드 싸이클입니다. 이것만 제대로 되면 리팩토링 책의 모든 리팩토링을 스스로 구성해낼 수 있으며, 다른 종류의 리팩토링까지 직접 발견해낼 수 있습니다.
그 책에서는 테스트의 중요성이 충분히 강조되지 않았습니다. 하지만 테스트 코드 없는 리팩토링은 안전벨트 없는 자동차 경주와 같습니다. 그리고 테스트 코드가 리팩토링의 방향을 결정하기도 합니다. 양자는 음과 양처럼 서로 엮여 있습니다. 이런 의미에서 리팩토링은 TDD(Test Driven Development)와 함께 수련하는 것이 좋습니다. 훨씬 더 빨리, 훨씬 더 많은 것을 배울 수 있을 겁니다.
리팩토링을 공부할 때는 우선 코드 냄새의 종류를 알고, 왜 그것이 나쁜 냄새가 될 수 있는지 이해하고(그게 불가하다면 리팩토링 공부를 미뤄야 합니다) 거기에 동의할 수 있어야 합니다. 그런 다음, 대충 어떤 종류의 리팩토링이 가능한지 죽 훑어봅니다. 그 중 몇 개는 메카닉스를 따라가면서 실험해 봅니다. 이제는 책을 덮습니다. 그리고 실제 코드를 접하고, 만약 거기에서 냄새를 맡는다면 이 냄새를 없애기 위해 어떻게 해야 할지 스스로 고민합니다. 리팩토링 책의 목록은 일단 무시하십시오. 그 냄새를 없애는 것이 목표이지, 어떤 리팩토링을 여기에'써먹는 것'이 목표가 되어선 안 됩니다. 이 때, 반드시 테스트 코드가 있어야 합니다. 그래야 '좋은' 리팩토링을 할 수 있습니다. 책을 떠나 있으면서도 책에서 떠나지 않는 방법입니다.
리팩토링을 하기 전에 초록색 불(테스트가 모두 통과)이 들어온 시점에서 코드를 일부 고치면 빨간 불(테스트가 하나라도 실패)로 바뀔 겁니다. 이게 다시 초록색 불이 될 때까지 최소한도의 시간이 걸리도록 하십시오. 현 초록색에서 다음 초록색까지 최소한의 시간을 소비하도록 하면서 코드와 테스팅을 오가게 되면 자기도 모르는 사이에 훌륭한 리팩토링이 자발공으로 터져 나옵니다. 여기서 목적지는 우선은 OAOO(Once And Only Once: 모든 것은 오로지 한 번만 말해야 한다)를 지키는 쪽으로 합니다. 그러면 OAOO와 짧은 테스트-코드 싸이클을 지키는 사이 어느새 탁월한 디자인이 튀어나옵니다. 참고로 저는 '모래시계 프로그래밍'이란 걸 가끔 합니다. 모래시계나 알람 프로그램으로 테스트-코드 사이클의 시간을 재는 것입니다. 그래서 가급적이면 한 사이클이 3분이내(대부분의 모래시계는 단위가 3분입니다)에 끝나도록 노력합니다. 여기서 성공을 하건 실패를 하건 많은 걸얻습니다.

@리팩토링 수련법

제가 고안, 사용한 몇 가지 리팩토링 수련법을 알려드립니다.
①일취집중후각법: 앞에 소개한 본지 2001년 11월호에서 인용된 글 참조
②주석 최소화: 주석을 최소화하되 코드의 가독성이 떨어지지 않도록(혹은 오히려 올라가도록) 노력합니다.
이렇게 하면 자동으로 리팩토링이 이뤄지는 경우가 많습니다.
③OAOO 따르기: OAOO 법칙을 가능하면 최대한, 엄격하게 따르려고 합니다. 역시 자동으로 좋은 리팩토링이 이뤄집니다. 여기서 디자인패턴이 창발하기도 합니다. GoF 책을 한번도 보지 못한 사람이 디자인패턴을 자유자재로 부리는 경우를 보게 됩니다.
④디미터 법칙(Law of Demeter) 따르기: 디미터 법칙을 가능하면 지키려고 합니다. 어떤 리팩토링이 저절로 이뤄지거나 혹은 필요 없어지는가요?
⑤짝(Pair) 리팩토링: 함께 리팩토링합니다. 혼자 하는 것보다 더 빨리, 더 많은 걸 배우게 됩니다.
특히, 각자 작성했던 코드를 함께 리팩토링하고, 제3자의 코드를 함께 리팩토링해 봅니다. 사람이 많다면 다른 짝이 리팩토링한 것과 서로 비교하고 토론합니다.
⑥'무엇'과 '어떻게'를 분리: 어떻게에서 무엇을 분리해 내도록 합니다. 어떤 리팩토링이 창발합니까?

여기서 번, 짝 리팩토링은 아주 효과적인 방법입니다. 저는 이것을 협동적 학습(Collaborative Learning)이라고 부릅니다. 상대가 나보다 더 많이 아는 경우만이 아니고, 서로 아는 것이 비슷해도 많은 양의 학습이 발생합니다. 특히, 전문가와 함께 짝 프로그래밍을 하면 무서울 만큼 빠른 학습을 경험할 수 있습니다. 저와 짝 프로그래밍을 한 사람이 학습하는 속도에서 경이감을 느낀 적이 한두 번이 아닙니다. 문화는 사회적으로 학습되는 것입니다. 우리가 지식이라고 하는 것의 상당 부분은 문화처럼 암묵적인 지식(Tacit Knowledge)입니다. 전문가가 문제가 생겼을 때 어떻게 사고하고, 어떤 과정을 거쳐 접근하며, 어떻게 디버깅하고, 키보드를 어떤 식으로 누르는지, 사고 도구로 무엇을 사용하는지, 일 계획과 관리를 어떻게 하는지, 동료와 어떻게 대화하는지 등은 성문화되어 있지 않습니다. 그러나 이런 것들은 아주 중요합니다. 프로페셔널의 하루 일과의 대부분을 이루고 있기 때문입니다. 이런 것들은 전문가 바로 옆에서 조금씩 일을 도와주면서 배워야 합니다. 도제 살이(Apprenticeship)입니다. 진정한 전문가는 모든 동작이 우아합니다. 마치 춤을 추는 것 같습니다. 이 모습을 바로 곁에서 지켜보게 되면, 주니어는 한마디로 엄청난 충격을 받습니다. 그리고 스펀지처럼 빨아들이게 됩니다. 도대체 이 경험을 책이나 공장화한 학교가 어떻게 대신하겠습니까. 이와 관련해서는 레이브와 웽거(Jean Lave, Etienne Wenger)의 『Situated Learning : Legitimate Peripheral Participation』을 강력 추천합니다. 이 글을 보는 모든 교육 종사자들이 꼭 읽어봤으면 합니다. 이 협동적 학습은 두 사람만이 아니고 그룹 단위로도 가능합니다. 스터디에 이용하면 재미와 유익함 일석이조를 얻습니다.
이 외에, 특히(어쩌면 가장) 중요한 것은 일취집중후각법 등을 이용해 자신의 코드 후각의 민감도를 높이는 것입니다. 코드 후각의 메타포 말고도 유사한 메타포가 몇 가지 더 있습니다. 켄트 벡은 코드의 소리를 들으라고 하고, 저는 코드를 향해 대화하라고 합니다. 코드의 소리를 듣는 것은 코드가 원하는 것에 귀를 기울이는 것을 말합니다. 코드는 단순해지려는 욕망이 있습니다. 그걸 이뤄주는 것이 프로그래머입니다. 그리고 짝 프로그래밍을 할 때 두 사람의 대화를 코드에 남기도록 합니다. 주석이 아닙니다. 왜 이것이 중요한가는 본지 2001년 12월호「허실문답 XP 강화」를 참고하기 바랍니다.
기학으로 우리 사상사에 큰 획을 그은 철학자요, '서울서 책만 사다 망한 사람'으로 이름을 날릴 정도로 엄청난 지식욕을 과시하던 조선시대 사상가 혜강 최한기는 그의 저술 『신기통』(神氣通)에서 '눈에 통하는 법(目通),귀에 통하는 법(耳通), 코에 통하는 법(鼻通)' 등을 이야기하고 있습니다. 어떻게 하면 우리는 코드에 도통할 수 있을까요? 리팩토링을 공부하거나 혹은 했던 사람들에게 많은 영감과 메타포를 주는 책으로 일독을 권합니다. 필자가 기회가 닿는다면 프로그래밍을 혜강의 사상적 측면에서 조망한 글을 써보고 싶습니다.
앞서의 것들이 어느 정도 이뤄지고, 리팩토링에 대한 감이 오게 되면 그 때 비로소 리팩토링 책을 하나 하나 파헤치고 또 거기서 제대로 된 비판을 할 수 있게 됩니다.


@디자인패턴 학습에서의 문제

잡지에 연재되거나 서적으로 출간된 혹은 세미나에서 진행되었던 디자인패턴 '강의'를 몇 가지 접했습니다. 훌륭한 강의도 많았지만 그렇지 못한 것도 있었습니다. 몇 가지 문제점을 지적하겠습니다.

◆패턴을 지나치게 실체화, 정형화해 설명한다.
◆컨텍스트와 문제 상황에 대한 설명이 없거나 부족하다. 결과적으로 문제를 해결하기 위해 패턴이 도입된 것이 아니라 패턴을 써먹기 위해 패턴이 도입된 느낌을 준다.
◆문제의식을 먼저 형성하게 하지 않고 답을 먼저 보여준 뒤 그걸 어디에 써먹을지 가르친다. 왜 이걸 쓰는 게 좋은지는 일언반구 언급이 없다. 독자는 '어린아이가 망치를 들고 있는 오류'에 빠질 것이다.
◆패턴이 어떻게 생성되었는지 그 과정을 보여주지 못한다. 즉, 스스로 패턴을 만들어내는 데 도움이 전혀 되지 않는다.
◆해당 패턴이 현실적으로 가장 자주 쓰이는 맥락을 보여주지 못한다. 대부분 장난감 문제(Toy Problem)에서 끝난다.

그런 패턴 강의를 하는 분들이 알렉산더(Christopher Alexander, 패턴언어 창시자)의 저작을 충실히 읽어봤다면 이런 병폐는 없을 것이라 생각합니다. 알렉산더의 저작을 접해보지 못 하고서 패턴을 가르치는 사람은 성경을 읽어보지 않은 전도사와 같을 것입니다. 알렉산더가 『The Timeless Way of Building』의 마지막에서 무슨 말을 하는가요?

“이 마지막 단계에는 더 이상 패턴은 중요하지 않다. … 패턴은 당신이 현실적인 것에 대해 수용적이 되는 것을 가르쳐줬다.”

패턴 역시 도구요, 방편일 뿐입니다. 패턴은 현실적인 것에 대해 수용적이 되도록 가르친다는 말은 결국 우리가 궁극적으로 추구하는 것은 패턴이 아니라 현실이어야 한다는 이야기입니다. 물론 처음 단계에는 교육적인 목적에서, 어느 정도 패턴에 얽매여도 괜찮다고는 해도, 나중에 패턴을 잊고 패턴에서 자유로워지려면 처음부터 패턴에 대해 도구적?방편적인 인식을 가져야 합니다.
미국 캘리포니아 주립대학의 교수 베티 에드워즈(Betty Edwards)가 쓴 책 중에 『Drawing on the Right Side of the Brain』이라는 유명한 베스트셀러가 있습니다. 사람의 뇌와 그림 그리기의 관계에 대한 탁월한 책입니다. 에드워즈는 자신의 그리기 실력을 향상시키기 위해 우뇌를 적극적으로 사용하는 구체적인 방법들을 가르쳐줍니다. 그 중 대표적인 것 하나가 대상을 뒤집어 놓고 그리는 것입니다. 지금 실험해 보길 바랍니다. 1000원권 지폐를 바로 놓고 그걸 비슷하게 그려보고, 이번에는 그걸 위아래가 거꾸로 되게 놓고 따라 그려보십시오. 아마 무척 놀랐을 겁니다. "아니 내가 이렇게 그림을 잘 그리다니! 그것도 거꾸로!" 그렇습니다. 우리는 자신의 머리 속 패턴에 얽매여 세상을 제대로 보지 못 할 때가 많습니다. 실체가 코에 약간이라도 비슷하게 보이면 우리는 그것을
이미 우리 머리 속에 추상적으로 갖고 있던 기하학적 '코'의 패턴으로 대체해버리는 것입니다.

@디자인 패턴 공부

우선은 제 교육철학과 언어교습론, 그리고 공부론 이야기를 잠깐 하겠습니다. 기본적으로 교육은 교육자가 피교육자가에게 지식을 그대로 전달하는 행위가 아닙니다. 진정한 교육은 피교육자의 개인적 체험에 기반한 전폭적 동의에서 출발합니다. 저는 이를 동의에 의한 교육이라고 합니다. 제가 "주석문을 가능하면 쓰지 않는 것이 더 좋다"는 이야기를 했을 때 이 문장을 하나의 사실로 받아들이고 기억하면 당장 그 시점에는 학습이 일어나지 않는다고 봅니다. 대신 여러분이 차후에 여러 가지 경험을 하면서도 이 화두를 놓치지 않고 있다가 어느 순간엔가, "아! 그래, 주석문을 쓰지 않는 게 좋겠구나!"하고 자각하는 순간, 바로 그 시점에 학습과 교육이 이뤄지는 것입니다. 이는 기본적으로 삐아제와 비갓스키(Lev Vygotsky)의 구성주의를 따르는 것이죠. 지식이란 외부에서 입력받는 것이 아니고, 그것에 대한 모델을 학습자 스스로가 내부에서 구축할 때 획득할 수 있는 것이라는 사상이죠. 권법에서 주먹에 대해 달통한 도사가 '권을 내지르는 법'에 대한 규칙들을 정리해서 애제자의 머리 속에 아무리 쑤셔 넣는 데 성공한들 그 제자가 도사만큼 주먹이 나갈리는 만무합니다. 권을 내지르는 법을 유추해 내기까지 그 스승이 겪은 과정을 제자는 완전히 쏙 빼먹고 있기 때문입니다. 소위 '몸'이 만들어지지 않은 것이지요. 제자는 마당 쓸기부터, 물 긷기 등의 수련 과정을 겪어야만 하고 스승이 정리한 그 일련의 규칙에 손뼉을 치고 춤을추며 기쁨의 동의를 할 수 있을 정도로 수련 과정이 축적된 이후에야 비로소 진정한 '가르침'이 이뤄지는 것이며, 청출어람의 가능성도 생각해 볼 수 있는 것입니다. 이런 동의라는 것은 학습자 자신만의 컨텍스트와 문제의식을 바탕으로 한 것입니다. 우리는 많은 경우, 어떤 지식과 동시에 그 지식의 필요성까지도 지식화해서 외부에서 주입을 받습니다. 하지만 진정 체화된 지식을 위해서는 스스로가 이미 문제의식을 갖고 있어야 합니다.
패턴도 마찬가지인데, 대부분 그 패턴의 필요성을 체감하지 못한 채 그냥 도식적 구조를 외우기에만 주력하는 사람이 많습니다만, 사실 그렇게 되면 어떤 경우에 이 패턴이 필요하고 어떤 경우에는 사용하면 안 되는지(GoF는 패턴을 정말 안다는 것은 그 패턴을 쓰면 안 될 때를 아는 것이라 했습니다) 등을 알기 힘듭니다. 설령 책에 나온 가이드를 암기했더라도요. 자신의 삶 속에서 문제의식이 구체적으로 실제 경험으로 형성되지 않았기 때문입니다.
GoF 중 한 명인 랄프 존슨(Ralph Johnson)은 다음과 같이 말합니다.

"우리[GoF]는 책에서, 정말 그 패턴들이