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 |