인터랙티브 프로그래밍

by Eonil

프로그래밍이 시간이 많이 걸리고 어려운 것은 이것이 기본적으로 예측에 기반하기 때문입니다.

프로그램은 명령의 목록인데, 실제로 해당 명령이 수행되기 전에는 환경의 상태가 어떨지 알 수 없습니다. 프로그래머는 여러가지 조건과 졔약을 통해 실행상태를 예측합니다. 명령을 통해 변화하는 상태도 예측합니다. 예측이 틀리면 오류가 발생하고, 그러면 프로그램을 고쳐야 합니다. 그리고 처음부터 다시 실행합니다.

버그를 없애기 위해서는 실행순간의 상태를 정확하게 예측해야 합니다. 결국 프로그래머는 정교한 예언가입니다. 몰려오는 비구름을 보고 폭풍우를 예측하는 것과 같은 일입니다. 하지만 막상 비구름이 오기 전에 사라질 수도 있으며, 폭풍이 아니라 소나기로 끝날지도 모릅니다.

프로그램이 실행되고 있는 순간의 상태를 알 수 있고, 해당 순간에 프로그램을 직접 고칠 수 있다면 수정을 위해 프로그램을 처음부터 돌리지 않아도 되며, 무엇보다 미래의 상태를 예측하는 점쟁이같은 짓을 하지 않아도 됩니다.

새로운 프레임워크

현재의 프로그래머는 언어가 아니라 프레임워크를 배웁니다. 언어는 아무리 어려워도 한달이면 배울 수 있습니다. 익숙해지는데 시간이 걸릴 뿐이죠. 하지만 자고나면 새로나오는 프레임워크를 배우는 것은 고역입니다. 문법이 문제가 아닙니다. 문제는 이 프레임워크가 어떻게 움직이는지 모른다는 것입니다. 많은 경우에는 문서가 충분하지 않습니다. 치명적인 오류만 간신히 피할 수 있는 정도의 문서만 있는 경우도 많죠. 이 경우 반복적인 관찰로 동작을 알아내야 합니다. 물론 동작이 잘 설명된 문서가 딸려 있는 좋은 SDK도 있지만, 어떤 순서로 사용하는 것이 옳은 것인지 확신을 갖기 위해서는 여전히 관찰을 해야 합니다.

그래서 프레임워크를 배우는 것은 문법을 배우는 것이 아니라 그 코드가 어떻게 작동하는지 관찰하는 것입니다. 동물학자들이 사막여우의 생태를 관찰하기 위해 사바나 한가운데서 몇달동안 지내는 것과 같죠. 명령을 수행시켜보고 어떻게 움직이는지 관찰하는 일련의 일련의 실험을 통해 코드의 동작을 파악합니다. 10년간 사막여우를 관찰한다면 어떤 확신이 생길 것이고 100만Km 떨어진 도시 한가운데에서도 책을 쓸 수 있을 겁니다.

그래서 좋은 프레임워크의 조건은 일관적인 사용법입니다. 한 가지 방법만 알면 나머지는 비슷하게 쓰면 된다는 것이죠. 하지만 세상은 깔끔하지 못하고, 프레임워크들은 각각 자기만의 방식으로 움직입니다. 그래도 이것저것 많이 다루어보다보면 대략 뻔한 동작 패턴들을 익히게 되니 점차 사용이 쉬워지긴 합니다.

인터랙티브 프로그래밍

현재는 미래보다 더 알기 쉽습니다. 프로그래머가 실행 순간의 상태에 서 있다면 프로그래밍은 쉽고 빠르며 재밌는 일이 될 것입니다. 코딩을 미래에 대한 예측이 아니라 현재의 동작을 정의하는 것으로 만들어야 합니다. 그러면 새로운 프레임워크에 관찰이 실시간으로 이루어집니다. 또한, 지금 작성하고 있는 코드가 바로 프로그램에 추가되기에, 관찰하면서 원하는 동작을 이끌어내면 프로그램 작성이 완료됩니다. 마치 워드프로세서의 매크로 같은거죠. 원하는 동작을 녹화하면 프로그램이 자동으로 작성되고, 다음에는 이것을 재생하기만 하면 똑같은 동작이 만들어지는 것이죠.

이것은 디버깅에도 탁월합니다. 오류가 나면 프로그램이 일시정지하면서 콘솔이 나옵니다. 프로그램에서 오류가 난 부분도 바로 보입니다. 프로그래머는 잘못된 부분을 수정합니다. 수정하는 즉시 프로그램이 고쳐집니다. 일종의 트랜젝션 기능이 있다면 특정한 단위로 상태를 롤백하고 재개할 수도 있을 것입니다. 그러면 최종 트랜젝션 때부터 프로그램을 재개하면 됩니다. 정상적으로 작동하는 것이 확인되면 프로그램 작성이 완료됩니다. 일상적인 디버깅 과정중 가장 많은 시간을 보내는 부분이 컴파일과 상태 재현입니다. 코딩하는 것은 사실 별 문제도 아니죠. 가끔씩 고난이도의 논리 버그를 만나 몇일씩 생각만 하기도 하지만, 이 때도 상태 재연에 집중력을 빼앗기지 않는다면 더 빨리 문제를 해결할 수 있습니다.

이 사실을 깨닫는 데는 리스프를 알게 된 것이 가장 큽니다.

필요한 것들

인터랙티브 프로그래밍을 위해서는 일단 언어가 중요합니다. 실행중에 프로그램 자체를 수정하고 저장할 수 있는 기능이 필요합니다. 부분적으로가 아니라 완전하게 수정될 수 있어야 합니다. 이를 위해서 프로그램은 반드시 인터프리터 방식이어야 합니다. 또한, 현재 메모리된 전역/지역 변수들을 확인할 수 있고 실행되고 있는 코드가 모듈이나 프로시저상에서 어디에 위치하고 있는지도 확인할 수 있어야 합니다. 이러한 정보를 보여주고 변경을 즉시 적용할 수 있는 콘솔이 필요합니다. 많은 디버거가 실행중에 메모리를 수정하고 재개하는 기능을 제공하지만, 동시에 코드를 수정하고, 수정된 코드를 바로 프로그램에 주입하는 기능은 없습니다. 이러한 콘솔이 있으면 디버거가 따로 있을 필요가 없습니다. 코딩과 디버깅이 하나의 콘솔에서 동시에, 같이 이뤄집니다.

제가 알기로는 인터프리터 언어는 모두 이러한 가능성을 갖고 있습니다.