우리가 자랑스럽게 저지르는 오류에 대해서...
코끼리는 힘이 너무 세서 어딘가 묶어 두는 건 불가능합니다. 하지만 방법이 있는데요. 아기 코끼리 때 교육 시키면 된다고 하네요. 그 방법도 간단합니다. 아기 코끼리를 적당한 길이의 끈으로 말뚝에 묶고 한참을 놔둡니다. 처음엔 아기 코끼리가 묶인 끈 보다 먼 곳을 가고 싶어서 당기거나, 말뚝을 뽑으려고 하지만 그만한 힘이 없으니 끈 길이보다 멀리 나갈 수 없다는 걸 깨닫고 포기하게 됩니다. 그 후 아기 코끼리는 커서도 말뚝 주변을 벗어나지 못한다고 하네요.
전통적으로, 소프트웨어 개발은 말뚝박기로부터 시작합니다. 말뚝을 막듯이 무언가를 '정하며' 프로젝트를 시작하지요. 정하는 것이 뭔지 따져볼 필요도 없습니다. 인원, 일정, 요구사항, 디자인부터 코딩 컨벤션, 개발 환경, 문서 작성 규칙등 프로젝트 시작에 떠오르는 대부분이 이에 해당하니까요.
물론, 이 과정에서 가끔 의견 충돌이 있긴 합니다만 그게 원래 당연한 것으로 여겨졌으니 순조롭게 일정이 만들어지고 일은 그렇게 흘러갑니다.
그리고, 우리의 프로젝트는 아주 예쁜 아기 코끼리가 되는 것입니다. 물론 코가 너무 짧아서 돼지와 구별이 쉽지 않은 경우도 있고, 너무 화장을 짙게 해서 화장한 돼지라는 비아냥을 듣기도 하지만, 뭐 결국은 뭔가 하나 만들어져서 출시하게 됩니다.
하지만, 너무 당연하게 이루어지는 이런 과정을 한번 뒤집어 생각해 보면 좋을 것 같아 이 글을 쓰게 되었습니다. 우리가 박은 말뚝이 정말 필요한 것이었는지, 말뚝을 박지 않고 키워냈다면 혹시 아기 코끼리 닮은 화장한 돼지가 아니라 매머드가 될 수 있는 프로젝트가 아녔을는지... 말입니다.
1958년 친구 하나가 프로그램을 작성한다( writing )가 아니라
구축한다( building )고 말하는 것을 들은 적이 있다.
- 프레더릭 브룩스, <맨먼스미신 20주년 판> -
소프트웨어를 처음 만들었던 사람들은 어떻게 코딩했을까요? 1940년대 중반 에니악에 계산식을 넣는 과정은 상당히 골치 아픈 일이었을 것입니다. 에니악을 운영하던 여성 계산원들은 에니악의 하드웨어 제원을 모두 알아야 했고, 논리식을 동작시키기 위한 수많은 스위치와 복잡한 케이블을 연결해서 탄도 계산을 할 수 있는 소프트웨어를 장착시켜야 했습니다.
그 후 천공카드를 사용하게 되고, 포트란과 코볼을 쓸 수 있게 되면서, 아마 한동안 소프트웨어 개발은 코드를 작성(writing) 한다는 용어를 사용했었나 봅니다.
하지만 1950년대 후반 브룩스의 친구는 '작성(writing)'이라는 메타포에서 벗어나는 놀라운 선택을 합니다. '작성(writinig)'이 아니라 '구축(building)'이라고 하면 코딩이 가지는 의미는 많이 달라지거든요. 이제 코드는 스위치를 켜고 끄거나 케이블을 연결하는 것들을 단순히 종이 위에서 기술(writing)하는 개념을 넘어서서 복잡한 건축물을 건축(build)하는 청사진을 만드는 과정이 되었습니다.
왜 이런 이미지 변신이 필요했을까요? 소프트웨어가 복잡해지기 때문이었을 것입니다. 처음엔 탄도 계산만 하면 되었지만, 곧이어 몬테카를로 기법으로 핵탄두 내의 중성자 움직임을 예측해야 했고, 복잡한 비즈니스 모델이나 과학적 계산도 해야 했습니다. 단순히 작성이라 하기엔 너무나 복잡한 구조를 가질 수밖에 없었던 소프트웨어는 '빌드'라는 개념으로 대우해야만 했습니다.
그러나 빌드 메타포도 한계에 다다르게 됩니다.
1986년 브룩스는 <은총알은 없다>라는 논문에서 build라는 메타포가 한계에 다다랐음을 선언합니다. 소프트웨어의 복잡도가 너무 증가했기 때문에 건축물 청사진을 만드는 개념으로는 소프트웨어 구조를 감당할 수 없다고 판단했습니다. 그리고 브룩스가 내놓은 메타포는 성장(grow)이었습니다. 이제 소프트웨어를 구축(build) 하지 말고 성장(grow)시키자는 게 브룩스의 주장이었는데요. 자연속에 생물이, 인간이 만든 건축물 보다 훨씬 더 복잡하지만, 매우 단순해 보이는 규칙으로 자라나고, 혹독한 자연환경에서도 생존할 수 있는 성체가 되어 가기 때문입니다.
말뚝을 박고 아기 코끼리를 '빌드'하는 과정을 진행하는 것이 아니라.
손바닥 만한 미니 돼지로 시작해서 아기 코끼리로 성장시키고 더 나아가 매머드로도 성장시켜보자는 성장의 메타포가 이미 40년 전에 만들어졌던 것입니다.
<실용주의 프로그래머>에서 언급되어 유명해진 DRY(Don't Repeat Yourself) 법칙은 이제 웬만한 개발자들은 다 아는 개념입니다. 때로는 DRY를 극단적으로 지키는 개발자들도 있는데요. 중복을 피하겠다고 두 줄짜리 함수를 만들어서 전역적으로 호출하게도 하더군요.
그런데요. <실용주의 프로그래머>에서 반복하지 말라고 한 게, 정말 코드였나요?
모든 지식은 시스템 내에서 단 한 번만,
애매하지 않고, 권위 있게 표현되어야 한다.
<실용주의 프로그래머 20 주년판>, 43 페이지
사실, <실용주의 프로그래머>에서 중복하지 말라는 건, 코드가 아니었습니다. 오히려 '코드의 중복이 지식의 중복은 아니다(47페이지)'라는 말도 하죠. 중복하지 말아야 하는 건 코드가 아니라 지식인 것입니다.
지식을 중복하지 말아야 한다는 개념은 다른 코딩 규칙들을 이해하는 데도 도움을 줍니다. 로버트 C 마틴이 정리한 SOLID 법칙 중 첫 번째인 SRP(단일 책임 원칙)을 볼까요? 로버트 C 마틴은 "소프트웨어 모듈은 변경의 이유가 하나 단 하나여야만 한다"(로버트 C 마틴, <클린 아키텍처>)라는 말로 이를 설명하는데요.
중복되지 않은 지식이 코드를 사용해 코드 뭉치(모듈이나 함수)로 표현되어 있다면, 그 코드가 바뀔이유는 단 한가지가 됩니다. 그 지식이 변경될 때이죠.
한 발자국 더 나아가 볼까요?
이와 같이 지식을 모듈로 만드는 과정에서 코드를 사용한다면, 그 코드는 지식을 이해하기 쉽게 표현하고 있어야 합니다.
컴퓨터가 이해하는 코드는 바보도 작성할 수 있다.
사람이 이해하도록 작성하는 프로그래머가 진정한 실력자다.
<리팩토링 2판>, 35 페이지
마틴파울러가 리팩토링에서 한 말은 다음과 같이 정리할 수 있습니다. '진정한 실력자는 코드로 지식을 이해하기 쉽게 표현한다'
그래서 소프트웨어 개발이라 함은 '어떤 지식을 모아서 코드로 표현하는 과정'이라 할 수 있습니다. 그럼 어떤 지식이 코드가 될까요? 크게 두 가지가 있습니다. 요구사항에 대한 지식, 구현에 대한 지식이죠.
먼저, 요구사항에 대한 지식은 사용자가 원하는 걸 말합니다. 우리가 작성하는 소프트웨어가 사용자의 어떤 필요를 채워줄 것인지에 대한 지식이죠.
다음으로, 구현에 대한 지식은 소프트웨어를 개발하는 개발자들 자신이 사용자의 요구사항을 구현할 때 필요한 지식입니다. 소프트웨어 기술적인 면도 있지만 사용자 업무영역에 대한 것도 있습니다.
그런데, 문제가 있습니다. 소프트웨어가 복잡해지게 되면서 이 두 가지 지식을 모두 정하고 가기 힘들어진다는 것이죠. 그럼 어떻게 해야 할까요? "말뚝을 박지 말아야 합니다."
앞에서 언급한 <실용주의 프로그래머>에서는 '가역성'이라는 토픽에서 다음과 같은 이야기를 합니다.
결정이 바뀌지 않을 것이라 가정하고서 발생할지도 모를 우연한 사건에 대비하지 않는 데에서 실수가 나온다. 결정이 돌에 새겨진 것이 아니라 바닷가의 모래 위에 쓰인 글씨라 생각하라. 언제든지 큰 파도가 글씨를 지워버릴 수 있다.
소프트웨어 개발은 지식을 축적하는 과정입니다. 코딩으로 지식을 잘 표현해서 중복되지 않게 모은 다음 잘 연결해서 성장 시켜나가는 것을 말합니다.
지속적으로 지식이 유입되어 코드의 일부가 될 수 있게 하는 것이죠. 지속적으로 바뀌어 간다면 점점 구조와 체계가 만들어질 겁니다. 그게 아키텍트가 되는 것이죠.
말뚝 박기로 프로젝트를 시작하면 이 모든 일들이 거꾸로 이뤄지게 됩니다. 말뚝 박고, 구조를 정하고, 그 구조에 모여있는 지식들을 끼워 맞추고 그러다 보니 비슷한 코드를 넣는 게 낭비라고 여겨지고 의미 없이 코드의 중복만 막다 보면 결국 코드는 전체가 한 덩어리가 되어 수정이 불가능한 소프트웨어가 되는 거죠.
소프트웨어 개발을 지식의 축적 과정이라 본다면, 소프트웨어 개발은 '구축(build)'가 아니라 성장(grow) 시켜야 맞습니다. 하지만 우리는 소프트웨어를 성장시킬 수 없는 고약한 관습을 가지고 있습니다.
지식을 모아서 유기적으로 연결하는 과정이 소프트웨어 개발이라면 소프트웨어 개발에 가장 큰 리스크는 일정입니다.
소프트웨어 개발의 결과물을 가지고 사용자가 필요를 충족하려면 어느 정도 선까지 결과가 도달해야 하기 때문에 그런 결과까지 도달하기 위해 수집해서 정리해야 할 지식의 분량은 정해진 셈이 되는데요.
일정을 정하는 시점에 모든 지식을 다 가지고 있다고 확신할 수 없습니다. 지식은 아는 것과 모르는 것만 있는게 아니라 모르는 지 아는 지식과 모르는 지도 모르는 지식이 있기 때문입니다. 만약 사용자의 필요를 충족하기 위해서는 꼭 포함되어야 하는 지식이 있는데, 이 지식이 모르는 지도 모르는 지식 영역에 있었다면, 그 부분은 일정에서 배제될 것이기 때문입니다.
다시 말해, 코끼리 코가 모르는 지도 모르는 지식의 영역에 있다면, 우리의 아기 코끼리 프로젝트는 회색 돼지 또는 화장한 돼지 프로젝트가 될 것입니다.
그리고, 아기 코끼리의 코가 '사용자의 필요를 충족하기 위해 반드시 필요했던 기능'이라면, 프로젝트는 망한 프로젝트가 됩니다. 프로젝트를 진행한 시간만큼 회사는 손해를 보게 되는 거죠.
물론, 그런 지식은 없을거라 확신하실지도 모릅니다. 하지만 그건 무척 관습적인 반응일 뿐입니다. 소프트웨어의 복잡도는 지속적으로 증가해왔고, 증가해 나갈 것이며, 그 안에 들어가는 지식들 역시 점점더 많아질 것입니다. 그렇다면 "모르는 지도 모르는 지식"이 프로젝트에 포함될 확률은 그만큼 커지게 되겠죠.
게다가, 대부분의 조직에서는 프로젝트 결과물 보다 프로젝트 자체를 성공시키는 걸 더 중요하게 여깁니다. 그래서, 프로젝트를 일정안에 끝내기 위해 일정안에 할 수 없는 작업은 제외시키거나 대충 마무리하게 됩니다. 이제 코만 없는 아기 코끼리가 아닙니다. 앞발은 닥스훈트 강아지 발이고 뒷발은 목발로 대치 될 수 있습니다.
또한, 일정이 말뚝 처럼 박혀버리면 코드 품질도 극도로 떨어집니다.
인간의 두뇌는 두가지 작동모드로 동작합니다. 그 중 하나는 우리가 이성적이라고 보는 방식으로 작동하고 또하나는 포괄적이고 무의식적인 방식으로 작동합니다. 코딩을 하는 사람은 코드 자체를 다루는 순간 전자의 경우 즉 이성적인 사고로 작업을 하게 됩니다. 이때는 '시간'을 염두에 두고 작업할 수 있는데요. 코드로 표현할 지식을 정리하거나 지식을 유기적으로 조직하는 영역은 포괄적이고 무의식적인 방식으로 작업해야 합니다. 하지만 이때는 비시간적입니다. 무의식의 영역이기 때문에 우리가 말을 논리로 표현하는 것처럼 툭툭 튀어나오지 않습니다. 일정이 정해진 경우엔 이 부분에 대해서 대충 얼버무리고 넘어가게 됩니다.
게다가 일정은 개발자들의 열정을 잠재웁니다.
<맨먼스 미신>의 에필로그를 읽으면서 크게 감동을 받았던 문구가 있습니다.
열정 때문에 공짜로라도 기꺼이 추구할 일을 생업으로 삼도록 신이 주신 특권을 누릴 수 있는 사람은 극소수에 불과하다. 저자는 매우 감사드린다.
코딩이 너무너무너무너무 재미있는 일이라는 것, 돈 안 받고도 하고 싶을 정도로 재미있는 일이라는 것, 그런데 그걸 한다고 밥벌이가 가능하다는 것, 그래서 브룩스는 신께 감사하고 있습니다. 그러나 저와 여러분은 브룩스와 같은 개발자보다는 전혀 반대의 삶을 살고 있는 개발자들을 더 많이 보아왔습니다.
너무 힘들어서 올해까지만 하고 내년부턴 장사할 거라고 습관처럼 한탄을 내뱉는 사람도 있었고, 귀농을 하고 싶다고 주말이면 귀농할 마을을 물색하고 다니는 선배도 있었습니다.
언제나 수심이 가득한 얼굴에 전쟁 포로처럼 축 처진 어깨로 다니고, 판다 같은 눈두덩이에 판다 같은 몸매로 멍하니 컴퓨터 화면을 쳐다보는 모습들이 눈에 선합니다.
뭐가 다른 걸까요?
이전 글 <테일러의 유령>에서 인용했던 스티브 맥코넬의 <소프트웨어 프로젝트 생존 전략>을 인용해 봅니다.
알버트 아인슈타인이 책상에 앉아 턱을 괴고 사색에 잠겨있는 상황을 상상해 보자. 그의 매니저가 "알버트! 상대성 이론이 지금 당장 필요하니까 빨리빨리 서둘러! 가만히 앉아만 있지 말고 말이야!(쾅쾅!)라고 다그치고 있다. 더 이상 무슨 말이 필요하겠는가? 아마도 대부분의 소프트웨어 개발자들은 아인슈타인처럼 똑똑하지는 않으리라. 그렇다면 아인슈타인보다는 더 나은 개발 환경이 필요하지 않을까?
일정이 문제입니다. 관리자는 너무 마음이 급하지만, 개발자는 논리가 꼬이는 순간 코드를 넣을 수 없게 되기 때문에 교착상태에 빠집니다. 관리자의 압박은 개발자의 머릿속을 더 헤집어 놓기만 할 테니까요.
100년 전통을 자랑하는 인력관리 방식인 '테일러 주의'에서는 업무를 단순하게 만들어서 일정을 관리했습니다. 관리자들은 테일러의 교지에 따라 100년 동안 일정으로 업무를 관리하는 것만 발전시켜 왔지요. 문제는 '지식 노동'은 단순한 업무로 만들 수 없다는 지점에 있습니다. 그럼 관리자들이 정확한 일정을 잡을 수 없습니다.
상황이 꼬이기 시작한 거죠. 관리자들은 작업자에게 일을 설명하고 일정을 물어봅니다. 이때는 상당히 공손하고 친근한 분위기인 경우가 많기 때문에 개발자들(특히 초보들)은 무의식적으로 상당히 긍정적인 일정을 내놓습니다.
'이틀이면 돼요'
<하드코드>의 저자 에릭 브레히너는 다음과 같이 일갈합니다.
양치기 소년은 "그 기능은 이틀이면 충분히 짭니다"라고 말한다. 프로젝트 전에 예측하는 개발 비용과 일정은 농담에 불과하다. 이런 헛소리를 진심으로 믿는 사람은 바보 아니면 풋내기 관리자다.
물론 개발자가 관리자를 골탕 먹이기 위해서 거짓말을 하는 것은 아니겠지만, 그 말을 믿는 건, 관리자 쪽의 실수라는 것입니다.
마이크 콘은 <불확실성과 화해하는 프로젝트 추정과 계획>에서 그다음 과정을 다음과 같이 묘사합니다.
추정치가 서약으로 변한다
개발자는 관리자를 위하는 마음에 긍정적인 태도로 극단적으로 짧은 일정을 추정했지만, 관리자는 이를 그대로 받아서 마케팅 일정으로 넘겨버립니다. 긍정적 추정치가 계약서의 날인이 되는 순간입니다.
특히 서로 간에 비슷한 프로젝트를 해본 경험이 전무하다면 일정은 극단적으로 짧게 잡게 될 테고, 이런 일정은 "죽음의 행진"으로 이어지게 되는데요. 결국, 진정한 판다의 모습이 된 개발자들은 수 없는 밤을 지새우고 관리자들은 키보드 위에 개발자들 손가락만 보며 타들어가는 마음을 삭히게 됩니다. 그리고 회사는 협력사와 소송을 하게 되지요.
이런 과정을 두어 번만 반복하면, 코딩에 대한 열정은 불구덩이 위에 초개처럼 사라집니다. 어느 누가 '서약을 어긴 배신자 취급을 받으면서 하는 일'을 열정적으로 할 수 있을까요?
열정을 잃은 개발자는 프로젝트를 사무적으로 대하게 될 겁니다.
옛날 장원의 한 영주가 산책길에 자신이 고용하고 있는 젊은 정원사가 땀을 흘리면서 부지런히 정원 일을 하는 것을 보았다. 걸음을 멈추고 살펴보니 정원 구석구석을 아주 아름답게 손질하고 있었다. 그뿐 아니라 젊은 정원사는 자기가 관리하는 화분마다 꽃을 조각하는 일에 열중하고 있었다. 이 광경을 목격한 영주는 그 젊은 정원사를 기특하게 여겨 그에게 물었다. "자네가 화분에다 꽃을 조각한다고 해서 품삯을 더 받을 수 있는 것도 아닌데, 어째서 거기에다 그토록 정성을 들이는가? 젊은 정원사는 이마에 맻힌 땀을 옷깃으로 닦으며 이렇게 대답했다. "나는 이정원을 매우 사랑합니다. 내가 맡은 일을 다 하고 나서 시간이 남으면 더 아름답게 만들기 위해 이 나무통으로 된 화분에 꽃을 새겨 넣고 있습니다. 나는 이런 일이 한 없이 즐겁습니다. " 이 말을 들은 영주는 젊은 정원사가 너무 기특하고 또 손재주도 있는 것 같아 그에게 조각 공부를 시켰다.
이민규 저, <1%만 바꿔도 인생이 달라진다>
짐작하시겠지만, 미켈란젤로의 이야기 입니다. 미켈란젤로는 르네상스시대에 레오나르도 다빈치와 양대산맥을 이루는 예술가였죠. 그 미켈란젤로의 시작점은 "열정있는 정원사"였습니다.
현재 우리는 미켈란젤로를 만들었던 이런 상황이 필요합니다. 열정을 빼앗기지 않은 개발자들이 정원을 가꾸듯 소프트웨어를 성장시켜서 아기코끼리에서 메머드의 가능성을 볼 수 있고 그런 개발자들이 미켈란젤로로 성장할 수 있는 환경 말입니다. 이게 안되면, 우리의 미래를 담보하기 힘듭니다.
앞에서 언급했듯 소프트웨어는 지난 70년간 지속적으로 복잡해졌고 앞으로도 복잡해질것이기 때문입니다. 특히 AI시대가 오면 소프트웨어는 더더욱 복잡하게 될 겁니다. AI가 소프트웨어 개발을 쉽게 만들어 줄거라 생각하실지도 모르겠는데 저는 반대로 봅니다. AI가 개발자들을 돕는 만큼 소프트웨어는 더 복잡한 걸 만들게 될 겁니다. 지금까지 그래왔습니다. 소프트웨어 복잡도를 낮출 기술이 개발되나 싶으면 이를 압도하는 복잡한 소프트웨어를 시장에서 요구했습니다.
이런 상황에서 빌드 메타포를 추구하는 현재 우리의 관습은 경쟁력 없는 소프트웨어를 만들어 내기만 할 것이 자명합니다. 그러니, 당장 모든걸 바꿀수는 없더라도, 우리가 자랑스럽게 여기는 말뚝박기들이 어쩌면 우리의 미래를 위협하고 있을지도 모른다는 문제 의식을 가졌으면 좋겠습니다.