책 읽다가 코딩하다 죽을래

클린코드 강의 3. 예외 본문

코딩/클린코드

클린코드 강의 3. 예외

ABlue 2021. 9. 21. 15:26

이 강의는 시리즈 별로 되어있습니다.

 

클린코드 강의 0. 클린코드의 목적[클릭]

클린코드 강의 1. 의미 있는 이름[클릭]

클린코드 강의 2. 추상화[클릭]

클린코드 강의 4. 리팩토링[클릭]

 

 

 

클린코드의 세 번째 원칙 예외입니다!

 

예외를 제대로 설정하지 않으면 이렇게 됩니다

 

📖 예외처리를 해야 하는 이유

 

(코드는 파이썬이지만 파이썬은 몰라도 다른 언어의 기본 배경지식을 이용해 이해할 수 있다면 상관없습니다.)

def buy_foods_for_mom():
    go_to_butcher_shop()
    buy_pork()
    go_to_supermarket()
    buy_milk()

 

위 코드를 보자

그냥 봐서는 정상적으로 동작할 것 같지만

만약 정육점에 고기가 없었다면 어떻게 될까요?

그렇다면 슈퍼 마켓은커녕 집에는 돌아오지 못하고

영원히 정육점에 고기가 생길 때까지 가만히 있게 되는 것입니다.

 

def buy_foods_for_mom():
    go_to_butcher_shop()

    if not fork:
        return go_home()

    buy_pork()
    go_to_supermarket()
    if not milk:
        return go_home()
    buy_milk()

 

이런 식으로 고기나 우유가 없을 경우에는 집으로 간다는 예외처리를 해야 한다.

 

 이처럼 실생활에 발생하는 수많은 에러처럼, 프로그램도 마찬가지로 실행하기 전까지는 예상하지 못하는 수많은 에러들이 있다. 혹은 에러로도 나타나지 않는 원치 않은 동작이 일어날 수도 있습니다.

 

유저가 잘못된 입력을 보내는 경우, 외부 API에서 장애가 나는 경우도 있고
존재해야 하는 파일의 경로가 변경되어서 에러가 날 수도 있습니다.

 

우리는 가능한 많은 예외를 발견하고 잘 처리해야 더 좋은 프로그램을 만들 수 있습니다.

 

def buy_foods_for_mom():
    try:
        go_to_butcher_shop() 
        buy_pork() # ! pork 가 없습니다!!
        go_to_supermarket() 
        buy_milk()
    except:
        print(e) 
    finally:
        go_to_home()

 

 이런 식으로 언어마다 try~catch, try~except 등등으로 예외처리 기능을 지원합니다.

 

그럼 여기서 생각나는 게

 

❓ 어떤 에러 처리에 따라 if문으로 오류코드를 return 해주는 거랑 예외를 쓰는 거랑 같은 게 아닌가?

 

라는 질문을 생각할 수 있다

 

몰론 전자나 후자 모두 에러 처리를 해주는 건 동일하지만

우리는 코드 상에서 최대한 간단하게 보여줘야 한다.

 

아래의 상황을 보자 에러코드를 상 수화시키고 어떤 특정 장소에 특정 물품이 있는지 확인하는

함수를 만들어 특정 장소에 갈 때마다 그 함수를 실행하는 코드이다.

 

THERE_IS_HAVE_ITEM = 0
THERE_IS_NO_MEAT = 1
THERE_IS_NO_MILK = 2

def buy_foods_for_mom():
    go_to_butcher_shop()
    if item_inspection('fork',buthcer_shop) == THERE_IS_NO_MEAT:
        return go_home()
    buy_pork()
    go_to_supermarket()
    if item_inspection('milk', supermarket) == THERE_IS_NO_MILK:
        return go_home()
    buy_milk()

def item_inspection(item, place):
    if item not in place:
        if item == 'fork':
            return THERE_IS_NO_MEAT
        elif item == 'milk':
            return THERE_IS_NO_MILK

    return THERE_IS_HAVE_ITEM

 

이 코드를 보시면 이미 item_inspection 함수에서 에러를 처리했는데도 불구하고

buy_foods_for_mom에서도 에러에 대한 로직을 처리해야 한다.

 

즉 에러코드가 의미가 없어진 것이다.

 

다음은 예외 구문을 사용한 코드이다.

 

class ThereIsNoMeat(Exception):
    pass


class ThereIsNoMilk(Exception):
    pass


def buy_foods_for_mom():
    try:
        go_to_butcher_shop()
        item_inspection('fork', buthcer_shop)
        buy_pork()
        item_inspection('milk', buthcer_shop)
        go_to_supermarket()
        buy_milk()
    except ThereIsNoMeat as e:
        go_home()
    except ThereIsNoMilk as e:
        go_home()


def item_inspection(item, place):
    if item not in place:
        if item == 'fork':
            raise ThereIsNoMeat("고기가 없습니다")
        elif item == 'milk':
            raise ThereIsNoMilk("우유가 없습니다")

 

이런 식으로 예외를 종류별로 처리하면 더 좋은 클린 코드가 나올 가능성이 크다.

 

📖 예외처리의 의의

 

예외처리는 많은 의미를 갖는다.

예외처리를 한 코드를 남에게 보여주면 남들은

'아 여기서 문제가 일어날수도 있는 코드구나.'

'이런 문제가 생기면 이렇게 대처하는구나.'

도 굳이 코드를 동작해보지 않아도 알 수 있게 됩니다.

 

또한 자신이 개발할 때에도 어떤 문제가 생기면 바로 어디서 문제가 일어났고 어떤 문제인지 바로 알아내어 개발 시간이 줄어든다는 것도 있지만 자신이 짠 코드가 남에게는 어떻게 쉽게 보이게 되는가도 생각해서 예외처리 코드를 짜는 것이 좋다.