✏️8.3 문장을 함수로 옮기기 (Move Statements into Function)

리팩터링 전

result.push(`<p>title: ${person.photo.title}</p>`);
result.concat(photoData(person.photo));

function photoData(aPhoto) {
  return [
    `<p>location: ${aPhoto.location}</p>`,
    `<p>date: ${aPhoto.date.toDateString()}</p>`,
  ];
}

리팩터링 후

result.concat(photoData(person.photo));

function photoData(aPhoto) {
  return [
    `<p>title: ${aPhoto.title}</p>`,
    `<p>location: ${aPhoto.location}</p>`,
    `<p>date: ${aPhoto.date.toDateString()}</p>`,
  ];
}

🧷 배경

중복 제거는 코드를 건강하게 관리하는 가장 효과적인 방법이다. 중복된 코드가 있으면 특정 함수를 호출 할 때마다 똑같은 코드가 추가로 실해되므로 반복되는 부분을 피호출 함수로 합치는 방법이 필요하다.

문장들을 함수로 옮기려면 문장들이 피호출 함수의 일부라는 확신이 있어야 한다.

🧷 절차

1. 반복 코드가 함수 호출 부분과 멀리 떨어져 있다면 문장 슬라이드하기를 적용해 근처로 옮긴다.

2. 타깃 함수를 호출하는 곳이 한 곳 뿐이면, 단순히 소스 위치에서 해당 코드를 잘라내어 피호출 함수로 복사하고 테스트 한다.

3. 호출자가 둘 이상이면 호출자 중 하나에서 '타깃 함수 호출 부분과 그 함수로 옮기려는 문장들을 함께' 다른 함수로 추출한다. 추출한 함수에 기억하기 쉬운 임시 이름을 지어준다.

4. 다른 호출자가 모두 방금 추출한 함수를 사용하도록 수정한다. 하나씩 수정할 때마다 테스트 한다.

5. 모든 호출자가 새로운 함수를 사용하게 되면 원래 함수를 새로운 함수 안으로 인라인한 후 원래 함수를 제거한다.

6. 새로운 함수의 이름을 원래 함수의 이름으로 바꿔준다.

🧷 예시

function renderPerson(outStream, person) {
  const result = [];
  result.push(`<p>${person.name}</p>`);
  result.push(renderPhoto(person.photo));
  result.push(`<p>제목: ${person.photo.title}</p>`);  // 제목 출력
  result.push(emitPhotoData(person.photo));
  return result.join("\n");
}

function photoDiv(p) {
  return [
    "<div>",
    `<p>제목: ${p.title}</p>`,  // 제목 출력
    emitPhotoData(p),
    "</div>",
  ].join("\");
}

function emitPhotoData(aPhoto) {
  const result = [];
  result.push(`<p>위치: ${aPhoto.location}</p>`);
  result.push(`<p>날짜: ${aPhoto.date.toDateString()}</p>`);
  return result.join("\n");
}

두 곳에서 emitPhotoData()를 호출하고, 두 곳 모두 바로 앞에 제목 출력 코드가 나온다. 제목을 출력하는 코드를 emitPhotoData() 안으로 옮겨 중복을 없애자.

  1. 함수 추출하기를 적용한다.

function renderPerson(outStream, person) {
  const result = [];
  result.push(`<p>${person.name}</p>`);
  result.push(renderPhoto(person.photo));
  // 추출된 함수
  result.push(zznew(person.photo)); 
  return result.join("\n");
}

function photoDiv(p) {
  return [
    "<div>",
    zznew(p),
    "</div>",
  ].join("\");
}

function zznew(p) {
  return [
  `<p>제목: ${p.title}</p>`, 
    emitPhotoData(p),
    "</div>",
  ].join("\");
}
  1. emitPhotoData() 함수를 인라인 한다.

function zznew(p) {
  return [
    `<p>제목: ${p.title}</p>`,
    `<p>위치: ${p.location}</p>`,
    `<p>날짜: ${p.date.toDateString()}</p>`,
    "</div>",
  ].join("\");
}
  1. 함수 이름을 바꾼다.

function renderPerson(outStream, person) {
  const result = [];
  result.push(`<p>${person.name}</p>`);
  result.push(renderPhoto(person.photo));
  result.push(emitPhotoData(person.photo)); 
  return result.join("\n");
}

function photoDiv(p) {
  return [
    "<div>",
    emitPhotoData(p),
    "</div>",
  ].join("\");
}

function emitPhotoData(p) {
  return [
    `<p>제목: ${p.title}</p>`,
    `<p>위치: ${p.location}</p>`,
    `<p>날짜: ${p.date.toDateString()}</p>`,
    "</div>",
  ].join("\");
}

Last updated