728x90
반응형
SMALL
자바로 배우는 리팩토링 입문
- Java Refactoring For Beginner
- 건강한 코드로 소프트웨어 체질을 개선하자!
- 유키 히로시 지금
- 길벗 출판사
- 2017.10.31
리팩토링을 위한 스터디 내용을 정리하자.
매직 넘버를 기호 상수로 치환
소스 코드에 특정한 숫자(매직 넘버)를 사용하는 것은 좋지 않은 코딩 스타일이다.
이유
- 의미를 파악하기 어렵다.
- 소스 코드에 100이라고 적혀 있으면 무엇을 의미하는지 바로 파악하기 어렵다.
- 대신 MAX_INPUT_LENGTH라는 기호 상수를 사용하면 의미를 바로 파악할 수 있다.
- 수정하기 어렵다.
- 요구사항이 변경되어 최대 입력 문자 길이가 200으로 수정되는 경우, 100이라는 숫자가 이곳저곳에 박혀 있어 수정이 어렵다.
- 모든 100을 200으로 수정할 수도 없다.
Before
public class Robot {
private final String _name;
public Robot(String name) {
_name = name;
}
public void order(int command) {
if (command == 0) {
sout(_name + "walk");
} else if (command == 1) {
sout(_name + "stop");
} else if (command == 2) {
sout(_name + "jump");
} else {
sout("error command : " + command);
}
}
}
public class Main {
public static void main(String[] args) {
Robot robot = new Robot("Andrew");
robot.order(0); // walk
robot.order(1); // stop
robot.order(2); // jump
}
}
After
public class Robot {
public static final int COMMAND_WALK = 0;
public static final int COMMNAD_STOP = 1;
public static final int COMMAND_JIUMP = 2;
private final String _name;
public Robot(String name) {
_name = name;
}
public void order(int command) {
if (command == COMMAND_WALK) {
sout(_name + "walk");
} else if (command == COMMAND_STOP) {
sout(_name + "stop");
} else if (command == COMMAND_JUMP) {
sout(_name + "jump");
} else {
sout("error command : " + command);
}
}
}
public class Main {
public static void main(String[] args) {
Robot robot = new Robot("Andrew");
robot.order(Robot.COMMAND_WALK);
robot.order(Robot.COMMAND_STOP);
robot.order(Robot.COMMAND_JUMP);
}
}
추가 리팩토링
- COMMAND_WALK, COMMAND_STOP처럼 매직 넘버를 기호 상수로 만든다고 해도 실제로는 0, 1이라는 int 값이다.
- 그렇기에, 프로그래머가 robot.order(0); 매직 넘버를 직접 적어도 컴파일 에러가 발생하지 않는다.
- 프로그래머의 실수를 컴파일러가 검출할 수 있게 분류 코드를 클래스로 치환하는 것이 좋다.
- 여기서는 int가 아닌 RobotCommand 타입으로 치환했다.
public class RobotCommnad {
private final String _name;
public RobotCommand(String name) {
_name = name;
}
public String toString() {
return "[RobotCommand: " + _name + "]";
}
}
public class Robot {
public static final int COMMAND_WALK = new RobotCommand("WALK");
public static final int COMMNAD_STOP = new RobotCommand("STOP");
public static final int COMMAND_JIUMP = new RobotCommand("JUMP");
private final String _name;
public Robot(String name) {
_name = name;
}
public void order(int command) {
if (command == COMMAND_WALK) {
sout(_name + "walk");
} else if (command == COMMAND_STOP) {
sout(_name + "stop");
} else if (command == COMMAND_JUMP) {
sout(_name + "jump");
} else {
sout("error command : " + command);
}
}
}
public class Main {
public static void main(String[] args) {
Robot robot = new Robot("Andrew");
robot.order(Robot.COMMAND_WALK);
robot.order(Robot.COMMAND_STOP);
robot.order(Robot.COMMAND_JUMP);
}
}
추가 리팩토링
- Java 5부터 ENUM으로 기호 상수를 표현할 수 있게 되었다.
- WALK, STOP, JUMP 기호 상수를 ENUM으로 선언하여 리팩토링을 진행한다.
- 일반적으로는 별도의 ENUM 클래스를 생성해서 공통으로 사용한다.
public class RobotCommnad {
private final String _name;
public RobotCommand(String name) {
_name = name;
}
public String toString() {
return "[RobotCommand: " + _name + "]";
}
}
public class Robot {
public enum Commnad {
WALK,
STOP,
JUMP
}
private final String _name;
public Robot(String name) {
_name = name;
}
public void order(int command) {
if (command == COMMAND_WALK) {
sout(_name + "walk");
} else if (command == COMMAND_STOP) {
sout(_name + "stop");
} else if (command == COMMAND_JUMP) {
sout(_name + "jump");
} else {
sout("error command : " + command);
}
}
}
public class Main {
public static void main(String[] args) {
Robot robot = new Robot("Andrew");
robot.order(Robot.COMMAND_WALK);
robot.order(Robot.COMMAND_STOP);
robot.order(Robot.COMMAND_JUMP);
}
}
기호 상수가 적합하지 않은 경우
// 나쁨
for (int i = 0; i < BUFFER_SIZE; i++) {
...
}
// 좋음
for (int i = 0; i < buffer.length; i++) {
...
}
배열에는 배열 길이를 나타내는 length 필드가 존재하기에 굳이 기호 상수를 사용할 필요가 없다.
괜히 기호 상수로 치환했다가 올바른 배열 길이가 아닌 값이 들어가는 휴먼 에러가 발생할 수 있다.
연습 문제
1-1. O, X
- 매직 넘버를 코드에 직접 쓰는 것보다 의미를 알기 쉬운 이름을 붙인 기호 상수를 사용하는 게 낫다. (O)
- 매직 넘버보다 기호 상수가 의미를 알기 쉽다.
- 사양이 변할 때 한꺼번에 치환할 수 있도록 매직 넘버를 사용하는 게 좋다. (X)
- 매직 넘버인 경우, 의도치 않은 값까지 함께 수정될 위험이 있어서 사용하지 않는 게 좋다.
- 매직 넘버 사용은 피해야 하므로 배열 인덱스 최솟값 0을 MIN_INDEX라고 선언하는 게 좋다. (X)
- 배열 인덱스 최솟값이 0이라는 건 자바 언어 규칙으로 정해져 있으므로 일부러 기호 상수를 선언하는 건 의미가 없다.
1-2. 다음 코드의 문제점을 지적하고 개선하시오.
public static double degreeToRadian(double degree) {
return degree / 180.0 * 3.1459265358979323846;
}
3.14592~는 원주율 매직 넘버이다. 매직 넘버를 Math 클래스의 상수 PI로 치환하자.
public static double degreeToRadian(double degree) {
return degree / 180.0 * Math.PI;
}
아직 180.0이라는 매직 넘버가 남아있다. 이것도 치환이 필요하다.
하지만, 원주율을 뜻 하는 표준 클래스 라이브러리가 있기에 Math.toRadians() 메서드를 쓰는 것도 방법이다.
public static double degreeToRadian(double degree) {
return Math.toRadians(degree);
}
728x90
반응형
LIST
'Study > Java Refactoring For Beginner' 카테고리의 다른 글
[Java Refactoring] 에러 코드를 예외로 치환 (0) | 2021.02.08 |
---|---|
[Java Refactoring] 분류 코드를 클래스로 치환 (0) | 2021.02.08 |
[Java Refactoring] 메서드 & 클래스 추출 (0) | 2021.02.08 |
[Java Refactoring] 제어 플래그 삭제 (0) | 2021.02.08 |
[Java Refactoring] 리팩토링이란 무엇인가? (0) | 2021.01.17 |