리팩터링이란 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법이다.
💡 리팩터링을 하면 소프트웨어 설계가 좋아진다. 아키텍처를 충분히 이해하지 못한 채 단기 목표만을 위해 코드를 수정하다 보면 기반 구조가 무너지기 쉽고, 설계가 나쁘면 같은 일을 하는 코드가 여러 곳에 나타나기에 코드는 길어진다. 바람직한 설계란, 모든 코드가 언제나 고유한 일을 수행함을 보장할 수 있어야 한다.
💡 리팩터링을 하면 소프트웨어를 이해하기 쉬워진다. 프로그램을 동작시키는 데만 신경 쓰다 보면 나중에 그 코드를 다룰 개발자를 배려하지 못한다는데 있다. 또한 그 다른 사람이 곧 나 자신일 때가 많기 때문에 더욱이 리팩터링은 중요하다. 리팩터링은 코드가 더 잘 읽히게 도와준다. 리팩터링하면 코드의 목적이 더 잘 드러나게, 내 의도를 더 명확하게 전달하도록 개선할 수 있다.
💡 리팩터링을 하면 버그를 쉽게 찾을 수 있다. 코드를 이해하기 쉽다는 말을 버그를 찾기 쉽다는 말이기도 하다. 리팩터링하면 코드가 하는 일을 깊이 파악하게 되면서 견고한 코드를 작성할 수 있다.
💡 리팩터링을 하면 개발 속도를 높일 수 있다. 리팩토링을 하면 내부 설계와 가독성이 개선되고 버그가 줄어든다. 이점은 모두 품질 향상에 직결된다. 내부 설계가 잘 된 소프트웨어는 새 기능을 추가할 지점과 어떻게 고칠지를 쉽게 찾을 수 있다. 코드가 명확하면 버그를 만들 가능성도 줄고, 버그를 만들더라도 디버깅하기가 쉬워진다.

👓 준비를 위한 리팩터링: 리팩터링하기 가장 좋은 시점은 기능을 새로 추가하기 직전이다. 코드를 살펴보면서, 구조를 살짝 바꾸면 다른 작업을 하기가 훨씬 쉬워질 만한 부분을 찾는다.
👓 이해를 위한 리팩토링: 코드를 수정하려먼 먼저 그 코드가 하는 일을 파악해야 한다. 코드의 의도가 명확하게 드러나도록 리팩터링할 여지는 없는지 찾아본다.
👓 쓰레기 줍기 리팩터링: 코드를 파악하던 중에 로직이 쓸데없이 복잡하거나 중복 코드를 발견한다면, 간단히 수정할 수 있는 것은 즉시 고치고 시간이 좀 걸리는 일은 하던 일을 끝내고 나서 처리하도록 한다. 보기 싫은 코드를 발견하면 리팩터링하자
👓 계획된 리팩터링과 수시로 하는 리팩터링: 따로 시간을 내서 새 기능을 추가하기 쉽도록 코드를 개선할 필요가 있는, 이런 계획된 리팩터링을 하게 되는 일은 최소한으로 줄여야 한다. 리팩터링은 작은 기회가 될 때마다 기능을 추가하거나 버그를 잡는 동안에 처리할 수 있도록 한다.
👓 오래 걸리는 리팩터링: 리팩터링을 할 때 몇 주는 걸리는 대규모 리팩터링이 있을 수 있다. 한 번에 해결하기 보다는 주어진 문제를 조금씩 해결해가는 편이 좋다. 예를 들어, 라이브러리를 교체하는 경우에는 기존 것과 새 것 모드를 포용하는 추상 인터페이스를 마련한다. 기존 코드가 추상 인터페이스를 호출하도록 만들고 나면 라이브러리를 훨씬 쉽게 교체할 수 있다.
🧙♂️ 관리자에게는 뭐라고 말해야 할까? 코드의 건강 상태가 생산성에 미치는 영향을 모르는 관리자라면, 리팩터링한다고 말하지 말자. 일정을 최우선으로 여기는 관리자는 최대한 빨리 끝내는 방향으로 진행하기를 원하고, 그 구체적인 방법은 개발자가 판단해야 한다. 개발자의 역할은 새로운 기능을 빠르게 구현하는 것이고, 가장 빠른 방법은 리팩터링이다. 그래서 리팩터링부터 해야 한다.
리팩터링의 궁극적인 목적은 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것이다.

📋 새 기능 속도 저하
많은 사람들이 리팩터링 때문에 개발하는 속도가 느려진다고 여기지만, 리팩터링은 개발 기간을 단축하고자 하는 것이기에 리팩터링을 함에 따라 코드베이스가 더 건강해진다는 것을 팀원들에게 명확히 밝혀야 한다.
📋 코드 소유권
함수를 호출하는 코드의 소유자가 다른 팀이라서 나에게는 쓰기 권한이 없을 수 있다. 그렇다고 리팩터링을 할 수 없는 것이 아니라 단지 제약이 따를 뿐이다. 기존 함수는 그대로 유지하되 함수 본문에서 새 함수를 호출하도록 우회하여 수정할 수 있는 부분이다.
📋 브랜치
독립 브랜치로 작업하는 기간이 길어질수록 작업 결과를 마스터로 통합하기가 어려워지고, 리팩토링을 진행할 수 없을 정도로 심각한 머지 문제가 발생하기 쉽다. 브랜치의 통합 주기는 모든 팀원이 하루에 최소 한 번 주기로 관리하여, 완료되지 않는 기능이 시스템 전체를 망치지 않도록 해야 한다.
📋 테스팅
리팩터링하기 위해서는 자가 테스트 코드를 마련해야 한다. 테스트 주기가 짧으면 짧을수록 단 몇 줄만 비교하면 되기에 버그는 그만큼 휠씬 쉽게 찾을 수 있다.
📋 레거시 코드
서로 관련된 부분끼리 나눠서 하나씩, 자주 보는 부분을 공략하도록 한다. 코드의 한 부분을 훑고 넘어갈 때마다 조금이라도 개선하려고 노력한다. 코드를 훑게 되는 횟수가 많다면 그 부분을 이해하기 쉽게 개선했을 때 얻는 효과도 크다.

소프트웨어를 빠르게 만드는 방법은 먼저 튜닝하기 쉽게 만들고 나서 원하는 속도가 나게끔 튜닝하는 것이다.
대부분 프로그램은 전체 코드 중 극히 일부에서 대부분의 시간을 소비한다. 그래서 코드 전체를 고르게 최적화한다면 그중 90%는 효과가 거의 없기 때문에 시간 낭비이다. 의도적으로 성능 최적화에 돌입하기 전까지는 성능에 신경쓰지 않고 코드를 다루기 쉽게 만드는 데 집중한다.
그러다 성능 최적화 단계가 되면 다음의 구체적인 절차를 따라 프로그램을 튜닝한다.
리팩터링은 성능 좋은 소프트웨어를 만드는 데 기여한다.
리팩터링이 잘 되어 있다면 기능 추가가 빨리 끝나서 성능에 집중할 시간을 더 벌 수 있고, 성능을 더 세밀하게 분석할 수 있다. 단기적으로 보면 리팩터링 단계에서는 성능이 느려질 수도 있지만, 최적화 단계에서 코드들을 튜닝하기 훨씬 쉬워지기 때문에 결국에는 더 빠른 소프트웨어를 얻게 된다.