리팩토링 18. 변수 쪼개기
- etc/리팩토링
- 2023. 5. 1.
들어가기 전
이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다.
리팩토링 18. 변수 쪼개기 (Split Variable)
- 어떤 변수가 여러 번 재할당 되어도 적절한 경우
- 반복문에서 순회하는데 사용하는 변수 또는 인덱스
- 값을 축적시키는데 사용하는 변수 (result += 1...)
- 이런 경우, 어떤 변수를 여러 번 재활용하는게 당연하다.
- 그밖에 재할당되는 변수가 있다면, 해당 변수는 여러 용도로 사용되는 것이다. 따라서 변수를 분리해야 더 이해하기 좋은 코드를 만들 수 있다.
- 변수 하나 당 하나의 책임을 지도록 만든다
- 상수를 활용하자.
어떤 변수가 여러 번 재할당 되어도 적절한 경우
아래 코드에서 볼 수 있는 두 가지의 변수는 여러 번 재할당 되어도 괜찮은 경우다.
- header : 값이 축적되는 경우. 비슷한 경우로는 result += 1이 있음.
- index : for문 내부에서 index를 표현하기 위해 사용되는 변수
이런 변수들은 재할당 되는 것이 자연스러워 허용해도 좋은 경우다. 그렇지만 이 외의 경우에는 변수를 재할당해서 사용한다면, '변수가 여러 용도로 사용되는 경우'로 의심할 수 있다. 이런 코드는 가독성이 떨어지기 때문에 재할당 되는 부분을 각각의 변수로 분리해서 명확한 이름을 주는 것이 더 좋다.
실습1
Rectangle의 updateGeometry() 메서드를 살펴보자. temp라는 변수가 여러 번 할당된 것을 볼 수 있다. temp는 지름을 구할 때 한번, 너비를 구할 때 한번 사용되어 총 2번 사용되었다. 그러면 이 temp는 원래 역할을 잘 표현하고 있는 것일까? temp는 지름과 너비를 각각 표현하고 있다. 따라서 하나의 변수가 여러 의미를 가지기 위해서 재할당되었다.
따라서 재할당되는 temp라는 변수를 분리해줘야한다.
public class Rectangle {
private double perimeter;
private double area;
// temp 변수는 그 자체의 이름도 의미가 없으며, 여러 번 재할당 됨.
public void updateGeometry(double height, double width) {
double temp = 2 * (height + width);
System.out.println("Perimeter: " + temp);
perimeter = temp;
temp = height * width;
System.out.println("Area: " + temp);
area = temp;
}
...
}
여러 번 재할당 된 temp 변수를 perimeter / area 변수로 각각 분리해주었다.
// temp 변수는 그 자체의 이름도 의미가 없으며, 여러 번 재할당 됨.
public void updateGeometry(double height, double width) {
final double perimeter = 2 * (height + width);
System.out.println("Perimeter: " + perimeter);
this.perimeter = perimeter;
final double area = height * width;
System.out.println("Area: " + area);
this.area = area;
}
실습2
- Haggis의 distanceTravelled() 메서드를 살펴보자. 내부적으로 살펴보면, acc가 두 번 재할당 되어 사용되는데, 서로 다른 의미로 사용되었다. 따라서 이 acc라는 변수를 재할당하는 부분을 각각의 의미를 가지도록 변수로 분리해주자.
- 변수 result도 재할당 되고 있다. 그렇지만 그대로 사용되어도 된다. 축적의 용도로 사용되고 있기 때문이다.
// Haggis.class
// acc가 서로 다른 의미를 가지고 있는데, 여러 번 재할당 됨.
// result는 축적의 의미를 가지고 있으므로 괜찮음.
public double distanceTravelled(int time) {
double result;
double acc = primaryForce / mass;
int primaryTime = Math.min(time, delay);
result = 0.5 * acc * primaryTime * primaryTime;
int secondaryTime = time - delay;
if (secondaryTime > 0) {
double primaryVelocity = acc * delay;
acc = (primaryForce + secondaryForce) / mass;
result += primaryVelocity * secondaryTime + 0.5 * acc * secondaryTime + secondaryTime;
}
return result;
}
acc가 재할당 되는 부분을 두 개의 변수로 쪼개어 PrimaryAcceleration, SecondaryAcceleration으로 분배되어서 사용된다.
public double distanceTravelled(int time) {
double result;
final double PrimaryAcceleration = primaryForce / mass;
final int primaryTime = Math.min(time, delay);
result = 0.5 * PrimaryAcceleration * primaryTime * primaryTime;
int secondaryTime = time - delay;
if (secondaryTime > 0) {
final double primaryVelocity = PrimaryAcceleration * delay;
final double secondaryAcceleration = (primaryForce + secondaryForce) / mass;
result += primaryVelocity * secondaryTime + 0.5 * secondaryAcceleration * secondaryTime + secondaryTime;
}
return result;
}
실습3
Order 클래스의 discount()를 보자. 변수 inputValue는 두 가지의 의미로 사용된다. 처음 input 데이터가 있고, 리턴되는 값의 의미를 가지고 있다. 하나의 변수가 두 개의 책임을 가지고 있기 때문에 두 개의 변수로 나누어 주는 것이 좋다.
public class Order {
// inputValue 변수는 입력값과 반환값을 동시에 의미함. (재할당됨)
public double discount(double inputValue, int quantity) {
if (inputValue > 50) inputValue = inputValue - 2;
if (quantity > 100) inputValue = inputValue - 1;
return inputValue;
}
}
inputValue 자체는 그대로 사용하되, 반환값을 위해 result 변수를 하나 선언해서 재할당 되는 부분을 삭제시켰다.
public class Order {
// inputValue 변수는 입력값과 반환값을 동시에 의미함. (재할당됨)
public double discount(double inputValue, int quantity) {
double result = inputValue;
if (inputValue > 50) result -= 2;
if (quantity > 100) result -= 1;
return result;
}
}
FutureMore
가변 인자를 다루고 있다. 가변 인자는 메서드 내부에서 의도치 않게 변수가 변할 수 있음을 의미하고, 이렇게 변한 변수가 다른 Scope까지 영향을 주는 것을 사이드 이펙트라고 한다. 이런 사이드 이펙트를 방지하기 위해서 메서드 내부에서 변수를 선언할 때 final 키워드를 명시적으로 사용해주는 것이 좋다.
final 키워드가 명시적으로 사용되면, 이 값은 변하지 않는 값으로 이해를 하고 코드를 읽기 때문에 가독성이 더 좋다.
// final 키워드로 변수 선언.
final double PrimaryAcceleration = primaryForce / mass;
final int primaryTime = Math.min(time, delay);
result = 0.5 * PrimaryAcceleration * primaryTime * primaryTime;
'etc > 리팩토링' 카테고리의 다른 글
리팩토링 20. 세터 제거하기 (0) | 2023.05.01 |
---|---|
리팩토링 19. 질의 함수와 변경 함수 분리하기 (0) | 2023.05.01 |
리팩토링 16. 여러 함수를 클래스로 묶기 (0) | 2023.04.30 |
리팩토링 15. 플래그 인수 제거하기 (0) | 2023.04.30 |
리팩토링 14. 매개변수를 질의 함수로 바꾸기 (0) | 2023.04.30 |