오늘 회사에서 업무중에 아무 생각없이 if-else 중첩으로 코딩하고 “기능적으로” 잘
돌아가는 것을 확인한 뒤, 해당 업무를 접으려고 했습니다.
그런데 문득 이런 생각을 해보았습니다.
“왜 맨날 분기로직은 if-else로만 짜야할까… 과연 내가 아닌 다른 사람이
내 코드를 유지보수한다면 저걸 얼마나 이해하고 작업할 수 있을까”
그래서 과감하게 if-else 로직을 걷어내고 리팩토링 하기로 결정하고 구글링을 통해 그런
사례가 있는지 찾아서 테스트코드를 만들었습니다.
아래 참고 url은 꼭 한번 읽어보시기 바랍니다.
소소코드는 참고 url에서 다운받아서 인터페이스를 구현한 enum class의 메서드에서
String Object를 리턴하도록 약간 수정하였습니다.
1. 먼저 기존 if-else class입니다.
public class IfThenElse {
public String invoke(String operationName) {
String result = null;
if (StringUtils.equals(operationName, "operation1")) {
result = operation1();
} else if (StringUtils.equals(operationName, "operation2")) {
result = operation2();
} else if (StringUtils.equals(operationName, "operation3")) {
result = operation3();
}
return result;
}
public String operation1() {
return "operation_1";
}
public String operation2() {
return "operation_2";
}
public String operation3() {
return "operation_3";
}
}
2. 두번째로 if-else 분기문을 enum 클래스로 리팩토링한 코드입니다.
public class NewIfThenElse {
private interface IOperation {
String apply(String name);
}
private enum Operation implements IOperation {
OPERATION_1("operation1") {
public String apply(String name) {
return "operation_1";
}
},
OPERATION_2("operation2") {
public String apply(String name) {
return "operation_2";
}
},
OPERATION_3("operation3") {
public String apply(String name) {
return "operation_3";
}
};
private static Map<String, Operation> requestLookup;
static {
requestLookup = new HashMap<String, Operation>(3);
requestLookup.put(OPERATION_1.getName(), OPERATION_1);
requestLookup.put(OPERATION_2.getName(), OPERATION_2);
requestLookup.put(OPERATION_3.getName(), OPERATION_3);
}
private final String name;
private Operation(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Operation{" + "name='" + name + '\'' + '}';
}
public static Operation getOperationByName(String name) {
return requestLookup.get(name);
}
}
public String invoke(String operationName) {
String result = null;
Operation operation = Operation.getOperationByName(operationName);
if (operation != null) {
result = operation.apply(operationName);
}
return result;
}
}
3. 마지막으로 저 두개의 클래스를 단위테스트하는 코드입니다.
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* if-else Refactoring 테스트케이스
*
* @author bluepoet
*
*/
public class IfElseRefactoringTest {
Logger logger = LoggerFactory.getLogger(IfElseRefactoringTest.class);
private String result;
@Test
public void procedural() {
IfThenElse obj = new IfThenElse();
result = obj.invoke("operation2");
logger.debug("결과 : {}", result);
assertThat(result, is("operation_2"));
}
@Test
public void refactor() {
NewIfThenElse obj = new NewIfThenElse();
result = obj.invoke("operation1");
result = obj.invoke("operation1");
logger.debug("결과 : {}", result);
assertThat(result, is("operation_1"));
}
}
단위테스트 결과는 물론, 녹색막대가 뜨며 두개의 메서드 모두 통과로 나옵니다.

로그도 위와같이 console창에서 출력됩니다.
이번에 리팩토링을 진행하면서 기존의 if-else문 자체를 완벽히 거둬내지는 못했지만,
관심대상을 별도의 클래스로 분리해 독립적으로 구현하는 것에는 일부분 성공했습니다.
OOP적인 부분에서는 절반의 성공은 했다고 생각됩니다.
그리고 기존의 코드를 최대한 안 건드리려고 한 부분도 일부분은 만족스럽게 구현했구요.
이것도 예제의 일부분일 뿐이고, 아마 더 좋은 구현사례가 많이 있을 것입니다.
혹시 좋은 리팩토링 사례가 있다면 댓글 남겨주시구요.
오늘 회사 선배개발자님과 커피를 마시며 한 대화중에 떠오르는 말이 있네요
“리팩토링은 새로운 기능을 개발할 때 할 수 있는게 아니라 비교적 여유가 있을 때,
기존의 코드를 고치며 하는 것이 더 바람직하다. 그리고 오히려 그렇게 리팩토링을
하는 것이 실력향상에 더 도움이 된다.”
리팩토링의 길은 멀고도 험하지만, 그것을 해냈을 때 프로그래머로써 느끼는 “쾌감“은
다른 무엇과도 비교할 수 없는 달콤한 열매겠죠? ^^
*참고 url