[Daily Contents] 코드 리팩토링


학습 목표

  • 코드 리팩토링이란?
  • 언제 해야 할까?
  • 어떻게 해야 할까?
  • 필요한 이유

코드 리팩토링이란?

  • 소프트웨어의 겉보기 동작은 그대로 유지한 채…
  • 코드를 깨끗하고 이해하기 쉽게 구조만 변경하는 것
  • 핵심은 “이 코드를 더 좋게 만들 수 있습니까?”에 있으며…
    • 이에 대한 판단 기준으로는 확장성, 가독성, 유지보수성

언제 해야 할까?

  • 기능 구현이 우선이고, 정상작동되는지 확인한 후에 진행한다.
  • 한 번에 하나의 작업에만 집중하고 동시에 진행하지 않는다.
    • 기능추가 단계 : 기존 코드는 건드리지 말고, 신규 기능 추가에만 집중
    • 리팩토링 단계 : 기능을 추가하지 말 것, 좋은 설계로 코드를 재구성

어떻게 해야 할까?

  • 개발 프로세스에서는 리팩토링할 시점을 결정하는 게 매우 중요하며…
  • 시점을 정하는 가장 좋은 방법은 범위를 정하는 것
  • 한 번에 한 가지 명확하고 구체적인 목표를 갖고 진행하는 것이 중요

코드 리팩토링의 유형

  • 신규 기능 추가를 대비한 “준비를 위한 리팩토링”
  • 높은 가독성을 고려한 “이해를 위한 리팩토링”

준비를 위한 리팩토링

  • 목적 : 신규 기능을 추가하기 전에, 코드를 쉽게 추가할 수 있도록 대비
    • 현재 구조를 살펴보고, 추가되는 코드가 기존 구조에 녹여지기 어렵다면… 해당 구조를 다듬어서 새로운 기능을 쉽게 적용 가능할 수 있도록 만들어주자
    • Good Fit? »Yes» Add New Feature
    • Good Fit? »No» Refactoring to Good Fit » Add New Feature

예제1) 파편화된 코드

  • 동일 코드가 반복적으로 작성되어 있다면…
  • 별도의 Function으로 만들고, 이를 호출하는 방식으로 관심사를 분리
function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();

  // print details
  console.log(`name: ${invoice.customer}`);
  console.log(`amount: ${outstanding}`);
}
function printOwing(invoice) {
  printBanner();
  let outstanding = calculateOutstanding();
  printDetails(outstanding);

  function printDetails(outstanding) {
    console.log(`name: ${invoice.customer}`);
    console.log(`amount: ${outstanding}`);
  }
}

예제2) 중복된 유사 로직

  • 의미가 유사한 function이 2개 이상 존재하면…
  • 매개변수를 이용하는 것으로 function을 통합
function tenPercentRaise(aPerson) {
  aPerson, salary = aPerson.salary.multiply(1.1);
}
function fivePercentRaise(aPerson) {
  aPerson, salary = aPerson.salary.multiply(1.05);
}
function raise(aPerson, factor) {
  aPerson, salary = aPerson.salary.multiply(1 + factor);
}

예제3) 모든 분기마다 동일 로직

  • 조건부 모든 분기에 동일 로직을 구현했다면…
  • 분기 밖으로 해당 로직을 이동시켜서, 한 번만 작성
if(isSepcialDeal()) {
  total = price * 0.95;
  send();
}
else {
  total = price * 0.98;
  send();
}
if(isSepcialDeal()) {
  total = price * 0.95;
}
else {
  total = price * 0.98;
}
send();

이해를 위한 리팩토링

  • 목적 : 코드의 의도를 이해할 수 있도록 가독성을 높인다.
    • 코드를 수정하기 위한 전제조건은 그 코드가 무슨 일을 하는지 파악하는 것
    • 협업하는 동료와 함께 보는 코드는 의도가 명확하게 드러나야 함
    • 더 좋은 설계를 위해서는 사소한 것부터 명확하게 만드는 것이 중요

예제1) 모호한 변수명

  • a, b, c 등의 의도를 알 수 없는 모호한 변수명이라면…
  • 변수명을 직관적으로 선언
  • 좋은 프로그래머는 사람이 이해할 수 있는 코드를 작성
let a = height * width;
let area = height * width;

예제2) 길어지는 표현식

  • 하나의 표현식이 너무 길어지는 경우에는…
  • 표현식 또는 해당 부분의 결과를 의도 파악이 가능한 개별 변수로 선언
return order.quantity * order.itemPrice -
  Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 * Math.min(order.quantity * order.itemPrice * 0.1, 100);
const basePrice = order.quantity * order.itemPrice;
const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05;
const shipping = Math.min(basePrice * 0.1, 100);
return basePrice - quantityDiscount * shipping;

예제3) 변수가 한 번만 변경

  • 변경되는 변수가 하나뿐이라면…
  • 해당변수가 원래 표현식과 다를 바 없을 때는, 변수 선언 대신 인라인해서 리턴값으로 처리
let basePrice = anOrder.basePrice;
return (basePrice > 1000);
return anOrder.basePrice > 1000;

비효율적인 때는?

  • 코드 판독 자체가 불가하여 오히려 시간 낭비인 경우
  • 코드가 정상 작동하지 않는다면, 새로 짜는 것이 낫다
  • 납기가 임박했을 때는 지양

성능개선 vs 리팩토링

  • 성능을 높이는 작업도, 리팩토링의 작업 패턴은 유사
  • 그러나 성능 개선은 속도를 높이기 위한 목적이고…
  • 코드 리팩토링은 코드를 깨끗하게 만들기 위함

왜 필요해요?

  • 코드 리팩토링을 왜 해야 하나요?
  • 시간 낭비하는 거 아닌가요?
  • “깨끗하고 좋은 코드를 만들기 위해서”
  • 설계에 대한 고민없이 작성된 코드는 초반에는 개발속도가 빠르지만…
  • 코드 구조는 한 번 엉망이 되면, 시간이 갈수록 더 엉망진창이 되고…
  • 새로운 기능을 추가할수록, 개발 속도가 점점 뎌뎌진다.
  • 반면, 좋은 설계의 프로그램은 시간이 갈수록 개발 생산성이 높아진다

궁극적 목적

  • Enconomics(경제성)
  • 적은 인력으로 짧은 시간에 많은 기능을 개발하기 위해…

퀴즈

  • 좋은 코드의 판단 기준은 대표적으로 유지보수성, 확장성, 가독성이 있습니다.
  • 코드 리팩토링을 하기에 적절한 시점은? 기능 개발이 완료된 후
  • 코드 리팩토링의 대표적 유형 두 가지는? 준비, 이해
  • 코드 리팩토링의 궁극적 목적은? Economics(경제성)

댓글남기기