본문 바로가기

programming study/Refactoring

Refactoring - 기본적인 리팩터링(2)

본 내용은 마틴 파울러의 Refactoring 2판을 토대로 작성되었습니다.

 

기본적인 리팩터링

1. 함수 선언 바꾸기

예시 코드

function circum(radius) {...}
function circumference(radius) {...}

 

설명

  • 함수는 프로그램을 작은 부분으로 나누는 주된 수단
  • 함수 선언은 각 부분이 서로 맞물리는 방식을 표현
    • 구성 요소를 조립하는 연결부 역할
    • 소프트웨어도 이러한 연결부에 상당히 의존
  • 연결부를 잘 정의하면 시스템에 새로운 부분을 추가하기 쉬워짐
    • 잘못 정의하면 지속적인 방해 요인으로 작용
  • 좋은 이름의 함수는 호출문만 보고도 무슨 일을 하는지 파악할 수 있음
  • 함수의 매개변수는 외부 세계외 어우러지는 방식을 정의
    • 함수를 사용하는 문맥을 설정

 

절차

  1. 매개변수를 제거하려면 함수 본문에서 제거 대상 매개변수를 참조하는 곳은 없는지 확인
  2. 메서드 선언을 원하는 형태로 바꿈
  3. 기존 메서드 선언을 참조하는 부분을 모두 찾아 바뀐 형태로 수정
  4. 테스트

 

마이그레이션 절차

  1. 이어지는 추출 단계를 수월하게 만들어야 한다면 함수의 본문을 적절히 리팩터링
  2. 함수 본문을 새로운 함수로 추출
  3. 추출한 함수에 매개변수를 추가해야 한다면 간단한 절차를 따라 추가
  4. 테스트
  5. 기존 함수를 인라인
  6. 이름을 임수로 붙였다면, 함수 선언 바꾸기를 한 번 더 적용해서 원래 이름으로 되돌림
  7. 테스트

 

2. 변수 캡슐화하기

예시 코드

let defaultOwner = {firstName: "마틴", lastName: "파울러"};
let defaultOwnerData = {firstName: "마틴", lastName: "파울러"};
export function defaultOwner() return {defaultOwnerData};
export function setDefaultOwner(arg) return {defaultOwnerData = arg};

 

설명

  • 함수는 데이터보다 다루기 수월
    • 함수를 사용하는 것은 대체로 호출한다는 뜻
    • 함수의 이름을 바꾸거나 다른 모듈로 옮기기는 어렵지 않음
    • 기존 함수를 그대로 둔 채 전달 함수로 활용할 수 있으므로
  • 데이터는 함수보다 다루기가 까다로움
    • 데이터는 참조하는 모든 부분을 함번에 바꿔야 코드가 제대로 작동
    • 전역 데이터는 골칫거리
  • 접근할 수 있는 범위가 넓은 데이터를 옮길 때는 먼저 그 데이터로의 접근을 독점하는 함수를 만들어 캡슐화
  • 데이터 재구성을 함수 재구성이라는 더 단순한 작업으로 변환
  • 데이터 캡슐화의 의의
    • 데이터를 변경하고 사용하는 코드를 감시
    • 데이터 변경 전 검증이나 변경 후 추가 로직을 쉽게 끼워넣을 수 있음
  • 불변데이터는 가변 데이터보다 캡슐화할 이유가 적음
    • 데이터가 변경될 일이 없음

 

절차

  1. 변수로의 접근과 갱신을 전담하는 캡슐화 함수들을 만듦
  2. 정적 검사를 수행
  3. 변수를 직점 참조하던 부분을 모두 적절한 캡슐화 함수 호출로 바꿈
    • 하나씩 바꿀 때마다 테스트
  4. 변수의 접근 범위를 제한
  5. 테스트
  6. 변수 값이 레코드라면 레코드 캡슐화하기를 적용할지 고려

 

3. 변수 이름 바꾸기

예시 코드

let a = hegiht * width;
let area = hegiht * width;

 

설명

  • 변수는 프로그래머가 하려는 일에 많은 것을 설명
  • 맥락으로부터 변수의 목적을 잘 파악할 수 있도록 짓기

 

절차

  1. 폭넓게 쓰이는 변수라면 변수 캡슐화하기를 고려
  2. 이름을 바꿀 변수를 참조하는 곳을 모두 찾아서 하나씩 변경

 

4. 매개변수 객체 만들기

예시 코드

function amountInvoice(startDate, endDate) {...};
function amountReceived(startDate, endDate) {...};
function amountOverdue(startDate, endDate) {...};
function amountInvoiced(aDateRange) {...};
function amountReceived(aDateRange) {...};
function amountOverdue(aDateRange) {...};

 

설명

  • 데이터 항목 여러개가 여러 함수에서 함께 몰려다는 경우 객체로 묶기
    • 데이터 관계가 명확해짐
  • 데이터에 공통으로 적용되는 동작을 추출해서 함수로 만들 수 있음
    • 이 함수들과 데이터들을 합쳐 클래스로 만들 수도 있음
    • 새로 만든 데이터 구조가 문제 영역을 훨씬 간결하게 표현하는 새로운 추상 개념으로 격상

 

절차

  1. 적당한 데이터 구조가 아직 마련되어 있지 않다면 새로 만듦
  2. 테스트
  3. 함수 선언 바꾸기로 새 데이터 구조를 매개변수로 추가
  4. 테스트
  5. 함수 호출 시 새로운 데이터 구조 인스턴스를 넘기도록 수정
  6. 기존 매개변수를 사용하던 코드를 새 데이터 구조의 원소를 사용하도록 바꿈
  7. 다 바꾼 후, 기존 매개변수를 제거하고 테스트