자바 if 문 리팩토링 - jaba if mun lipaegtoling

조건문 Refactoring

if ~ else문은 꼭 필요하면서도, 프로젝트를 복잡하게 만드는 요소입니다. 잘못 사용한다면, 열심히 개발한 프로젝트가 최악의 프로젝트가 될 수도 있죠.

조건문을 작성하면서 많은 개발자 분들이 실수하고 있는 부분들을 담을테니 참고해주세요!

1. return true; / return false;를 사용하지 마라!

조건 절이 Boolean 반환 값을 가지는데, 굳이 if ~ else문을 사용하면 코드가 복잡해집니다.

[Bad😢]

public boolean isAdmin(User user) { if(user.role == UserRole.ADMIN) { return true; } else { return false; } }

[Good😍]

public boolean isAdmin(User user) { return user.role == UserRole.ADMIN; }

2. 삼항연산자를 사용하라!

함수가 flag에 따른 return값을 가진다면, 삼항연산자를 쓰는 것이 바람직합니다.

[Bad😢]

public int getPrice(User user) { if(user.role == UserRole.ADMIN) { return 5000; } else { return 10000; } }

[Good😍]

public int getPrice(User user) { return user.role == UserRole.ADMIN ? 5000 : 10000; }

3. 다중 if문을 사용하지 마라!

클린 코드에서는 if문이 1번도 많다고 하고, 정말 많이써봐야 2번이라고 합니다. 따라서, if문을 적절히 메서드로 분리하는 것이 중요합니다.

[Bad😢]

public void getMedal(User user) { if(user.role == UserRole.USER) { int rank = repository.getRanking(user); if(rank <= 3) { user.medal += 1; } } }

[Good😍]

public void getMedal(User user) { if(user.role == UserRole.USER && isRanker(user)) { user.medal += 1; } }

조건문 개선안은 꾸준히 나오고있습니다.

부정문 처리를 먼저 해서 return으로 탈출을 시켜야 한다, return은 가능한 적게 호출해야 한다, 와 같은 내용도 있었지만,

그런 부분들은 정답으로 보기 어려운 것 같다고 생각해서 뺐습니다.

더 공부해서 2편으로 찾아오겠습니다.

감사합니다.

조건문 쪼개기(Decompose Conditional)

조건문의 분기 부분이 너무 복잡하다면 if, else 절들의 분기점을 각각 메서드로 빼서 분리해주자.
프로그램의 로직에서 가장 복잡한 부분중 하나가 조건문절이다. 각 조건에 따른 각기 다른 작업을 해주기에 코드가 복잡해지기 가장 쉬운 부분이다.
당연히 복잡도가 올라가니 메서드의 길이도 비례해서 길어진다.
이럴때 각 조건절에 해당하는 부분의 로직을 메서드 단위로 묶어서 처리해주면 직관성 + 재사용성 이 늘어난다. 특히 해당 분기가 무엇을 의미하는지 한눈에 알 수 있다.


리팩토링 전

public double getRealProductPrice(double productPrice,People people){ if(productPrice > OVER_CHARGE_LIMIT && "NORMAL".equals(people.getGrade())) realPrice = productPrice * OVER_CHARGE_TAX; else realPrice = productPrice * NORMAL_TAX; }

리팩토링 후

public final static double OVER_CHARGE_LIMIT = 3000000; public final static double OVER_CHARGE_TAX = 0.3; public final static double NORMAL_TAX = 0.1; public double getRealProductPrice(double productPrice,People people){ if(isExceedCharge(productPrice, people)) realPrice = getOverChargePrice(productPrice); else realPrice = getNormalChargePrice(productPrice); } private boolean isExceedCharge(double productPrice,People people){ return productPrice > OVER_CHARGE_LIMIT && "NORMAL".equals(people.getGrade()) } private double getOverChargePrice(double productPrice){ return productPrice * OVER_CHARGE_TAX; } private double getNormalChargePrice(double productPrice){ return productPrice * NORMAL_TAX; }

조건문의 공통 실행 코드 빼내기(Consolidate Duplicate Conditional Fragments)

조건문의 모든 조건분기 부분에 같은 실행코드가 있다면 같은부분을 조건문 밖으로 꺼내서 선언해주자.
간혹 작업을 하다보면 if의 모든 분기지점에 동일한 코드를 실행하는 부분이 있다. 이러한 중복 코드는 조건문 밖에 빼줘서 한번만 선언하도록 변경 한다.
이러한 간단한 작업만으로도 코드의 중복성이 사라진다.


리팩토링 전

public double getRealProductPrice(double productPrice,People people){ if(isExceedCharge(productPrice, people)){ realPrice = getOverChargePrice(productPrice); printingPrice(realPrice); }else{ realPrice = getNormalChargePrice(productPrice); printingPrice(realPrice); } }

리팩토링 후

public double getRealProductPrice(double productPrice,People people){ if(isExceedCharge(productPrice, people)) realPrice = getOverChargePrice(productPrice); else realPrice = getNormalChargePrice(productPrice); printingPrice(realPrice); }

여러 겹의 조건문을 감시 절로 전환(Replace Nested Conditional with Guard Clauses)

메서드의 조건문에서 실행경로를 파악하기 어려울 경우 모든 특수 경우의 감시 절을 사용하자.
조건문은 if절에 해당되는 정상적 동작 부분과 , 비정상적인 동작을 나타낸다.
해당 리팩토링 기법은 감시절을 이용해서 복잡한 분기를 직관적으로 표현한다. 어려울 수 있으나 예시를 보면 금방 이해할 수 있다.


리팩토링 전

public double getRealProductPrice(double productPrice,People people){ if(isExceedCharge(productPrice, people)) realPrice = getOverChargePrice(productPrice); else{ if(isVip) realPrice = getVipPrice(productPrice); else{ if(isFree) realPrice = 0; else realPrice = getNormalPrice(); } } }

리팩토링 후

public double getRealProductPrice(double productPrice,People people){ if(isExceedCharge(productPrice, people)) realPrice = getOverChargePrice(productPrice); if(isVip) realPrice = getVipPrice(productPrice); if(isFree) realPrice = 0; else realPrice = getNormalPrice(); }

조건 분기의 복잡도가 확연히 줄어든 것을 볼 수 있다.

객체를 통째로 전달(Preserve Whole Object)

메서드에 전달하는 매개변수의 인자들이 객체에서 가져온 값들이라면 매개변수에 해당 객체 자체를 전달하도록 바꾸어 주자.
메서드에 매개변수를 넣어줄때 객체를 통째로 넣어주게 되면 매개변수가 변하거나 추가, 삭제되는 경우 메서드의 매개변수를 일일이 바꾸어 주지않고 객체가 변경되었으니 메서드 선언부에서 해당 매개변수 객체에 대한 변경만 해주면 되니 코드의 직관성 + 유지보수의 편리함 이라는 장점이 생긴다.


리팩토링 전

String firstName = people.getFirstName(); String lastName = people.getLastName(); String fullName = util.getFullName(firstName, lastName);

리팩토링 후

String fullName = util.getFullName(people);

에러 부호를 예외 통지로 교체(Replace Error Code with Exception)

메서드에서 에러를 나타내는 부호를 반환할 땐 반환하는 부호를 예외 통지 코드로 바꾸어 주자.
프로그램을 만들다 보면 문법적 오류가 아닌 논리적 인 오류로 인해 예외가 발생할 수 있다.
예를들어 특정 글을 불러오려는데 글이 삭제되어서 없다면 글을 불러오는 과정에서 Null포인터 에러가 발생할 수 있다.
이러한 방법을 처리하기 위해 해당 케이스를 검사해 특정 플래그 부호로 검사해서 예외를 처리하는데 자바에서는 플래그 값이 아닌 아에 예외라는 것으로 분리시켜서 처리하면 에러처리와 일반 로직차이를 완전히 분리 시킬수 있다. 예외와 일반로직의 관심사가 분리되는 것이다.


리팩토링 전

@Override public void updateBoardContent(BoardVO boardVO) { if(isValidUpdateBoard(boardVO)){ blogBoardMapper.updateBoardContent(boardVO); return true; }else return false; }

리팩토링 후

@Override public void updateBoardContent(BoardVO boardVO) { if(isValidUpdateBoard(boardVO)){ blogBoardMapper.updateBoardContent(boardVO); }else{ throw new BoardVaildException(ExceptionMessage.BOARD_UPDATE_VAILD_FAIL_MESSAGE); } }

Toplist

최신 우편물

태그