#acl +All:read = BabySteps = ''주니어 개발자들을 위한 패턴 언어 - 시스템의 생명력을 유지하며 복잡한 변경을 수행하는 방법'' <> == The Story 1: The Long Tunnel vs. Stepping Stones (Programming) == 두 명의 개발자, 민수와 하나가 똑같이 복잡한 리팩토링 작업을 맡았다. 거대한 `User` 클래스에서 `Billing` 로직을 분리하는 작업이다. '''민수의 접근 (The Big Jump):''' 민수는 생각했다. "이건 다 연결되어 있으니까 한 번에 옮겨야 해." 그는 코드를 자르고 붙여넣기 시작했다. 30개의 파일이 수정되었고 컴파일 에러가 150개 떴다. 민수는 "금방 잡을 수 있어"라고 말했지만, 3시간 후에도 에러는 여전했고 무엇이 문제였는지 기억조차 희미해졌다. 시스템은 3시간 동안 '죽어' 있었다. '''하나의 접근 (Baby Steps):''' 하나는 다르게 시작했다. 1. 새로운 `Billing` 클래스를 빈 상태로 만들었다. (Green) 2. `User`의 메서드 하나를 `Billing`으로 복사했다. (Green) 3. `User`가 `Billing`의 메서드를 호출하도록 위임했다. (Green) 하나는 10분마다 커밋했다. 커피를 마시러 갈 때도, 퇴근할 때도 그녀의 코드는 항상 작동했다. 작업이 끝났을 때 민수는 여전히 디버깅 중이었고, 하나는 이미 다음 기능을 만들고 있었다. == The Story 2: The Piano Lesson (Ordinary Life) == 민수와 하나는 취미로 피아노를 배우고 있다. 오늘 숙제는 아주 빠르고 복잡한 쇼팽의 연습곡이다. '''민수의 연습 (The Whole Song):''' 민수는 곡의 처음부터 끝까지 한 번에 완벽하게 치고 싶어 한다. 그는 악보를 펴고 양손으로 힘겹게 연주를 시작했다. 중간에 계속 틀렸지만, "연습하다 보면 되겠지"라며 멈추지 않고 끝까지 쳤다. 한 시간을 연습했지만 민수의 연주는 여전히 뚝뚝 끊겼고, 어디가 틀렸는지조차 알 수 없게 되었다. '''하나의 연습 (One Bar at a Time):''' 하나는 다르게 연습했다. 1. 첫 번째 마디의 오른손만 완벽하게 친다. 2. 그 마디의 왼손만 완벽하게 친다. 3. 양손을 합쳐 한 마디를 완벽하게 친다. 하나는 단 한 마디라도 '완벽하고 리드미컬하게' 들릴 때까지 다음으로 넘어가지 않았다. 그녀의 연습은 매 순간 '음악'이었고, 민수보다 느려 보였지만 결국 곡 전체를 가장 먼저 마스터했다. 기예는 작은 성공을 쌓아 올리는 과정임을 하나는 알고 있었다. == Context == 당신은 무엇을 만들어야 할지 알고 있다([[TinyExperiment]]를 통해). 하지만 그 작업은 크고 복잡하다. 리팩토링이거나, 큰 기능 추가일 수 있다. 일상적인 상황: * 코드를 수정하기 시작해서 1시간이 지났는데, 아직 컴파일이 안 된다. * "거의 다 됐어, 이것만 연결하면 돼"라고 말하지만, 그 상태가 반나절 지속된다. * 변경 사항이 너무 많아서 어디서 버그가 발생했는지 알 수 없다. * 동료가 "그거 지금 실행돼?"라고 물으면 "아니, 지금 작업 중이라 안 돼"라고 답한다. == Problem == '''한 번에 너무 많은 변화를 시도하면, 시스템의 "생명력(Wholeness)"이 깨진다.''' 시스템이 작동하지 않는 상태가 길어질수록 복잡성은 폭주하고 심리적 압박은 커진다. * '''복잡성의 폭주:''' 여러 변경 사항이 서로 얽혀 문제가 생겼을 때 원인을 찾을 수 없다. * '''심리적 압박:''' "돌아갈 수 없다"는 공포가 생기고, 앞이 보이지 않는다. * '''중단 불가능:''' 긴급한 다른 이슈가 생겨도 현재 작업을 멈출 수 없다. == Solution == '''시스템을 항상 작동하는 상태로 유지할 수 있는 가장 작은 단위로 쪼개어 변경하라.''' BabySteps는 각 단계가 끝날 때마다 시스템이 온전해야(Structure-Preserving) 한다는 규율이다. === Principle 1: Always Green (항상 녹색 상태 유지) === 가장 중요한 규칙이다. 한 단계를 마쳤을 때, '''모든 테스트가 통과해야 한다.''' 만약 테스트가 깨졌다면? 당신은 보폭을 너무 크게 잡은 것이다. * '''Comment Out and Revert (한 보 후퇴):''' 새로 작성한 코드에서 오류가 발생했을 때, 즉시 해당 코드를 주석 처리(Comment out) 하십시오. 한 스텝 뒤로 가서 제대로 동작하는 것을 재확인하고, 그 지점에서 다시 아주 작은 증분을 탐색하십시오. === Principle 2: Parallel Change (평행 변경) === 기존 것을 지우고 새 것을 넣는 것이 아니라, 새 것을 옆에 만들고 서서히 옮겨라. 1. '''확장(Expand):''' 새 기능을 추가한다. 2. '''이주(Migrate):''' 사용하는 곳을 하나씩 새 기능으로 옮긴다. 3. '''수축(Contract):''' 사용하지 않는 기존 기능을 제거한다. === Principle 3: Make it Easy, Then Make it Right === Kent Beck의 조언: "Make the change easy, then make the easy change." * 기능을 추가하기 쉽게 구조를 먼저 바꿔라(리팩토링). 그 다음 기능을 추가하라. == Real Examples == === Example 1: Function Signature Change === 인자를 추가할 때, 기존 호출부를 다 고치는 대신 기본값(Default value)을 주어 먼저 작동하게 만든 뒤, 하나씩 호출부를 수정해 나가는 방식. === Example 2: Renaming a Class === 기존 클래스를 상속받는 새 이름의 클래스를 만들고, 사용하는 곳을 하나씩 옮긴 뒤 마지막에 옛 클래스를 삭제하는 방식. == Common Pitfalls == === "It's slower!" (느려 보여요!) === 토끼와 거북이다. 거북이는 멈추지 않기 때문에 빠르다. 디버깅 지옥에 빠지지 않는 것이 가장 빠른 길이다. === "Just one more line..." (한 줄만 더...) === 이 유혹에 넘어가는 순간 3시간의 디버깅이 시작된다. 5분이 지나도 해결이 안 되면 무조건 돌아가라(Revert). == Connection to Other Patterns == * '''[[TightLoop]]''' - 빠른 피드백 루프가 있어야 보폭을 작게 유지할 용기가 생깁니다. ''동력'' * '''[[AtomicCommit]]''' - 각 Baby Step의 끝이 바로 원자적 커밋의 시점입니다. ''기록의 단위'' * '''[[GreenRefuge]]''' - 발을 헛디뎠을 때 즉시 돌아갈 안전 지대입니다. ''보완'' * '''[[TinyExperiment]]''' - 보폭을 떼기 전 어디로 갈지 먼저 길을 찾으십시오. ''선행'' == Signs of Success == * 코딩이 평온한 리듬을 탄다. 스트레스가 없다. * 디버거를 켜지 않는다. 문제가 생겨도 방금 작성한 3줄 안에 원인이 있다. * 언제든 퇴근할 수 있다. 10분만 정리하면 작업 끝이다. * 코드 리뷰가 쉽다. 동료가 작은 커밋들을 보며 의도를 쉽게 파악한다. == The Ultimate Insight == '''속도는 "빨리 타이핑하는 것"에서 나오지 않는다. "멈추지 않는 것"에서 나온다.''' BabySteps는 멈추지 않게 해주는 기술입니다. 시스템을 항상 살아있게 하십시오. 그것이 가장 빠르고 안전하게 목적지에 도달하는 방법입니다. ---- CategoryPatternLanguage CategoryProgramming CategoryRefactoring CategoryTDD