본문 바로가기
북스터디/클린코드

07장 - 오류 처리

by 혀닙 2025. 5. 26.
📘 클린 코드 북스터디 정리입니다

📚 도서: 로버트 C. 마틴 《Clean Code》
🧑‍💻 목적: 좋은 코드에 대한 감각과 습관을 익히기 위해
🗓️ 진행 기간: 2025년 5월 ~ 매주 2장

📖 [7장] 오류 처리


✅ 핵심 요약 (Key Takeaways)

이 장의 핵심 문장

깨끗한 코드는 읽기도 좋아야 하지만 안정성도 높아야 한다

저자가 전달하고자 하는 메시지 요약 (3~5줄)

  • 깨끗한 코드는 읽기도 좋아야 하지만 안정성도 높아야 함
  • 오류 처리를 프로그램 논리와 분리하면 독립적인 추론이 가능해지며 코드 유지보수성도 크게 높아짐
  • 예외 처리 시 호출자를 고려해야 함

💡 내용 정리

깨끗한 코드와 오류 처리의 연관성

  • 깨끗한 코드는 읽기도 좋아야 하지만 안정성도 높아야 함
  • 오류 처리를 프로그램 논리와 분리하면 독립적인 추론이 가능해지고 코드 유지보수성도 향상

오류 코드보다 예외 사용

  • 오류 플래그 설정이나 반환 방식은 호출자 코드를 복잡하게 만듦
  • 예외를 던지면 오류 처리 코드와 논리를 분리할 수 있음

try-catch-finally 문부터 작성

  • catch문을 사용하면 예외의 범위를 정의할 수 있음
  • TDD에서 try 범위를 자연스럽게 먼저 고려하게 되어 트랜잭션 경계 설계가 쉬움

public List<RecordedGrip> retrieveSection(String sectionName) {
    try {
        FileInputStream stream = new FileInputStream(sectionName);
    } catch (Exception e) {
        throw new StorageException("retrieval error", e);
    }
    return new ArrayList<>();
}

// 리팩토링 가능
public List<RecordedGrip> retrieveSection(String sectionName) {
    try {
        FileInputStream stream = new FileInputStream(sectionName);
        stream.close();
    } catch (FileNotFoundException e) {
        throw new StorageException("retrieval error", e);
    }
}

미확인 예외(unchecked exception) 사용

  • 확인된 예외는 OCP 위반 위험 → 실익을 따져 신중히 사용
  • 최하위 함수가 새로운 예외를 던질 경우, 호출자 모두 수정 필요

예외에 의미를 제공하라

  • 실패한 연산 이름, 실패의 전후 상황 등 의미 있는 메시지를 제공

호출자를 고려해 예외 클래스를 정의

  • 예외 정의 시 가장 중요한 관심사는 "오류를 잡아내는 방법"
  • 단일 예외로 처리 가능한 경우와, 분기처리 필요한 경우 구분
  • 외부 라이브러리는 Wrapper로 감싸 추상화

try {
    captureSpotService.getPhoto();
} catch (CustomException e) {
    log.error("에러 발생", e);
    return ErrorResponse.of("오류 발생");
}

try {
    paymentService.charge();
} catch (CardDeclinedException e) {
    return ResponseEntity.status(402).body("카드 거절됨");
} catch (NetworkTimeoutException e) {
    return ResponseEntity.status(504).body("결제 서버 응답 없음");
}

정상 흐름을 정의하라 (Special Case Pattern)

  • 예외 케이스를 객체로 캡슐화 → 클라이언트 코드 간소화

null 반환

  • null 대신 예외 또는 특수 객체 반환
  • 외부 API에서 null 반환 시, 감싸기 메서드로 처리

// 방법1
List<Employee> employees = getEmployees();
if (employees != null) {
    for (Employee e : employees) {
        totalPay += e.getPay();
    }
}

// 방법2
List<Employee> employees = getEmployees();
for (Employee e : employees) {
    totalPay += e.getPay();
}

public List<Employee> getEmployees() {
    if (직원이 없다면) {
        return Collections.emptyList();
    }
}

null 전달

  • null을 인수로 기대하지 않는 메서드에 전달하는 일은 지양
  • null 허용이 아닌 경우 명시적으로 금지 정책을 유지

💡 인상 깊었던 문장 & 나의 인사이트

책에서 가장 기억에 남는 문장 1~2개 인용

오류를 분류하는 방법은 수없이 많다. 발생한 위치…(중략)…
하지만 오류를 정의할 때 프로그래머에게 가장 중요한 관심사는 오류를 잡아내는 방법이 되어야 한다

왜 인상 깊었는가

생각해보지 못한 생소한 관점이라 인상깊었다.

사실 오류가 발생하면 보통은 “어떤 오류인지”, “어디서 발생했는지”에만 집중하게 된다.
즉, 오류를 사후적으로 추적하고 대응하는 데 초점을 두는 것이다.


하지만

오류를 정의할 때 프로그래머에게 가장 중요한 관심사는 오류를 잡아내는 방법이 되어야 한다

는 문장은, 오류 처리 역시 설계의 일부로 보아야 한다는 메시지를 담고 있다.


오류가 발생한 후에 당황하며 원인을 쫓는 것이 아니라,
애초에 어떤 오류가 발생할 수 있는지를 정의하고,
그에 따라 예측 가능한 흐름과 복구 전략을 설계하라는 뜻이다.


결국 오류 처리는 ‘디버깅 포인트’가 아니라,
처음부터 설계에 포함되어야 할 요소라는 것이다.


🛠 실무 적용 아이디어 (To Action)

오늘부터 실천해볼 작고 구체적인 실천 1~2가지

  • 오류 코드보다 예외 사용하기
  • 외부 API 감싸기
  • 예외의 정보 제공하기 (실패한 연산 이름, 실패 유형 등)

'북스터디 > 클린코드' 카테고리의 다른 글

09장 - 단위 테스트  (1) 2025.06.03
08장 - 경계  (0) 2025.05.29
06장 - 객체와 자료 구조  (0) 2025.05.21
05장 - 형식 맞추기  (1) 2025.05.20
04장 주석(Comments)  (1) 2025.05.18

댓글