개발공부

[리팩터링] Refactoring 2판 - 2,3장

햄❤️ 2023. 2. 10. 01:15
728x90

1. 리팩터링 원칙

 

1-1) 리팩터링의 정의

  • 리팩터링(하다): [동사] 소프트웨어의 겉보기 동작은 그대로 유지한 채, 여러 가지 리팩터링 기법을 적용해서 소프트웨어를 재구성하다.
  • 리팩터링: [명사] 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법
    • 겉보기 동작을 유지한다 = 성능, 기능, 버그까지 그대로 있어야 한다.

1-2) 리팩터링 목적

  • 소프트웨어 설계가 좋아진다 → 처음부터 완벽한 설계는 없다!
  • 소프트웨어를 이해하기 쉬어진다.
  • 버그를 쉽게 찾을 수 있다.
  • 프로그래밍 속도를 높일 수 있다.

1-3) 리팩터링의 시점

  • 비슷한 일을 세번째 하게 되면 (3의 법칙)
  • 하지 말아야 할 때? → 지저분해도 굳이 할 필요 없다면 하지 않는다.

 

2. 코드에서 나는 악취

2-1) 기이한 이름

  • 함수 이름 바꾸기(명확한 역할, 축약 지양)
  • 변수 이름 바꾸기
/// 리팩토링 전
let a = height * width;

/// 리팩토링 후
let area = height * width;

2-2) 중복 코드

  • 동일한 부분을 하나의 함수로 추출한다.
  • 비슷한 부분만 슬라이스해서 추출한다(문장 슬라이드하기)

2-3) 긴 함수

  • 긴 함수는 이해하기 어렵다. 적극적으로 함수를 쪼갠다.
  • 함수를 짧게 만들기 위함은 함수 추출하기가 99% 차지
/// 리팩토링 전
function printOwing(invoice) {
	printBanner();
	let outstanding = calculateOutstanding();
	
	//세부 사항 출력
	console.log(`고객명: ${invoice.customer}`);
	console.log(`세무액: ${outstanding}`);
}

/// 리팩토링 후
function printOwing(invoice) {
	printBanner();
	let outstanding = calculateOutstanding();
	printDetails(outstanding);
}
	

fucntion printDetails(outstanding) {
	//세부 사항 출력
	console.log(`고객명: ${invoice.customer}`);
	console.log(`세무액: ${outstanding}`);
}

2-4) 긴 매개변수 목록

  • 매개변수를 질의 함수로 바꾼다.
/// 리팩토링 전
availableVacation(anEmployee, anEmployee.grade);

/// 리팩토링 후
availableVacation(anEmployee) {
	const grade = anEmployee.grade;
}
  • 객체를 통째로 넘긴다.

2-5) 전역 데이터

  • 전역 변수 사용 지양 → 변수 캡슐화 (데이터를 함수로 감싸는 것), 접근하는 데이터의 범위를 독점하는 함수를 만든다.
/// 리팩토링 전
let defaultOwner = {firstName: "마틴", lastName: "파울러"};

/// 리팩토링 후
let defaultOwner = {firstName: "마틴", lastName: "파울러"};

export function defaultOwner () {
	return defaultOwnerData;
};

export function setDefaultOwner (arg) {
	defaultOwnerData = arg;
}

2-6) 가변 데이터

2-7) 뒤엉킨 변경

  • 단일책임원칙(SRP)를 지키지 않으면 발생 → 단계 쪼개기, 함수 옮기기, 함수 추출하기

2-8) 산탄총 수술

  • 코드를 변경할 때, 자잘하게 수정해야 하는 클래스가 많을때 발생 → 여러 함수를 클래스로 묶기

2-9) 기능 편애

  • 어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용이 많을 때 발생

2-10) 데이터 뭉치

  • 데이터 여러개를 계속 써야한다면 묶어서 하나의 객체로 만든다.

2-11) 기본형 집착

  • 기본형 타입을 객체로 바꾸기

2-12) 반복되는 switch문

  • 중복되는 switch문 지양

2-13) 반복문

  • 반복문을 파이프라인으로 바꾸기
    • 처리과정을 일련의 연산으로 표현할 수 있음. 흐름의 이해가 쉬워짐.
/// 리팩토링 전
const names = [];
for(const i of input) {
if(j.job === "programmer") {
	names.push(i.name);
}

/// 리팩토링 후
const names = input.filter(i => i.job === "programmer").map(i => i.name);
// reduce

2-14) 성의 없는 요소

2-15) 추측성 일반화

  • 나중에 필요할 것이라고 생각하고 남겨 놓은 필요없는 코드 → 죽은 코드는 제거한다.

2-16) 임시 필드

  • 특정 상황에서만 값이 설정되는 필드를 가진 클래스 → 조건부 로직을 추가해서 유효하지 않을 때를 대비

2-17) 메세지 체인

  • 한 객체를 통해 다른 객체를 얻은 뒤, 방금 얻은 객체에 또 다른 객체를 요청하는 식(객체 요청의 연쇄)
    • 체인을 줄이는 것이 우선…
  • 위임 숨기기로 해결 → 캡슐화로 필드를 숨긴다. 무언가를 변경해야할 때 고려해야할 모듈 수가 적어져서 코드를 변경하기 쉬워짐
/// 리팩토링 전
manager = aPerson.department.manager;

/// 리팩토링 후
manager = aPerson.manager;

class Person {
	get manager() {
		return this.department.manager;
	}
}

2-18) 중개자

  • 중재자 제거하기 → 단순히 전달만 하는 위임 메서드들이 많아지면 직접 호출하는게 낫다.
/// 리팩토링 전
manager = aPerson.manager;

class Person {
	get manager() {
		return this.department.manager;
	}
}

/// 리팩토링 후
manager = aPerson.department.manager;

2-19) 내부자 거래

  • 모듈 사이의 결합도를 낮추기

2-20) 거대한 클래스

  • 클래스가 너무 많은 일을 하지 않도록 클래스를 추출한다.

2-21) 서로 다른 인터페이스의 대안 클래스들

2-22) 데이터 클래스

2-23) 상속 포기

2-24) 주석

  • 군더더기 주석은 제거하는게 낫다. 주석이 필요하지 않는 코드로 리팩터링한다.
728x90

'개발공부' 카테고리의 다른 글

[리팩터링] Refactoring 2판 - 6장  (1) 2023.02.24
[리팩터링] Refactoring 2판 - 1장 2차  (0) 2023.02.20
[리팩터링] Refactoring 2판 - 1장  (2) 2023.02.16