작동 가능한 가장 단순한 것
요약 워드 커닝햄이 빌 베너스와 함께 '힘을 실어주는 복잡성'과 '어려움을 초래하는 복잡성'의 차이, 해결책으로 가는 최단 경로로서의 단순성, 그리고 막혔을 때 가장 단순한 것을 코딩하는 방법에 대해 이야기합니다.
소프트웨어 업계에서 워드 커닝햄은 아이디어의 원천으로 명성이 높습니다. 그는 객체 발견을 돕는 기법인 CRC 카드를 고안했습니다. 또한 소프트웨어 패턴의 발견과 문서화를 돕기 위해 웹 기반 협업 저작 도구인 위키(Wiki)를 세계 최초로 발명했습니다. 가장 최근에는 익스트림 프로그래밍(Extreme Programming, XP)의 여러 기법에 주된 영감을 준 인물로 꼽힙니다.
2003년 9월 23일, 빌 베너스는 덴마크 오르후스에서 열린 JAOO 컨퍼런스에서 워드 커닝햄을 만났습니다. Artima.com에 여러 편에 걸쳐 연재되는 이 인터뷰에서 커닝햄은 위키와 익스트림 프로그래밍의 여러 측면에 대한 통찰을 제공합니다.
[제1부: 위키를 이용한 탐험]에서 커닝햄은 협업 탐험을 위한 위키 사용과 위키 작성자와 독자 간의 균형(tradeoff)에 대해 논의합니다.
[제2부: 코드와 텍스트의 공동 소유]에서 커닝햄은 어떻게 위키를 코드 공동 소유의 모델로 설계했는지, 소유권에 대한 자부심을 위한 공동의 인센티브, 그리고 실수를 저지르는 비용을 제거함으로써 의견 충돌을 다루는 법에 대해 이야기합니다.
[제3부: 프로그램을 다듬기(Working the Program)]에서 커닝햄은 변경 비용 곡선의 평탄화, 미래 예측의 문제점, 그리고 예술가의 손에 들린 점토로서의 프로그램에 대해 논의합니다.
[제4부: 계획할 것인가, 말 것인가]에서 커닝햄은 아이디어를 설계하고 소통하기 위해 화이트보드 대신 프로그래밍 언어를 사용하는 것에 대해 이야기합니다.
이 다섯 번째이자 마지막 편에서 커닝햄은 역량을 강화하는 복잡성과 어려움을 초래하는 복잡성, 해결책에 이르는 최단 경로로서의 단순성, 그리고 막혔을 때 가장 단순한 것을 코딩하는 것에 대해 논의합니다.
힘을 실어주는 복잡성 (Complexity that Empowers) 빌 베너스: 단순성이란 무엇입니까? 단순함을 볼 때 그것을 어떻게 알아볼 수 있으며, 왜 우리는 그것을 추구해야 할까요?
워드 커닝햄: 저는 사실 힘을 실어주는(empowering) 복잡성을 즐깁니다. 저에게 도전 의식을 준다면, 그 복잡성은 매우 즐거운 것입니다. 하지만 때로는 힘을 빼앗는(disempowering) 복잡성을 다루어야 할 때가 있습니다. 그런 복잡성을 이해하기 위해 들이는 노력은 지루한 작업일 뿐입니다. 제 능력에 아무런 보탬이 되지 않죠.
제 친구가 이런 말을 한 적이 있습니다. 세상에는 문제(problems)가 있고 어려움(difficulties)이 있다고요. '문제'는 음미할 만한 것입니다. 당신은 "음, 흥미로운 문제네. 저 문제에 대해 좀 생각해 봐야겠어."라고 말합니다. 그 문제에 대해 생각하는 것을 즐깁니다. 왜냐하면 해결책을 찾았을 때 깨달음을 얻기 때문입니다.
반면에 '어려움'이 있습니다. 컴퓨터는 어려움을 주기로 유명하죠. 어려움은 그저 진보를 가로막는 장애물일 뿐입니다. 당신은 수많은 시도를 해야 합니다. 마침내 작동하는 방법을 찾아낸다 해도, 그것은 당신에게 아무것도 가르쳐주지 않습니다. 내일이면 또 달라질 테니까요. 컴퓨터를 작동시키는 일은 너무나 자주 이런 '어려움'을 처리하는 일입니다.
우리가 경멸하는 복잡성은 바로 이런 어려움을 초래하는 복잡성입니다. 문제를 제기하는 복잡성이 아닙니다. 세상에는 많은 복잡성이 있습니다. 세상은 복잡하니까요. 그 복잡성은 아름답습니다. 저는 사물이 어떻게 작동하는지 이해하려 노력하는 것을 좋아합니다. 그 복잡성을 마스터함으로써 배울 것이 있기 때문입니다.
단순성: 해결책으로 가는 최단 경로 (Simplicity: the Shortest Path to a Solution) 그렇다면 단순성이란 무엇일까요? 단순성은 해결책으로 가는 최단 경로입니다. 누군가 어떤 수학 문제에 대한 증명을 20페이지에 걸쳐서 해냈다고 칩시다. 당신은 그 20페이지를 공부하고 마침내 "아, 이제 알겠어."라고 말합니다. 그 증명을 이해한 결과로 보상을 얻습니다. 왜냐하면 그 증명은 단순한 '어려움'이 아니라 흥미로운 '문제'에 대한 해결책이었기 때문입니다.
나중에 다른 누군가가 같은 문제에 대해 10페이지짜리 증명을 내놓습니다. 어쩌면 이 새로운 증명은 당신이 마스터해야 할 새로운 수학 분야를 사용할지도 모릅니다. 하지만 일단 그 분야를 마스터하면 그것을 활용할 수 있습니다. 그리고 20페이지짜리 증명은 10페이지짜리가 됩니다. 더 짧은 경로이기 때문에 이것이 더 단순하다고 말해야 합니다. 비록 새로운 수학 분야를 배우기 위해 잠시 우회해야 해서 시간이 더 걸릴지라도 말이죠. 하지만 시간이 지나면서 우리 모두가 이 분야를 아는 것이 중요하다고 깨닫고 익숙해진다고 가정해 봅시다.
우리가 소프트웨어에서 진정으로 하려는 것은 문제 해결책으로부터 가치를 얻는 일을 쉽게 만드는 방법을 찾는 것입니다. 어떻게 해야 할까요? 우리는 프로그램을 짤 때(work the program), 해결책으로 가는 최단 경로라고 생각되는 것을 집어넣습니다. 그리고 문제가 우리가 생각했던 것과 다르다는 것을 발견하면, 다시 작성합니다. 그리고 또 다시 작성합니다. 프로그램을 계속 다듬는 것입니다. 이 과정은 증명을 반복해서 하는 것과 같습니다.
조만간 우리는 30줄의 코드로 하던 일을 15줄로 할 수 있다는 것을 발견하게 됩니다. 이제 딱 맞는 또 다른 기능(capability)을 갖게 되었기 때문입니다. 정말 딱 맞는 기능이라서, 거기서 이미 해놓은 일을 여기서 다시 할 필요가 없습니다. 그냥 여기서 그 기능을 호출하기만 하면 됩니다. 이렇게 하면 해결책을 따라가기가 더 쉬워집니다. 게다가 오늘 코드를 이해하기 위해 들이는 노력은 내일 당신을 더 강력한 프로그래머로 만들어 줄 것입니다. 그래서 그러한 단순화는 매우 가치 있습니다.
프로그램을 많이 짜보고, 항상 코드를 쥐어짜는(압축하는) 것에 익숙해지면, 단순한 프로그램을 짜는 것이 쉽다는 것을 알게 됩니다. 많은 부분은 자신이 말하고자 하는 바를 명확히 아는 것에서 옵니다. 증명을 쓸 때 무엇을 증명할지 선택하고 그것을 명확히 하는 것처럼 말이죠. 프로그래밍에서 단순함의 많은 부분은 무엇이 중요하고 무엇이 중요하지 않은지를 아는 데서 옵니다. 많은 경우 프로그램은 불필요한 세부 사항에 신경 쓰거나, 피할 수 있었거나, 다른 곳으로 위임할 수 있었던 것들 때문에 복잡해집니다.
누군가는 "항상 인자가 범위 내에 있는지 확인해야 한다"고 말합니다. 다른 누군가는 "이 프로그램 문장의 절반은 본질적으로 범위 내에 있을 수밖에 없는 인자들을 확인하고 있다"고 말합니다. 그들이 프로그램을 더 낫게 만들었을까요, 아니면 더 나쁘게 만들었을까요? 아니요, 저는 그들이 더 나쁘게 만들었다고 생각합니다. 저는 인자 확인(argument checking)의 팬이 아닙니다.
반면에, '빨리 실패(fail fast)'해야 합니다. 실수를 했다면 프로그램은 멈춰야 합니다. 따라서 어디서 확인해야 할지 알고, 실수를 했을 때 프로그램이 즉시 실패하도록 만드는 데는 기술(art)이 필요합니다. 그런 선택을 하는 것이 단순화 기술의 일부입니다.
아인슈타인은 이렇게 말했습니다. "가능한 한 단순하게, 하지만 그보다 더 단순해서는 안 된다(As simple as possible, but no simpler)." 그는 복잡하다는 비난을 받고 있었고, 이에 대해 "그래요, 단순한 것은 중요합니다, 하지만..."이라고 말했던 거죠. 그는 설명되지 않은 관찰 사실들을 취해서 설명해 냈습니다. 네, 그의 이론과 모델은 뉴턴의 것보다 복잡했지만, 더 많은 것을 해냈습니다. 공부할 가치가 있었죠. 그는 "보세요, 나는 이것들을 가능한 한 단순하게 만들었지만, 필요 이상으로 단순화하지는 않았습니다."라고 말하고 있었던 겁니다.
그러니 오늘 우리는 프로그램을 단순하게 짭시다. 하지만 내일은 프로그램을 더 복잡하게 만들게 될 거라는 점도 인식합시다. 내일은 더 많은 일을 할 테니까요. 그래서 우리는 그 단순함을 가져가서 일부는 잃게 될 것입니다. 하지만 바라건대 내일의 프로그램은 내일의 요구 사항에 대해 가능한 한 단순한 상태일 것입니다. 프로그램이 성장하더라도 단순성이 유지되기를 희망합니다.
작동 가능한 가장 단순한 것은 무엇인가? (What's the Simplest Thing that Could Possibly Work?) 켄트 벡(Kent Beck)과 제가 스몰토크(Smalltalk)를 가지고 놀 때, 우리가 이전에 사용했던 어떤 것보다 스몰토크가 해내는 일들이 정말 놀라웠습니다. 스몰토크는 정말로 우리가 무언가를 시도해 보기를 원하는 것 같았습니다. 종종 우리는 우리가 뭔가를 프로그래밍할 줄 아는지 확인하기 위해 그냥 시도해보곤 했습니다. 우리는 무언가에 대해 이야기하다가, "이런, 우리가 저걸 프로그래밍할 수 있을까?"라고 말하곤 했죠. 그리고 바로 뛰어들어 프로그래밍을 시작했습니다. 때로는 프로그래밍이 거의 힘이 들지 않아서, 마치 스몰토크가 그 프로그램을 짜기 위해 만들어진 것처럼 느껴졌습니다. 정말 놀라웠죠.
하지만 어떤 때는 프로그래밍을 하다가 "잠깐, 우리가 지금 뭘 하고 있는 거지?"라고 말하게 될 때가 있었습니다. 그냥 딱 막혀버리는 거죠. 1분 이상 막혀 있으면, 저는 멈추고 이렇게 말했습니다. "켄트, 작동 가능한 가장 단순한 게 뭐지?"
그것은 질문이었습니다. "우리가 지금 하려는 것을 고려할 때, 작동할 수 있는 가장 단순한 것은 무엇일까?" 다시 말해, 목표에 집중하자는 것이었죠. 지금의 목표는 이 루틴이 이 일을 하게 만드는 것입니다. 내일 코드를 읽을 사람이 어떻게 생각할지는 걱정하지 맙시다. 효율적인지도 걱정하지 맙시다. 심지어 그것이 작동할지조차 걱정하지 맙시다. 그냥 작동할 가능성이 있는 가장 단순한 것을 작성합시다.
일단 작성하고 나면, 우리는 그것을 볼 수 있습니다. 그리고 "아 맞다, 이제 어떻게 돌아가는지 알겠어."라고 말하게 되죠. 작성하는 행위 자체가 우리의 생각을 정리해 주었기 때문입니다. 작동했을 수도 있고, 안 했을 수도 있습니다. 코드를 좀 더 짜야 했을 수도 있죠. 하지만 우리는 진전 없이 막혀 있었는데, 이제는 그렇지 않게 되었습니다.
우리는 한 번에 너무 많은 것을 생각하고 있었고, 너무 복잡한 목표를 달성하려 했으며, 코드를 너무 잘 짜려고 노력하고 있었습니다. 어쩌면 친구들에게 우리의 컴퓨터 지식을 뽐내려 했을지도 모르죠. 하지만 우리는 가장 단순한 것을 시도하기로 했습니다. if 문을 쓰거나, 상수를 반환하거나, 선형 검색(linear search)을 사용하는 것처럼요. 우리는 그냥 작성하고 그것이 작동하는지 봅니다. 일단 작동하면, 우리가 진짜 원하는 것이 무엇인지 생각하기 더 좋은 위치에 있게 된다는 것을 알았습니다.
그래서 제가 "작동 가능한 가장 단순한 것이 뭘까?"라고 물었을 때, 저는 확신이 없었습니다. "작동할 거라고 '알고 있는' 것이 뭐냐"고 물은 게 아닙니다. 저는 "가능한 게 뭘까? 우리가 코드로 말할 수 있는 가장 단순한 게 뭘까? 그래서 머릿속에서 형체가 불분명한 것 대신 화면에 있는 무언가에 대해 이야기할 수 있게 하려면 말이야."라고 물은 것입니다. 저는 "일단 화면에 뭔가를 띄우면, 우리는 그것을 볼 수 있어. 더 많은 것이 필요하면 더 만들면 돼. 우리의 문제는 지금 아무것도 없다는 거야."라고 말하고 있었던 겁니다.
저는 이것이 돌파구(breakthrough)라고 생각합니다. 왜냐하면 당신은 항상 할 수 있는 한 많이 하라고 배우니까요. 항상 체크를 넣어라. 항상 예외를 찾아라. 항상 가장 일반적인 경우를 처리해라. 항상 사용자에게 최고의 조언을 해라. 항상 의미 있는 에러 메시지를 출력해라. 항상 이거 해라, 항상 저거 해라. 배경에 해야 할 일이 너무 많아서 생각할 여유가 없습니다. 저는 그 모든 것을 잊어버리고 스스로에게 물어보라고 말합니다. "작동 가능한 가장 단순한 것은 무엇인가?"
제 생각엔 이 조언이 "작동 가능한 가장 단순한 것을 하라(Do the simplest thing that could possibly work)"는 명령으로 변질된 것 같습니다. 이건 좀 더 혼란스럽습니다. 왜냐하면 일단 하고 나면 즉시 평가해 보자는 개념이 없기 때문입니다. 사람들은 묻습니다. "그게 가장 단순한 건지 어떻게 알죠?" 제 경우엔, 우리도 몰랐습니다. 우리는 그냥 화면에 띄워놓고 보려고 했던 겁니다. 하지만 이것이 명령이 되는 순간, 우리는 그것을 분석하고 "저게 가장 단순한가?"라고 따져야 합니다. 그러자 갑자기 복잡해집니다. 무엇이 단순하고 무엇이 단순하지 않은가?
무엇이 단순한지 아닌지에 대해 끔찍할 정도로 많은 논의가 있었고, 사람들은 단순성에 대해 꽤 정교한 개념을 갖게 되었지만, 그것이 도움이 되었는지는 확신할 수 없습니다. 오히려 혼란만 줄 수도 있습니다. 때로는 "맙소사, 나는 단순성에 대한 토론조차 이해 못 하는 멍청이인가 봐."라고 생각하게 되니까요. 그건 사람들을 겁먹게 합니다.
작동 가능한 가장 단순한 것을 코딩한다는 것은 사실 이런 것입니다. 머릿속에 5가지를 동시에 담아두고 결정을 내릴 수 없다면, 3가지만 담아보세요. 딱 1가지만 머릿속에 담아두고 결정을 내릴 수 있는지 보세요. 그러고 나서 다음 것을 생각하면 됩니다.
놀랍게도, 이렇게 멍청하고 직진하는 코드를 작성해 보면, 종종 그게 필요한 전부인 경우가 많습니다. 아주 잘 작동하죠. 나중에 두 번째 프로그래머가 와서 코드를 보고 이렇게 말할지도 모릅니다. "이거 짠 사람들은 바보 아냐? 여기에 그냥 단순한 선형 검색을 썼네. 이건 정렬되어 있으니까 이진 검색(binary search)을 쓸 수도 있었잖아. 해시 테이블을 쓸 수도 있었고. 왜 선형 검색을 한 거야?" 글쎄요, 선형 검색이 작동했으니까요. 그리고 그 프로그래머가 선형 검색 코드를 봤을 때, 1분 만에 이해했습니다.
다음 주 예고 1월 26일 월요일, C#의 창시자 안데르스 하일스버그(Anders Hejlsberg)와의 대화가 연재됩니다. Artima.com의 새 기사 알림을 매주 이메일로 받고 싶으시면 Artima 뉴스레터를 구독하세요.