가수면
리팩토링 본문
리팩토링 핵심
1. 기본 원칙
목표
- 코드의 가독성 향상
- 복잡성 감소
- 유지보수성 향상
- 확장성 향상
지향점
- 누구나 잘 알아볼 수 있는가 (성능 최적화 신경쓰지 않고 코드를 다루기 쉽게 만드는 것(가독성)에 집중.)
- 한 가지 역할만 수행하는가
- 재사용 가능한 단위인가
- 기능의 원하는 부분만 수정할 때 용이한가
- 너무 미래 지향적인 코드 x (점진적 확장)
- 매개 변수로 불리언 타입 받아 분기 처리하는 함수 지양
- 되도록 매개 변수 없는 함수 지향
- 모듈 간 독립성 유지 - 변수(어떤 데이터) / 함수(어떤 일) / 모듈(어떤 책임) 명확한 분리
리팩토링 중 피해야 할 행동
- 기능의 변경이나 추가:
기능 변경이나 추가는 리팩토링 과정에서의 핵심 목표가 아닙니다. 리팩토링은 코드의 내부 구조를 개선하는 것에 초점을 맞추어야 합니다. - 성능 개선을 목표로 한 리팩토링:
성능 최적화는 종종 코드의 가독성이나 복잡성을 증가시킬 수 있기 때문에 리팩토링의 주요 목표로 삼지 않습니다. 물론, 리팩토링 후 성능이 개선되는 부수적인 효과는 있을 수 있습니다. - 리팩토링 과정에서 발견한 버그 수정:
리팩토링 과정에서 버그를 발견하면, 그 버그를 고치기 전에 리팩토링을 먼저 완료해야 합니다. 이렇게 하는 이유는 리팩토링과 버그 수정을 구분하여, 각각의 변경 사항이 어떤 영향을 미치는지 명확히 파악하기 위함입니다. - 버전의 업데이트:
리팩토링은 기존의 기능을 변경하거나 추가하지 않기 때문에, 보통 버전 업데이트를 수반하지 않습니다.
2. 명명 및 스타일 가이드
- 변수: 형용사+명사
- 함수: 동사+명사
- boolean변수: be동사 + 주어 + 보어(명사, 대명사, 형용사 등)
- 클래스/객체/모듈 안에서 속성처럼 쓰이는 경우 (긴 계산이 아니라, 속성값과 유사한 경우) 명사로도 사용 가능
3. 함수형 리팩토링
계산한 데이터를 영원히 간직할 필요 없이 일시적으로 한번만 계산해야한다면 변환 함수를 사용하는 것이 더 좋음
변환 함수 사용 시 주의할 점
- 불변성 유지
// const reading = { customer: "ivan", quantity: 10, month: 5, year: 2017 };
export function acquireReading() {
return reading;
}
const rawReading = acquireReading();
rawReading.quantity = 20; // 데이터를 직접 변경
위처럼 데이터를 복사하지 않고 변경하게 되면 원본 데이터가 변경되기 때문에 이후 reading이나 acquireReading를 사용하는 다른 곳에서는 원본이 아닌 변경된 데이터를 사용하게 되어 문제가 발생할 수 있다.
- 파생된 값 동기화
불변성을 주의하여 깊은 복사해 사용하는 경우에도 주의해야할 점이 있다.
변환 함수의 경우 호출 시에만 계산해서 영원히 변수에 저장해둔다는 특징이 있다.
// const original = { customer: "ivan", quantity: 10, month: 5, year: 2017 };
function enrichReading(original) {
const result = JSON.parse(JSON.stringify(original));
result.baseCharge = calculateBaseCharge(result);
result.taxableCharge = Math.max(
0,
result.baseCharge - taxThreshold(result.year),
);
return result;
}
const enrichedReading = enrichReading(rawReadingData);
enrichedReading.quantity = 20;
console.log(enrichedReading.baseCharge);
console.log(enrichedReading.taxableCharge);
예를 들어 위처럼 변환 함수를 사용하여 기존 객체에 새로운 속성을 추가하는 경우 이 함수가 실행된 시점에서만 계산되어 저장되기 때문에 'enrichedReading.quantity = 20;'으로 값을 바꿔주더라고 console에는 quantity가 20으로 바뀌어 동적으로 계산된 값이 아닌 10이었던 예전 값을 출력하게 된다.
이처럼 변환 함수의 경우 값을 변경하면 파생된 값들이 더 이상 올바르지 않게된다는 문제가 발생한다.
그렇기에 변환 함수는 읽기 전용으로 사용될 때만 사용하는 것이 좋다.
이 문제를 해결하기 위해서는 2가지 방법이 있다.
- 함수를 재호출해 업데이트 시키기
enrichedReading.quantity = 20; // 값 변경
const updatedReading = enrichReading(enrichedReading);
console.log(updatedReading.baseCharge); // 재계산된 값
console.log(updatedReading.taxableCharge); // 재계산된 값
- 변환 함수가 아닌 클래스를 만들어 get으로 불러오기
4. 객체 지향 리팩토링
장점
- 소프트웨어와 아키텍쳐가 복잡해질수록 좀 더 고립되고 독립된 모듈로 만들어나갈 수 있음
- 함수를 다 쪼개다보면 여러 함수들이 만들어지게되고 자칫 복잡해질 수도 있는데 클래스로 만들어두면 직관적인 걸 유지하면서 캡슐화까지할 수 잇음
- 함수를 다 쪼개서 한 함수 안에서 호출하다보면 매개변수를 인자로 넘겨주게 되는데 클래스를 사용하면 생성자에서 한 번만 받아서 내부적으로 사용할 수 있어 코드가 깔끔해짐
- 확장성
- 좀 더 명시적으로 의도를 나타낼 수 잇음
주의할 점
- 상속 때문에 확장성이 떨어지거나 유지보수성이 떨어지는 경우가 있음. 상속 쓰기 전에 다른 방법은 없는지 고민
- 클래스도 복사한 값이나 새로운 인스턴스로 반환하지 않으면 외부에서 접근해서 값 변경 가능
- 클래스가 제공하는 메서드 중 절반이 다른 클래스를 위임하고 있다면,.모듈사이 거래가 많으면 리팩토링 대상
- 위임 숨기기
const person = new Person('Tom', new Department('aManager', '999'));
console.log(person.name);
console.log(person.department.manager);
console.log(person.department.chargeCode);
캠슐화한 클래스 내부에서 위임을 해서 사용하고 있다면 이처럼 외부에 노출시키는 건 좋지 않음
외부에서 접근시키지 않도록 하려면 private(#)를 사용
5. 기타
- 실패하는 케이스도 테스트 코드 작성(이 경계를 벗어나면 어떠한 일이 벌어지는지에 대한 테스트)
- 매개 변수 직접 수정하지 말고 let으로 할당해 계산
- 함수를 한번만 선언해서 호출하는 것과 필요할 때마다 인스턴스를 생성하는 것에서 비용적인 차이가 있을 수 있음
'웹 개발 > 웹 개발' 카테고리의 다른 글
CSS 애니메이션 (0) | 2023.09.26 |
---|---|
mkcert를 이용해 로컬 환경 https로 실행시키기 (0) | 2023.09.04 |
모노레포 (MonoRepo) 설정 (0) | 2023.08.18 |
ESLint 설정 (1) | 2023.07.19 |
rgba와 opacity (1) | 2023.04.18 |
Comments