자바와 JUnit을 활용한 단위테스트_08
8장. 깔끔한 코드로 리팩토링하기.
낮은 중복성과 높은 명확성이라는 두 가지 목표를 합리적인 비용과 놀라운 투자 수익률로 달성할 수 있다.
단위 테스트를 만들면 이러한 목표에 도달할 수 있다.
이 장에서는 이런 목표를 마음에 두고 코드를 리팩토링 하는 방법에 대해 알아보도록 한다.
리팩토링
코드를 이리저리 옮겨서 시스템이 정상 동작함을 보장하는 것.
마음대로 코드를 바꾸는 것은 위험하다.
이런저런 방식으로 바꾸었을 때 적절한 보호 장치가 있는지 확인할 필요가 있는데 이것이 바로 테스트이다.
리팩토링의 가장 중요한 것은 이름짓기. 대상은 클래스, 메서드, 모든 종류의 변수들이다.
명확성은 코드 의도를 선언하는 것이고 좋은 이름은 코드 의도를 전달하는 가장 좋은 수단이다.
누군가가 메서드나 클래스명만 봐도 이것이 무슨 기능인지 어떤 것을 하고싶어 하는지 대략적으로 추측이라도 할 수 있게 이름짓기!
조건문은 흔히 잘 읽히지 않는데 특히 복잡할 때 더욱 그렇다.
for (Criterion criterion: criteria) {
Answer answer = answers.get(criterion.getAnswer().getQuestionText());
boolean match = criterion.getWeight() == Weight.DontCare
|| answer.match(criterion.getAnswer());
// ...
}
위의 boolean match 부분을 별도의 매서드로 추출해서 복잡성을 고립시키자!
for (Criterion criterion: criteria) {
Answer answer = answers.get(criterion.getAnswer().getQuestionText());
boolean match = matches(criterion, answer);
// ...
}
private boolean matches(Criterion criterion, Answer answer) {
return criterion.getWeight() == Weight.DontCare || answer.match(criterion.getAnswer());
}
조건과 답변이 어떻게 매치되는지 알고 싶다면 새로 추출된 matches() 메서드로 이동한다.
한단계 더 리팩토링한다면 메서드 추출한게 어느 클래스와 연관되어있는지 보고 해당 클래스로 이동시켜주는 것이다.
answer 지역 변수에 할당하는 문장은 꽤 길고 복잡하다.
이것을 개선하고자 한다면 할당문의 우변을 새로운 메서드로 추출해서 가독성을 좋게 하는 것이다.
Answer answer = answers.get(criterion.getAnswer().getQuestionText());
// 우변을 새로운 메서드로 추출
Answer answer = answerMatching(criterion);
private Answer answerMatching(Criterion criterion) {
return answers.get(criterion.getAnswer().getQuestionText());
}
answer 지역 변수는 코드의 명확성을 높이지 않고 한 번만 사용한다.
변수를 제거하고 answerMatching(criterion) 표현을 인라인하자.
for (Criterion criterion: criteria) {
boolean match = criterion.matches(answerMatching(criterion));
if (!match && criterion.getWeight() == Weight.MustMatch) {
kill = true;
}
if (match) {
score += criterion.getWeight().getValue();
}
anyMatches |= match;
}
또한 대부분의 IDE는 인라인 리팩토링을 자동화하고있다.
이클립스의 경우 Refactor > Inline 메뉴를 선택하면 된다고 한다.(나는 인텔리제이가 더 좋아ㅎㅎㅎㅎㅎㅎㅎ)