✏️8.1 함수 옮기기 (Move Function)

리팩터링 전

class Account {
  get overdraftCharge() {...}

리팩터링 후

class AccountType {
  get overdraftCharge() {...}

🧷 배경

좋은 소프트웨어 설계의 핵심은 모듈화가 얼마나 잘 되어 있느냐를 뜻하는 모듈성이다. 모듈성이란 프로그램의 어딘가를 수정하려 할 때 해당 기능과 깊이 관련된 작은 일부만 이해해도 가능하게 해주는 능력이다.

📍 모듈성을 높이려면?

  • 서로 연관된 요소들을 함께 묶기

  • 요소 사이의 연결 관계를 쉽게 찾고 이해할 수 있도록 하기

→ 프로그램을 얼마나 잘 이해했냐에 따라 구체적인 방법이 달라지는데 이해도가 높아질수록 소프트웨어 요소들을 더 잘 무끈 새로운 방법을 깨우친다. 높아진 이해를 반영하려면 요소들을 이리저리 옮겨야 할 수 있다.

📍 함수를 옮길지 정하는 방법

대상 함수의 현재 컨텍스트와 후보 컨텍스트를 둘러보면 도움이 된다.

  • 대상 함수를 호출하는 함수들은 무엇인지

  • 대상 함수가 호출하는 함수들은 무엇이 있는지

  • 대상 함수가 사용하는 데이터는 무엇인지

🧷 절차

1. 선택한 함수가 현재 컨텍스트에서 사용 중인 모든 프로그램 요소를 살펴보고 같이 옮겨야 하는지 판단한다.

2. 선택함 함수가 다형 메서드(오버라이드 오버로드된 함수인지) 확인 한다.

3. 원래의 함수를 source function이라고 하고 새로운 함수를 target function이라고 해서 target function이 새로운 터전에 자리잡도록 (옮기고 빌드 되도록) 다듬는다.

4. 정적 분석을 수행한다.

5. 소스 컨텍스트에서 타깃 함수를 참조할 방법을 찾아 반영한다.

6. 소스 함수를 타깃 함수의 위임 함수가 되도록 수정한다.

7. 테스트 한다.

8. 소스 함수를 인라인 할지 고민한다.

🧷 예시: 중첩 함수를 최상위로 옮기기

function trackSummary(points) {
  const totalTime = calculateTime();
  const totlaDistance = calculateDistance();
  const pace = totalTime / 60 / totalDistance;
  return {
    time: totalTime,
    distance: totlaDistance,
    pace: pace
  };
  
  fuction calculateDistance() {  // 총 거리 계산  
    let result = 0;
    for (let i = 1; i < points.length; i++) {
      result += distance(points[i-1], points[i]);
    }
    return result;
  }

function distance(p1, p2) {...}  // 두 지점 거리 계산
function radians(degrees) {...}  // 라디안 값으로 변환
function calculateTime() {...}  // 총 시간 계산
  1. calculateDistance() (중첩함수) 를 최상위로 복사하기

  2. 정의되지 않은 심벌 points 을 사용하기 때문에 매개변수로 넘겨준다.

function trackSummary(points) {
  const totalTime = calculateTime();
  const totlaDistance = calculateDistance();
  const pace = totalTime / 60 / totalDistance;
  return {
    time: totalTime,
    distance: totlaDistance,
    pace: pace
  };
  
  fuction calculateDistance() {   
    let result = 0;
    for (let i = 1; i < points.length; i++) {
      result += distance(points[i-1], points[i]);
    }
    return result;
  }

function distance(p1, p2) {...}  
function radians(degrees) {...}  
function calculateTime() {...}  

// 최상위로 복사하면서 새로운 임시 이름 지어주기, 매개변수 넘겨주기
function top_calculateDistance(points) {
  let result = 0;
  for (let i = 1; i < points.length; i++) {
    result += distance(points[i-1], points[i]);
  }
  return result;
}

함수를 복사할 때 이름을 달리해주면 소스 함수와 타깃 함수를 쉽게 구분할 수 있다. 이름은 임시로 지어주면 된다.

  1. distance() 도 똑같이 옮겨준다.

// trackSummary 함수 ...
function distance(p1, p2) {
  // 공식에 따른 함수
  const dLat = radians(p2.lat) - radians(p1.lat);
  // ...
  return EARTH_RADIUS * c;
}

function radians(degrees) {
  return degrees * Math.PI / 180;
}
  1. distance()radians()만 사용하며, radians()는 어떤 것도 사용하지 않는다. 매개변수로 옮기는 것보다 함께 옮겨버리는게 낫다.

  2. 이를 위해 calculateDistance() 함수 안으로 이 함수들을 옮겨보자.

function trackSummary(points) {
  const totalTime = calculateTime();
  const totlaDistance = calculateDistance();
  const pace = totalTime / 60 / totalDistance;
  return {
    time: totalTime,
    distance: totlaDistance,
    pace: pace
  };
  
  fuction calculateDistance() {   
    let result = 0;
    for (let i = 1; i < points.length; i++) {
      result += distance(points[i-1], points[i]);
    }
    return result;
  }
  
  // 함수 안으로
  function distance(p1, p2) {...}  
  function radians(degrees) {...}  
}
  1. top_calculateDistance() 함수로도 복사한다.

function top_calculateDistance(points) {
  let result = 0;
  for (let i = 1; i < points.length; i++) {
    result += distance(points[i-1], points[i]);
  }
  return result;
  
  // 함수 안으로 복사
  function distance(p1, p2) {...}  
  function radians(degrees) {...}  
}
  1. calculateDistance()의 본문을 수정하여 top_calculateDistance()를 호출하게 하자.

function trackSummary(points) {
  const totalTime = calculateTime();
  const totlaDistance = calculateDistance();
  const pace = totalTime / 60 / totalDistance;
  return {
    time: totalTime,
    distance: totlaDistance,
    pace: pace
  };
  
  fuction calculateDistance() {   
    return top_calculateDistance(points);
  }
  1. 소스 함수를 제거한다.

function trackSummary(points) {
  const totalTime = calculateTime();
  const totlaDistance = top_calculateDistance(points);
  const pace = totalTime / 60 / totalDistance;
  return {
    time: totalTime,
    distance: totlaDistance,
    pace: pace
  };
  1. 새 함수에 이름을 지어준다.

function trackSummary(points) {
  const totalTime = calculateTime();
  const pace = totalTime / 60 / totalDistance(points);
  return {
    time: totalTime,
    distance: totalDistance(points),
    pace: pace
  };
  
  function totalDistance(points) {
    let result = 0;
    for (let i = 1; i < points.length; i++) {
      result += distance(points[i-1], points[i]);
    }
    return result;

Last updated