Split View: 리팩터링의 경제학, 언제 비용이 회수되나 — 변경 빈도로 계산하는 법
리팩터링의 경제학, 언제 비용이 회수되나 — 변경 빈도로 계산하는 법
- 들어가며 — 83퍼센트 절감, 그리고 39.7센트
- 새 실험이 실제로 측정한 것 — 그리고 저자가 스스로 단 단서
- 오래된 증거는 생각보다 얇습니다
- 회수 기간 계산 — 변경 빈도가 곱셈 항입니다
- 이자 비유가 작동하는 곳과 무너지는 곳
- 매니저를 설득하는 법 — 미학이 아니라 이력으로
- 마치며 — 코드는 읽힐 때만 이자를 냅니다
- 참고 자료
들어가며 — 83퍼센트 절감, 그리고 39.7센트
2026년 7월 30일, martinfowler.com에 Thoughtworks의 Giles Edwards-Alexander가 쓴 The Economic Benefit of Refactoring이 올라왔습니다. 실험 설계가 깔끔합니다. AI 에이전트만으로 만든 15만 줄짜리 애플리케이션에서 문제가 되는 1만 7,155줄짜리 Rust 데이터 접근 모듈을 하나 고르고, "대표적인 변경"을 요청하는 프롬프트를 하나 고정한 뒤, 15단계에 걸쳐 리팩터링하면서 매 단계마다 같은 프롬프트를 다시 돌려 토큰 소비를 측정했습니다. 단계 사이에 변경 사항은 버려서 에이전트가 학습하지 못하게 했습니다.
결과는 인용하기 좋습니다. 입력 토큰이 159,564개에서 27,360개로, 132,204개(83퍼센트) 줄었습니다. 그리고 해커뉴스 토론에서 곧바로 나온 반박도 인용하기 좋습니다 — 그 절감액은 당시 가격으로 39.7센트입니다. 시간당 100달러짜리 시니어 개발자가 이 리팩터링을 지시하고 감독한 8시간과 비교하면 회수에 수천 번의 변경이 필요합니다.
두 숫자 모두 맞습니다. 그리고 이 대비가 리팩터링 논쟁이 20년째 결론에 도달하지 못하는 이유를 정확히 보여 줍니다 — 비용은 눈에 보이고 편익은 미래에 흩어져 있어서, 편익을 세는 방법에 따라 답이 뒤집힙니다. 이 글은 그 세는 방법을 다룹니다. 새 실험이 실제로 측정한 것, 기존 증거가 얼마나 얇은지, 회수 기간을 계산하는 식, 이자 비유가 무너지는 지점, 그리고 매니저 앞에서 미학 대신 쓸 숫자를 뽑는 명령어까지.
새 실험이 실제로 측정한 것 — 그리고 저자가 스스로 단 단서
먼저 이 실험이 측정한 대상을 정확히 해 둡시다. 사람의 이해 시간이 아니라 에이전트의 입력 토큰입니다. 즉 "이 변경을 하려면 얼마나 많은 코드를 읽어야 하는가"의 대리 지표입니다. 이 정의가 이 실험을 흥미롭게 만듭니다. 사람은 같은 파일을 두 번째 읽을 때 빨라지지만 에이전트는 매번 처음부터 읽으므로, 구조의 비용이 매 변경마다 정직하게 청구됩니다. 사람 대상 실험에서는 학습 효과 때문에 분리하기 어려운 신호가 여기서는 깨끗하게 보입니다.
숫자에서 읽을 것이 몇 가지 더 있습니다.
가장 큰 절감을 낸 것은 파일을 도메인에 맞춰 쪼갠 단계였습니다. 15단계 중 마지막 단계 하나가 입력 토큰을 107,205개에서 27,360개로 떨어뜨렸습니다. 저자는 여기서 중요한 단서를 답니다 — 파일을 아무렇게나 잘게 나누는 것은 별로 도움이 안 되며, 에이전트가 여러 파일을 뒤져야 하기 때문입니다. 앞선 단계들(중복 추출 같은 국소 정리)이 마지막 분할을 가능하게 한 준비 작업이었다는 것입니다. 즉 효과는 마지막 단계에 몰려서 나타나지만 그 단계만 따로 할 수는 없습니다.
출력 토큰은 거의 변하지 않았습니다(약 1,700~2,460개). 리팩터링이 "읽는 비용"은 줄였지만 "쓰는 비용"에는 영향이 없었다는 뜻이고, 저자도 이 부분은 결론을 내리지 않습니다.
그리고 총 코드량은 줄지 않았습니다. 가장 큰 파일이 17,155줄에서 9,269줄로 내려갔지만, 데이터 접근 계층 전체는 19개 파일에 걸쳐 약 16,500줄로 거의 그대로입니다. 해커뉴스에서 이 점을 지적한 댓글이 있었는데, 리팩터링이 보통 코드량을 줄인다는 통념과 어긋난다는 것입니다.
저자 자신이 붙인 단서가 꽤 길고, 그대로 옮길 가치가 있습니다.
- 토큰 계수 방식이 근사치입니다. 문자 수를 4로 나누는 방식을 썼고, 저자는 실시간으로 토큰을 정확히 세는 신뢰할 만한 방법이 없었다고 적습니다. 해커뉴스에서 "제대로 된 토크나이저 라이브러리가 있는데 왜"라는 반박이 나왔습니다.
- 그린필드 앱 하나, 개발자 한 명, 모듈 하나, 변경 유형 하나에 대한 단일 실험입니다.
- 리팩터링 계획을 세우고 실행하는 데 든 토큰은 세지 않았습니다. 상한을 500만 토큰으로 추정하지만 검증된 값이 아닙니다.
- 그리고 가장 흥미로운 단서 — 에이전트는 리팩터링을 잘하지 못했습니다. 어떤 리팩터링이 적절한지 스스로 판단하지 못해 단계마다 사람이 명시적으로 지시해야 했고, 실제 변환 작업은 grep과 sed를 쓰는 파이썬 스크립트로 이뤄졌는데 들여쓰기에서 자주 혼동을 일으켰습니다. 가장 가치 있었던 리팩터링은 처음에 놓쳐서 나중에 다시 적용해야 했습니다.
요컨대 이 글은 "리팩터링이 돈이 된다"의 증명이 아니라, 에이전트 기반 개발에서 구조 비용을 측정할 방법 하나를 제안한 첫 시도입니다. 저자도 "하나의 실험일 뿐이지만 흥미로운 첫걸음"이라고 썼습니다. 그렇게 읽는 것이 맞습니다.
오래된 증거는 생각보다 얇습니다
리팩터링이 이득이라는 주장에는 40년치 직관과 놀랄 만큼 적은 정량 근거가 붙어 있습니다. 실제로 인용할 만한 것을 나열하면 목록이 짧습니다.
가장 자주 인용되는 것은 Adam Tornhill과 Markus Borg의 Code Red: The Business Impact of Code Quality(2022)입니다. 39개의 상용 프로덕션 코드베이스, 30,737개 파일을 대상으로 소스 분석과 버전 관리 이력, Jira 이슈를 결합해 세 가지를 보고했습니다 — 품질이 낮은 코드에 결함이 15배 많고, 이슈 해결에 평균 124퍼센트 더 오래 걸리며, 최대 사이클 타임이 9배까지 벌어집니다.
이 연구는 진지하지만 한계도 분명합니다. 코드 품질 측정에 저자들이 만든 상용 도구의 지표를 썼고, 관계는 상관이지 인과가 아닙니다. 애초에 어려운 문제 영역이 지저분한 코드와 긴 해결 시간을 동시에 만들어 냈을 가능성이 배제되지 않습니다. 그리고 결정적으로, 이 연구는 품질이 낮은 코드의 비용을 측정한 것이지 리팩터링의 수익을 측정한 것이 아닙니다. 둘은 다릅니다. 리팩터링에는 비용과 회귀 위험이 따로 있습니다.
Martin Fowler 본인의 입장도 인용할 가치가 있습니다. Is High Quality Software Worth the Cost?(2019, 2024년에 Tornhill과 Borg 연구를 인용해 갱신)에서 그는 설계 지구력 가설을 제시하면서 동시에 이렇게 인정합니다 — 소프트웨어 팀이 전달한 기능을 측정할 방법이 없으므로 그 결과에 확실한 숫자를 붙이는 것은 불가능하다는 것입니다. 그가 제시한 그래프는 예시이지 데이터가 아닙니다. 이 분야에서 가장 영향력 있는 주장의 저자가 근거의 성격을 이렇게 명확히 밝혀 둔 것은 오히려 신뢰할 만한 태도입니다. 그가 덧붙이는 실무적 관찰 하나는 유용합니다 — 숙련 개발자들은 나쁜 코드가 자신을 눈에 띄게 느리게 만드는 것을 몇 주 안에 체감하며, 따라서 품질과 비용을 맞바꿀 구간 자체가 그리 길지 않다는 것입니다.
반대 방향 증거도 실재합니다. 리팩터링과 버그의 관계를 다룬 차등 재현 연구(ESEC/FSE 2020)는 특정 리팩터링 유형, 특히 상속 계층을 건드리는 작업이 새 결함 도입과 자주 연관된다고 보고합니다. MSR 2022의 Is refactoring always a good egg?는 리팩터링이 코드 스멜을 제거하거나 아무 영향을 주지 않는 경우가 대부분이며 이는 선행 연구와 어긋난다고 적습니다. 더 최근 연구들은 방법론 문제를 지적합니다 — 리팩터링과 버그 수정, 버그 유입이 같은 커밋 안에 뒤엉켜 있어서 효과를 분리하는 것 자체가 어렵다는 것입니다.
정직한 요약은 이렇습니다. 낮은 품질이 비싸다는 증거는 있고, 리팩터링이 그 비용을 회수한다는 일반적 증거는 얇으며, 어떤 종류의 리팩터링은 위험을 늘립니다. 그러니 "리팩터링은 좋은 것"이라는 전제로 논의를 시작하면 안 되고, 케이스별 계산이 필요합니다.
회수 기간 계산 — 변경 빈도가 곱셈 항입니다
증거가 얇을 때 쓸 수 있는 방법은 일반 명제 대신 특정 모듈에 대한 계산입니다. 필요한 항은 다섯 개뿐입니다.
연간 절감액은 두 갈래로 나옵니다. 하나는 변경 비용 절감이고, 다른 하나는 결함 비용 절감입니다.
연간 절감 = (C × T × S × H) + (D × F × K)
C : 이 모듈을 건드리는 연간 변경 횟수 (git 이력에서 뽑음)
T : 변경 한 건당 평균 소요 시간 (이슈 트래커에서 뽑음)
S : 그중 구조 때문에 낭비되는 비율 (추정. 0.2~0.5가 보수적)
H : 시간당 인건비
D : 이 모듈에서 유래한 연간 결함 수
F : 결함 한 건당 총비용 (대응 + 재작업 + 고객 영향)
K : 리팩터링으로 줄어들 것으로 보는 결함 비율 (추정. 0.3이면 낙관적)
리팩터 비용 = (R × H) + (P × F_reg)
R : 리팩터링 작업 시간 (테스트 보강 포함)
P : 회귀를 낼 확률 × 예상 건수
F_reg : 회귀 한 건의 비용
회수 기간(개월) = 리팩터 비용 / (연간 절감 / 12)
여기서 구조적으로 중요한 것은 C가 곱셈 항이라는 사실입니다. C가 0이면 T, S, H가 아무리 커도 절감은 0입니다. 이것이 "바뀌지 않는 코드는 정리할 가치가 없다"의 수학적 표현입니다. 5년 전에 짜서 아무도 손대지 않고 잘 돌아가는 지저분한 모듈은 회수되지 않습니다. 미학적으로 거슬리는 것과 경제적으로 손해인 것은 다른 문제이고, 이 식은 그 둘을 분리해 줍니다.
세 모듈을 놓고 계산해 보면 차이가 극명합니다. 시간당 인건비 10만 원, 결함 한 건 200만 원, S는 0.3, K는 0.3으로 잡은 예시입니다. 리팩터 비용은 인건비 항만 넣었고 회귀 위험 항은 뺐으니, 실제로는 아래 회수 기간보다 길어집니다.
| 모듈 | 연간 변경 C | 건당 시간 T | 연간 결함 D | 연간 절감 | 리팩터 비용 | 회수 기간 |
|---|---|---|---|---|---|---|
| 주문 처리 (핫스팟) | 84회 | 6시간 | 11건 | 약 2,172만 원 | 160시간 = 1,600만 원 | 약 9개월 |
| 리포트 생성기 | 12회 | 8시간 | 2건 | 약 408만 원 | 120시간 = 1,200만 원 | 약 35개월 |
| 레거시 정산 배치 | 1회 | 20시간 | 0건 | 약 60만 원 | 200시간 = 2,000만 원 | 약 33년 |
세 번째 줄이 이 표의 요점입니다. 레거시 정산 배치는 아마 코드베이스에서 가장 읽기 괴로운 파일일 것이고, 팀에서 가장 자주 언급되는 부채일 것입니다. 그리고 손대면 안 되는 코드입니다. 회수 기간이 서비스 수명보다 깁니다.
숫자를 만들 때 주의할 점 셋. S는 정직하게 낮게 잡으세요. Code Red의 124퍼센트를 그대로 S로 환산하면 0.55가 나오지만, 그건 상관 데이터에서 나온 상한이지 당신 모듈의 값이 아닙니다. P를 0으로 두지 마세요. 앞서 본 반대 방향 연구들이 말하는 게 이 항입니다. 특히 상속 계층을 건드리는 리팩터링에는 위험 프리미엄을 붙이세요. 그리고 계산 결과가 "하지 말 것"으로 나오면 그 결론을 받아들이세요. 이 계산의 가치는 승인을 얻는 데 있는 게 아니라 어디에 쓰지 않을지를 정하는 데 있습니다.
이자 비유가 작동하는 곳과 무너지는 곳
기술 부채라는 말은 1992년 Ward Cunningham이 만들었고, 지금은 이 논의의 기본 언어가 됐습니다. 이 비유는 실제로 두 가지 일을 잘합니다 — 지금 빨리 가는 대가로 나중에 더 낸다는 구조를 재무 언어로 번역해 주고, 그래서 엔지니어링 밖의 사람에게 논증이 통하게 만들어 줍니다. 그것만으로도 충분히 유용합니다.
다만 세 지점에서 무너집니다.
첫째, 이자가 시간이 아니라 접촉에 붙습니다. 금융 부채는 가만히 있어도 이자가 쌓이지만, 기술 부채는 그 코드를 건드릴 때만 청구됩니다. Cunningham 자신의 표현도 "제대로 되지 않은 코드에 쓰는 모든 시간이 그 부채의 이자"입니다 — 시간이 흐르는 것이 아니라 시간을 쓰는 것이 조건입니다. 앞 절의 C가 곱셈 항인 이유가 이것이고, 이 차이 하나 때문에 "부채는 빨리 갚을수록 좋다"는 금융적 직관이 코드에서는 틀립니다.
둘째, 원금을 계산할 수 없습니다. 이율도, 상환 일정도, 만기도 없습니다. 부채 총액을 금액으로 환산해 대시보드에 띄우는 도구들이 있지만, 그 숫자의 분모가 무엇인지 설명할 수 있는 사람은 드뭅니다. 비유를 모델로 착각하는 순간 이 지표는 관리 대상이 되고, 관리 대상이 된 지표는 최적화되기 시작합니다.
셋째, 선형이 아닙니다. 결합도가 높은 지점의 부채는 국소적인 부채보다 훨씬 비쌉니다. 같은 100줄의 지저분한 코드라도 20개 모듈이 의존하는 자리에 있으면 비용이 다릅니다. 금융 비유에는 이 위치 개념이 없습니다.
그리고 Cunningham 본인이 여러 번 정정한 오해가 하나 있습니다 — 그가 말한 부채는 나중에 제대로 하겠다며 일부러 대충 짜는 것이 아닙니다. 빨리 출시해서 도메인에 대한 이해를 얻고, 그 이해를 코드에 반영하기 위해 리팩터링하는 순환을 뜻했습니다. 즉 원래 비유에서 부채는 "나쁜 코드"가 아니라 아직 반영되지 않은 학습이었습니다. 이 정의가 실무적으로 더 유용한 이유는, 무엇을 정리해야 하는지를 알려 주기 때문입니다 — 지금 우리가 도메인에 대해 아는 것과 코드가 가정하는 것이 어긋난 자리입니다.
매니저를 설득하는 법 — 미학이 아니라 이력으로
"이 코드는 지저분합니다"는 설득력이 없습니다. 듣는 쪽에서 검증할 방법이 없고, 취향 문제로 접수되기 때문입니다. 대신 앞 절의 계산식에 넣을 값들을 실제 데이터에서 뽑아 오세요. 전부 감사 가능한 숫자입니다.
# 1) 변경 빈도 C: 지난 12개월 파일별 커밋 수 상위 20
git log --since="12 months ago" --name-only --pretty=format: \
| sed '/^$/d' | sort | uniq -c | sort -rn | head -20
# 2) 결함 관련 변경 D: 버그 수정 커밋만 걸러 같은 집계
# (커밋 규약이 있다면 --grep, 없다면 이슈 키 패턴으로)
git log --since="12 months ago" --name-only --pretty=format: \
--grep='^fix' --grep='hotfix' --grep='BUG-' \
| sed '/^$/d' | sort | uniq -c | sort -rn | head -20
# 3) 핫스팟: 변경 빈도가 높은 파일 중 큰 것만 남긴다
git log --since="12 months ago" --name-only --pretty=format: \
| sed '/^$/d' | sort | uniq -c | sort -rn \
| awk '{ n=$1; f=$2; cmd="wc -l < " f; cmd | getline loc; close(cmd);
if (loc > 500 && n > 20) printf "%5d changes %6d loc %s\n", n, loc, f }'
이 출력을 그대로 들고 가면 대화가 달라집니다. "주문 처리 모듈은 지난 12개월 동안 84번 수정됐고, 그중 23번이 버그 수정이었으며, P2 인시던트의 31퍼센트가 이 파일을 지나갑니다"는 검증 가능한 진술입니다. 여기에 회수 기간 하나를 붙이면 승인 요청이 아니라 투자 제안이 됩니다.
그다음에 붙일 것이 범위가 정해진 실험입니다. 전면 정리를 요구하지 말고, 핫스팟 하나에 정해진 시간을 배정하고 리드 타임의 전후를 재겠다고 제안하세요. 실패하면 그 범위에서 끝나고, 성공하면 다음 회차의 근거가 생깁니다. 앞서 본 새 실험이 실무에 주는 시사도 여기입니다 — 같은 변경 요청을 리팩터링 전후로 한 번씩 돌려 보는 것이 가장 값싼 측정 방법입니다. 에이전트를 쓰고 있다면 토큰 수가, 사람만 쓰고 있다면 첫 커밋까지의 시간이 대리 지표가 됩니다.
마지막으로, 논쟁에서 이기려 하지 마세요. 세 모듈을 계산해 두 개는 "안 함"으로 결론 내고 하나만 제안하는 사람이, 전부 정리해야 한다고 주장하는 사람보다 훨씬 빨리 승인을 받습니다.
마치며 — 코드는 읽힐 때만 이자를 냅니다
정리하면 이렇습니다.
- 새로 나온 실험은 리팩터링 15단계로 같은 변경의 입력 토큰을 83퍼센트 줄였지만, 금액으로는 변경당 39.7센트이고 저자 스스로 단일 그린필드 실험이라고 못 박습니다. 결론이 아니라 측정 방법의 제안으로 읽는 것이 맞습니다.
- 기존 증거는 얇습니다. 낮은 품질이 비싸다는 상관 근거는 있지만(결함 15배, 해결 시간 124퍼센트), 리팩터링이 그 비용을 회수한다는 일반 근거는 없고 일부 리팩터링 유형은 결함 유입과 연관됩니다.
- 그래서 일반 명제 대신 모듈별로 계산하세요. 변경 빈도가 곱셈 항이므로, 바뀌지 않는 코드는 아무리 지저분해도 회수되지 않습니다.
- 이자 비유는 매니저에게 통하지만 모델이 아닙니다. 이자는 시간이 아니라 접촉에 붙고, 원금은 계산되지 않으며, 결합도에 따라 비선형입니다.
- 설득은 미학이 아니라 git 이력으로 하세요. 세 후보 중 둘을 스스로 탈락시키는 제안이 가장 빨리 통과합니다.
한 줄로 줄이면, 리팩터링의 가치는 코드의 상태가 아니라 그 코드를 앞으로 몇 번 읽을 것인지에 달려 있습니다.
참고 자료
- Giles Edwards-Alexander — The Economic Benefit of Refactoring (martinfowler.com, 2026-07-30)
- Hacker News — The Economic Benefit of Refactoring 토론(방법론 비판 포함)
- Tornhill & Borg — Code Red: The Business Impact of Code Quality (arXiv:2203.04374)
- Martin Fowler — Is High Quality Software Worth the Cost? (2019, 2024 갱신)
- On the relationship between refactoring actions and bugs: a differentiated replication (ESEC/FSE 2020)
- Is refactoring always a good egg? (MSR 2022)
- Agile Alliance — Introduction to the Technical Debt Concept (Cunningham 비유의 원래 의미)
- AI로 코드베이스를 옮기는 실전 절차 — 측정 지표 편 (관련 글)
The Economics of Refactoring: When Does It Pay Off — Calculating With Change Frequency
- Introduction — An 83 Percent Cut, and 39.7 Cents
- What the New Experiment Actually Measured — and the Caveats the Author Attached Himself
- The Existing Evidence Is Thinner Than You'd Think
- Calculating Payback Period — Change Frequency Is the Multiplying Term
- Where the Interest Metaphor Works, and Where It Breaks Down
- Persuading Your Manager — With History, Not Aesthetics
- Closing — Code Only Charges Interest When It's Read
- References
Introduction — An 83 Percent Cut, and 39.7 Cents
On July 30, 2026, Thoughtworks' Giles Edwards-Alexander published The Economic Benefit of Refactoring on martinfowler.com. The experimental design is clean. He picked one problematic 17,155-line Rust data-access module out of a 150,000-line application built entirely by an AI agent, fixed a single prompt requesting a "representative change," then refactored the module across 15 steps — re-running the same prompt at every step — and measured token consumption. Between steps, he discarded the changes so the agent could not learn from them.
The result is eminently quotable. Input tokens dropped from 159,564 to 27,360 — a reduction of 132,204 tokens, or 83 percent. And the rebuttal that immediately surfaced in the Hacker News discussion is just as quotable — at then-current prices, that savings amounts to 39.7 cents. Set against the eight hours a senior developer at 100 dollars an hour spent directing and supervising the refactor, it would take thousands of changes to earn that back.
Both numbers are correct. And that contrast shows exactly why the refactoring debate has failed to reach a conclusion for twenty years — the cost is visible and the benefit is scattered across the future, so the answer flips depending on how you count the benefit. This post is about that counting method: what the new experiment actually measured, how thin the existing evidence really is, the formula for calculating payback period, where the interest metaphor breaks down, and the commands for pulling numbers to use in front of your manager instead of aesthetics.
What the New Experiment Actually Measured — and the Caveats the Author Attached Himself
Let's first be precise about what this experiment measured. Not human comprehension time, but the agent's input tokens — a proxy for "how much code has to be read to make this change." That definition is what makes the experiment interesting. A human gets faster the second time they read the same file, but an agent reads from scratch every single time, so the cost of structure gets honestly billed on every single change. A signal that's hard to isolate in human studies, because of learning effects, shows up cleanly here.
There are a few more things worth reading out of the numbers.
The biggest single reduction came from the step that split files along domain lines. One step alone, the last of the fifteen, dropped input tokens from 107,205 to 27,360. The author attaches an important caveat here — splitting files arbitrarily into smaller pieces doesn't help much, because the agent then has to hunt across more files. The earlier steps (local cleanups like extracting duplication) were preparatory work that made that final split possible. In other words, the payoff is concentrated in the last step, but that step can't be done on its own.
Output tokens barely moved (roughly 1,700 to 2,460). That means the refactoring cut the "cost of reading" but had no effect on the "cost of writing," and the author himself draws no conclusion on this point.
And total code volume didn't shrink. The largest file went from 17,155 lines down to 9,269, but the data-access layer as a whole stayed at roughly the same 16,500 lines spread across 19 files. One Hacker News comment pointed this out specifically, noting that it cuts against the common assumption that refactoring usually reduces code volume.
The caveats the author attaches himself are fairly long, and worth carrying over in full.
- The token-counting method is an approximation. He divided character count by four, and notes there was no reliable way to count tokens precisely in real time. Hacker News pushed back with "why not just use a proper tokenizer library."
- It is a single experiment on one greenfield app, one developer, one module, one type of change.
- Tokens spent planning and executing the refactoring itself weren't counted. He estimates an upper bound of 5 million tokens, but it isn't a verified figure.
- And the most interesting caveat — the agent wasn't good at refactoring. It couldn't judge on its own which refactoring was appropriate, so a human had to give explicit instructions at every step, and the actual transformation work was done by a Python script using grep and sed, which frequently got confused about indentation. The single most valuable refactoring was missed the first time around and had to be applied again later.
In short, this piece is not a proof that "refactoring pays off" — it's a first attempt at proposing one way to measure the cost of structure in agent-based development. The author himself writes that it's "just one experiment, but an interesting first step." That's the right way to read it.
The Existing Evidence Is Thinner Than You'd Think
The claim that refactoring pays off comes wrapped in forty years of intuition and a surprisingly thin body of quantitative evidence. When you actually list what's worth citing, the list is short.
The most frequently cited work is Adam Tornhill and Markus Borg's Code Red: The Business Impact of Code Quality (2022). Combining source analysis, version-control history, and Jira issues across 39 commercial production codebases and 30,737 files, it reports three findings — low-quality code carries 15 times more defects, issue resolution takes 124 percent longer on average, and the worst-case cycle time stretches out to 9 times longer.
The study is serious, but its limits are clear too. Code quality was measured using metrics from a commercial tool the authors themselves built, and the relationship is correlational, not causal. It isn't ruled out that an inherently difficult problem domain produced both the messy code and the long resolution times at once. And critically, this study measured the cost of low-quality code, not the return on refactoring. The two are different — refactoring carries its own cost and its own regression risk.
Martin Fowler's own position is worth citing too. In Is High Quality Software Worth the Cost? (2019, updated in 2024 to cite the Tornhill and Borg study), he presents the design stamina hypothesis while at the same time acknowledging that there's no way to measure the functionality a software team has delivered, which makes it impossible to attach a solid number to the outcome. The graph he offers is illustrative, not data. For the author of the most influential claim in this field to be this explicit about the nature of his own evidence is, if anything, a trustworthy stance. One practical observation he adds is useful — skilled developers feel bad code visibly slowing them down within a few weeks, so the window in which you're actually trading quality against cost isn't very long to begin with.
Evidence pointing the other way exists too. A differentiated replication study (ESEC/FSE 2020) on the relationship between refactoring and bugs reports that certain types of refactoring — especially ones that touch inheritance hierarchies — are frequently associated with introducing new defects. Is refactoring always a good egg? (MSR 2022) finds that refactoring mostly either removes code smells or has no effect at all, which runs counter to prior work. More recent studies point to a methodological problem — refactoring, bug fixes, and bug-introducing changes are tangled together within the same commits, which makes isolating the effect difficult in the first place.
The honest summary is this: evidence exists that low quality is expensive; general evidence that refactoring recovers that cost is thin; and certain kinds of refactoring increase risk. So the discussion shouldn't start from the premise that "refactoring is good" — it needs a case-by-case calculation.
Calculating Payback Period — Change Frequency Is the Multiplying Term
When the evidence is thin, the approach available to you is a calculation for a specific module, not a general proposition. You only need five terms.
Annual savings come in two parts. One is savings on change cost, the other is savings on defect cost.
Annual savings = (C × T × S × H) + (D × F × K)
C : number of changes touching this module per year (pulled from git history)
T : average time spent per change (pulled from the issue tracker)
S : share of that time wasted due to structure (estimate; 0.2-0.5 is conservative)
H : hourly labor cost
D : annual defects originating in this module
F : total cost per defect (response + rework + customer impact)
K : share of defects expected to be prevented by refactoring (estimate; 0.3 is optimistic)
Refactor cost = (R × H) + (P × F_reg)
R : refactoring work hours (including added test coverage)
P : probability of a regression × expected count
F_reg : cost of a single regression
Payback period (months) = Refactor cost / (Annual savings / 12)
What matters structurally here is the fact that C is a multiplying term. If C is zero, savings are zero no matter how large T, S, and H are. This is the mathematical expression of "code that never changes isn't worth cleaning up." A messy module that was written five years ago, that nobody has touched since, and that still runs fine, will never pay back. Being aesthetically annoying and being economically costly are different problems, and this formula is what separates them.
Running the calculation across three modules makes the difference stark. This example sets hourly labor cost at ₩100,000, cost per defect at ₩2,000,000, S at 0.3, and K at 0.3. The refactor cost here only includes the labor term and leaves out the regression-risk term, so the real payback period would run longer than the figures below.
| Module | Annual changes C | Time per change T | Annual defects D | Annual savings | Refactor cost | Payback period |
|---|---|---|---|---|---|---|
| Order processing (hotspot) | 84 | 6 hrs | 11 | ~₩21,720,000 | 160 hrs = ₩16,000,000 | ~9 months |
| Report generator | 12 | 8 hrs | 2 | ~₩4,080,000 | 120 hrs = ₩12,000,000 | ~35 months |
| Legacy settlement batch | 1 | 20 hrs | 0 | ~₩600,000 | 200 hrs = ₩20,000,000 | ~33 years |
The third row is the point of this table. The legacy settlement batch is probably the single most painful file to read in the whole codebase, and probably the debt the team complains about most often. And it's code you should not touch. Its payback period outlasts the service itself.
Three cautions when producing these numbers. Keep S honestly low. Converting Code Red's 124 percent directly into an S value gives you 0.55, but that's an upper bound drawn from correlational data, not the value for your module. Don't set P to zero. This is exactly the term the opposing-direction research from earlier is talking about — attach a risk premium especially for refactoring that touches inheritance hierarchies. And if the calculation comes back "don't do it," accept that conclusion. The value of this calculation isn't in winning approval — it's in deciding where not to spend your effort.
Where the Interest Metaphor Works, and Where It Breaks Down
The term technical debt was coined by Ward Cunningham in 1992, and it has since become the default vocabulary for this discussion. The metaphor genuinely does two things well — it translates the structure of "pay more later for going fast now" into financial language, and that's what makes the argument land with people outside engineering. That alone makes it useful enough.
But it breaks down at three points.
First, interest accrues on contact, not on time. Financial debt piles up interest just sitting there, but technical debt is only billed when you touch that code. Cunningham's own phrasing was that "all the time that you spend on not-quite-right code is interest on that debt" — the condition is spending time, not time passing. This is exactly why C is a multiplying term in the previous section, and this single difference is what makes the financial intuition that "debt is better paid off quickly" wrong when applied to code.
Second, you can't calculate the principal. There's no interest rate, no repayment schedule, no maturity date. Tools exist that convert total debt into a single monetary figure on a dashboard, but few people can explain what the denominator of that number actually is. The moment you mistake the metaphor for a model, that figure becomes something to manage — and a figure that gets managed starts getting optimized.
Third, it isn't linear. Debt sitting at a highly coupled point costs far more than debt that's purely local. The same 100 lines of messy code cost something different depending on whether 20 modules depend on it. The financial metaphor has no concept of position.
And there's one misunderstanding Cunningham himself has corrected repeatedly — the debt he was talking about is not deliberately sloppy code written with the intent of doing it properly later. He meant the cycle of shipping fast to gain understanding of the domain, then refactoring to reflect that understanding back into the code. In the original metaphor, debt wasn't "bad code" — it was learning not yet reflected. This definition is more useful in practice because it tells you exactly what needs cleaning up: the places where what we currently know about the domain and what the code assumes have drifted apart.
Persuading Your Manager — With History, Not Aesthetics
"This code is messy" isn't persuasive. The person listening has no way to verify it, and it gets filed away as a matter of taste. Instead, pull the values for the formula from the previous section out of real data. Every one of them is an auditable number.
# 1) Change frequency C: top 20 files by commit count over the last 12 months
git log --since="12 months ago" --name-only --pretty=format: \
| sed '/^$/d' | sort | uniq -c | sort -rn | head -20
# 2) Defect-related changes D: same aggregation, filtered to bug-fix commits only
# (use --grep if you have a commit convention, or an issue-key pattern if not)
git log --since="12 months ago" --name-only --pretty=format: \
--grep='^fix' --grep='hotfix' --grep='BUG-' \
| sed '/^$/d' | sort | uniq -c | sort -rn | head -20
# 3) Hotspots: keep only the large files among those with high change frequency
git log --since="12 months ago" --name-only --pretty=format: \
| sed '/^$/d' | sort | uniq -c | sort -rn \
| awk '{ n=$1; f=$2; cmd="wc -l < " f; cmd | getline loc; close(cmd);
if (loc > 500 && n > 20) printf "%5d changes %6d loc %s\n", n, loc, f }'
Walk in with this output as-is and the conversation changes. "The order-processing module was modified 84 times over the last 12 months, 23 of those were bug fixes, and 31 percent of P2 incidents pass through this file" is a verifiable statement. Attach a single payback period to that, and it stops being a request for approval and becomes an investment proposal.
What to attach next is a scoped experiment. Don't ask for a full cleanup — propose allocating a fixed amount of time to one hotspot and measuring lead time before and after. If it fails, it fails within that scope; if it succeeds, you have grounds for the next round. This is also where the new experiment discussed earlier offers something practical — running the same change request once before and once after refactoring is the cheapest way to measure it. If you're using an agent, token count becomes the proxy metric; if you're relying on humans alone, time to first commit does.
Finally, don't try to win the argument. Someone who calculates three modules, concludes "don't" on two of them, and proposes only one, gets approval far faster than someone who insists everything needs cleaning up.
Closing — Code Only Charges Interest When It's Read
To sum up:
- The new experiment cut input tokens for the same change by 83 percent across 15 refactoring steps, but in monetary terms that's 39.7 cents per change, and the author himself is careful to call it a single greenfield experiment. Read it as a proposed measurement method, not a conclusion.
- The existing evidence is thin. Correlational evidence that low quality is expensive does exist (15 times the defects, 124 percent longer resolution), but there's no general evidence that refactoring recovers that cost, and some types of refactoring are associated with introducing defects.
- So calculate per module instead of arguing in general terms. Because change frequency is a multiplying term, code that never changes won't pay back no matter how messy it is.
- The interest metaphor lands with managers, but it isn't a model. Interest accrues on contact rather than time, the principal can't be calculated, and it's nonlinear with respect to coupling.
- Persuade with git history, not aesthetics. A proposal that rules out two of three candidates itself is the one that gets approved fastest.
Reduced to one line: the value of refactoring depends not on the state of the code, but on how many more times that code is going to be read.
References
- Giles Edwards-Alexander — The Economic Benefit of Refactoring (martinfowler.com, 2026-07-30)
- Hacker News — discussion of The Economic Benefit of Refactoring (including methodological critiques)
- Tornhill & Borg — Code Red: The Business Impact of Code Quality (arXiv:2203.04374)
- Martin Fowler — Is High Quality Software Worth the Cost? (2019, updated 2024)
- On the relationship between refactoring actions and bugs: a differentiated replication (ESEC/FSE 2020)
- Is refactoring always a good egg? (MSR 2022)
- Agile Alliance — Introduction to the Technical Debt Concept (the original meaning of Cunningham's metaphor)
- A Practical Procedure for Moving a Codebase with AI — the Measurement Metrics Edition (related post)