기술 부채를
처음 실감한 순간
버튼 하나를 바꾸는 데 3일이 걸린 날 — 그 이유를 알고 나서
그 버튼 하나가 시작이었다
입사 5개월 차였다. PM이 Slack으로 메시지를 보냈다. "결제 페이지 '구매하기' 버튼 색상을 파란색에서 초록색으로 바꿔주세요. A/B 테스트 결과가 나왔어요." 간단한 태스크였다. CSS 한 줄 고치면 되는 것이었다.
그렇게 생각했다. 근데 3일이 걸렸다.

버튼 컴포넌트를 찾으려고 코드를 열었다. 결제 페이지 파일을 찾았다. 2,400줄짜리 파일이었다. 스크롤을 내려도 버튼이 어디 있는지 보이지 않았다. 검색해봤다. "구매하기"를 검색하니 17개가 나왔다. 어떤 게 결제 페이지의 버튼인지 구분이 안 됐다.
button 태그를 검색해봤다. 결제 파일 안에만 43개가 있었다. 버튼 컴포넌트가 따로 있는지, 인라인 스타일인지, styled-components인지, className인지 전부 달랐다. 이 파일 안에서 여러 개발자가 각자 다른 방식으로 버튼을 만든 것이 분명했다.
3일 동안 실제로 있었던 일들
결제 버튼 색상을 정의하는 곳이 네 군데였다. globals.css에 한 번, 결제 페이지 컴포넌트 파일 상단에 styled-components로 한 번, 같은 파일 하단에 인라인 스타일로 한 번, 그리고 공통 Button 컴포넌트의 variant='primary'로 한 번. 우선순위가 어떻게 되는지 파악하는 데만 두 시간이 걸렸다.
가장 확실해 보이는 곳을 고쳤다. 로컬에서 확인하니 결제 버튼이 초록색이 됐다. 그런데 같은 컴포넌트를 쓰는 다른 페이지의 버튼도 초록색이 됐다. 헤더의 로그인 버튼, 장바구니 버튼, 리뷰 작성 버튼까지 전부. 수정 범위가 예상보다 훨씬 넓었다.
선배한테 물어봤다. "Button 컴포넌트 primary 색상 바꾸면 안 돼요. 거기 의존하는 게 너무 많아서 건드리면 온 서비스가 바뀌어." 그래서 결제 페이지에서만 override 해야 했다. 방법을 찾느라 또 반나절. !important를 써야 하는 상황이 됐다.
ESLint 룰에 no-important 설정이 있었다. !important 쓰면 빌드가 실패했다. 그럼 어떻게? styled-components로 새 컴포넌트를 만들어야 했다. BuyButton이라는 컴포넌트를 새로 만들었다. 프로덕션에 버튼 컴포넌트가 하나 더 생겼다.
배포 직전 QA에서 발견됐다. 모바일 Safari에서 버튼 색상이 데스크톱과 달랐다. 알고 보니 미디어 쿼리 안에 별도 색상 정의가 또 있었다. 그걸 찾아서 고치고, 다시 테스트하고, 다시 PR 올리고. 그게 수요일이었다.
버튼 색상이라는 단순한 스타일이 4군데에 분산 정의돼 있고, 공통 컴포넌트가 너무 많이 의존돼서 건드릴 수 없고, 미디어 쿼리에 별도 정의가 숨어있고, !important를 금지하는 룰이 있지만 그 룰이 생긴 이유는 아무도 설명 못 하는 상태. 이게 3년 동안 여러 개발자가 급하게 만들면서 쌓인 기술 부채였다.
PM과의 대화 — "왜 이렇게 오래 걸려요?"
그게 기술 부채를 PM에게 처음 설명하려 한 순간이었다. 설명하면서 나 자신도 이게 얼마나 심각한 건지를 처음으로 언어화했다.
선배한테 물어봤다 — "원래 다 이래요"
리드 개발자한테 조용히 물어봤다. "결제 페이지가 왜 이렇게 됐어요? 누가 이렇게 만든 건가요?" 리드가 잠깐 생각하다가 말했다. "3년 전에 처음 만든 사람은 퇴사했어요. 그 다음에 두 명이 거기에 기능을 붙였는데, 건드리면 깨질 것 같아서 기존 구조를 안 바꾸고 옆에 붙인 거예요. 저도 그렇게 했고."
그 말이 인상적이었다. 의도적으로 나쁘게 짠 게 아니었다. 각자 당시에 가장 안전한 선택을 한 것이었다. 건드리면 깨질까봐 기존 것을 건드리지 않고 옆에 붙인 것. 그게 반복되면서 지금의 상태가 됐다. 그리고 나도 이번에 BuyButton이라는 컴포넌트를 새로 만들었다. 나도 같은 패턴을 반복한 것이었다.
기술 부채는 나쁜 개발자가 만드는 게 아니었다. 각자 최선의 판단으로 급하게 만든 것들이 쌓여서 생기는 것이었다. 그리고 그 사실이 더 무서웠다.
기술 부채의 종류 — 그때 처음 제대로 이해했다
버튼 하나 사건 이후 기술 부채에 대해 찾아봤다. 그때까지는 막연하게 "지저분한 코드" 정도로만 알았는데, 훨씬 다양한 형태가 있었다. 우리 코드베이스를 보면서 각 종류가 실제로 있다는 걸 확인했다.
결제 페이지 2,400줄짜리 파일이 딱 이것이었다. 한 파일에 너무 많은 책임이 있었다. 분리했어야 할 것들이 한 곳에 모였다.
"이 버튼 건드리면 안 된다"는 게 코드 어디에도 없었다. 퇴사한 사람 머릿속에만 있었다. 암묵지가 문서화되지 않은 상태.
결제 페이지에 테스트 코드가 없었다. 그래서 내가 버튼을 바꿨을 때 다른 곳이 깨진 걸 자동으로 못 잡았다. QA에서 수동으로 발견했다.
공통 Button 컴포넌트가 너무 많이 의존돼서 건드릴 수 없는 상태. 변경해야 할 곳이 생겨도 영향 범위가 너무 커서 손댈 수 없다.
실제 코드에서 본 기술 부채 패턴들
// ② 복사된 코드 (같은 로직이 5곳에) const formatPrice = (price) => { // checkout.js const formatPrice = (price) => { // cart.js const formatPrice = (price) => { // product.js // ... 모두 조금씩 다름. 어떤 게 정답인지 모름
// ③ 아무도 지우지 못하는 코드 const legacyPaymentHandler = () => { // 아무데서도 호출 안 되는 것 같은데 지우면 안 될 수도 있음 // 2022년 이후 수정 이력 없음 }
// ④ 어디에 있는지 모르는 비즈니스 로직 if (user.type === 'premium') { // premium 유저 정의가 어디 있는지 아무도 모름 // DB에 type 컬럼이 있는데 언제 채워지는지도 모름 }
기술 부채를 팀에 말하려고 했을 때
스프린트 계획 회의에서 "결제 페이지 리팩토링을 일정에 넣으면 어떨까요"를 꺼냈다. 처음 꺼내는 말이어서 어색했는데, 생각보다 반응이 다양했다.
리드는 "필요한 건 알아요. 근데 언제 할 수 있을지..."라고 했다. PM은 "비즈니스 기능이 아니면 우선순위 올리기 어렵다"고 했다. CTO는 "얼마나 걸려요? 그동안 다른 기능 개발 멈추는 건가요?"라고 물었다. 아무도 반대를 한 게 아니었다. 필요하다는 걸 모두가 알았다. 그런데 언제 할 수 있는지, 얼마나 걸리는지가 문제였다.
"다음 분기 이후에"는 결국 오지 않았다. 다음 분기에도 데드라인이 있었다. 이게 기술 부채가 계속 쌓이는 구조라는 걸 그때 이해했다. 모두가 필요하다는 걸 알지만, 지금 당장 비즈니스 기능이 더 급하다는 논리가 항상 이겼다.
기술 부채가 눈에 보이기 시작하면서
버튼 하나 사건 이후로 코드를 보는 방식이 달라졌다. 이전엔 "이게 왜 이렇게 복잡하지"라고만 생각했는데, 이제는 "이게 언제 어떤 맥락에서 이렇게 됐을까"를 생각하게 됐다.
# 기술 부채 신호들 — 코드를 읽으면서 보이기 시작한 것들
[WARN] 파일 라인 수가 500줄 이상인 컴포넌트 → 분리가 필요하다는 신호
[WARN] 같은 로직이 여러 파일에 복사 → 추상화 기회 놓침
[FAIL] "건드리면 안 된다"는 주석 → 테스트 없는 핵심 로직
[FAIL] TODO 주석에 날짜 없음 → 언제 생겼는지 모르는 미완성
[WARN] Props가 10개 이상인 컴포넌트 → 책임이 너무 많음
[FAIL] any 타입이 많은 TypeScript → 타입 안전성 포기
─────────────────────────────────────────────────
# 이것들이 보이기 시작하면 기술 부채를 인식하게 된 것
# 보이는 것과 고치는 것은 다른 차원의 문제
기술 부채에서 배운 것들
처음엔 나쁜 개발자가 만드는 것이라고 생각했다. 아니었다. "지금 당장 만들어야 하니까"라는 의도적인 트레이드오프의 결과다. 문제는 그 트레이드오프를 인식하고 기록했느냐다. 인식 없이 쌓인 부채가 나중에 제일 무섭다.
"코드가 지저분해요"는 설득이 안 된다. "버튼 색상 변경에 3일이 걸렸고, 다음에 유사한 변경이 생기면 또 그렇게 걸릴 거예요"가 훨씬 설득력 있다. 기술 부채를 비즈니스 시간과 비용으로 번역하는 능력이 필요하다.
BuyButton 컴포넌트를 새로 만든 순간, 나도 버튼 컴포넌트를 하나 더 추가했다. 더 나은 방법이 있었지만 시간이 없어서 우선 이렇게 했다. 다음 사람은 이게 왜 있는지 모를 것이다. 기술 부채를 인식한 그 순간에 나도 부채를 만들고 있었다.
한 번에 다 고치려는 "빅뱅 리팩토링"은 실패 확률이 높다. 작업하면서 지나는 곳을 조금씩 개선하는 "보이스카우트 룰" — 내가 지나간 자리는 들어왔을 때보다 조금 더 낫게 두고 나가는 것. 이게 팀 전체가 동의할 수 있는 현실적인 방법이었다.
기술 부채를 못 보는 사람은 새 기능을 빠르게 만드는 것처럼 보이지만, 결국 다음 사람이 느리게 만들게 된다. 부채를 인식하고, 팀에 말할 수 있고, 점진적으로 줄여가는 개발자가 장기적으로 팀에 더 가치 있다는 걸 그 경험 이후 실감했다.
기술 부채는 완전히 없앨 수 없다. 빠르게 만드는 것과 잘 만드는 것 사이의 트레이드오프는 항상 존재한다. 현실적인 방법은 세 가지다. 첫째, 새로 만들 때 부채를 최소화한다. 둘째, 기존 부채를 건드릴 때는 조금씩 개선한다. 셋째, 부채의 존재를 팀과 공유하고 우선순위를 협의한다. 인식과 소통이 전부다.
버튼 하나를 바꾸는 데 3일이 걸렸던 그 경험이 지금도 기준점이 된다. 새 기능을 만들 때 "이게 나중에 바꾸기 쉬운 구조인가"를 한 번 더 생각하게 됐다. 완벽할 수는 없지만, 적어도 다음 사람이 이 코드를 열었을 때 "왜 이렇게 됐지"라는 말이 덜 나오도록.
그리고 BuyButton이라는 컴포넌트를 새로 만들었던 그 선택도, 나중에 기회가 됐을 때 공통 Button 컴포넌트와 합쳐서 정리했다. 작게라도 갚는 것. 그게 기술 부채와 함께 사는 현실적인 방법이었다.
💬 기술 부채를 처음 실감한 순간이 있으신가요?
단순해 보이는 작업이 예상보다 훨씬 오래 걸렸던 경험, 기술 부채를 팀에 설명하려다 어려웠던 경험 — 어떤 이야기든 댓글로 나눠주세요. 비슷한 상황에 있는 분들에게 가장 현실적인 이야기가 될 것 같습니다.
'개발자 > 실무 개발 현장' 카테고리의 다른 글
| 개발자의 하루 루틴, 실제로 어떻게 생겼나 (0) | 2026.08.03 |
|---|---|
| 야근이 일상인 스타트업에서 버틴 방법 (0) | 2026.07.27 |
| 내가 짠 코드가 운영 중 터졌을 때의 경험담 (0) | 2026.07.20 |
| 개발자가 PM·기획자와 갈등했던 실제 사례 (0) | 2026.07.13 |
| 스프린트와 애자일, 현장에서 실제로 어떻게 돌아가나 (0) | 2026.07.06 |