함수의 이름은 매우 중요하다. 의미가 와닿지 않는 함수 명을 발견해도 고작 이름일 뿐이라서 그대로 두는 경우가 있는데 이는 나중에 큰 혼란을 불러일으키기 때문에 꼭 명확한 이름으로 변경해야 한다.
전화번호 포매팅 함수의 경우 매개변수로 사람을 받게되면 회사 전화번호에는 사용하지 못하고, 함수는 사람 관련 정보를 알아야 한다. 그래서 이런 경우 전화번호 자체를 받는다면 활용 범위도 넓어지고 다른 모듈과의 의존성도 제거할 수 있다.
- 매개변수를 제거하려거든 먼저 함수 본문에서 제거 대상 매개변수를 참조하는 곳은 없는지 확인한다.
- 메서드 선언을 원하는 형태로 바꾼다.
- 기존 메서드 선언을 참조하는 부분을 모두 찾아서 바뀐형태로 수정한다.
- 테스트한다.
-
예시
function circum(radius) { return 2 * Math.PI * radius; }
위 코드는 반지름을 매개변수로 받아서 원의 둘레를 구하는 함수다. 원의 둘레라는 이름으로 함수명을 선언하는 것이 바람직하지만 너무 축약해버린 케이스다. 이런 경우 간단한 절차를 통해 아래와 같이 함수 이름을 수정할 수 있다.
function circumference(radius) { return 2 * Math.PI * radius; }
함수의 이름을 변경하는 것이 어려운 경우가 있다. 이 경우 마이그레이션 절차를 통해 함수를 수정해야 한다.
- 이어지는 추출 단계를 수월하게 만들어야 한다면 함수의 본문을 적절히 리팩터링한다.
- 함수 본문을 새로운 함수로 추출한다. (6.1절)
- 추출한 함수에 매개변수를 추가해야 한다면 ‘간단한 절차’를 따라 추가한다.
- 테스트한다.
- 기존 함수를 인라인 한다. (6.2절)
- 이름을 임시로 붙여뒀다면 함수 선언 바꾸기를 한 번 더 적용해서 원래 이름으로 되돌린다
- 테스트한다
-
예시1 : 마이그레이션 절차를 이용한 함수 이름 바꾸기
function circum(radius) { return 2 * Math.PI * radius; }
위 코드는 아까 간단한 절차에서 봤던 이름을 너무 축약했던 함수이다. 이 함수를 리펙터링 하는 과정을 마이그레이션 절차에 따라 수행한다면 아래 코드와 같다.
function circum(radius) { return circumference(radius); } function circumference(radius) { return 2 * Math.PI * radius; }
함수 본문을 새로운 함수로 추출한 후, 예전 함수를 인라인 했다.
이 방법을 사용하는 경우는 직접 고칠 수 없는 외부 코드가 함수를 참조하고 있을 때(대표적으로 공개된 API에서 클라이언트들이 불러오는 함수)위와 같은 방법을 사용하고 circum 함수가 deprecated 라는 것을 표시한다. 모든 클라이언트가 새로운 함수를 사용했다는 확신이 드는 경우에 circum을 삭제한다.
-
예시2: 매개변수 추가하기
--- Book 클래스 addReservation(customer, isPriority) { this._reservations.push(customer); }
도서 관리 프로그램의 Book 클래스에 예약 기능이 구현돼 있었는데 여기에 우선순위 큐를 지원하라는 요구사항이 추가되어서 매개변수로 예약 정보를 일반큐에 넣을지 우선순위 큐에 넣을지 정보를 받아야 하는 경우 아래와 같이 리펙터링을 진행할 수 있다.
--- Book 클래스 addReservation(customer) { this.zz_addReservation(customer); } zz_addReservation(customer) { this._reservations.push(customer); }
먼저 addReservation()의 본문을 새로운 함수로 추출 후, 새로 추출한 함수에는 임시 이름을 붙인다. 이 때 이름은 나중에 찾기 쉽도록 붙여야 한다.(변경해야 하기 때문)
--- Book 클래스 addReservation(customer) { this.zz_addReservation(customer, false); } zz_addReservation(customer, isPriority) { assert(isPriority === true || isPriority === flase); this._reservations.push(customer); }
새로 추출된 함수에 매개변수를 추가한다. assert를 추가하여 호출하는 곳에서 새로 추가한 매개변수를 실제로 사용하는지 확인할 수 있다.
위 절차를 모두 수행한 후 addReservation을 사용하던 코드들이 zz_addReservation을 사용하도록 변경하고, 모두 변경 후 새 함수의 이름을 기존 함수로 변경한다.
-
예시3: 매개변수를 속성으로 바꾸기
function inNewEngland(aCustomer) { return ['MA', 'CT', 'ME', 'VT', 'NH', 'RI'] .includes(aCustomer.address.state); }
위 함수를 고객이 거주하는 주 이름을 보고 뉴 잉글랜드에 사는지 판단한다. 현재 이 함수는 고객에 대한 의존성이 있기 때문에 효율적이지 않다. 따라서 고객 의존성을 제거하는 방향으로 리펙터링 할 것이다.
function inNewEngland(aCustomer) { const stateCode = aCustomer.address.state; return ['MA', 'CT', 'ME', 'VT', 'NH', 'RI'] .includes(aCustomer.address.state); }
- 매개변수로 사용할 코드를 변수로 추출한다.
function inNewEngland(aCustomer) { const stateCode = aCustomer.address.state; return xxNewinNewEngland(stateCode); } function xxNEWinNewEngland(statCode){ return ['MA', 'CT', 'ME', 'VT', 'NH', 'RI'] .includes(aCustomer.address.state); }
- 함수를 추출해 새 함수로 만든다.
function inNewEngland(aCustomer) { return xxNewinNewEngland(aCustomer.address.state); }
기존 함수 안에 변수로 추출해둔 입력 매개변수를 인라인한다.