나의 노트

프로그램을 다듬기

번역 워드 커닝햄과의 대화, 제3부 글: 빌 베너스 (Bill Venners) 2004년 1월 5일 www.artima.com/articles/working-the-program ↗

요약 워드 커닝햄이 빌 베너스와 함께 변경 비용 곡선의 평탄화, 미래 예측의 문제점, 그리고 예술가의 손에 들린 점토로서의 프로그램에 대해 이야기합니다.

소프트웨어 업계에서 워드 커닝햄은 아이디어의 원천으로 명성이 높습니다. 그는 객체 발견을 돕는 기법인 CRC 카드를 고안했습니다. 또한 소프트웨어 패턴의 발견과 문서화를 돕기 위해 웹 기반 협업 저작 도구인 위키(Wiki)를 세계 최초로 발명했습니다. 가장 최근에는 익스트림 프로그래밍(Extreme Programming, XP)의 여러 기법에 주된 영감을 준 인물로 꼽힙니다.

2003년 9월 23일, 빌 베너스는 덴마크 오르후스에서 열린 JAOO 컨퍼런스에서 워드 커닝햄을 만났습니다. Artima.com에 여러 편에 걸쳐 연재되는 이 인터뷰에서 커닝햄은 위키와 익스트림 프로그래밍의 여러 측면에 대한 통찰을 제공합니다.

[제1부: 위키를 이용한 탐험]에서 커닝햄은 협업 탐험을 위한 위키 사용과 위키 작성자와 독자 간의 균형(tradeoff)에 대해 논의합니다.

[제2부: 코드와 텍스트의 공동 소유]에서 커닝햄은 어떻게 위키를 코드 공동 소유의 모델로 설계했는지, 소유권에 대한 자부심을 위한 공동의 인센티브, 그리고 실수를 저지르는 비용을 제거함으로써 의견 충돌을 다루는 법에 대해 이야기합니다.

이 세 번째 편에서 커닝햄은 변경 비용 곡선의 평탄화, 미래 예측의 문제점, 그리고 예술가의 손에 들린 점토로서의 프로그램에 대해 논의합니다.

변경 비용 (The Cost of Change) 빌 베너스: 켄트 벡(Kent Beck)은 그의 저서 Extreme Programming Explained에서 "소프트웨어 공학의 보편적인 가정 중 하나는 프로그램 변경 비용이 시간이 지남에 따라 기하급수적으로 증가한다는 것이다"라고 썼습니다. 그리고 "기술과 프로그래밍 실천법(practices)을 결합하면, 그와는 정반대인 곡선을 경험하는 것이 가능하다"고 제안했습니다. 어떻게 변경 비용 곡선을 평평하게 만들 수 있습니까?

워드 커닝햄: 전통적으로 변경 비용 곡선은 변경의 필요성을 일찍 감지할수록 늦게 감지하는 것보다 비용이 적게 든다는 것을 의미했습니다. 저는 "거의 의도적으로 실수를 저질러서 그것을 수정하는 연습을 하자"고 말함으로써 그 곡선에 도전했습니다. 그 연습이 나중에 변경을 수행할 때 드는 비용을 줄이는 데 도움이 될 것이라 보았죠.

우리의 생각은 어떤 변경이든 제한 요소(limiting factor)는 변경이 수행된 시점이 아니라, 얼마나 많은 사고(thinking)가 필요한가라는 점이었습니다. 1주 차에 변경을 수행했는데 진짜 필요한 게 무엇인지 이해하는 데 이틀이 걸렸다면, 변경하는 데 이틀이 걸린 것입니다. 21주 차에 변경을 수행했는데 진짜 필요한 게 무엇인지 이해하는 데 이틀이 걸렸다면, 역시 변경하는 데 이틀이 걸린 것입니다.

1주 차에는 코드를 20줄 작성해야 했을지 모릅니다. 21주 차에는 20줄을 작성하고 기존 코드 4줄을 변경해야 했을 수도 있습니다. 하지만 변경하는 연습이 되어 있다면, 4줄을 바꾸는 데 걸리는 시간은 그리 길지 않습니다. 해당 구문을 찾아서 바꾸면 됩니다. 1분이면 될 수도 있죠.

따라서 변경의 필요성을 이해하는 것이 제한 요소였습니다. 프로그래밍 자체는 부차적인 문제였죠. 일단 변경 사항을 이해하면, 초반이든 후반이든 프로그래밍할 수 있었습니다. 실제로 코드를 변경하는 비용이 프로그래밍 전체를 지배하지 않았습니다. 지배적인 비용은 요구 사항을 이해하는 데 걸리는 시간이었고, 바로 그 점이 변경 비용 곡선을 평평하게 만들어 주었습니다.

많은 사람이 변경을 두려워합니다. 왜냐하면 코드를 작성할 당시에는 이해하고 있었지만, 그 이해가 사라졌기 때문입니다. 그들은 이렇게 말할 겁니다. "이 코드 짜느라 정말 고생했어. 무슨 일이 있어도 이 부분은 건드리지 마!" 그들은 그 코드로 다시 돌아가고 싶어 하지 않습니다. 다시 이해하는 데 비용이 너무 많이 들 테니까요. 그래서 변경 비용 곡선을 평탄하게 만드는, 즉 나중에 변경해도 지금 변경하는 것보다 비용이 더 들지 않게 만드는 또 다른 방법은, 변경할 사람이 코드를 보고 이해할 수 있어야 한다고 결정하는 것입니다. 그러므로 코드를 작성할 때는, 그 코드를 실행할 기계보다는 그 코드를 읽게 될 사람을 위해 작성해야 합니다.

그리고 다시 말하지만, 미래에 누군가가 원할지 모르는 변경을 수행하는 방법을 설명하는 긴 주석을 달아서는 안 됩니다. 그들이 어떤 변경을 원할지 당신은 모르기 때문입니다. 미래의 프로그래머가 변경하는 것을 당신이 도울 수는 없다는 태도를 갖는 게 낫습니다. 당신이 할 수 있는 일은 오직 당신이 무엇을 하려고 했는지 그들이 쉽게 이해하도록 만드는 것뿐입니다. 그리고 당신이 하려고 했던 것을 그들이 가장 쉽게 이해하는 방법은 당신이 너무 많은 것을 하려고 하지 않도록 매우 주의하는 것입니다. 당신이 더 많은 것을 하려고 노력할수록, 미래의 프로그래머는 당신이 해놓은 일을 이해하는 데 더 많은 노력을 들여야 할 것입니다.

예를 들어, 미래의 프로그래머가 처리해야 할 상황을 당신이 아주 노골적으로(blatantly) 무시했다고 칩시다. 그들은 코드를 보고 당신이 그 상황을 아예 무시했다는 것을 발견할 것입니다. 이것은 그들에게 필요한 일은 무엇이든 할 수 있는 자유가 있다는 뜻입니다. 하지만 당신이 그 상황을 미리 고려해서 처리하려고 시도했다면, 그들은 들어와서 그것이 작동하지 않는다는 것을 깨닫게 됩니다. 그들은 당신이 그것을 처리하려 했다는 것을 보고, 먼저 당신이 무엇을 하려고 했는지 이해하려 애쓸 것입니다. 당신의 의도를 이해한 후에야 그들은 자신들이 필요로 하는 일을 하기 위해 그것을 어떻게 고쳐야 할지 알아낼 수 있습니다. 그들은 차라리 당신이 그 문제에 대해 아예 생각조차 안 했다는 사실을 발견하는 편을 훨씬 더 선호할 것입니다. 어쩌면 당신은 생각은 했지만, 코드로 옮기지는 않았을 수도 있겠죠.

미래 예측하기 (Predicting the Future) 빌 베너스: 미래를 예측하는 것이 어렵다는 데에는 누구나 동의하겠지만, 그것이 항상 나쁜 생각일까요?

워드 커닝햄: 과학에서 미래를 예측하는 것은 쉽습니다. 과학은 물리적 시스템의 행동을 연구하는 것에 기초하고 있으며, 날씨 정도를 제외하면 물리적 시스템은 꽤 놀랍도록 예측 가능합니다. 우리는 이론의 예측 능력을 검증함으로써 이론을 시험합니다. 로켓을 우주로 쏘아 올려 궤도를 돌게 할 수 있다는 사실, 이것이 예측의 전형입니다. 하지만 미래에 무엇이 요구될지에 대해 이야기하기 시작하면, 우리는 어떤 직감을 가질 수 있고 그것이 맞을 수도 있지만, 항상 맞지는 않을 것입니다. 그리고 우리는 그것이 맞지 않을 때에 대비해야 합니다.

저는 새로운 요구 사항이 들어왔을 때 우리가 그것을 보고 "음, 그건 쉽네. 프로그램이 원래 그걸 하게끔 만들어져 있으니까."라고 말할 수 있을 때가 정말 좋습니다. 조각들을 프로그램에 넣으면 딱 들어맞는 거죠. 반대로 마치 프로그램이 그 요구 사항을 어렵게 만들기 위해 설계된 것처럼, 새로운 요구 사항이 잘 들어맞지 않을 때는 정말 싫습니다. 그런 경우 우리는 할 일이 많습니다. 하지만 그 일의 본질은 먼저 새 요구 사항이 쉽게 들어맞도록 프로그램을 변경하고, 그다음에 그 요구 사항을 통합하는 쉬운 작업을 수행하는 것입니다. 다시 말해, 그것을 수용하도록 만들어지지 않은 아키텍처에 새 요구 사항을 억지로 덧대어 붙이는(patch) 대신, 요구 사항을 구현하기 쉽도록 아키텍처를 변경하는 힘든 작업을 마음먹고 수행하는 것입니다. '패치' 방식은 그다음에 올 사람에게 원래 새 요구 사항을 처리하도록 만들어지지 않은 시스템과, 그 시스템을 변경하지 않고 극복하려고 시도한 패치 둘 다를 이해해야 하는 부담을 줍니다. 새로운 기능을 쉽게 수용하도록 시스템을 변경하는 것이 훨씬 낫습니다.

누군가는 이렇게 말할지도 모릅니다. "왜 미리 앞을 내다보고 우리가 해야 할 모든 일을 살피지 않죠? 처음부터 모든 작업을 쉽게 만드는 시스템을 설계하면 되잖아요?" 만약 그렇게 해낼 수 있다면, 아주 좋겠죠. 단지, 사람들이 내일의 작업을 쉽게 만드는 시스템을 설계하려고 계속 시도하지만, 막상 내일이 되면 그들이 내일의 작업을 제대로 이해하지 못했다는 것이 드러나고, 실제로는 일을 더 어렵게 만들었다는 경우가 비일비재하다는 게 문제입니다.

우연한 아키텍처 (The Accidental Architecture) 빌 베너스: 변경 비용 곡선을 해결하기 위해, 당신은 프로젝트의 수명 주기 내내 변경을 수행하는 것이 현실적으로 가능한 방법을 찾아냈습니다. 그리고 이는 미래를 위해 계획하는 것을 덜 중요하게 만들었습니다. 왜냐하면 미래가 펼쳐짐에 따라 변경이 실제로 필요할 때 변경하면 되니까요. 그렇다면 전체적인 아키텍처는 단순히 각각의 작은 단계에만 집중하는 과정에서 저절로 드러나는(emerge) 것입니까?

워드 커닝햄: 저는 마치 예술가가 점토 덩어리를 다루듯이 프로그램을 다듬는다(working the program)는 개념을 좋아합니다. 예술가는 조각상을 만들고 싶어 하지만, 조각을 만들기 전에 점토를 그저 주무릅니다(massage). 조각을 만들기 시작하면서 점토가 무엇을 하려는지 봅니다. 점토를 만지면 만질수록 점토는 점점 더 그녀가 원하는 대로 움직여 줍니다. 그녀의 의지에 순응하게 되는 것이죠.

개발팀은 몇 달 동안 코드 한 조각을 다룹니다. 처음에 코드를 만들면 약간 뻣뻣합니다(stiff). 작지만 여전히 뻣뻣하죠. 그러다 코드를 옮기면, 옮기기가 조금 더 쉬워집니다. 제가 앞서(2부에서) 언급했던 프로젝트에서 우리는 데이터베이스에 스키마 진화(schema evolution) 기능을 추가했습니다. 그것은 프로그램을 부드럽게(soften up) 만들었습니다. 변경하기가 훨씬 쉬워졌죠. 스키마 변경을 할 때마다 우리는 더 능숙해졌습니다. 프로그래머들과 코드가 하나의 단위로서 부드러워진 것입니다. 우리는 프로그램을 계속 다듬었고(worked the program), 유연하게 유지했습니다.

프로젝트가 끝날 때 당신은 해야 할 모든 일, 어쨌든 누군가가 비용을 지불한 모든 일을 완료했습니다. 그리고 코드를 보며 묻습니다. "이 덩어리의 핵심에는 무엇이 들어있지?" 이렇게 묻죠. "결과가 어떻지? 매일매일 프로그램을 다듬은 결과, 결국 어떻게 되었지?" 종종 프로그램은 놀라운 결말을 보여줍니다. 당신은 "이건 아름답게 아키텍처가 잡혀있어."라고 말할 겁니다. 글쎄요, 그 아키텍처는 어디서 왔을까요?

이 경우 아키텍처는 우리가 다양한 요구 사항을 다루는 체계적인 방법을 의미합니다. 아키텍처는 우리가 프로그램에 필요한 작업을 하려고 할 때, 사물들이 어디로 가야 하는지 찾을 수 있게 해 줍니다. 그것은 우리가 내린 모든 작은 결정들, 즉 옳았던 작은 결정들과 틀려서 수정된 작은 결정들에 의해 프로그램 속으로 스며든(worked into) 시스템입니다. 어떤 의미에서 우리는 실제로 노력하지 않고도 아키텍처를 얻습니다. 다른 결정들의 맥락 안에서 내려진 모든 결정이 자연스럽게 굳어져(gel) 아키텍처가 되는 것입니다.

다음 주 예고 1월 12일 월요일, 워드 커닝햄과의 대화 다음 편이 연재됩니다. Artima.com의 새 기사 알림을 매주 이메일로 받고 싶으시면 Artima 뉴스레터를 구독하세요.