이번 장은 데이터 구조에 집중한 리팩토링이다.
변수 쪼개기
역할이 둘 이상인 변수는 쪼개야 한다.
역할 하나당 변수 하나다.
function distanceTravelled(scenario, time) {
let result;
let acc = scenario.primaryForce / scenario.mass; // 가속도(a) = 힘(F) / 질량(m)
let primaryTime = Math.main(time, scenario.delay);
result = 0.5 * acc * primaryTime * primaryTime; // 전파된 거리
let secondaryTime = time - scenario.delay;
if (secondaryTime > 0) {
// 두 번째 힘을 반영해 다시 계산
let primaryVelocity = acc * scenario.delay;
acc = (scenario.primaryForce + scenario.secondaryForce) / scenario.mass;
result +=
primaryVelocity * secondaryTime +
0.5 * acc * secondaryTime * secondaryTime;
}
return result;
}
위의 코드는 acc 변수에 값이 두 번 대입되는 것이다.
역할이 두 개라는 것이다. 쪼개야 할 변수다.
- 변수에 새로운 이름을 지어준다.
- 선언 시 const를 붙여 불변으로 만든다.
- 두 번째 대입 전까지 모든 참조를 새로운 이름으로 바꾼다.
- 두 번째로 대입할 때 변수를 새로 선언한다.
function distanceTravelled(scenario, time) {
let result;
const primaryAcceleration = scenario.primaryForce / scenario.mass; // 1,2
let primaryTime = Math.main(time, scenario.delay);
result = 0.5 * primaryAcceleration * primaryTime * primaryTime; // 3
let secondaryTime = time - scenario.delay;
if (secondaryTime > 0) {
// 두 번째 힘을 반영해 다시 계산
let primaryVelocity = primaryAcceleration * scenario.delay; // 3
let acc = (scenario.primaryForce + scenario.secondaryForce) / scenario.mass; // 4
result +=
primaryVelocity * secondaryTime +
0.5 * acc * secondaryTime * secondaryTime;
}
return result;
}
- 두 번째 용도에 적합한 이름으로 수정
function distanceTravelled(scenario, time) {
let result;
const primaryAcceleration = scenario.primaryForce / scenario.mass;
let primaryTime = Math.main(time, scenario.delay);
result = 0.5 * primaryAcceleration * primaryTime * primaryTime;
let secondaryTime = time - scenario.delay;
if (secondaryTime > 0) {
// 두 번째 힘을 반영해 다시 계산
let primaryVelocity = primaryAcceleration * scenario.delay;
const secondaryAcceleration = (scenario.primaryForce + scenario.secondaryForce) / scenario.mass; // 5
result +=
primaryVelocity * secondaryTime +
0.5 * secondaryAcceleration * secondaryTime * secondaryTime;
}
return result;
}
파생 변수를 질의 함수로 바꾸기
가변 데이터는 문제를 일으키는 가장 큰 골칫거리로 완전히 배제하기란 현실적으로 불가능해 유효 범위를 최대한 좁혀야 한다.
한쪽 코드에서 수정한 값이 연쇄 효과를 일으켜 다른 쪽 코드에 원인을 찾기 어려운 문제를 야기하기도 한다.
// before
class ProductionPlan {
get production() {
return this._production;
}
applyAdjustment(adjustment) {
this._adjustments.push(adjustment);
this._production += adjustment.amount;
}
}
adjustment 값을 적용할 때 production까지 갱신하는 문제가 있다. (필요 없는 동작)
여러 곳에서 하나의 데이터를 수정하게 된다면 실수할 가능성이 높아진다.
아래 get production처럼 필요할 때 adjustments를 통해 값을 구하도록 수정해야 한다.
// after
class ProductionPlan {
get production() {
return this._adjustments.reduce((sum, a) => sum + a.mount, 0);
}
applyAdjustment(adjustment) {
this._adjustments.push(adjustment);
}
}
참조를 값으로 바꾸기
값
값 그 자체, 불변성, 원시 타입, 한 번 만들면 그 자체를 바꿀 순 없다.
a = 1; 에서 1을 바꿀 순 없다 a에 2라는 값을 재할당할 순 있다.
참조
가변성, object
참조로 다루는 경우 내부 객체는 그대로 둔 채 그 객체의 속성만 갱신하고, 값으로 다루는 경우에는 새로운 속성을 담은 객체로 기존 내부 객체를 통째로 대체한다.
참조값을 사용하게 되면 내부 데이터를 수정할 수 있기 때문에 좋지 않다.
// before
class Person {
constructor() {
this._telephoneNumber = new TelephoneNumber();
}
get officeAreaCode() {
return this._telephoneNumber.areaCode;
}
set officeAreaCode(arg) {
this._telephoneNumber.areaCode = arg;
}
get officeNumber() {
return this._telephoneNumber.number;
}
set officeNumber(arg) {
this._telephoneNumber.number = arg;
}
}
class TelephoneNumber {
get areaCode() {
return this._areaCode;
}
set areaCode(arg) {
this._areaCode = arg;
}
get number() {
return this._number;
}
set number(arg) {
this._number = arg;
}
}
// after
class Person {
constructor() {
this._telephoneNumber = new TelephoneNumber();
}
get officeAreaCode() {
return this._telephoneNumber.areaCode;
}
set officeAreaCode(arg) {
this._telephoneNumber = new TelephoneNumber(arg, this.officeNumber);
}
get officeNumber() {
return this._telephoneNumber.number;
}
set officeNumber(arg) {
this._telephoneNumber.number = new TelephoneNumber(this.officeAreaCode, arg);
}
}
class TelephoneNumber {
get areaCode(areaCode, number) {
this._areaCode = areaCode;
this._number = number;
}
get number() {
return this._number;
}
}
매직 리터럴 바꾸기
매직 리터럴이란 소스 코드에 등장하는 일반적인 리터럴 값
코드를 읽는 사람이 값의 의미를 모른다면 해석하기 어렵기 때문에 코드 자체가 뜻을 분명하게 드러내는 게 좋다.
// before
function areaOfCircle(r){
return r * r * 3.14
}
// after
const PERIMETER = 3.14
function areaOfCircle(r){
return r * r * PERIMETER
}
'스터디 > 리팩토링 2판' 카테고리의 다른 글
[리팩토링 2판] 11장. API 리팩토링 (11월 24일, 12월 8일) (0) | 2022.12.08 |
---|---|
[리팩토링 2판] 10장. 조건부 로직 간소화 (11월 16일) (0) | 2022.11.23 |
[리팩토링 2판] 7장. 캡슐화, 8장. 기능 이동 (11월 2일) (0) | 2022.11.03 |
[리팩토링 2판] 6장. 기본적인 리팩토링 (10월 19일) (0) | 2022.10.23 |
[리팩토링 2판] 3장. 코드에서 나는 악취 (10월 12일) (0) | 2022.10.12 |