본문 바로가기
Programming/Refactoring

[Refactoring] 간단한 리팩토링 모음

by 흑시바 2023. 3. 5.

코딩할 때 가볍게 다루기 좋은 리팩토링에 대해 소개하려고 한다. 😀

코드의 이해를 높이는 데 도움이 되며 사실상 어떠한 비용도 들지 않으니 신경 써주는 게 좋다. 👍

사소하지만 코딩하는 과정에 도움이 되었으면 한다. 필자도 프로젝트하면서 한 번씩 참고하려고 포스팅한다.

"부정을 피하자"

코드에서는 긍정적인 표현식이 부정적인 표현식보다 훨씬 이해하기가 쉽다.

즉, Objects.nonNull(), !StringUtils.hasText() 등 보다 Objects.isNull(), StringUtils.hasText()가 좋다.

 

@Test
void goodRefactoring() {
	Shiba shiba = null;
	if(Objects.isNull(shiba)) {
		System.out.println("Null 입니다.");
	}
	if(Objects.nonNull(shiba)) {
		System.out.println("Null이 아닙니다.");
	}
        
	String empty = "";
	if(StringUtils.hasText(empty)) {
		System.out.println("text가 비어있지 않습니다.");
	}
	if(!StringUtils.hasText(empty)) {
		System.out.println("text가 비어있습니다.");
	}
}

"여러 조건은 간소화하자"

Boolean 조건이 여러 개 있으면 가독성이 좋지 않아서 복잡하고 읽기 어렵다.

조건이 3개 이상이라면 간소화를 고려해 보자.

 

@Test
void goodRefactoring() {
	Shiba shiba = Shiba.builder().name("흑시바").age(20).color(Color.BLACK).build();
	if(shiba.getName() == "흑시바" && shiba.getAge() >= 20 && shiba.getColor() == Color.BLACK) {
		System.out.println("흑시바 입니다.");
	}
}

 

이런 경우, 필드 값으로  빼거나 메서드로 만들어서 가독성을 높인다.

 

@Test
void goodRefactoring() {
	Shiba shiba = Shiba.builder().name("흑시바").age(20).color(Color.BLACK).build();
	if(isBlackShiba(shiba)) {
		System.out.println("흑시바 입니다.");
	}
}

private boolean isBlackShiba(Shiba shiba) {
	return shiba.getName() == "흑시바" && shiba.getAge() >= 20 && shiba.getColor() == Color.BLACK;
}

"하드코딩된 문자열, 숫자는 상수로 대체한다"

코드에서 종종 문자열, 숫자를 하드 하게 작성하는 경우가 있다.

이러한 문자열, 숫자는 코드를 이해하기 어렵게 만들고 중복이 발생할 수 있다.

 

@Test
void goodRefactoring() {
	Shiba shiba = Shiba.builder().name("흑시바").age(20).color(Color.BLACK).build();
	if(shiba.getName().equals("흑시바")) {
		System.out.println("흑시바1");
	}
	if(shiba.getName().equals("흑시바")) {
		System.out.println("흑시바2");
	}
	if(shiba.getName().equals("흑시바")) {
		System.out.println("흑시바3");
	}
	if(shiba.getAge() == 10) {
		shiba.setRunning(274);
	}
	if(shiba.getAge() == 20) {
		shiba.setRunning(322);
	}
}

 

해당 코드를 보면 "흑시바"라는 문자열을 반복해서 검증하는 것을 볼 수 있다.

만약 어떤 경우에 의해서 "흑시바"가 아닌 "적시바" 등으로 변경할 경우 코드를 여러 번 고쳐야 하는 번거로움이 있다.

또한, 이렇게 변경해야 할 곳이 많은 경우 실수할 확률도 변경할 개수만큼 높아진다.

 

그리고 setRunning에 274와 322라는 숫자(매직 넘버)가 들어가 있는데,

다른 프로그래머가 코드를 봤을 때 274와 322라는 숫자가 무엇을 의미하는지 정확히 알 수 없기 때문에 setRunning에 대한 설명을 확인해야 하는 번거로움이 생긴다.

 

각 문자열, 숫자에 유의미하고 이해하기 쉬운 이름을 추가하면 의미가 명확해지고 실수할 확률도 줄어든다.

 

private static final String SHIBA = "흑시바";
private static final int BLACK_SHIBA_SPEED = 274;
private static final int BLACK_SHIBA_BOOST_SPEED = 274;

@Test
void goodRefactoring() {
	Shiba shiba = Shiba.builder().name("흑시바").age(20).color(Color.BLACK).build();
	if(shiba.getName().equals(SHIBA)) {
		System.out.println("흑시바1");
	}
	if(shiba.getName().equals(SHIBA)) {
		System.out.println("흑시바2");
	}
	if(shiba.getName().equals(SHIBA)) {
		System.out.println("흑시바3");
	}
	if(shiba.getAge() == 10) {
		shiba.setRunning(BLACK_SHIBA_SPEED);
	}
	if(shiba.getAge() == 20) {
		shiba.setRunning(BLACK_SHIBA_BOOST_SPEED);
	}
}

"정수 상수 대신 열거형을 사용하자"

확실히 매직 넘버(숫자)보다 상수가 훨씬 낫지만, 만약 값들에 연관된 의미가 있는 경우라면 열거형(Enum)을 사용하는 것이 훨씬 좋다.

 

private static final int WHITE = 1;
private static final int BLACK = 2;
private static final int YELLOW = 3;

@Test
void goodRefactoring() {
	Shiba shiba = Shiba.builder().name("흑시바").age(20).color(1).build();
	String color = getShibaColorName(4);
	shiba.setColorName(color);
}

private String getShibaColorName(int color) {
	if(color == WHITE) {
		return "WHITE";
	} else if(color == BLACK) {
		return "BLACK";
	} else if(color == YELLOW) {
		return "YELLOW";
	}
	throw new IllegalArgumentException("잘못된 색상입니다.");
}

 

getShibaColorName() 메서드는 매개변수가 정수인 경우, 어떤 정수값이든 넣을 수 있다. 음수나 다른 정수 상수를 넣는 것도 가능하다. 반드시 1, 2, 3을 사용해야 한다고 컴파일러에서 강제하지 않기 때문이다.

 

getShibaColorName() 메서드는 파라미터에 1,2,3 외 값을 넣으면 호출 시점에 예외가 발생한다. 그러므로 문제가 발생한다는 걸 컴파일 과정에서 알 수가 없다. 또한, 만약 프로그램이 실행 중에 호출되지 않는 경우 한참 뒤에 발견되거나 영영 발견되지 않을 수 있다.

 

Enum을 사용하면 이러한 문제를 해결할 수 있다.

 

@Test
void goodRefactoring() {
	Shiba shiba = Shiba.builder().name("흑시바").age(20).color(Color.BLACK).build();
	String color = getShibaColorName(Color.BLACK);
	shiba.setColorName(color);
}

private String getShibaColorName(Color color) {
	if(color == Color.WHITE) {
		return "WHITE";
	} else if(color == Color.BLACK) {
		return "BLACK";
	} else if(color == Color.YELLOW) {
		return "YELLOW";
	}
	throw new IllegalArgumentException("잘못된 색상입니다.");
}

댓글