Study/CleanCode

[클린코드] 7장. 오류처리

Wonol 2024. 6. 28. 16:44
반응형

클린코드(CleanCode)를 읽고 간략하게 정리한 글입니다.


7장. 오류처리

1. 오류 코드보다 예외를 사용하라

- 오류 코드를 반환하는 방식보다 예외를 사용하는 것이 더 바람직하다.

- 오류 코드는 코드의 흐름을 복잡하게 만들고, 정상 코드와 오류 처리 코드를 섞어 놓는다.

- 반면에 예외는 오류 처리 코드와 정상 코드를 명확히 구분해준다.

// Bad Example - 오류 코드를 사용하는 경우
public int divide(int a, int b) {
    if (b == 0) {
        return -1; // 오류 코드
    }
    return a / b;
}

// Good Example - 예외를 사용하는 경우
public int divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Divisor cannot be zero");
    }
    return a / b;
}

2. Try-Catch-Finally 문부터 작성하라

- 오류 처리는 프로그램의 논리에 중요한 부분이다.

- Try-Catch-Finally 문을 먼저 작성하면 오류 처리와 관련된 부분을 명확하게 만들 수 있다.

public void processFile(String fileName) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        // 파일 처리 로직
    } catch (IOException e) {
        System.err.println("File processing failed: " + e.getMessage());
    } finally {
        // 리소스 정리 로직
    }
}

3. 미확인(Unchecked) 예외를 사용하라

- Checked 예외는 오류 처리 코드를 강제하지만, 코드가 지저분해질 수 있다.

- Unchecked 예외를 사용하면 메소드 시그니처가 깔끔해지고, 진짜 오류 처리가 필요한 곳에서만 예외 처리를 할 수 있다.

public void doSomething() {
    if (someCondition) {
        throw new RuntimeException("Unchecked exception");
    }
    // 정상 로직
}

4. 예외에 의미를 제공하라

- 예외 메시지는 문제의 본질을 명확히 전달해야 한다.

- 구체적인 예외 클래스를 만들어서 오류 상황을 구체적으로 기술하는 것이 좋다.

public class InsufficientFundsException extends RuntimeException {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

5. 호출자를 고려해 예외 클래스를 정의하라

- 예외는 오류가 발생했음을 알리기 위한 수단이다.

- 예외가 발생할 수 있는 상황을 호출자가 명확히 이해할 수 있도록 예외 클래스를 정의해야 한다.

public void withdraw(double amount) {
    if (amount > balance) {
        throw new InsufficientFundsException("Balance is not enough to withdraw " + amount);
    }
    balance -= amount;
}

6. 정상 흐름을 정의하라

- 예외는 예외적인 상황에서만 사용해야 한다.

- 정상적인 흐름에서 예외를 사용하는 것은 코드의 가독성을 떨어뜨린다.

- 정상 흐름에서 처리해야 할 상황은 예외를 사용하지 말고, 명확한 조건문 등을 사용해야 한다.

// Bad Example
try {
    int result = divide(a, b);
    // 정상 흐름 처리
} catch (IllegalArgumentException e) {
    // 예외 흐름 처리
}

// Good Example
if (b != 0) {
    int result = divide(a, b);
    // 정상 흐름 처리
} else {
    // 예외 흐름 처리
}

7. null을 반환하지 마라

- null을 반환하면 null 검사 코드가 많이 생겨난다.

- null 대신 예외를 던지거나, 빈 컬렉션, 옵셔널 등을 반환해야 한다.

// Bad Example
public String getCustomerName(int id) {
    if (customer == null) {
        return null;
    }
    return customer.getName();
}

// Good Example
public Optional<String> getCustomerName(int id) {
    return Optional.ofNullable(customer).map(Customer::getName);
}

8. null을 전달하지 마라

- 메서드 인수로 null을 전달하는 것은 위험하다.

- null 대신 의미 있는 객체를 전달해야 한다.

// Bad Example
public void printCustomerName(Customer customer) {
    if (customer != null) {
        System.out.println(customer.getName());
    }
}

// Good Example
public void printCustomerName(Customer customer) {
    Objects.requireNonNull(customer, "Customer cannot be null");
    System.out.println(customer.getName());
}

9. 결론

- 오류 처리는 프로그램의 중요한 부분이다.

- 예외를 잘 활용하면 코드의 가독성을 높이고 유지보수성을 향상시킬 수 있다.

- 오류 처리 코드는 명확하게 작성하고, 호출자에게 의미 있는 정보를 제공하는 것이 중요하다.

- null을 반환하거나 전달하는 것을 피하고, 가능한 한 예외 상황을 명확히 구분하는 코드를 작성해야 한다.

반응형