1. 클린 코드의 의미
클린 코드에 대한 유일하고 엄격한 정의는 없다.
프로그래밍 언어의 진정한 의미는 아이디어를 다른 개발자에게 전달하는 것이다.
클린 코드의 진정한 본질은 클린 코드인지 아닌지는 다른 엔지니어가 코드를 읽고 유지 관리할 수 있는지 여부에 달렸다.
우리는 코드를 작성하는 것보다 읽는데 훨씬 많은 시간을 소비한다. 기존 코드의 수정이나 새로운 기능을 추가할 때마다 코드의 환경을 먼저 읽어야만 한다. 파이썬이라는 언어 자체는 의사소통을 하기 위한 도구일 뿐이다.
2. 클린 코드의 중요성
클린 코드가 중요한 이유는 많다. 유지보수성 향상, 기술 부채의 감소, 애자일 개발을 통한 효과적인 작업 진행, 성공적인 프로젝트 관리로 이어지는 것들이다.
2-1. 클린 코드에서 포매팅의 역할
클린 코드가 의미하는 바가 PEP-8 또는 프로젝트 가이드라인 같은 표준 지침에 따라 코드를 포매팅하고 구조화하는 것을 말하는 것일까?
아니다.
클린 코드는 품질 좋은 소프트웨어를 개발하고, 견고하고 유지 보수가 쉬운 시스템을 만들고, 기술 부채를 회피하는 것을 말한다.
그러나 코드를 올바르게 포매팅하는 것은 작업을 효율화하기 위해 중요하다.
2-2. 프로젝트 코딩 스타일 가이드 준수
코딩 가이드라인은 품질 표준을 지키기 위해 프로젝트에서 따라야 하는 최소한의 요구사항이다.
좋은 코드 레이아웃에서 가장 필요한 특성은 일관성이다. 코드가 일관되게 구조화되어 있으면 가독성이 높아지고 이해하기 쉬워진다.
특히 파이썬이 따라야 하는 코딩 스타일은 PEP-8이다.
PEP-8 : PEP란 Python Enhancement Proposal 의 약자로 파이썬 개선을 위한 제안서를 의미한다. 각 제안서는 고유 번호를 가지며, PEP 8번 Style Guide for Python Console 에서 코딩 컨벤션에 대한 내용을 다룬다.
PEP-8 은 다음과 같은 특징을 갖는다.
- 검색 효율성(Grepability) : cli 로 grep 을 통해 파일의 일부에서 특정 문자열을 찾을 때 검색의 효율성을 높여준다. PEP-8은 키워드 인자 할당에는 띄어쓰기를 사용하지 않지만, 변수에 값을 할당할 때는 띄어쓰기를 사용하도록 권고하고 있다. 이를 이용하여 검색 조건을 변경할 수 있다.
-
$ grep -nr "location=" . ./core.py:13: location=current_location, $ grep -nr "location =" . ./core.py:10: current_location = get_location()
-
- 일관성 : 코드가 일정한 포맷을 가지면 훨씬 쉽게 읽을 수 있다.
- 코드 품질 : 코드를 구조화하여 살펴보면 한 눈에 코드를 이해하고 버그와 실수를 쉽게 찾을 수 있다.
3. Docstring과 어노테이션
코드를 문서화하는 것은 주석을 추가하는 것과는 다르다. 주석은 가급적 피해야 한다.
파이썬은 동적으로 타입을 결정하기 때문에 함수나 메서드를 거치면 변수나 객체의 값이 무엇인지 알기가 어려운 경우가 많으므로 어노테이션을 통해 이러한 정보를 명시하면 향후 다른 개발자가 쉽게 이해하는데 도움이 된다.
3-1. Docstring
Docstring 은 소스 코드에 포함된 문서라고 말할 수 있다. Docstring 은 코멘트가 아니라 문서이다.
코드에 주석을 다는 것은 나쁜 습관이다.
- 주석은 코드로 아이디어를 제대로 표현하지 못했음을 나타내는 것이다.
- 오해의 소지가 있다. 주석이 업데이트 되지 않을 경우, 혼란을 야기할 수 있다.
Docstring 은 코드의 특정 컴포넌트(모듈, 클래스, 메서드 또는 함수)에 대한 문서화이다.
Docstring 을 코드에 포함시키는 것이 좋은 이유는 파이썬이 동적 타이핑을 하기 때문이다. 예를 들어 함수는 파라미터의 값으로 무엇이든사용할 수 있다. 파이썬은 파라미터의 타입을 체크하거나 강요하지 않는다. 따라서 함수를 수정해야 하는데 함수의 이름과 파라미터의 이름이 그 목적을 잘 담고 있지 않을 경우, 이를 파악하기가 어렵다.
객체에 docstring 이 정의되어 있으면 __doc__ 속성을 통해서 접근 가능하다.
단점은 지속적으로 수작업을 해야 한다는 점이다. 가치 있는 문서를 만들기 위해서는 모든 팀원이 문서화에 노력이 필요하다는 것에 공감해야 한다.
3-2. 어노테이션
PEP-3107 에서는 어노테이션을 소개하고 있다. 기본 아이디어는 코드 사용자에게 함수 인자로 어떤 값이 와야 하는지 힌트를 주자는 것이다.
class Point:
def __init__(self, lat, long):
self.lat = lat
self.long = long
def locate(latitude: float, longitude: float) -> Point:
"""맵에서 좌표에 해당하는 객체를 검색"""
return Point(latitude, longitude)
파이썬이 타입을 검사하거나 강제하지는 않는다.
어노테이션을 사용하면 __annotations__ 라는 속성이 생긴다.
>>> locate.__annotations__
{'latitude': <class 'float'>, 'longitude': <class 'float'>, 'return': <class '__main__.Point'>}
파이썬 3.5부터는 새로운 typing 모듈이 소개되었고 파이썬 코드에서 타입과 어노테이션을 정의하는 방법이 크게 향상 되었다.
파이썬 3.6부터는 변수에 직접 주석을 달 수 있다.
class NewPoint:
lat: float
long: float
>>> NewPoint.__annotations__
{'lat': <class 'float'>, 'long': <class 'float'>}
3-3. 어노테이션은 docstring 을 대체하는가?
docstring 과 어노테이션은 상호 보완적인 개념이다.
docstring 정보의 일부를 어노테이션으로 대체할 수 있으나, 동적 데이터 타입과 중첩 데이터 타입의 경우 예제를 제공하여 어떤 형태의 데이터를 다루는지 문서화하는 것이 좋다.
def data_from_response(response: dict) -> dict:
if response["status"] != 200:
raise ValueError
return {"data": response["payload"]}
위 함수는 사전 형태의 파라미터를 받아서 사전 형태의 값을 반환한다. 파라미터의 status 키의 값이 기댓값과 다를 경우 예외가 발생한다. 그러나 상세 내용은 알 수가 없다. 따라서 함수 반환 값의 예상 형태를 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"]}
3-4. 기본 품질 향상을 위한 도구 설정
코드는 사람이 이해하기 위한 것이므로 좋은 코드인지 나쁜 코드인지 판단할 수 있는 것도 오직 사람이다.
동료가 작성한 코드를 살펴볼 때는 다음 질문을 해야 한다.
- 이 코드를 동료 개발자가 쉽게 이해하고 따라갈 수 있을까?
- 업무 도메인에 대해서 말하고 있는가?
- 팀에 새로 합류하는 사람도 쉽게 이해하고 효과적으로 작업할 수 있을까?
코드 포매팅, 일관된 레이아웃, 적절한 들여쓰기를 살펴보는데 시간을 낭비하기 보다는 실제 어떤 패턴이 사용되었는지 살펴서 코드의 실제 의미와 가치를 이해하는데 시간을 투자하는 것이 효과적이다.
이 모든 검사는 자동화해야 한다. 테스트 또는 체크리스트의 일부가 되어 지속적인 통합 빌드(continuous integration build)의 하나가 되어야 한다. 빌드 시 자동으로 실패하도록 해야 객관성을 얻을 수 있다.
# Mypy를 사용한 타입 힌팅
mypy는 파이썬에서 가장 일반적으로 사용하는 정적 타입 검사 도구이다. mypy를 설치하면 프로젝트의 모든 파일을 문석하여 타입 불일치를 검사해준다.
# Pylint 를 사용한 코드 검사
PEP-8을 준수했는지 여부를 검사한다. Flake8 등의 도구가 있다.
# 자동 검사 설정
리눅스 개발환경에서 빌드를 자동화하는 가장 일반적인 방법은 Makefile 을 사용하는 것이다. Makefile 은 프로젝트를 컴파일하고 실행하기 위한 설정을 도와주는 파워풀한 도구이다. 빌드 외에도 포매팅 검사나 코드 컨벤션 검사를 자동화하기 위해 사용할 수도 있다.
'python' 카테고리의 다른 글
파이썬 클린 코드 - 3장 (좋은 코드의 일반적인 특징) (0) | 2022.02.03 |
---|---|
파이썬 클린 코드 - 2장 (Pythonic code) (0) | 2022.01.27 |
Architecture Patterns with Python(13장) (0) | 2022.01.20 |
Architecture Patterns with Python(12장) (0) | 2022.01.14 |
Architecture Patterns with Python(11장) (0) | 2022.01.07 |