모든 재작성은 이번이 마지막일 거라 믿었다

나는 내 시스템의 동일한 핵심 컴포넌트를 세 번 다시 작성했다. 패치한 것도, 리팩터링한 것도 아니다 — 거의 처음부터, 별개로 세 번, 새로 만들었다. 그리고 매번, 나는 이 버전이 진짜라고 확신했다. 마침내 영원히 그 위에 쌓아 올릴, 깨끗하고 올바른 아키텍처라고.

나는 세 번 연속으로, 매번 완전한 확신을 가진 채 틀렸다. 틀렸다는 것 자체는 짜증나는 일이었다. 하지만 내가 정말로 이야기하고 싶은 부분은 그 완전한 확신이다. 그것은 똑같은 감정의 반복이었고, 나는 단 한 번도 그것을 경고로 알아채지 못했기 때문이다.

”이번엔 맞다”

새로 시작하는 재작성에는 특유의 도취감이 따라온다. 옛 코드는 엉망진창이다 — 모든 타협, 모든 패치, 현실이 당신을 굽히게 만든 모든 지점이 눈에 보인다. 머릿속에 깨끗하게 자리 잡은 새 설계에는 그런 것이 하나도 없다. 그것은 우아하다. 그것은 명백하다. 그것은 분명히 더 낫다.

그래서 당신은 옛것을 허물고 새것을 짓는다. 그리고 한동안은 그것이 진전처럼 느껴진다. 새 코드가 정말로 더 깨끗하기 때문이다. 그러다 당신은 그것을 쓰기 시작하고, 굽힘이 다시 시작되고, 얼마 후 당신은 두 번째 엉망진창 앞에 서서, 다시 처음부터 시작하고 싶은 정확히 똑같은 충동을 느낀다.

왜 재작성은 항상 더 나아 보이는가

그 비교는 조작되어 있다. 그리고 나는 그것이 어떻게 조작되었는지 알아채는 데 세 라운드가 걸렸다. 재작성을 판단할 때, 당신은 신선하고 이상화된 설계를, 실제 사용의 마찰을 몇 달 동안 흡수해 온 옛 설계와 비교하고 있다. 당연히 새것이 더 나아 보인다. 그것은 아직 어떤 문제도 만나본 적이 없다.

옛 코드가 추해 보이는 것은 그것이 불완전하게 설계되었기 때문만이 아니라, 그것이 자신의 경험을 입고 있기 때문이다. 그 안의 어색한 분기 중 상당수는 실제 엣지 케이스가 남긴 흉터다 — 세상이 그것에 던졌고, 깨끗한 새 설계는 단지 한 번도 살아남아야 했던 적이 없는 것들 말이다. 당신은 늘 좋은 설계를 나쁜 설계와 비교하고 있는 것이 아니다. 종종 당신은 베테랑을 신병과 비교하면서, 그 신병이 얼마나 흉터 없는지에 감탄하고 있는 것이다.

내가 계속 치른 비용

각각의 재작성은 코드 이상의 것을 버렸다. 그것은 지식을 버렸다 — 옛 버전이 조용히 대처하는 법을 배운 온갖 이상한 상황들에 대해, 축적되고 힘겹게 얻은 처리 방식을. 그리고 그 지식이 내 머릿속이 아니라 코드 속에 살고 있었기 때문에, 다시 짓는다는 것은 그것을 재발견한다는 뜻이었다. 같은 이상한 케이스를 또 만나고, 같은 문제를 또 디버깅하고, 내가 이미 사들인 교훈에 대해 두 번째, 세 번째로 비용을 치르는 것.

버그를 고치고 나서, 이 정확히 똑같은 버그를 더 이상 존재하지 않는 버전의 코드에서 전에 고쳤다는 것을 깨닫는 데에는 특유의 탈진감이 있다. 그것이 내 세 번째 재작성의 상당 부분이었다 — 두 번째에서 내던졌던 지식을 천천히 다시 벌어들이는 것.

그 밑에 있던 것: 성급한 추상화

이 모든 재구축의 진짜 엔진은 내가 설계를 생각하는 방식의 실수였다. 나는 계속 다시 작성했다. 문제를 실제로 이해하기도 전에 계속 올바른 구조를 찾으려 했기 때문이다. 나는 올바른 추상화를, 내가 충분히 영리하기만 하다면 앉아서 미리 정확하게 설계할 수 있는 무언가로 취급했다.

내 경험상, 유용한 추상화가 미리 올바르게 설계되는 일은 드물었다. 그것들은 사용을 통해 벌어들여졌다. 그것들은 문제와 충분히 오래 함께 살면서 그것이 실제로 어디에서 굽는지 — 어느 부분이 변하고 어느 부분이 고정되어 있는지, 진짜 이음매가 어디에 있는지 — 를 배우는 데서 나온다. 그것을 미리 완전히 설계하는 것은 추측이고, 각각의 재작성은 단지 내가 다시 추측하는 것이었다. 약간 더 정보를 갖췄지만, 여전히 잘 추측할 만큼 충분히 배우기 한참 전이었다.

재작성이 실제로 가치 있을 때

나는 재작성이 항상 틀렸다고 주장하고 싶지 않다. 때로는 설계가 정말로 당신이 가야 할 곳까지 늘어나지 못하고, 그것을 제자리에서 진화시키는 것이 처음부터 새로 시작하는 것보다 더 큰 비용이 들기도 한다. 내가 결국 그어내는 법을 배운 구분은 그 충동의 원천에 관한 것이다.

문제에 대한 진정한 새 이해에서 비롯된 재작성 — “내가 하나의 개념으로 취급했던 이것이 사실은 둘이라는 걸 이제 알겠다” — 은 종종 진짜 진전이다. 주로 현재 코드에 대한 불편함에서 비롯된 재작성 — “이건 추하다, 깨끗한 걸 원한다” — 은 더 자주 새 페인트칠을 한 동작에 불과하다. 첫 번째는 의미 있는 구조적 진전을 만들어낼 가능성이 더 높다. 두 번째는 대개 몇 주 동안 그것에 대한 당신의 기분만 바꿔놓을 뿐이다, 새것 역시 추해질 때까지.

해법: 정말로 안 될 때까지 제자리에서 구부려라

내가 만든 습관은 재작성을 첫 번째 본능에서 최후의 수단으로 강등시키는 것이었다. 나를 짜증나게 하는 구조를 마주하면, 나는 이제 먼저 그것을 제자리에서 바꾸려고 한다 — 형태를 다시 잡고, 리팩터링하고, 그것이 축적한 지식을 유지하게 하면서 내가 필요한 쪽으로 옮긴다. 나는 전면적인 재구축을, 단지 그것이 내 정돈된 감각을 거스를 때가 아니라, 기존 구조가 진화시키려는 모든 시도와 진정으로 싸울 때를 위해 아껴두려 한다.

많은 경우, 당신이 처음부터 다시 시작하고 싶게 만드는 그 불편함은 정보지 판결이 아니다. 그것은 코드가 어디가 아픈지 당신에게 말해주는 것이다 — 그리고 그것이야말로 처음부터 다시 지음으로써 당신이 내던질 바로 그 지식이다.

그 확신이 신호였다

세 번의 재작성 모두를 관통한 실은 나쁜 코드가 아니었다. 그것은 하나의 감정이었다: 이번엔 내가 제대로 했다는 깨끗하고 완전한 확신. “이것이 최종 아키텍처다”는 사실상 내가 매번 그 전에 내뱉은 문장이었다. 한 문장이 계속 틀린 것으로 드러난다면 그것에 대한 당신의 신뢰는 낮아져야 하고, 천천히 그렇게 되었다.

아직 스트레스 테스트하지 않은 설계에 대한 강한 확신은 통찰과 같지 않다. 그것은 종종 당신을 달리 가르쳤을 흉터의 부재일 뿐이다 — 아직 세상을 만나지 않은 계획의 편안한 자신감. 요즘 나는, 새 설계가 최종본이라고 완전히 확신하는 느낌이 들 때, 그 느낌 자체를 내가 그 의견을 신뢰받을 만큼 문제와 충분히 오래 함께 살지 않았을지도 모른다는 힌트로 취급하려 한다.

— 시그널도 없고, 수익도 없고, 투자 자문도 아니다.