일정 예상은 왜 실패할까?

모든 일에서 데드라인을 지키는 것은 중요하다. 마감을 지키는 것은 일의 기본이다. 특히 팀으로 작업하는 일에서는 더더욱 그렇다. 소프트웨어 개발의 많은 일은 파이프라인 형식으로 진행되기 때문에, 내가 약속한 일정을 못 맞추면, 내 일만 뒤로 밀리는 것이 아니라 협업 중인 다른 사람의 일정에까지 영향을 주는 경우가 많다.

하지만 일정을 맞추는 것은 어렵다. 그게 뭐가 어렵냐고 생각할 수 있는데 정말 어렵다. 언제나 이번만큼은 예외라고 생각하지만, 언제나 일정은 틀어진다. 심지어 예상보다 오래 걸릴 것이라는 경험을 바탕으로 계산보다 일정을 길게 잡아도 여전히 마감을 못 지킨다. 이런 현상을 호프스태터의 법칙이라고 부른다. 그렇다면 호프스테터의 법칙은 왜 생길까?

일정 예측이 틀리는 이유를 알아보기 전에 우선 짚고 넘어갈 것이 있다. 어떤 프로젝트는 일정을 맞출 수 없다. 애초에 부족한 시간이 주어진 경우가 그렇다. 아쉽게도 많은 프로젝트에서 일정은 기술적 요인만으로 결정되지 않고, 다른 사업적 이유로 결정된다. 이런 경우는 답이 없다. 하지만 이런 것은 "프로젝트가 * 같았다"라고 말하지 예측이 실패했다고는 하지 않는다. 이 글에서 말하는 일정 예상이 틀렸다고 말하는 것은 기술적 요인을 충분히 고려하여 일정을 잡았어도 예상한 경우보다 많이 걸리는 경우를 말한다. 애초에 이루어질 수 없는 스케줄을 주고 일정 예측에 실패했다고 말하는 것은 그냥 양심 없는 짓이다.

일정이 틀린 이유를 물어보면 다양한 답이 나온다. 과거에 작업했던 코드에서 버그가 있어 수정하느라 늦었다고 하는 경우도 있고, 스펙이 완전치 않아 스펙을 보완하느라 늦어졌다고 하기도 한다. 레거시 코드를 다루는 경우 기존 코드를 완전히 이해하지 못한 채로 시작을 해 늦어졌다고 하기도 한다. 어떤 경우는 구현해야 할 기능에 대한 지식이 부족하여 일정을 잘못 예상했다고 대답하는 경우도 있다.

이 모든 것들은 일정 예측이 틀리는 타당한 이유이긴 하지만 근본적인 이유는 아니다. 만약 위와 같은 것들이 근본 원인이었다면, 경험이 많고 실력 있는 프로그래머의 예측은 뉴비들보다 덜 틀려야 한다. 하지만 그렇지 않다. 오차는 줄어들지만 예측은 여전히 틀리다.

호프스테터의 법칙이 생기는 근본적인 원인은 좋은 코드라는 것이 끝이 없기 때문이다. 좋은 코드라는 것은 주관적 판단이 들어간다. 경험 있는 프로그래머일수록 좋은 코드에 대한 기대치가 높아진다. 그래서 경험이 쌓일수록 자신이 만족하는 코드를 만들기 위해서는 더 많은 시간이 필요해지는 것이다.

게다가 좋은 코드에 대한 판단은 사람에 따라 정해진 기준이 있는 것이 아니라 코드를 보는 매 순간 새로이 이루어진다. 자극이 줄어들면, 사람은 점차 전에는 자극이 아니었던 것도 같은 크기의 자극으로 느끼게 된다. 예를 들어 파란색 점을 찾아야 할 때, 파란색 점이 충분히 많으면 자주색 점은 파란색으로 인지하지 않지만, 파란색 점이 드물어지면, 사람은 자주색도 파란색으로 인지하게 된다. 이런 현상을 시쳇말로 "인간의 욕심은 끝이 없다"라고 말하고, 있어 보이게 말하면 prevalence-induced concept change라고 한다. 즉, 기존의 문제를 해결하면 문제가 아니라고 생각했던 것이 문제로 보이기 시작하는 것이다. 코드를 작성하면서 발견되는 문제들을 그때그때 하나하나 해결하고 있다 보면, 마감이 다가왔을 때 일부분은 좋은 코드지만 전체적으로는 동작하지 않는 코드를 발견하게 될 것이다. 게다가 그 좋은 일부분도 만족스럽지 못할 확률이 높다.

그렇다면 일정을 맞추기 위해서는 어떻게 해야 할까? 간단하다. Make it work. Make it right. Make it fast.의 순서로 코드를 작성하되 시간이 되는데 까지만 right하게 만드는 것이다. 우선 work하는 코드를 작성하자. 이렇게 하면 예정된 기한이 끝났을 때 최소한 동작하는 코드를 얻을 수 있다. 일정을 제대로 예상했다면, 오히려 시간이 남을 것이다. 그 후에 시간이 허용하는 한 right한 코드를 확보하면 된다.

이 글을 읽고 코드 퀄리티를 신경 쓰지 말고 기능 구현을 중시하라는 조언으로 받아들이는 사람이 있을 것 같아서 걱정된다. 하지만 정 반대다. 코드 퀄리티는 중요하다. Work하지만 right하지 않은 코드는 code debt이다. 빚을 많이 진 프로젝트는 나중에 큰 대가를 치른다. 빨리 work하는 코드를 확보하여, 일정을 맞추라는 조언은 코드 퀄리티를 높게 유지할 시간을 확보하기 위해서다.

프로젝트가 가장 많은 빚을 지는 단계는 출시 일정이 촉박한데, 원하는 기능을 다 구현하지 못하리라는 것을 깨닫게 됐을 때다. 이때가 죽음의 행진을 시작하는 때다. 죽음의 행진의 결말은 언제나 안 좋다. 운이 좋으면 결국 출시를 못 하고 끝난다. 운이 없으면 출시에는 성공한다. 출시에 성공했더라도 코드의 퀄리티는 말이 아니다. 사람들이 work하는 코드만을 생성했기 때문이다. 그리고 괴로운 기억을 머릿속에서 지워버린다. 이 빚은 결코 갚아지지 않는다.

그렇다면 work하는 코드를 먼저 확보하는 방식에서는 언제 빚을 갚을까? 앞에서도 말했듯이 소프트웨어 개발은 협업이다. 나의 의도와 상관없이 시간이 남을 때가 있다. 다른 사람에게 코드 리뷰를 요청했을 때, 다른 사람의 작업이 아직 끝나지 않아 내가 작업을 시작할 수 없을 때, 어떤 때는 내가 진행하는 일이 생각보다 쉽게 끝나 시간이 많이 남을 수도 있다. 이런 시간에 right한 코드를 만들면 된다. 도저히 이런 시간이 남지 않는 때도 있다. 이럴 때는 기능 구현을 잠시 멈추고 리팩토링을 위한 일정을 따로 잡아 진행해야 한다. Right한 코드를 만드는 것은 일정을 잡기에 충분할 정도로 중요하다.

댓글

  1. 좋은 글 감사합니다. 북마크 해두고 데드라인 못지킬때마다 읽어야겠네요

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

RAII는 무엇인가

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API