The mythical 10x programmer

Salvatore Sanfilippo

신화 속 10배 프로그래머

10배 프로그래머란 프로그래밍이라는 분야의 신화 속에서, 다른 평범한 프로그래머보다 열 배 많은 일을 해낼 수 있는 프로그래머를 말합니다. 여기서 평범한 프로그래머란 자기 일을 잘하지만 10배 프로그래머의 마법 같은 능력은 갖추지 못한 사람이라고 생각할 수 있습니다. 다만 ‘평범한 프로그래머’를 더 정확히 정의하려면, 이 분야의 전문가인 프로그래머들 가운데 평균적인 프로그래밍 성과를 내는 사람을 뜻한다고 하는 편이 낫습니다.

프로그래밍 커뮤니티는 이런 존재가 실제로 있는지를 두고 극도로 양극화되어 있습니다. 10배 프로그래머 같은 것은 없다고 말하는 사람도 있고, 그런 프로그래머는 실제로 존재할 뿐 아니라 어디서 찾아야 하는지만 안다면 100배 프로그래머도 있다고 말하는 사람도 있습니다.

프로그래밍을 ‘선형적인’ 분야로 본다면 10배 프로그래머는 분명 비합리적인 가능성처럼 보입니다. 어떤 달리기 선수가 다른 선수보다 열 배 빠르게 달릴 수 있을까요? 건설 노동자가 같은 시간에 다른 노동자보다 열 배나 많은 것을 지을 수 있을까요? 하지만 프로그래밍은 아주 특별한 의미에서 설계 분야입니다. 프로그래머가 프로그램의 실제 아키텍처 설계에 참여하지 않는 경우에도, 구현하는 행위 자체에는 구현 전략을 하위 설계하는 일이 포함됩니다.

따라서 프로그램의 설계와 구현이 선형적인 능력이 아니라면, 경험, 코딩 능력, 지식, 쓸모없는 부분을 알아보는 능력 같은 요소는 단순한 선형적 우위가 아닙니다. 제 생각에는 이런 요소들이 프로그램을 만드는 과정에서 서로 곱해지는 방식으로 작용합니다. 물론 프로그래머가 프로그램의 설계와 구현을 모두 다룰 수 있을 때 이런 현상은 훨씬 더 두드러집니다. 과제가 ‘목표 지향적’일수록 잠재적인 10배 프로그래머는 자신의 능력을 활용해 훨씬 적은 노력으로 목표에 도달할 수 있습니다. 반대로 당면한 과제가 훨씬 더 경직되어 있고 어떤 도구를 사용해야 하는지, 어떻게 구현해야 하는지에 대한 구체적인 지침이 있다면, 짧은 시간에 많은 일을 해내는 10배 프로그래머의 능력은 약해집니다. 여전히 ‘국소적인’ 설계 가능성을 활용해 훨씬 더 나은 결과를 낼 수는 있지만, 목표에 도달하는 경로를 더 근본적인 방식으로 바꿀 수는 없습니다. 그 경로를 바꾸는 일에는 어쩌면 명세의 일부를 프로젝트에서 완전히 제거하는 것까지 포함될 수 있습니다. 그러면 달성하려는 목표는 거의 같아 보이면서도 목표에 도달하는 데 필요한 노력은 크게 줄어듭니다.

프로그래머로 20년 동안 일하면서 저는 함께 일한 동료 프로그래머들, 제가 특정 목표를 달성하도록 이끈 사람들, Redis와 다른 프로젝트에 패치를 제공한 사람들을 지켜보았습니다. 동시에 많은 사람이 제가 매우 빠른 프로그래머라고 말해 왔습니다. 저는 워커홀릭과는 거리가 멀기 때문에, 코딩을 빠르게 하는 사람의 기준으로 제 자신도 활용해 보겠습니다.

다음은 프로그래머의 생산성에 가장 큰 차이를 만든다고 제가 생각하는 자질의 목록입니다.

  • 기본적인 프로그래밍 능력: 하위 작업을 끝내는 능력

    프로그래머의 가장 분명한 한계이자 강점 중 하나는 프로그램의 일부를 실제로 구현하는 하위 작업을 처리하는 능력입니다. 함수든 알고리즘이든 무엇이든 말입니다. 놀랍게도 제 경험상 무언가를 구현하기 위해 기본적인 명령형 프로그래밍 구성 요소를 매우 효율적으로 사용하는 능력은 사람들이 생각하는 것만큼 널리 퍼져 있지 않습니다. 팀에서 일하다 보면 간단한 정렬 알고리즘조차 알지 못하는 매우 무능한 프로그래머가, 이론적으로는 대단히 유능하지만 실제로 해결책을 구현하는 능력은 형편없는 전공 졸업자보다 더 많은 일을 해내는 경우를 보기도 했습니다.

  • 경험: 패턴 매칭

    제가 말하는 경험이란 반복적으로 발생하는 여러 작업에 대해 이미 탐색해 본 해결책들의 집합을 뜻합니다. 경험 많은 프로그래머는 결국 다양한 하위 작업을 처리하는 방법을 알게 됩니다. 이는 설계 작업을 많이 줄여 줄 뿐 아니라, 특히 단순함의 가장 큰 적에 속하는 설계 오류를 막아 주는 매우 강력한 무기가 됩니다.

  • 집중력: 실제 시간과 가상의 시간

    코드를 작성하는 데 보낸 시간은 그 시간의 질을 살펴보지 않으면 의미가 없습니다. 집중력 부족은 내부 요인과 외부 요인에서 생길 수 있습니다. 내부 요인으로는 미루는 습관, 당면한 프로젝트에 대한 무관심(좋아하지 않는 일을 잘할 수는 없습니다), 운동 부족이나 건강 상태, 수면 부족 등이 있습니다. 외부 요인으로는 잦은 회의, 제대로 된 사무 공간이 없는 업무 환경, 자주 끼어드는 동료 등이 있습니다. 집중력을 높이고 방해를 줄이려는 노력이 프로그래밍 생산성에 상당한 영향을 미치리라는 것은 자연스러운 결론처럼 보입니다. 때로는 집중력을 얻기 위해 극단적인 조치가 필요합니다. 예를 들어 저는 이메일을 가끔씩만 읽고, 대부분에는 답장하지 않습니다.

  • 설계의 희생: 5%를 버리고 90%를 얻기

    프로젝트의 핵심이 아닌 목표 하나가 설계 복잡성의 매우 큰 부분을 차지하거나, 핵심 기능과 비핵심 기능 사이에 설계상의 긴장이 생겨 더 중요한 다른 목표에 도달하기 어렵게 만들고 있다는 사실을 인정하려 하지 않을 때 복잡성이 생기는 경우가 많습니다. 설계자는 설계의 모든 부분 가운데 쉽게 얻을 수 있는 성과가 아닌 부분, 즉 투입한 노력과 이점이 비례하지 않는 부분을 알아보는 것이 매우 중요합니다. 결과를 극대화하기 위해 실행하는 프로젝트는 정확히 중요한 부분, 그리고 합리적인 시간 안에 구현할 수 있는 부분에 집중하게 됩니다. 예를 들어 메시지 브로커인 Disque를 설계할 때, 어느 순간 메시지에 대해 최선의 노력 수준으로 순서만 보장하면 프로젝트의 다른 모든 측면, 즉 가용성, 쿼리 언어와 클라이언트 상호작용, 단순성, 성능을 크게 개선할 수 있다는 사실을 깨달았습니다.

  • 단순성

    이것은 모든 것을 뜻하면서 동시에 아무것도 뜻하지 않는, 너무나 당연한 항목입니다. 단순성이 무엇인지 이해하려면 복잡성이 어떻게 생기는지 살펴볼 필요가 있습니다. 제가 생각하기에 복잡성을 만들어 내는 가장 큰 요인은 두 가지입니다. 설계상의 희생을 감수하지 않으려는 태도와 설계 과정에서 오류가 누적되는 것입니다.

    설계 과정을 생각해 보면, 잘못된 경로를 선택할 때마다 최적의 해법에서 점점 더 멀어집니다. 잘못된 설계가 잘못된 사람의 손에 들어가면 같은 시스템을 다시 설계하는 대신, 처음의 오류를 수습하기 위해 또 다른 복잡한 해결책을 설계하게 됩니다. 그 결과 프로젝트는 잘못된 단계를 밟을 때마다 더 복잡해지고 효율은 떨어집니다.

    단순성을 얻는 방법은 머릿속에서 작은 ‘개념 증명’을 해 보는 방식으로 사고하는 것입니다. 그러면 프로그래머의 머릿속에서 수많은 단순한 설계를 탐색할 수 있고, 가장 실현 가능하고 직접적인 해결책처럼 보이는 것에서 작업을 시작할 수 있습니다. 이후에는 경험과 개인적인 설계 능력을 바탕으로 설계를 개선하고, 해결해야 하는 하위 설계에 대한 합리적인 해결책을 찾을 수 있습니다.

    하지만 복잡한 해결책이 필요해질 때마다 그 복잡성을 피할 방법을 오랫동안 고민해야 합니다. 완전히 다른 대안까지 고려한 뒤에도 더 나은 가능성을 찾지 못했을 때에만 그 방향으로 계속 나아가야 합니다.

  • 완벽주의, 혹은 생산성을 죽이고 설계를 편향시키는 방법

    완벽주의에는 두 가지 형태가 있습니다. 하나는 프로그램에서 측정 가능한 성능을 최대한 끌어내려는 엔지니어링 문화이고, 다른 하나는 성격적 특성입니다. 어느 경우든 저는 완벽주의가 프로그래머가 일을 빠르게 내놓는 데 가장 큰 장벽 중 하나라고 봅니다. 완벽주의와 외부의 평가에 대한 두려움은 설계상의 편향을 만들어 냅니다. 그 결과 설계는 심리적 기준이나 아주 단순하게 측정할 수 있는 기준에 따라서만 다듬게 되고, 견고성, 단순성, 제때 결과를 내는 능력 같은 요소는 고려 대상에서 빠지는 경우가 많습니다.

  • 지식: 이론도 어느 정도는 도움이 됩니다

    복잡한 작업을 다룰 때 자료 구조, 계산의 근본적인 한계, 특정 작업을 모델링하는 데 매우 적합한 난이도 높은 알고리즘에 관한 지식은 적절한 설계를 찾아내는 능력에 영향을 줍니다. 모든 분야의 초전문가가 될 필요는 없지만, 문제에 적용할 수 있는 잠재적인 해결책을 많이 알고 있는 것은 분명 중요합니다. 예를 들어 설계상의 희생을 받아들이고(일정 비율의 오류를 허용하고) 확률적 집합 카디널리티 추정기를 알고 있다면, 스트림에서 고유한 항목의 수를 세기 위해 복잡하고 느리며 메모리 효율이 떨어지는 해결책을 쓰지 않아도 됩니다.

  • 저수준 이해: 기계를 이해하기

    고수준 언어를 사용할 때조차 프로그램에서 발생하는 여러 문제는 컴퓨터가 특정 작업을 어떻게 수행할지 제대로 이해하지 못해서 생깁니다. 사용하는 도구나 알고리즘에 근본적인 문제가 있어 프로젝트를 처음부터 다시 설계하고 구현해야 하는 경우도 있습니다. C를 능숙하게 다루고, CPU가 어떻게 작동하는지 이해하며, 커널이 어떻게 동작하고 시스템 호출이 어떻게 구현되는지 명확히 알고 있다면 프로젝트 후반의 나쁜 돌발 상황을 피할 수 있습니다.

  • 디버깅 능력

    버그를 찾기 위해 엄청난 노력을 쏟는 일은 매우 쉽습니다. 버그의 상태 정보를 조금씩 확보해 합리적인 단계로 문제를 해결하는 능력과, 애초에 버그가 너무 많이 생기기 어려운 단순한 코드를 작성하는 태도가 결합되면 프로그래머의 효율성에 큰 영향을 줄 수 있습니다.

프로그래머의 위와 같은 자질들이 결과물에 10배의 영향을 줄 수 있다는 사실은 제게 전혀 놀랍지 않습니다. 이런 자질이 결합되면 실행 가능한 모델에서 출발해 다른 대안보다 몇 배나 단순한 설계를 훌륭하게 구현할 수 있습니다. 저는 단순성을 강조하는 한 가지 방법을 ‘기회주의적 프로그래밍’이라고 부르기를 좋아합니다. 기본적으로 개발의 각 단계에서 구현할 기능의 집합을 선택할 때, 최소한의 노력만으로 프로그램 사용자층에 최대한 큰 영향을 줄 수 있도록 정하는 방식입니다.

원문은 Salvatore Sanfilippo님이 에 게재했습니다.

이 글은 gpt-5.6-luna 모델을 사용해 번역했습니다.