Search

점진적 개선 멘탈 모델

한 문장

점진적 개선이란, 동작은 그대로 두고 표현만 바꾸는 작은 단위의 변경을 누적하여, 학습과 구조 개선이 함께 일어나게 하는 것이에요.

왜 필요한가

초보자 작업기억: [변수명][함수길이][중복][책임분리][에러처리][포맷][남 눈치] (7/7) → 꽉 참, 고차원 사고 불가 전문가 작업기억: [코드스멜][남 눈치][ ][ ][ ][ ][ ] (2/7) → 여유 있음, "이 설계가 비즈니스에 맞나?" 생각 가능
Plain Text
복사
한번에 많은 것을 바꾸면 작업기억이 꽉 차요. 뭐가 잘못됐는지 파악하기 어렵고, 실패했을 때 어디로 돌아가야 하는지도 모르겠어요. 반면 작은 단위로 바꾸면 작업기억에 여유가 생기고, 그 여유 속에서 학습이 일어나요.

두 개의 모자

TDD에서는 "기능 모자"와 "리팩토링 모자"를 구분해요.
🎩 기능 모자 🎨 리팩토링 모자 동작을 바꾼다 표현을 바꾼다 Red → Green Green → Refactor "뭘 하게 만들까" "어떻게 표현할까"
Plain Text
복사
핵심 규칙: 한 번에 하나의 모자만 쓸 수 있다.
기능 모자를 쓰고 있을 때는 코드가 예쁘든 말든 신경 쓰지 마세요. 일단 돌아가게 만드는 데 집중해요. 리팩토링 모자를 쓰고 있을 때는 새 기능을 추가하지 마세요. 동작은 그대로 두고 표현만 바꿔요.
두 모자를 동시에 쓰면 뭐가 문제인지 알 수 없어요. 테스트가 실패했을 때 "기능이 잘못된 건가, 리팩토링하다 망가뜨린 건가?"를 구분할 수 없거든요.

초보자와 전문가의 차이

"이게 뭔소리야?" 또는 "아 머리아파" — 이 감각은 초보자와 전문가 모두 느껴요. 차이는 타이밍과 단위예요.
초보자는 이미 복잡해진 코드 앞에서 느껴요.
"뭔소리야... 일단 돌아가니까 넘어가자." 나중에 개선을 시도할 때는 큰 단위로 한번에 잘하려고 해요. 여러 가지가 뒤섞이고, 실패할 이유가 많아져요. 요리 초보가 번잡한 주방에서 요리 내내 고통받고, 설거지도 마지막에 한번에 다 하려다 지치는 것처럼요.
전문가는 복잡해지기 직전에 신호를 느껴요.
"지금은 맥락이 있어서 읽히는데, 다음에 돌아오면 못 읽겠다." 작은 비용으로 당장 시작해서 금방 끝내요. 실패할 수 없는 작은 단위로 하고, 기회는 여러 번 있다고 생각해요. <냉장고를 부탁해> 같은 방송에서 볼 수 있듯 훈련 받은 셰프가 요리 중간중간 작은 정리와 청소를 습관적으로 해서 계속 깔끔한 환경을 유지하고, 마지막 설거지 양도 적은 것처럼요.
신호는 같아요. 반응하는 단위와 타이밍이 달라요.

핵심 질문

아래 질문들은 한국어로 질문을 떠올리고, 영어 표현의 방향성에 따라 행동을 이어나가도록 설계되어 있어요.

1. 명확한 신호로부터 출발하는가? (Act on Signal)

'미래에 필요할 것 같아서'라는 막연한 예측이 아닌, '지금 나타난 명확한 신호'에 기반하여 개선을 시작해요.
"(일단 리팩토링 하려다가) 나 지금 코드 스멜 보고 그거 고치려고 했나? 아니, 그냥 일단 하려고 했던 거 같아. Act on Signal 하자. 아직은 안 해도 돼. 다음 사이클에 다시 생각해보자."

2. 결과에 기여하고 있나? (Ship Value First)

모든 개선은 '자기만족'이나 '맹목적 규칙 준수'가 아닌, '동작하는 소프트웨어'라는 최종 결과물에 기여해야 해요.
관측 가능한 트리거:
"이유는 없지만 그냥 파일이 길어서 나누고 싶다."
"이 리팩토링의 목적을 한 문장으로 설명하기 어렵다."
"이대로 가면 시간 내에 기능 완성을 못 할 것 같다."
실천법:
코드를 나누기 전, "이 분리를 통해 OOO가 더 쉬워진다"와 같이 기대 효과를 먼저 적어요.
지금 당장 결과물에 기여하지 않는 리팩토링은 // TODO:로 표시하고, 기능 구현을 우선해요.
리팩토링이 생각처럼 안 되면 중단하거나 되돌릴 수 있어야 해요.
"(한참 정신 팔려서 리팩토링 하다가) 나 지금 결과에 기여하고 있나? -> 아, Ship Value First 하자..."

3. 안전한가? (Mark Your Checkpoint)

리팩토링은 '동작하는 코드'를 망가뜨릴 수 있는 활동이에요. 항상 작은 단위로 움직이고, 언제든 되돌아올 수 있는 안전지대를 확보해요.
관측 가능한 트리거:
"이 코드를 고치면 다른 곳이 깨질 것 같은데..."라는 불안감이 들 때
내가 지금 고치고 있는 코드에 대한 테스트가 없을 때
실천법:
리팩토링 시작 직전에 반드시 커밋해요. (git commit -m "refactor: before extracting user logic")
롤백 지점 없이 큰 변경을 시작하지 마세요.
10분 타이머 훈련:
리팩토링 모자를 쓰고 10분 타이머를 설정해요.
10분 안에 끝내지 못하면 되돌리고, 더 작은 단위로 다시 시도해요.
모자를 쓰고 있는 동안에는 다른 모자 활동 금지. "아 이것도 고쳐야겠다"가 떠오르면 TODO로 적어두고 넘어가요.
"나 지금 안전한가? 커밋했나? Mark Your Checkpoint 하자."

4. 하나만 바꾸고 있나? (One Thing at a Time, 한번에 하나씩)

앞서 말한 "한 번에 하나의 모자만"을 실천하는 거예요. 여러 가지를 동시에 바꾸면 뭐가 문제인지 알 수 없어요.
관측 가능한 트리거:
이번 커밋에 "이름 변경 + 구조 변경 + 로직 변경"이 섞여 있을 때
테스트가 실패했는데 뭐 때문인지 모를 때
실천법:
리팩토링 모자를 쓰고 있다면: 동작은 그대로, 표현만 바꿔요.
Step 1: 이름만 바꿈 → 테스트 통과 확인
Step 2: 구조만 바꿈 → 테스트 통과 확인
Step 3: 로직만 바꿈 → 테스트 통과 확인
// 원래 코드 for (let i = 0; i < cart.items.length; i++) { if (cart.items[i].category === 'electronics') { total += cart.items[i].price * 0.9 } } // Step 1: 동작 그대로, 조건만 추출 const isElectronics = (item) => item.category === 'electronics' // Step 2: 동작 그대로, 계산만 추출 const applyDiscount = (item, { rate }) => item.price * (1 - rate) // Step 3: 동작 그대로, 반복 구조만 변경 cart.items .filter(isElectronics) .reduce((sum, item) => sum + applyDiscount(item, { rate: 0.1 }), 0)
TypeScript
복사
"나 지금 한번에 하나씩 하고 있나? One Thing at a Time 하자."

불확실성을 다루는 원칙

확정한 것은 기반으로 삼는다 — 이미 아는 것을 구조에 새겨 인지적 발판으로 써요
불확실한 것은 옵션으로 남긴다 — 미래 변경 권리를 확보하는 방식으로 열어둬요
모르는 걸 미리 설계하려고 하지 마세요. 아는 것만 구조에 새기고, 모르는 건 나중에 알게 되면 그때 구조를 고치면 돼요. 그 과정에서 코드는 계속 돌아가요.
// Step 1: 확정한 것만 — "결제를 받는다" <PaymentForm onSubmit={handlePayment} /> // Step 2: 앎이 쌓임 — "결제수단이 여러 개다" <PaymentForm method={cardPay} onSubmit={handlePayment} /> // Step 3: 앎이 더 쌓임 — "제출 전에 검증이 필요하다" <PaymentForm method={cardPay} onSubmit={handlePayment} validate={validateCard} /> // Step 4: 앎이 더 쌓임 — "분석 추적이 필요하다" <PaymentForm method={cardPay} onSubmit={withAnalytics(handlePayment, { event: 'purchase' })} validate={validateCard} /> // 매 단계마다 코드는 돌아간다. // 긴장이 느껴질 때만 구조를 고친다.
TypeScript
복사

학습 사이클

작은 성공 사이사이에 학습이 일어나요. 이번 리팩토링에서 배운 게 다음 리팩토링을 더 잘하게 해요.
[시도] → [성공/실패] → [학습] → [다음 시도에 반영] ↑ │ └────────────────────────────────────┘
Plain Text
복사
한번에 크게 하면 이 사이클이 안 돌아요. 실패해도 뭘 배워야 하는지 모르고, 성공해도 뭐가 잘한 건지 몰라요.

오작동을 방지하려면

점진적 개선이 아닌 것

한번에 크게 바꾸기: "이번에 제대로 리팩토링하자"면서 여러 파일을 동시에 건드리는 것
동작을 바꾸면서 표현도 바꾸기: 버그 수정과 리팩토링을 같이 하면 뭐가 문제인지 알 수 없어요
중간에 안 돌아가는 상태: "지금은 깨져 있지만 다 고치면 돌아갈 거야"
미리 설계하고 한번에 적용: 처음부터 완벽한 구조를 그리고 한번에 적용하는 것

흔한 실수

"시간이 없어서 점진적으로 못 했어요"
거꾸로예요. 시간이 없을수록 점진적으로 해야 해요. 한번에 크게 하다가 실패하면 시간을 더 많이 잃어요. 작게 하면 중간에 멈춰도 그만큼은 건진 거예요.
"너무 작은 단위로 하면 비효율적이지 않나요?"
작은 단위의 비용은 낮아요. 커밋 한 번 더 하는 거예요. 반면 큰 단위로 하다가 실패하는 비용은 높아요. 어디서 잘못됐는지 찾아야 하고, 롤백해야 하고, 다시 시작해야 해요.
"이 정도는 한번에 해도 되지 않나요?"
"이 정도"가 점점 커져요. 오늘 "이 정도"가 내일은 더 커지고, 어느 순간 감당 안 되는 크기가 돼요. 작은 단위를 습관으로 만드세요.