1. 소개, 코드 포매팅과 도구

hyuckhoon.ko·2022년 6월 29일
0

1. 클린 코드의 의미

"수십 년 동안 프로그래밍 언어라는 것은 인간의 아이디어를 컴퓨터에 전달하기 위해 사용하느느 언어라고 생각해왔다. 그러나 그건 틀린 생각이다. 이러한 생각은 진실이 아니라 진실의 일부이다. 프로그래밍 언어의 진정한 의미는 아이디어를 다른 개발자에게 전달하는 것이다."

여기에 클린 코드의 진정한 본질이 있다.
클린 코드인지 아닌지는 다른 엔지니어가 코드를 읽고 유지 관리할 수 있는지 여부에 달려 있다.


2. 클린 코드의 중요성

기술 부채: 나쁜 결정이나 적당한 타협의 결과로 생긴 소프트웨어 결함

코드는 지금 바꾸는 것보다 미래에 변경하는 것이 더 어렵기 때문에 부채다.
부채는 이자를 유발하기 때문이다. 기술 부채가 발생했다는 것은 내일은 코드를 수정하기가 더 어렵고 비싸며, 내일모레는 더더욱 비싸질 것이라는 뜻이다.

✅ 클린 코드에서 코드 포매팅의 역할

클린 코드란 PEP-8(Python Enhancement Proposal) 또는 프로젝트 가이드라인 같은 표준 지침을 따른 것을 의미할까?
대답은 No!

클린 코드는 코딩 표준, 포매팅, 린팅을 통한 코드 레이아웃 설정 그 이상의 것을 말한다. 더 나아가 품질 좋은 소프트웨어를 만들고, 유지 보수가 쉬게 하고, 기술 부채를 피할 수 있어야 한다.

요약하면 클린 코드는 PEP-8이나 코딩 표준과 관련이 없다고 말할 수 있다.
하지만, 우리는 다수의 개발자와 함께 일한다. 같은 회사의 프로젝트에서 서로 다른 스타일의 코드가 지속적으로 통합되는 것은 효율적이지 않다.
위에서 언급했듯이, 프로그래밍은 아이디어를 다른 개발자에게 전달하는 것이라 했다.
따라서, 공통 포맷팅의 준수는 (클린 코드 개념과는 별개로) 작업 효율화를 위해 중요하다.

✅ 프로젝트 코딩 스타일 가이드 준수

코딩 가이드라인은 품질 표준을 지키기 위해 프로젝트에서 따라야만 하는 최소한의 요구사항이다. 만약 개발팀의 모든 멤버가 표준화된 구조를 사용한다면 훨씬 익숙한 코드를 작성하게 될 것이다. 그 결과 신속하게 패턴을 파악할 수 있으며 (두 번째 볼 때는 더욱 쉽게) 이러한 패턴을 염두에 두고 있다면 오류를 감지하는 것이 훨씬 쉽다. 예를 들어 평소 패턴과 비교해보면 오류가 있는 부분에서 뭔가 이상한 점을 느낄 수 있을 것이다. 이 부분을 자세히 살펴보는 것만으로도 실수를 발견할 확률이 높아진다.

파이썬이 따라야 하는 코딩 스타일은 PEP-8이다. 다른 표준을 고안하기 보다는 순수 PEP-8을 사용하든 PEP-8을 확장해서 사용하는 것을 권장한다. PEP-8은 이미 파이썬 언어만의 특수성을 고려하여 작성됐고, 파이썬 핵심 개발자가 만든만큼 이보다 좋은 표준을 찾기가 어렵기 때문이다.

검색 효율성(Grepability)

# location 파라미터에 값을 할당하는 위치를 찾을 때
$ grep -nr "location=" .
./core.py:13: location=current_location,

# location 변수에 값을 할당하는 위치를 찾을 때
$ grep -nr "location =" .
./core.py:10: current_location = get_location()

일관성

코드가 일정한 포맷을 가지면 훨씬 쉽게 읽을 수 있다.

코드 품질

구조화 된 코드는 버그와 실수를 쉽게 찾을 수 있다. 이 외에도 코드 품질 도구를 통해 잠재적인 버그를 찾을 수도 있다. 정적 분석 도구로 한 줄당 버그의 개수를 줄이는데 도움이 된다..


3. Docstring과 어노테이션

훌륭한 코드는 그 자체로 자명하지만 문서화 또한 잘 되어 있어야 한다.
주석(Comment)은 가급적 피해야 한다. 

파이썬은 동적으로 타입이 결정된다. 
함수나 메서드를 거치면서 변수나 객체의 값이 무엇인지 알기 어렵게 된다.
따라서, 어노테이션을 통해 이러한 정보를 명시하면 다른 개발자가 쉽게
이해할 수가 있다.
 초반에 언급한 내용을 다시 상기시켜보자.
'프로그래밍 언어의 진정한 의미는 아이디어를 다른 개발자에게 전달하는 것이다'이다.

Docstring

쉽게 말해 소스 코드에 포함된 문서(documentation)라고 말할 수 있다.
주석을 다는 것이 아니다. 코드의 특정 컴포넌트(모듈, 클래스, 메서드 또는 함수)에 대한 문서화이다. 가능한 많은 docstring을 추가하는 것이 좋다.

>>> def my_function():
...     """임의의 함수"""
...     return None
...
>>> my_function.__doc__
'임의의 함수'

docstring은 코드에서 분리되거나 독립된 것이 아니다.
코드의 일부가 되어 접근할 수 있어야 한다.
위와 같이 객체에 docstring이 정의되어 있으면 __doc__ 속성으로 접근할 수 있다.

어노테이션

어노테이션은 docstring을 대체하는 것일까?

파이썬에 어노테이션 개념이 도입되기 전에 docstring으로 함수의 파라미터나 속성의 타입을 문서화 했었기에 이러한 질문이 생기기 됐다.
결론부터 말하자면 어노테이션과 docstring은 상호 보완적인 개념이다.

아래의 예시를 살펴보자.

def data_from_response(respnose: dict) -> dict:
    if response["status"] != 200:
        raise ValueError
    return {"data": response["payload"]}

이 함수는 사전 형태의 파라미터를 받고 사전 형태의 값을 반환한다. 파라미터의 status 키의 값이 200이 아닌 경우 예외가 발생한다.
그러나 상세한 내용은 알 수가 없다.
예를 들어, response 인스턴스는 어떤 형태일까? 또한, 마지막에 리턴하는 값은 어떤 형태일까?

그렇다면 docstring으로 어떻게 설명해야 할까

def data_from_response(response: dict) -> dict:
    """response에 문제가 없다면 response의 payload 반환

    - response 예시::
    {
        "status": 200, # <int>
        "timestamp" : "....", # 현재 시간의 ISO 포맷 문자열
        "payload": { ... } # 반환될 사전 데이터
    }

    - 반환 사전 값 예시::
    {"data": {...}}

    - 발생 가능한 예외::
    - HTTP status가 200이 아닌 경우 ValueError 발생
    """
    if response["status"] != 200:
        raise ValueError
    return {"data": response["payload"]}

이제 이 함수에 입력값과 반환값의 형태를 이해할 수 있다.
문서화 효과 뿐만 아니라 유닛 테스트 작성/이해/수정 작업에도 도움이 된다. 어떤 입력값을 생성해야 하는지, 어떻게 테스트의 성공, 실패를 판단할 수 있을지 알 수 있다.

반면, docstring을 사용하면 코드가 좀 더 길어지게 되고, 효과적인 문서가 된다면 코드는 더 길어질 수 밖에 없다.

기본 품질 향상을 위한 도구 설정

Mypy를 사용한 타입 힌팅
Pylint를 사용한 코드 검사
자동 검사 설정

Black이라는 도구를 도입하여 자동으로 코드를 포맷팅할 수도 있다. 일관되게 엄격한 기준으로 포맷팅하기에 항상 같은 결과를 출력한다.
예를 들어, Black은 문자열에 항상 쌍따옴표를 사용한다. 엄격하게 들릴 수 있겠지만, 개발자 간 코드의 차이를 줄이는 최선의 방법이기도 하다.


4. 요약

중요한 것은 클린 코드가 코드의 구조나 레이아웃보다 훨씬 중요한 것임을 이해했다는 점이다.

0개의 댓글