Programming Language/Python

[Python Clean Code] 1. 코드 포매팅과 도구

HJChung 2021. 5. 20. 09:34

※ 본 포스트는 마리아노 아냐야의 <파이썬 클린 코드> 을 참고하여 작성하였습니다.

1. 클린 코드의 의미

  • 프로그래밍 언어의 진정한 의미는 아이디어를 다른 개발자에게 제공하는데 있다.
  • 그러므로 클린코드인지 아닌지는 다른 엔지니어가 코드를 읽고 유지 관리할 수 있는지 여부에 달려 있다.

그래서 이 학습의 목표는 '파이썬의 주요 개념을 이해하고, 훌륭한 코드와 좋은아키텍쳐의 특징을 식별하여 나(팀)만의 파이썬 클린 코드의 정의를 하는 것' 이다.

2. 코드 포메팅

PEP란 Python Enhancemennt Proposal의 약자로 파이썬 개선을 위한 제안서를 의미한다. 각 제안서는 곡유한 번호르 ㄹ갖게 되는데 PEP 8번 Style Guid for Python Code에서 코딩 컨벤션에 대한 내용을 다룬다.
클린 코드는 단순히 PEP 8과 같은 표준 지침에 따라 코드를 포매팅하고 구조화하는 것보다 더 나아가
'품질 좋은 SW를 개발하고, 견고하고 유지 보수가 쉬운 시스템을 만들고, 기술 부채를 회피'하는 것을 의미한다. 그러나 PEP8과 같은 어떤 기준을 가지고 코드를 올바르게 포매팅하는 것은 작업을 '효율화'하기 위해서 중요하다.

3. 파이썬 코드 안에 직접 문서화를 하는 방법 - Docstring과 어노테이션

1) Docstring

코드 문서화와 주석 추가는 다르다!
Docstring은 주석이 아니라 코드의 특정 컴포넌트(모듈, 클래스, 메서드, 함수)에 대한 문서화이다.
Doctring은 동적 타이핑을 하는 python을 사용하면서 정확한 타입 사용 등에 대해서 설명을 남겨놓는데 유용하다.

def my_func():
    """ this is Docstring"""
    return None

my_func.__doc__
'this is Docstring'

2) 어노테이션

어노테이션의 아이디어는 코드 사용자에게 함수 인자로 어떤 값이 와야 하는지 '힌트'를 주고, type hinting(: 코드 전체에 올바른 타입이 사용되었는지를 확인하고 호환되지 않는 타입이 발견되었을 때 사용자에게 힌트를 주는 것)을 활성화한다. 즉, 어노테이션을 사용해 변수와 함수 반환값에 대한 예상 타입을 지정할 수 있다. ('지정'인 것이지 파이썬이 타입을 검사하거나 강제하지는 않음)

class Point:
    def __init__(self, lat, long):
        self.lat = lat
        self.long = long

def locate(latituude: float, longitude: float) -> Point:
    """ 맵에서 좌표에 해당하는 객체를 검색 """


    >>> locate.__annottations__
        {'latitude': float, 'longitude': float, 'return': __main__.Point}

파이썬 3.6부터 변수에 직접 주석을 달 수 있다.

class Point:
    lat: float
    long: float

    >>> Point.__annotations__
        {'lat': <class 'float'>, 'long': <class 'float'> }

3) Docstring와 어노테이션의 활용


- 사용 전

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

- 사용 후

def data_from_response(response: dict) -> dict:
    """ response에 문제가 없다면 response의 payload를 반환
     - respoonse dict의 예제::
      {
          "status": 200, # <int>
          "timestamp": "....." # 현재 시간의 ISO 포맷 문자열
          "payload": { ... } # 반환하려는 사전 데이터
      }

     - return dict의ㅣ 예제::
     {"data": { .. } } 

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

- 이슈
코드가 길어지는 것과 효과적인 문서가 되기 위해 상세한 정보가 필요하다는 것 사이의 trade off

4. 코드의 레이아웃을 일정하게 유지하여 팀 멤버들이 문제의 본질을 해결하는데 초점을 맟출 수 있도록 도구를 설정하는 방법

이 모든 검사는 자동화하여 CI build의 하나가 되도록 하는 것이 바람직하다.

  1. Mypy를 사용한 type hinting
  2. Pylint를 사용한 코드 검사
  3. Makefile을 활용한 자동 검사 설정
    1. 코딩 가이드 검사
    2. 올바른 타입을 사용했는지 검사
    3. 최종적으로 테스트 실행
  4. Black을 사용한 코드 포매팅