책 읽다가 코딩하다 죽을래

개발자 취업 필수 개념 1주차 개발일지(의미 있는 이름, 추상화, 예외, 리팩토링) 본문

GD프로젝트/개발일지

개발자 취업 필수 개념 1주차 개발일지(의미 있는 이름, 추상화, 예외, 리팩토링)

ABlue 2021. 8. 19. 14:49

 

 

개발자 취업 필수 개념 1주 차가 시작되었다.

 

 

목차

0. 클린 코드의 목적

1. 의미 있는 이름

2. 추상화

3. 예외

4. 리팩토링

 

 

 


0. 클린 코드의 목적


더보기

 

 

깨끗한 코드는 단순하고 직접적이다. 깨끗한 코드는 잘 쓴 문장처럼 읽힌다. 깨끗한 코드는 결코 설계자의 의도를 숨기지 않는다. 오히려 명쾌한 추상화와 단순한 제어문으로 가득하다.

- Object Oriented Analysis and Design with Application의 저자 그래디 부치-

 

항상 코드를 깨끗한 상태로 유지해야 합니다.
왜냐면, 깨끗한 코드가 있어야 깨끗한 코드를 만들 수 있습니다.
기존에 깨끗한 코드가 있어야 빠르게 코드를 이해하고 깨끗한 코드를 작성할 수 있기 때문입니다.
빨리 가기 위한 단 하나의 방법은 "깨끗한 코드를 항상 유지하는 것"입니다.

 

 

 

 


1. 의미 있는 이름


더보기

 

 

 변수 이름을 짓는 것은 프로그래머에 있어서 대단히 중요한 문제이다.

한 번 지은 이름이 10번이고 수십 번이고 쓰이기 때문이다.

 

mca = 3

 

다음 코드를 보자

무엇을 설명하는 것 같아 보일까?

 

만약 제가 이런 코드를 작성한다면, 6개월 후에 mca라는 단어를 보고 원래 의미를 떠올릴 수 있을까?

하물며, 이 코드를 본 다른 개발자는 mca라는 단어를 구글링 해보거나 당황할 것이다.

 

 

# my cat age
mca = 3

 

그러면은 주석으로 변수를 설명을 해볼까?

주석으로 변수를 설명하는 것은 절대 해서는 안 되는 행동이다!

차라리 변수가 길어질지라고 my_cat_age라고 명확하게 변경하는 것이 좋다.

 

다시 한번 명심하자

주석으로 변수를 설명하는 것은 아니 되며,

 

변수 이름은 영어를 배운 초등학생이나 1년 후에 내가 다시 봐도 이해할 수 있도록 짜야한다

 

다음 예시를 보자

 

def get_them(the_list):
    result = [] 
    for x in the_list:
        if x.p1 > 19:
            result.append(x) 
    
    return result

 

 이 코드가 무엇을 의미하는 코드인지는 아무도 알 수 없다.

 

당황스럽게도 이 함수는 나이를 입력해서 배열(the list)에 담은 후

 그중 나이가 19 이상인 사람들을 반환하는 함수입니다.

 

실제 코드는 정상적으로 그 기능을 완벽히 수행한다 해도

변수 이름을 이해하기 힘들게 지어놓는다면

가까운 미래에 코드를 알아보지 못할뿐더러 더 이상 새로운 코드를 추가하거나 유지 보수하기 어렵게 된다.

 

 

저 코드를 실제 동작하지 않더라도 이해할 수 있게 만들려면

의미 있는 변수 이름 지어야 합니다.

 

 

def get_adults(people):
    adults = [] 
    for person in people:
        if person.age > 19:
            adults.append(person)
    return adults

 

아까보다는 되게 많이 좋아졌다.

그런데 나라마다 성인의 기준은 다르다.

성인의 기준을 상수로 만들자

 

 

ADULT_AGE = 19

def get_adults(people):
    adults = []
    for person in people:
        if person.age > ADULT_AGE:
            adults.append(person)
    return adults

 

이런 식이면 처음보다 훨씬 코드의 의도를 명확히 파악할 수 있다

 

 

 

 


2. 추상화


더보기

 

이것의 구조는 접점(接點)과 그것을 동작시키는 기구로 되어 있다. 손으로 동작시키는 간단한 것에서 전자력(電磁⼒)에 의하여 작동되는 대형까지 매우 많은 방식과 구조가 있다. 전력용에서는 개폐에 수반돼 는 불꽃이나 열에 의한 접점의 소손(燒損)을 피하기 위하여 빨리 끊는 기구를 설치한 것이 있으며, 대형 에는 소호 장치(消弧裝置)를 붙이기도 한다. 신호회로에는 다접점(多接點)의 이것이 사용되며 또 전기 신호로 동작하는 계전기(릴레이) ·진공관 ·반도체 등을 이용한 이것은 논리회로로서 이용된다. 이와 같이 전압 ·전류 ·사용목적 등에 따라 많은 종류가 있다.

 

이것은 무엇일까요?

마치 수능 국어영역 문제를 푸는 듯 문제를 읽으면 읽을수록 머리는 복잡해집니다.

 

 이것은 스위치였습니다.

 

우리는 사람과 대화할 때 스위치를 언급하려면 스위치를 말한다.

"접점과 그것을 동작시키는 ... 논리회로로서 이용되는 그것!" 이라고 말하진 않는다.

 

복잡한 구조, 원리, 설명을 간추리고 핵심만 말하는 것을 추상화라 한다.

 

컴퓨터 과학에서 추상화(abstraction) 또한 의미가 같다.

추상화 : 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것을 말한다.

 

목적을 명확히 하여 복잡한 것은 숨기고 핵심만 드러내는 것이 추상화의 목적입니다.

 

란초 형님의 말씀은 프로그래밍에도 통하는 것이었다...!

 

다시 말해서,
추상화의 수준이 높다라는 것은 디테일을 많이 숨겼다는 것이고

추상화의 수준이 낮다라는 것은 디테일이 많이 드러났다고 볼 수 있습니다.

 

 

예로 들어보자면 다음과 같습니다.

 

 

1.
추상화 수준이 높다 : 김밥 준비하겠습니다.
추상화 수준이 낮다 : 김밥을 말기 위해서 여러 재료들을 준비하고 밥에 밑간을 하겠습니다.
2.
추상화 수준이 높다 : 나 오늘 프로그래밍 공부했어

추상화 수준이 낮다 : 나 오늘 Python 반복문에 대해 공부했어.
3.
추상화 수준이 높다 : 스위치 누른다.
추상화 수준이 낮다 : 접점(接點)을 이용하여 전자적 충격을 통해 논리회로로 이용한다.

 

 

프로그래밍의 함수에도 추상화의 원리가 적용된다.

 

 다음 예시를 보자

import time

def going_to_work(person, bus):
    if not time.localtime() < time.localtime("07:00"):
        return
    
    person.wake_up_from_the_bed() 
    person.go_to_bathroom() 
    person.turn_on_the_water() 
    person.wash_face() 
    if not person.already_shower_yesterday():
        person.take_a_shower()
    
    if person.gender == "woman":
        person.pull_on("클로니더블자켓") 
        if person.like("화장"):
            person.make_up() 
    
    elif person.gender == "man":
        person.pull_on("맨투맨") 
        person.shave()

    person.walk_to(person.near_bus_stop) 
    
    while bus.location is person.near_bus_stop:
        person.wait()
    
    person.ride(bus) 
    if not person.type == "DISABLED" and not person.type == "NATIONAL_MERIT":
        person.pay_fee(bus)
    
    while bus.location is person.company_near_bus_stop:
        person.wait()
    
    person.walk_to(person.company)

 

코드를 다 읽어보면 우리가 아침마다 하는 일이 코드로 적혀있다는 것을 알 수 있다.

하지만 읽는 내내 불편하다는 것을 느끼지 못했는가?

뭔가 같은 역할을 하는 것들은 하나로 합쳐서 정리하고 싶은 욕구가 없었는가? 

 

같은 역할을 하는 것들은 하나로 합치기 위해 이제 코드 하나하나마다 어떤 역할을 하는지 파헤쳐보자

 

import time

def going_to_work(person, bus):
    if not time.localtime() < time.localtime("07:00"):  # 출근 시각이 아니라면 멈춘다.
        return

    person.wake_up_from_the_bed() # 침대에서 일어난다 -> 일어나서 씻는다
    person.go_to_bathroom() # 화장실에 간다 -> 일어나서 씻는다
    person.turn_on_the_water() # 물을 켠다 -> 일어나서 씻는다
    person.wash_face() # 얼굴을 씻는다 -> 일어나서 씻는다
    if not person.already_shower_yesterday(): # 어제 샤워 안했다면
        person.take_a_shower() # 샤워를 한다 -> 일어나서 씻는다

    if person.gender == "woman": # 여자라면
        person.pull_on("클로니더블자켓") # 자켓을 입는다 -> 외출 준비를 한다
        if person.like("화장"): # 화장을 좋아하면
            person.make_up() # 화장을 한다 -> 외출 준비를 한다

    elif person.gender == "man": # 남자라면
        person.pull_on("맨투맨") # 맨투맨을 입는다 -> 외출 준비를 한다
        person.shave() # 면도를 한다 -> 외출 준비를 한다

    person.walk_to(person.near_bus_stop) # 버스 정류장으로 걸어간다 -> 버스 타서 회사로 간다

    while bus.location is person.near_bus_stop: # 버스가 올 때까지 -> 버스 타서 회사로 간다
        person.wait() # 기다린다 -> 버스 타서 회사로 간다

    person.ride(bus) # 버스 탄다 -> 버스 타서 회사로 간다
    if not person.type == "DISABLED" and not person.type == "NATIONAL_MERIT": # 장애인이거나 국가유공자라면
        person.pay_fee(bus) # 버스비를 낸다 -> 버스 타서 회사로 간다

    while bus.location is person.company_near_bus_stop: # 버스의 위치가 회사일 때까지 -> 버스 타서 회사로 간다
        person.wait() # 기다린다 -> 버스 타서 회사로 간다

    person.walk_to(person.company) # 회사로 걸어간다 -> 버스 타서 회사로 간다

 

 

이렇게 코드가 어떤 역할을 하는지 추려내는 것이 추상화 수준을 높이는 것이다.

 

이제 같은 역할을 하는 것은

일어나서 씻는다. -> get_up_and_wash()

외출 준비를 한다. -> get_ready_to_go_out()

버스 타서 회사로 간다. -> take_the_bus_and_go_to_the_company()

 

로 합쳐보도록 하겠습니다.

 

 

import time


def going_to_work(person, bus):
    if not time.localtime() < time.localtime("07:00"):
        return

    get_up_wash(person)
    get_ready_to_go_out(person)
    take_the_bus_and_go_to_the_company(bus, person)


def get_up_wash(person):
    person.wake_up_from_the_bed()
    person.go_to_bathroom()
    person.turn_on_the_water()
    person.wash_face()
    if not person.already_shower_yesterday():
        person.take_a_shower()


def get_ready_to_go_out(person):
    if person.gender == "woman":
        person.pull_on("클로니더블자켓")
        if person.like("화장"):
            person.make_up()
    else:
        person.pull_on("맨투맨")
        person.shave()


def take_the_bus_and_go_to_the_company(bus, person):
    person.walk_to(person.near_bus_stop)
    while bus.location is person.near_bus_stop:
        person.wait()
    person.ride(bus)
    if not person.type == "DISABLED" and not person.type == "NATIONAL_MERIT":
        person.pay_fee(bus)
    while bus.location is person.company_near_bus_stop:
        person.wait()
    person.walk_to(person.company)

 

어떠한가?

맨 처음 코드보다 더 보기 쉬워졌다.

또한 어떤 부분이 잘못되면 그 부분이 어디인지 찾아내기도 쉬워졌다.

 

저럴 거면 오히려 함수만 여러 번 호출되어 성능이 떨어지는 거 아닌가요?

 

겨우 함수 몇 번 아니 수백 번 호출한다 해서 성능이 느려지지 않는다.

왜냐하면 우리는 그만큼 성능이 우수한 인터프린터, 스크립트를 사용하기 때문이다.

오히려 저렇게 추상화하여 함수를 나눠야지 더욱 좋은 코드를 짜게 돼서

결국엔 성능과 유지보수 두 마리 토끼를 잡는 것이다.

 

 

 

 


3. 예외


더보기

 

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

 

 

 

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("우유가 없습니다")

 

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

 

 

 

 


4. 리팩토링


더보기

 

리팩토링은 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법으로, 소프트웨어 시스템을 변경하는 프로세스이다. 소프트웨어를 보다 이해하기 쉽고, 수정하기 쉽도록 만드는 것, 겉으로 보이는 소프트웨어의 기능을 변경하지 않는 것이다.

 

현업에서의 웹 개발자는 완성된 프로젝트란 없다.

프로젝트가 완성되면 요구사항이 생기고

그 요구사항을 완료하면 또 다른 요구사항이 생긴다.

 

우리는 요구사항을 구현해주기 위해서는 코드를 한줄한줄 읽어보면서 이해해야 하고

다른 변수들에 부수효과가 일어나지 않을지 걱정해야 한다.

 

 

부수효과 : 한 곳의 문제를 해결하면 다른 곳에서 문제가 일어난다

 

리팩토링의 첫 번째 단계는 테스트이다 

 

 현재 작동하는 코드들이 정상적으로 작동하는 것을 유지하되,

내부적으로 코드를 개선해 이해하고 수정하기 쉽게 만드는 작업을 리팩토링이니까말이다.

 

 

리팩토링을 실습으로 배워보자

여기 간단한 가감산 기능을 하는 함수가 있다.

 

 

def calculator(number1, number2, operator):
    if operator == '+':
        return number1 + number2
    elif operator == '-':
        return number1 - number2

assert calculator(3, 5, '+') == 8
assert calculator(10, 4, '-') == 6

 

파이썬의 assert를 활용해 테스트를 해보려 한다.

3+5, 10-4 해당 연산의 결과가 잘 나오면 그냥 넘어가고 아니면 오류를 일으켜 테스트를 하는 것이다.

이제 우리는 여기서 기능을 추가하거나 코드를 수정할 때마다 assert를 돌려서 원래의 기능이 잘 수행되는지 보면 된다.

그것이 리팩토링의 목적이기 때문이다.

 

 

리팩토링의 두 번째 단계는 함수 쪼개기 이다.

 

 다음은 가계부를 작성하는 코드이다.

spending = {'installment_savings':5000, 'telecommunication_fee':500,'gas_fee':1000 }
income = {'salary':10000, 'stock_gains':3000}


def calculator(number1, number2, operator):
    if operator == '+':
        return number1 + number2
    elif operator == '-':
        return number1 - number2


def my_housekeeping_book():
    previous_month_money = 10000
    current_my_money = previous_month_money

    for cost in income.values():
        current_my_money = calculator(current_my_money, cost, '+')

    for cost in spending.values():
        current_my_money = calculator(current_my_money, cost, '-')

    print(current_my_money)
	return current_my_money

my_housekeeping_book()
assert calculator(3, 5, '+') == 8
assert calculator(10, 4, '-') == 6
assert my_housekeeping_book() == 16500

 

물론 이 코드는 나름 정리가 잘되어있고 긴 편은 아니다.

여러분이 갑자기 엄청 긴 코드를 보면 블로그 창 닫을까 봐 일부러 짧은 코드를 준비해보았다.

 

그래도 리팩토링을 실습하기 위해 한번 위의 코드를 개선해보자

리팩토링의 두 번째 단계 함수 쪼개기의 원칙은

 

 

1. 추상화 수준을 높여 같은 일을 하는 것들을 추출하라

2. 추출한 것들을 따로 함수로 만들어 함수는 최대한 작게 만들어라

 

 

spending = {'installment_savings':5000, 'telecommunication_fee':500,'gas_fee':1000 }
income = {'salary':10000, 'stock_gains':3000}


def calculator(number1, number2, operator):
    if operator == '+':
        return number1 + number2
    elif operator == '-':
        return number1 - number2


def my_housekeeping_book():
    previous_month_money = 10000 # 전월 갖고있는 내 자산 -> 자산 확인
    current_my_money = previous_month_money # 전월 갖고있는 내 자산을 현재 자산으로 대입 -> 자산 확인

    for cost in income.values(): # 현재 자산에 수입을 합쳐 계산
        current_my_money = calculator(current_my_money, cost, '+') # 현재 자산에 수입을 합쳐 계산

    for cost in spending.values(): # 현재 자산에 지출을 빼 계산
        current_my_money = calculator(current_my_money, cost, '-') # 현재 자산에 지출을 빼 계산

    print(current_my_money) # 결과 출력
    return current_my_money

my_housekeeping_book()
assert calculator(3, 5, '+') == 8
assert calculator(10, 4, '-') == 6
assert my_housekeeping_book() == 16500

 

같은 역할을 하는 코드가 보이지 않은가?

현재 자산에 수입을 합쳐 계산 -> income_calculation()

현재 자산에 지출을 빼 계산 -> spending_calculation()

 

이런 식으로 다시 묶어주자  

 

 

 

파이썬에선 어떤 코드들을 함수 밖으로 빼내어 새로운 함수를 만들고 싶을 때

해당 코드를 드래그한 다음 우클릭 -> Refactor -> Extract Method를 클릭한 후

 

 

 

나오는 모달 창에 원하는 함수 이름을 짓고 ok를 눌러주면

 

 

 

이렇게 함수 밖으로 빼주고 원래 함수에도 형식에 잘 맞춰 변환해준다.

spending_calculation() 함수도 이렇게 변환해주면

 

spending = {'installment_savings':5000, 'telecommunication_fee':500,'gas_fee':1000 }
income = {'salary':10000, 'stock_gains':3000}


def calculator(number1, number2, operator):
    if operator == '+':
        return number1 + number2
    elif operator == '-':
        return number1 - number2


def my_housekeeping_book():
    previous_month_money = 10000 # 전월 갖고있는 내 자산 -> 자산 확인
    current_my_money = previous_month_money # 전월 갖고있는 내 자산을 현재 자산으로 대입 -> 자산 확인

    current_my_money = income_calculation(current_my_money)
    current_my_money = spending_calculation(current_my_money)

    print(current_my_money) # 결과 출력
    return current_my_money


def spending_calculation(current_my_money):
    for cost in spending.values():  # 현재 자산에 지출을 빼 계산
        current_my_money = calculator(current_my_money, cost, '-')  # 현재 자산에 지출을 빼 계산
    return current_my_money


def income_calculation(current_my_money):
    for cost in income.values():  # 현재 자산에 수입을 합쳐 계산
        current_my_money = calculator(current_my_money, cost, '+')  # 현재 자산에 수입을 합쳐 계산
    return current_my_money


my_housekeeping_book()
assert calculator(3, 5, '+') == 8
assert calculator(10, 4, '-') == 6
assert my_housekeeping_book() == 16500

 

이렇게 my_houseKeeping_book 함수가 더 클린 해지는 것이다.

또 이렇게 코드를 클린 하게 변하게 했더라면 assert를 활용해 테스트도 완벽히 통과하는지도 봐야 한다.

 

 

또한 리팩토링의 3단계는 임시 변수 제거하기이다.

 

 

 눈치챈 사람은 이미 눈치챘겠지만

여기 previous_month_money는 단 한 번만 사용되고 사용되지 않는다.

previous_month_money는 임시 변수이다. 

 

임시 변수란 값이 한번만 대입되고 변경되지 않는 변수이다.

 

 

임시 변수는 과감히 지워주자

 

또한 이렇게 지워준 후에도 테스트하는 것을 잊지 말자

내가 저 임시 변수를 지워줌으로써 다른 곳에서 부수 효과가 일어날 수 있기 때문이다.

 

spending = {'installment_savings':5000, 'telecommunication_fee':500,'gas_fee':1000 }
income = {'salary':10000, 'stock_gains':3000}


def calculator(number1, number2, operator):
    if operator == '+':
        return number1 + number2
    elif operator == '-':
        return number1 - number2


def my_housekeeping_book():
    current_my_money = 10000 # 전월 갖고있는 내 자산을 현재 자산으로 대입 -> 자산 확인

    current_my_money = income_calculation(current_my_money)
    current_my_money = spending_calculation(current_my_money)

    print(current_my_money) # 결과 출력
    return current_my_money


def spending_calculation(current_my_money):
    for cost in spending.values():  # 현재 자산에 지출을 빼 계산
        current_my_money = calculator(current_my_money, cost, '-')  # 현재 자산에 지출을 빼 계산
    return current_my_money


def income_calculation(current_my_money):
    for cost in income.values():  # 현재 자산에 수입을 합쳐 계산
        current_my_money = calculator(current_my_money, cost, '+')  # 현재 자산에 수입을 합쳐 계산
    return current_my_money


my_housekeeping_book()
assert calculator(3, 5, '+') == 8
assert calculator(10, 4, '-') == 6
assert my_housekeeping_book() == 16500

 

이것이 총 리팩토링의 결과이다.

my_housekeeping_book 함수를 보자

파이썬을 모르더라도

코딩을 모르더라도

어떤 순서를 거쳐 내 현재 자산이 나오는지 알 수 있게 된다.

 

 

그것이 클린 코드이다. 코딩이 뭔지 모르는 사람이라도 쉽게 읽혀야 한다. 

 

리팩토링 정리.

 

 

1. 테스트 케이스를 잘 짜 놓는다.

2. 추상화 수준을 높여 함수를 쪼갠다

3. 임시 변수를 제거한다