책 읽다가 코딩하다 죽을래

클린코드 강의 2. 추상화 본문

코딩/클린코드

클린코드 강의 2. 추상화

ABlue 2021. 9. 21. 15:13

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

 

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

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

클린코드 강의 3. 예외[클릭]

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

 

 

클린코드의 두 번 째 원칙 추상화입니다!

 

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

 

이것은 무엇일까요?

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

 

 이것은 스위치였습니다.

 

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

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

 

📚 추상화란?

 

 

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

 

 

컴퓨터 과학에서 추상화(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)

 

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

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

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

이때 필요한 것이 바로 추상화입니다.

 

📚 추상화하는 방법

추상화하는 과정은 다음과 같습니다.

 

1. 코드 한 줄마다 어떤 역할을 하는지 적기

2. 같은 역할을 하는 것들을 묶기

3. 같은 역할을 하는 코드들을 따로 빼서 함수 하나에 묶기

 

 

1. 코드 한 줄 마다 어떤 역할을 하는지 적기

 

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

 

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) # 회사로 걸어간다 -> 버스 타서 회사로 간다

 

 

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

 

2. 같은 역할을 하는 것들을 묶기 

 

이제 같은 역할을 하는 것은

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

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

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

 

로 묶을 수가 있습니다.

이제 같은 역할을 하는 것끼리 빼서 

 

3. 같은 역할을 하는 코드들을 따로 빼서 함수 하나에 묶기

 

 

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)

 

어떤가요?

맨 처음 코드보다 더 보기 쉬워졌지 않나요?

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

 

 

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

 

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

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

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

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

 

📚 추상화와 함수의 기본 원칙

 

또한 여기서 설명드리지 못한 부분이 있는데

추상화라는 것은 함수의 기본 원칙인

'함수는 단 한가지의 동작만 해야 한다'

와 맞아 떨어집니다.

 

함수는 여러 동작을 동시에 수행하면 다른 함수, 모듈과의 종속성이 더욱 커져 유지보수를 힘들게 합니다.

그래서 함수 안에 여러 동작이 포함되어 있으면 추상화를 통해 여러 개의 함수로 나뉘어야 합니다.

그래야 나중에 기능이 첨삭될 때 그 기능이 포함되는 함수만 적절히 고치기 쉬워집니다!