[자바 코딩의 기술] 1. 코드 정리 생기초

봄도둑·2022년 4월 11일
3

자바코딩의기술

목록 보기
1/4

3개월차 신입 비전공 개발자가 읽기 좋은 코드를 만들어보고자 공부하는 내용입니다. 부족하거나 새롭게 공부해보면 좋을 것 같은 추천, 글에서 발견된 문제에 대한 이야기는 언제든 환영합니다!

1. boolean 비교 하지 맙시다.

public class ExampleService {

    private int a = 10;
    private int b = 20;

    public int escapeBooleanCompare() {

        if (compareIntA(100) == true) {
            return a;
        } else {
            return b;
        }

    }

    private boolean compareIntA(int param) {
		return param == a;
    }
}
  • 예시를 위해 막 만든 코드인데 조건문에서 값을 비교할 때 boolean 원시값은 == 비교하지 말자.
  • 이러한 비교는 전혀 필요 없을 뿐더러 코드의 가독성과 이해를 떨어뜨림
  • 수정사안
public int escapeBooleanCompare() {

    if (compareIntA(100)) {
        return a;
    } 
    return b;
    
}
  • else문을 써도 되지만 early return 방식을 적용도 같이 해봄 → if문도 깔끔해지고, 불필요한 else 문도 정리됨

2. 부정 피하기

  • 조건문을 쓸 때 부정표현 if(!isTrue()) 보다 if(isTrue()) 처럼 !가 들어가는 부정은 사용하지 않는 게 좋다 → 긍정의 표현은 부정의 표현보다 코드의 이해도를 높이는데 도움이 됨

3. boolean 표현식 직접 반환

public class ExampleService {

    private String name;
    private int age;

    public boolean checkUserInfo(String name, int age) {
        if (age < 19 || Objects.isNull(name) || name.trim().isEmpty()) {
            return false;
        } else {
            return true;
        }
    }

}
  • 나이가 19 미만이면서 이름값이 null이거나 이름이 공백으로 들어오면 false를 리턴해주는 사용자 인증 코드
  • 조건문에 뭔가 덕지덕지 들어가면서 코드 보기가 어려움. → 들여쓰기와 분기문이 들어가서 가독성이 떨어짐
public boolean checkUserInfo(String name, int age) {
        return age > 19 && !Objects.isNull(name) && !name.trim().isEmpty();
}
  • 조건문이 3개 이상 쓰일 경우 간소화를 하는 게 좋음 → 이 때 간소화 하는 조건문 덩어리들이 공통적으로 사용되는 부분이 있다면 메소드(함수)로 빼내는 게 좋음
	public boolean checkUserInfo(String name, int age) {
		boolean isValidAge = age > 19;
		boolean isValidName = !Objects.isNull(name) && !name.trim().isEmpty();
		return isValidAge && isValidName;
  }
  • x && y || z → (x && y) || z → 불 연산 시 &&이 || 보다 먼저 연산됨

4. 조건문에서 nullPointException 피하기

public void writeMessage(String message, Path location) {
    if (Files.isDirectory(location)) {
        throw new IllegalArgumentException("유효하지 않은 경로입니다.");
    }

    if (message.trim().isEmpty() || Objects.isNull(message)) {
        throw new IllegalArgumentException("유효하지 않은 메시지입니다.");
    }
}
  • 자바 개발을 하다가 유효성(인수 검증)을 할 때 마주치는 가장 큰 문제 → nullPointexception
  • 이러한 유효성 검사 시 순서가 가장 중요! → 위의 코드는 인수값이 사용하기 적합한 형태인지 먼저 확인한 후, null 여부를 확인함 → 이 때, 인수값이 사용되기 적합한 형태인지 확인하는 과정에서 nullPointException이 발생할 가능성이 높음.
  • 유효성 검사의 올바른 순서는 null 체크 → 값의 사용 가능 여부(인수를 사용한 메소드면 좋음)
  • 읽기 좋고 동작이 원활하게 되는 코드로 바꿔보자
public void writeMessage(String message, Path location) {
    if (Objects.isNull(message) || message.trim().isEmpty()) {
        throw new IllegalArgumentException("유효하지 않은 메시지입니다.");
    }

    if (Objects.isNull(location) || Files.isDirectory(location)) {
        throw new IllegalArgumentException("유효하지 않은 경로입니다.");
    }
}
  • 먼저 파라미터의 순서에 따라 유효한 파라미터 체크를 함 → 가독성이 올라감(message의 유효성과 location 유효성 조건문의 위치 맞바꿈)
  • null 체크 후 해당 값이 유효한지 여부에 대한 확인을 진행
  • 그러나 항상 이러한 수준의 파라미터 유효성 검사는 하지 않아도 괜찮음
  • 주로 public, protected, default에서 유효성 검사를 해줌
  • private에서는 아예 null이 넘어오지 않도록 해주는 게 좋음

5. switch case 구문과 break

public void writeMessage(int a) {
    String result;

    switch (a) {
        case 1 :
            result = "one";
        case 2 :
            result = "two";
            break;
        case 3 :
            result = "three";
            break;
        default:
            result = "other";
            break;
    }
}
  • switch case 구문은 정말 많은 버그를 일으키는 구문 중 하나
  • 위의 예제 코드에서 case 1 블록에 break; 가 빠져있음 → 즉, 첫번째 case는 무조건 실패하고 두번째 case부터 나아가게 됨. → switch case가 버그로 악명 높은 이유 중 하나
  • switch 구문은 관심사 분류가 어려울 수 있음

6. 중괄호 항상 사용하기

  • 코드의 가독성을 높이기 위해서는 중괄호를 생략하기보다 사용하는 것이 좋음
public void writeMessage(int a) {
    String result;

    if (a == 1)
        result = "one";
    if (a == 2)
        result = "two";
    if (a == 3)
        result = "three";
		a++;
}
  • 위의 코드처럼 if문이 한 줄로 끝나면 중괄호를 생략할 수 있음.
  • 위의 예제 코드는 괄호를 안쓰고 잘못된 들여쓰기로 코드를 잘못 이해함 → if(a == 3) 구문에 a++;가 연결되어 있는 것으로 보임
  • 여담으로 if문의 중괄호는 예전부터 많은 논의의 대상이 됨 → 자신에게 맞는 걸 사용하자.

7. 코드 대칭 이루기

public void checkAuth() {
    if (checkUserUnknown()) {
        return;
    } else if (checkSupplier()) {
        System.out.println("반갑습니다. 판매자님");
    } else if (checkConsumer()) {
        System.out.println("반갑습니다. 고객님");
    }
}
  • 위의 코드를 보면 분기(if)구문들이 동일한 관심사로 분류를 하고 있지 않음
  • checkUserUnknown()checkSupplier() , checkConsumer() 는 서로 처리하는 관심사가 다름 → 사용자의 로그인 여부와 사용자의 페르조나(권한) 설정 2개의 관심사로 분리됨 → 얘를 분리해서 코드의 대칭성을 이루자.
public void checkAuth() {
    if (checkUserUnknown()) {
        return;
    } 
    
    if (checkSupplier()) {
        System.out.println("반갑습니다. 판매자님");
    } else if (checkConsumer()) {
        System.out.println("반갑습니다. 고객님");
    }
}
  • 로그인과 사용자 페르조나에 대해 분리를 함으로 코드의 대칭성 달성
profile
배워서 내일을 위해 쓰자

0개의 댓글