나는 만들고 싶은 프로그램을 어떻게 짜야할지 생각해내기 어려울 때, 다른 사람이 만든 오픈 소스 프로젝트의 코드(이하 오픈 소스)를 읽어본다. 오픈 소스를 읽다보면 배우는 점이 많다. 보통 프로그램은 어떤 문제를 해결하기 위한 것이고, 오픈 소스를 읽다보면 프로젝트 저자가 그 문제를 어떻게 생각하는지 들여다볼 수 있다. 또한 그런 생각을 어떻게 코드로 풀어내는지 보면서, 코드를 어떻게 짜야할지와 관련한 다양한 아이디어를 얻기도 한다.
관심 있는 오픈 소스 프로젝트를 찾았더라도 규모가 크고 복잡한 경우도 많았다. 개인적으로 복잡한 프로젝트를 이해하기에는 무리가 있다고 느껴서, 이 대신 프로젝트 초기 버전의 소스 코드를 찾아 읽는다. 비록 최신 버전에 추가된 기능이나 에러 처리 등이 없지만, 초기 버전은 최신 버전에 비해 비교적 다룰 수 있을 만큼의 복잡도를 가지고 있을 확률이 높다.
그러면 초기 버전 소스는 어떻게 구할까? 해당 프로젝트가 버전관리되고 있다면 초기 버전의 기록을 찾아서 그 때의 소스가 어땠는지 살펴볼 수 있다. jekyll 프로젝트의 경우, 깃허브에서 버전관리되고 있다. 저장소를 로컬로 가져와서 처음 버전을 기준으로 로그를 출력하면 첫 커밋부터 시작해서 커밋 해시값을 알아낼 수 있다.
$ cd /tmp
$ git clone https://github.com/jekyll/jekyll.git
$ cd jekyll
$ git log --pretty=oneline --abbrev-commit --reverse | head -n4
d189e05d2 first commit
7dfe32a59 read layout files into hash
6fb91f4f7 cleanup and tests
6c0eeb573 read posts
커밋 해시를 알아내고 나면, 첫 커밋부터 따라가면서 소스를 볼 수 있다. 나는 checkout과 show 명령을 주로 쓴다. checkout 명령은 해당 커밋 당시의 환경으로 이동해 소스 전체를 확인하거나, 소스를 편집할 수 있다. show 명령으로는 이전 커밋과 달라진 내용을 확인할 수 있다.
$ git checkout d189e05d2 # 첫 커밋 당시의 환경으로 이동한다
$ git show 7dfe32a59 # 첫 커밋과 비교해 두번째 커밋에서 달라진 점을 보여준다
...
초기 커밋도 이해하기 어려운 경우 적절히 타협하는 것도 방법이다. 파서를 만들 일이 생겨서 오픈 소스를 조사해보다 kramdown이라는 마크다운 파서 라이브러리를 알게 되었다. 하지만 첫 커밋의 내용부터 이해하기가 어려웠다. 적당한 시간 동안 코드 분석을 시도해보고 이건 지금 내가 이해할 수 없는 코드란 걸 인정했다. 깔끔하게 포기하고, 더 간단한 다른 오픈 소스를 찾아 나섰다. 실제로 쓸만한 정도는 아니었지만, 구현 관련해 꼼꼼한 블로그 글을 제공하는 오픈 소스를 찾았고, 이걸 기반으로 작업했다.
초기 버전은 소스가 훨씬 간단하긴 하지만, 어떤 점에선 번거롭다. 나는 소스를 분석할 때, 실제로 실행 가능하게 만들어 놓고 학습 테스트를 추가하거나 프로그램 본문에 프린트 구문을 추가해 확인해보면서 프로그램을 이해하는 경우가 많다. 하지만 초기 버전은 오래된 환경에서 만들어져서 그때와 동일한 상태를 재현하는 게 어렵다.
초기 버전 당시의 환경을 쉽게 재현할 수 없으면, 내가 설정 가능한 가장 오래된 환경과 초기 버전 당시의 상태 사이에 일어난 변화에 따른 프로그램의 깨짐을 고쳐야 한다. Jim Weirich의 Rake 프로젝트는 꽤나 오래 된 프로젝트다. Rake 초기 버전을 읽으면서 이런 문제를 여러 개 경험했다.
Rake에서와 같이 실행 가능한 상태를 만들기 위해 기존 코드를 많이 바꿔야 한다면, 분석할 당시의 커밋에서 다음 커밋으로 옮겨갔을 때 코드가 꼬일 가능성이 다분하다. 따라서 이런 점을 고려해 가능한 덜 번거롭게 실행 가능한 상태를 만들 수 있도록 해주는 것이 괜찮은 것 같다. 나의 경우, 파일 단위의 변경인 경우 실행 시 참조할 경로에 추가했고, 기존 파일에 라인 단위로 추가되는 내용이라면 patch 파일로 만들어 git apply 등의 명령으로 한 번에 기존 코드에 덧댈 수 있게 했다.