Clean Code - 7장. 오류 처리

Clean Code - 7장. 오류 처리

깨끗한 코드를 다루는 책에 오류 처리를 논하는 장이 있어 이상하게 여길지도 모르겠습니다.

하지만 오류 처리는 프로그램에 반드시 필요한 요소 중 하나일 뿐입니다.

뭔가 잘못될 가능성은 늘 존재합니다.

뭔가 잘못되면 바로 잡을 책임은 바로 우리 프로그래머에게 있습니다.

에러를 뱉는다는 것은 좋은 것입니다.

즉, 프로그램에서 무언가가 잘못되었을 때 런타임에서 성공적으로 확인되면

현재 스택에서 함수 실행을 중단하고 프로세스를 종료하고 스택 추적으로 콘솔에서 사용자에게 그 이유를 알려줍니다.

단순히 에러를 확인하지 마세요

단순히 에러를 확인하는 것으로 그 에러가 해결되거나 대응할 수 있게 되는 것은 아닙니다.

console.log를 통해 콘솔에 로그를 기록하는 것은 에러 로그를 잃어버리기 쉽기 때문에 좋은 방법이 아닙니다.

만약 try/catch로 어떤 코드를 감쌌다면 그건 당신이 그 코드에 어떤 에러가 날지도 모르기 때문에 감싼 것이므로

그에 대한 계획이 있거나 어떠한 장치를 해야 합니다

BEFORE

try { functionThatMightThrow(); } catch (error) { console.log(error); }

AFTER

try { functionThatMightThrow(); } catch (error) { // 첫번째 방법은 console.error를 이용하는 것입니다. 이건 console.log보다 조금 더 알아채기 쉽습니다. console.error(error); // 다른 방법은 유저에게 알리는 방법입니다. notifyUserOfError(error); // 또 다른 방법은 서비스 자체에 에러를 기록하는 방법입니다. reportErrorToService(error); // 혹은 그 어떤 방법이 될 수 있습니다. }

예외에 의미를 제공하라

예외를 던질 때는 전후 상황을 충분히 덧붙인다.

그러면 오류가 발생한 원인과 위치를 찾기가 쉬워진다.

자바는 모든 예외에 호출 스택을 제공한다. 하지만 실패한 코드의 의도를 파악하려면 호출 스택만으로 부족하다.

오류 메시지에 정보를 담아 예외와 함께 던진다.

실패한 연산 이름과 실패 유형도 언급한다.

애플리케이션이 로깅 기능을 사용한다면 catch 블록에서 오류를 기록하도록 충분한 정보를 남겨준다.

null을 반환하지 마라

오류 처리를 논하는 장이라면 우리가 흔히 저지르는 바람에 오류를 유발하는 행위도 언급해야 한다고 생각한다.

그중 첫 째가 null을 반환하는 습관이다.

한 줄 건너 하나씩 null을 확인하는 코드로 가득한 애플리케이션을 지금까지 수도 없이 봤다.

public void registerItem(Item item) { if(item != null) { ItemRegistry registry = peristentStore.getItemRegistry(); if(registry != null) { Item existing = registry.getItem(item.getID()); if(existing.getBillingPeriod().hasRetailOwner()) { existing.register(item); } } } }

null을 반환하는 코드는 일거리를 늘릴 뿐만 아니라 호출자에게 문제를 떠넘긴다.

누구 하나라도 null 확인을 빼먹는다면 애플리케이션이 통제 불능에 빠질지도 모른다.

위 코드에서 persistentStore가 null인지 확인하는 과정이 빠져있다.

만약 persistentStore가 null이라면 NullPointerException이 발생하리라

위쪽 어디선가 NullPointerException을 잡을지도 아닐지도 모른다.

어느 쪽이든 나쁘다.

위 코드는 null 확인이 누락된 문제라 말하기 쉽다.

하지만 실상은 null 확인이 너무 많아 문제다.

메서드에서 null을 반환하고픈 유혹이 든다면 그 대신 예외를 던지거나 특수 사례 객체를 반환한다.

Promise가 실패된 것을 무시하지 마세요

BEFORE

getdata() .then(data => { functionThatMightThrow(data); }) .catch(error => { console.log(error); });

AFTER

getdata() .then(data => { functionThatMightThrow(data); }) .catch(error => { // 첫번째 방법은 console.error를 이용하는 것입니다. 이건 console.log보다 조금 더 알아채기 쉽습니다. console.error(error); // 다른 방법은 유저에게 알리는 방법입니다. notifyUserOfError(error); // 또 다른 방법은 서비스 자체에 에러를 기록하는 방법입니다. reportErrorToService(error); // 혹은 그 어떤 방법이 될 수 있습니다. });

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

이 둘은 상충하는 목표가 아니다.

오류 처리를 프로그램 논리와 분리해 독자적인 사안으로 고려하면

튼튼하고 깨끗한 코드를 작성할 수 있다.

from http://bang-jh.tistory.com/15 by ccl(A) rewrite - 2021-09-20 13:01:17