: 어떠한 요소를 다른 컨텍스트(클래스, 모듈 혹은 코드 라인)로 옮기는 방식의 리팩터링.
1. 함수 옮기기
- 모듈성을 높이기 위해 연관된 요소들끼리 묶는다. -> 모듈을 잘 분리하면 응집도가 높은 코드가 되고 캡슐화가 좋아진다.
- 프로그램 언어마다 모듈화 수단이 다르다. 자바의 경우 객체지향의 패러다임을 가지며, 따라서 핵심 모듈화 컨택스트 단위는 클래스이다.
- 리팩터링하고자하는 프로그램의 이해도가 높을수록 요소들을 잘 묶는 방법을 알 수 있다.
2. 필드 옮기기
- 데이터 구조가 주어진 문제에 적합하게 잘 설계되어있다면 보통 동작 코드는 단순하고 직관적인 코드가 된다.
- 데이터 구조는 곧 클래스의 필드들이기 때문에 각 클래스에는 필요한 필드들로 잘 구성되어있어야 한다. 그런데, 초기 설계에서 적절한 데이터 구조를 가져가도록 구성하는 것이 쉽지 않다. 객체지향이 어려운 이유 중 하나이며, 잘못됨을 깨달을 때 항상 수정을 해 개선해야한다.
3. 문장을 함수로 옮기기
: 특정 함수를 호출하는 부분 전후로 특정 코드가 항상 반복되는 경우, 해당 문장을 함수 내부로 옮길 수 있을지를 고민한다. 이 때는 해당 문장이 그 함수의 일부분이라는 확신이 있어야한다. 이렇게하면 수정이 필요할 때 해당 메서드만 고치면 된다.
4. 문장을 호출한 곳으로 옮기기
- 초기에는 한 가지 일만 수행하던 함수가 둘 이상의 일을 수행하게 변할 수 있다.
- SRP가 깨지는 상황이 되며, 코드의 응집도는 낮아진다. 이 경우 문장을 호출한 곳으로 옮기는 리팩터링을 적용한다.
5. 인라인 코드를 함수 호출로 바꾸기
- 인라인 코드를 함수 호출로 바꾸면 네이밍을 통해 해당 코드 호출의 목적을 보다 명확히 알 수 있다.
- 수정이 필요할 때 함수 한군데만 수정하면 된다. 이 때 모든 호출부가 수정된 코드를 원하는지를 확인해야하지만 보통은 그런 경우가 많지 않다. 만약 그런 경우라면 함수의 목적이 원래의 인라인 코드와 목적이 다른 경우이다. (우발적 중복) 이 때라면 별도의 함수로 두고 네이밍을 다르게 두는게 맞아보인다.
6. 문장 슬라이드하기
: 주로 다른 리팩터링의 준비단계로, 관련 코드를 한군데로 모으는 작업이다. 주의해야 할 점은 side effect가 존재하는 코드는 좀더 주의를 기울이고, 꼭 테스트를 하면서 리팩터링을 해야한다.
7. 반복문 쪼개기
- 한 반복문 내에서 두가지 일을 수행한다면 해당 함수는 서로 다른 일들이 수행되고 있을 확률이 높다. 대개 반복문을 쪼개고 난 시점에는 함수 추출하기를 수행할 수 있고, 그 후 파이프라인으로 바꾸기를 수행할 수 있다.
- 최적화에 대한 고민 : 대부분의 경우 n번의 loop를 2 * n번으로 바꾼다고해서 성능이 달라지는 경우는 드물다. 리팩터링을 끝낸 후 벤치마크 테스트를 해 비교를해도 된다. 그 시점에 다시 합치는 것은 쉬운 일이다.
8. 반복문을 파이프라인으로 바꾸기
: filter
, map
등의 연산을 통해 논리 흐름을 표현할 수 있어 코드를 이해하기에 좋아보인다. 또, 최근에는 많은 언어들이 함수형 프로그래밍을 지향하면서 Side effect를 줄이는 방식의 개발을 지향하는데, 그러한 측면에서도 가능하다면 최신의 방식을 택하는 것이 적합해보인다.
9. 죽은 코드 제거하기
: deprecated되고 해당 코드의 클라이언트가 없다는 확신이 있으면 과감히 지우면 된다. 혹시나 미래에 해당 코드가 필요하다면 형상관리 툴을 통해 히스토리를 보면 된다.
Reference)
리팩터링 2판