✏️6.1 함수 추출하기 (Extract Function)
↔️ 함수 인라인하기
function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOtustanding();
  
  // 세부사항 출력
  console.log(`고객명: ${invoice.customer}`);
  console.log(`체무액: ${outstanding}`);
  함수 추출하기 진행 후
function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOtustanding();
  
  funtion printDetails(outstanding) {
  console.log(`고객명: ${invoice.customer}`);
  console.log(`체무액: ${outstanding}`);
  }
}🧷 배경
코드 조각을 찾아 무슨 일을 하는지 파악한 다음, 독립된 함수로 추출하고 목적에 맞는 이름을 붙인다.
📍 언제 독립된 함수로 묶어야 할까?
- 길이를 기준 
- 재사용성 
- 목적과 구현을 분리: 코드를 보고 무슨 일을 하는지 파악하는 데 한참이 걸리는 경우 
📍 함수가 짧아지면 함수 호출이 많아져서 성능이 느려질까?
함수가 짧으면 캐싱하기가 더 쉽기 때문에 컴파일러가 최적화하는데 유리한 경우가 더 많다. 짧은 함수의 이점은 이름을 잘 지어야 발휘된다. 긴 함수의 코드 덩어리의 주석을 참고하면 도움된다.
캐싱하기 쉬운 경우는 어떤 경우일까?
🧷 절차
- 함수를 새로 만들고 목적을 잘 드러내는 이름을 붙인다. (어떻게가 아닌 무엇을 하는지가 드러나야 한다.) 
- 추출할 코드를 원본 함수에서 복사하여 새 함수에 붙여넣는다. 
- 추출한 코드 중 원본 함수의 지역 변수를 참조하거나 추출한 함수의 유효범위를 벗어나느 변수는 없는지 검사한다. 있다면 매개변수로 전달한다. 
- 변수를 다 처리했다면 컴파일 한다. 
- 원본 함수에서 추출한 코드 부분을 새로 만든 함수를 호출하는 문장으로 바꾼다. 추출한 함수로 일을 위임한다. 
- 테스트한다. 
- 다른 코드에 방금 추출한 것과 똑같거나 비슷한 코드가 없는지 살핀다. 있다면 방금 추출한 새 함수를 호출하도록 바꿀지 검토한다. 인라인 코드를 함수 호출로 바꾼다. 
🧷 리팩터링 전
function printOwing(invoice) { 
  let outstanding = 0;
  
  console.log("********");
  console.log("**고객 채무**");
  console.log("********");
  
  //미해결 채무(outstanding) 계산
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  //마감일(dueDate)을 기록한다.
  const today = Clock.today; 
  invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
   today.getDate() + 30);
  
  //세부 사항을 출력한다.
  console.log(`고객명: ${invoice.customer}`);
  console.log(`채무액: ${outstanding}`);
  console.log(`마감일: ${invoice.dueDate.toLocaleDateString()}`);
}🧷 예시: 유효범위를 벗어나는 변수가 없을 때
- Banner 출력하는 코드 추출하기. 해당 코드를 잘라내서 새 함수에 붙이고, 원래 자리에 새 함수 호출문을 넣는다. 
function printOwing(invoice) { 
  let outstanding = 0;
  
  printBanner();  // 배너 출력 로직을 함수로 추출
  
  //미해결 채무(outstanding) 계산
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  //마감일(dueDate)을 기록한다.
  const today = Clock.today; 
  invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
   today.getDate() + 30);
  
  //세부 사항을 출력한다.
  console.log(`고객명: ${invoice.customer}`);
  console.log(`채무액: ${outstanding}`);
  console.log(`마감일: ${invoice.dueDate.toLocaleDateString()}`);
  
  function printBanner () {
    console.log("********");
    console.log("**고객 채무**");
    console.log("********");
  }
}- 마찬가지로, 세부 사항을 출력하는 코드도 간단히 추출한다. 
function printOwing(invoice) { 
  let outstanding = 0;
  
  printBanner();  // 배너 출력 로직을 함수로 추출
  
  //미해결 채무(outstanding) 계산
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  //마감일(dueDate)을 기록한다.
  const today = Clock.today; 
  invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
   today.getDate() + 30);
  
  printDetails();  // 세부 사항 출력 로직을 함수로 추출
  
  function printBanner () {
    console.log("********");
    console.log("**고객 채무**");
    console.log("********");
  }
  
  function printDetails () {
    console.log(`고객명: ${invoice.customer}`);
    console.log(`채무액: ${outstanding}`);
    console.log(`마감일: ${invoice.dueDate.toLocaleDateString()}`);
  }
}🧷 예시: 지역 변수를 사용할 때
지역 변수와 관련하여 가장 간단한 경우는 변수를 사용하지만 다른 값을 다시 대입하지는 않을 때다. 이 경우에는 지역 변수들을 그냥 매개변수로 넘기면 된다.
- 세부사항을 출력하는 코드를 지역 변수 두 개를 매개변수로 받는 함수로 추출한다. 
function printOwing(invoice) { 
  let outstanding = 0;
  
  printBanner();  // 배너 출력 로직을 함수로 추출
  
  //미해결 채무(outstanding) 계산
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  //마감일(dueDate)을 기록한다.
  const today = Clock.today; 
  invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
   today.getDate() + 30);
  
  printDetails(invoice, outstanding);  // 지역변수를 매개변수로 전달
  
  function printBanner () {
    console.log("********");
    console.log("**고객 채무**");
    console.log("********");
  }
  
  function printDetails (invoice, outstanding) {
    console.log(`고객명: ${invoice.customer}`);
    console.log(`채무액: ${outstanding}`);
    console.log(`마감일: ${invoice.dueDate.toLocaleDateString()}`);
  }
}- 마감일을 설정하는 코드를 추출한다. 
function printOwing(invoice) { 
  let outstanding = 0;
  
  printBanner();  // 배너 출력 로직을 함수로 추출
  
  //미해결 채무(outstanding) 계산
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  recordDueDate(invoice);  // 마감일 설정 로직을 함수로 추출
  printDetails(invoice, outstanding);  // 지역변수를 매개변수로 전달
  
  function printBanner () {
    console.log("********");
    console.log("**고객 채무**");
    console.log("********");
  }
  
  function printDetails (invoice, outstanding) {
    console.log(`고객명: ${invoice.customer}`);
    console.log(`채무액: ${outstanding}`);
    console.log(`마감일: ${invoice.dueDate.toLocaleDateString()}`);
  }
  
  function recordDueDate (invoice) {
    const today = Clock.today;
    invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
    today.getDate() + 30);
  }
}🧷 예시: 지역 변수의 값을 변경 할 때
지역 변수에 값을 대입하면 문제가 복잡해진다. 변수가 추출한 함수 밖에서 사용되는 경우 변수에 대입된 새 값을 반환해야 한다.
function printOwing(invocie) {
  let outstanding = 0;
 
  printBanner();
  //미해결 채무(outstanding) 계산
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  recordDueDate(invoice);
  printDetails(invoice, outstanding);
}- 선언문을 변수가 사용되는 코드 근처로 슬라이드 한다. 
function printOwing(invocie) {
  printBanner();
  
  //미해결 채무(outstanding) 계산
  let outstanding = 0;  // 맨 위에 있던 선언문을 이 위치로 이동
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  recordDueDate(invoice);
  printDetails(invoice, outstanding);
}- 추출할 부분을 새로운 함수로 복사한다. 
function printOwing(invocie) {
  printBanner();
  
  //미해결 채무(outstanding) 계산
  let outstanding = 0;  // 맨 위에 있던 선언문을 이 위치로 이동
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  recordDueDate(invoice);
  printDetails(invoice, outstanding);
}
function calculateOutstanding (invoice) {
  let outstanding = 0;  // 추출할 코드 복사
    for(const o of invoice.orders) {
      outstanding += 0.amount;
  }
  return outstanding;  // 수정된 값 반환
}- outstanding의 선언문을 추출할 코드 앖으로 옮겼기 때문에 매개변수로 전달하지 않아도 된다. 추출할 코드에서 값이 변경된 변수는 outstanding뿐이므로 이 값을 반환한다. 
function printOwing(invocie) {
  printBanner();
  const outstanding = calculateOutstanding(invoice);  // 함수 추출 완료. 추출한 함수가 반환한 값을 원래 변수에 저장한다.
  for(const o of invoice.orders) {
  	outstanding += 0.amountl
  }
  
  recordDueDate(invoice);
  printDetails(invoice, outstanding);
}
function calculateOutstanding (invoice) {
  let result = 0;  //   변수 이름 변경
    for(const o of invoice.orders) {
      outstanding += 0.amount;
  }
  return result; 
}- 원본 변수인 outstanding에 const를 붙여 불변으로 만들었다. 
🧷 리팩터링 후
function printOwing(invoice) {
  printBanner();
  const outstanding = calculateOutstanding(invoice);
  recordDueDate(invoice);
  printDetails(invoice, outstading);
}
function printBanner () {
  console.log("********");
  console.log("**고객 채무**");
  console.log("********");
}
function calculateOutstanding (invoice) {
  let result = 0;
    for(const o of invoice.orders) {
      outstanding += 0.amount;
  }
  return result;
}
function recordDueDate (invoice) {
  const today = Clock.today;
  invoice.dueDate = new Date(today.getFullYear(), today.getMonth(),
  today.getDate() + 30);
}
function printDetails (invoice, outstanding) {
  console.log(`고객명: ${invoice.customer}`);
  console.log(`채무액: ${outstanding}`);
  console.log(`마감일: ${invoice.dueDate.toLocaleDateString()}`);
}Last updated