곰퓨타의 SW 이야기

CH1. 코드 포매팅과 도구 본문

TIL/클린코드

CH1. 코드 포매팅과 도구

곰퓨타 2023. 4. 26. 22:21

1. 서론

- 클린 코드의 의미

  • 프로그래밍 언어의 의미
    • 인간의 아이디어를 컴퓨터에 전달하기 위해 사용하는 언어 (X)
    • 아이디어를 다른 개발자에게 전달하는 것
  • 따라서, 클린 코드는 다른 엔지니어가 코드를 읽고 유지 관리할 수 있는지 여부에 따라 달려있다.

 

- 클린 코드의 중요성

  • 유지보수성 향상
    • 일정하게 예측 가능한 속도로 민첩한 개발과 지속적인 배포 가능
  • 기술 부채의 감소
    • 기술 부채 : 나쁜 결정이나 적당한 타협의 결과로 생긴 소프트웨어적 결함
      • 1. 현재 -> 과거의 방향 : 직면한 문제가 과거의 잘못된 코드로 생긴 건 아닐지
      • 2. 현재 -> 미래 : 현재의 문제를 적절하게 해결하기 위해 시간을 투자하지 않아서 미래에 문제가 발생하는 건 아닐지
    • 이자가 발생하는 부채처럼, 코드를 미래에 변경하는 것이 더 어렵다.
    • 기술 부채 有 -> 애자일 방식 개발 X
    • 코드 스멜이 있다면 잘못된 코드를 암시하는 신호로 명시적인 오류는 아니지만 장기적으로 코드에 나쁜 영향을 줄 수 있다.
    • EX ) 함수의 파라미터로 변경 가능한 기본 값을 사용한다고 해보자.
      • 결함 발견 전까지는 상당히 오랫동안 정상적으로 동작, 하지만 실제로는 프로그램을 비정상적으로 종료시키는 시한 폭탄이 될 수 있다.
      • -> 철저한 코드 리뷰 & 자동화된 테스트
    • 애자일 개발을 통한 효과적인 작업 진행
    • 성공적인 프로젝트 관리
    • 수정 가능한 코드를 만들기 위한 절대적인 요구사항

 

- 예외 상황

  • 해커톤 참여
  • 일회성 작업을 위한 간단한 스크립트 작성
  • 프로그래밍 경진 대회 참여
  • 기존에 없던 개념을 검증하기 위해 개발하는 경우
  • 나중에 버려질 것이라고 확신하는 프로토타입 개발 등

 

 

 

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

PEP-8(Python Enhancement Proposal) : 가장 잘 알려진 표준이며, 띄어쓰기, 네이밍 컨벤션, 줄 길이 제한 등의 가이드 랑니 제공

하지만, 클린 코드는 PEP-8 이나 코딩 스타일 그 이상의 유지 보수성이나 소프트웨어 품질에 관한 것을 말한다.

  • 프로젝트 코딩 스타일 가이드 준수
    • 코딩 가이드 라인 : 품질 표준을 지키기 위해 프로젝트에서 따라야 하는 최소한의 요구사항
    • 코드가 일관되게 구조화되어 있으면 가독성이 높아지고 이해하기 쉬워진다.
    • PEP-8 표준
      • 검색 효율성 (Searchability)
        • 코드에서 원하는 부분을 빠르게 검색할 수 있도록 한다.
        • 변수에 값을 할당하는 경우, 함수의 키워드 파라미터에 값을 할당하는 경우 구분 가능
      • 일관성
      • 더 나은 오류 처리
        • try~except 블록 내부의 코드를 최소화
      • 코드 품질
        • 한 눈에 코드를 이해하고 버그와 실수를 쉽게 찾을 수 있다.

 

  • PEP-8 표준 검색 효율성 예시
$ grep -nr "location="
./core.py:13:location=current_location, # keyword argument에 값을 할당하는 경우 띄어쓰기 X
$ grep -nr "location ="
./core.py:10:current_location = get_location(), # 변수에 값을 할당하는 경우 띄어쓰기 권고

 

포매팅은 문서화 방식이나 코드 품질 자동화 도구를 결정하는 데 영향을 많이 미친다.

 

3. 문서화 (Documentation)

훌륭한 코드는 그 자체로 분명하지만 문서화 또한 잘 되어 있다!

파이썬 코드를 문서화하는 방법으로는 Docstring, annotation이 있다.

파이썬은 변수의 타입이 동적이어서 변수나 객체의 값이 무엇인지 잃어버리기 쉬우므로, 타입 정보를 명시해두는 것이 좋다.

cf ) 어노테이션은 mypy, pytype과 같은 도구를 통해 변수 타입 힌트와 같은 자동화에 좋다.

 

코드 주석 (code comments) (a.k.a. 악마)

  • 주석은 적어야 한다.
  • 주석을 작성하기 전에 새로운 함수를 추가하거나 보다 나은 변수명을 사용하는 것 등의 방법을 고려해보자
  • 외부 함수의 문제를 피하기 위해 특정한 파라미터를 넘겨야 하는 경우는 허용된다.
    • (이름이 지정되어 있는 경우, 설명이 필요할 때를 이야기하는건가?)
  • 주석 처리된 코드는 없어야 한다.

 

 

Docstring

  • 소스 코드에 포함된 문서 (Documentation)
  • Docstring은 리터럴 문자열이며, 로직의 일부분을 문서화하기 위해 코드 어딘가에 배치된다.
  • 모듈, 클래스, 메서드 또는 함수에 대해 문서를 제공하기 위한 것
  • 동작 방식과 입출력 정보 등을 확인할 수 있다.
  • 프로그램 디자인과 아키텍처에 대해 문서화 유용
  • EX)
    • dict.update에 대해 알고 싶은 경우
Help on method_descriptor:

update(...)
	D.update([E,]**F)->None. Update D from dict/iterable E and F.
    If E is present and has a.keys() method, then does: for k in E : D[k] = E[k]
    If E is present and lacks a.keys() method, then does: for k, v in E : D[k] = v
    In either case, this is followed by: for k in F : D[k] = F[k]
 (END)

-> 새로운 함수가 어떻게 동작하는지, 어떻게 활용될 수 있는지 이해하는데 중요한 역할을 할 것이다.

    • 객체에 docstring이 정의되어 있으면 __doc__속성 (property, attribute)로 접근이 가능하다
>>> def my_function():
...	"""임의의 연산 수행"""
...	return None
...
>>> my_function.__doc__
'임의의 연산 수행'
>>> help(my_function)
  • 도구
    • Sphinx: 프로젝트 문서화를 위한 골격 만들어준다.
      • Autodoc 익스텐션 (sphinx.ext.autodoc)을 사용하면 코드에서 docstring을 가져와서 문서화된 페이지를 만들어준다.
    • 도구 오픈을 위해 "read the docs" 와 같은 도구를 사용할 수 있다. (오픈 소스의 경우)
  • 단점 : 지속적으로 수작업을 해야 한다.

 

어노테이션

  • 코드 사용자에게 함수 인자로 어떤 값이 와야하는지 힌트를 준다
  • Type hinting을 활성화한다.
  • 변수의 예쌍 타입을 지정할 수 있다.
  • 변수의 의도를 설명하는 문자열, 콜백이나 유효성 검사 함수로 사용할 수 있는 callable 이 있다.
  • 함수.__annotations__로 활용 가능
  • 유의미한 이름을 사용하거나 적절한 데이터 타입 추상화를 할 수 있도록 도와줄 수 있다.

ex ) Docstring과 어노테이션의 활용

def data_from_response(response:dict) -> dict:
	"""response의 HTTP status가 200이라면 response의 payload를 반환
    - response 사전의 예제::
    {
    "status":200, # <int>
    "timestamp": ...,	# 현재 시간의 ISO 포맷 문자열
    "payload" : {...]	# 반환하려는 사전 데이터
    }
    
    - 반환 사전 값의 예제::
    {"data":{...}}
    - 발생 가능한 예외:
    	- HTTP Status가 200이 아닌 경우 ValueError 발생
    """
    if response["status"] != 200:
    	raise ValueError
    return {"data" : response["payload"]}

4. 도구 설정

  • 이 코드를 동료 개발자가 쉽게 이해하고 따라갈 수 있을까?
  • 업무 도메인에 대해서 말하고 있는가?
  • 팀에 새로 합류하는 사람도 쉽게 이해하고 효과적으로 작업할 수 있을까?
  • 이 검사는 모두 자동화로 해야 한다. 테스트와 체크리스트가 지속적으로 통합 빌드 (Continuous Integration Build)와 하나가 되도록 해야 한다.

 

데이터 타입 일관성 검사

  • mypy, pytype
  • mypy {파일명} : 의심되는 오류 보고
  • mypy와 pytype의 가장 큰 차이 : 오류를 확인하는 시점
    • pytype은 일시적으로 지정된 데이터 타입과 다른 타입을 사용하여도 최종 결과가 선언된 유형을 준수하는 한 문제로 간주되지 않는다.
    • 런타임 시에는 문제되지 않는 코드
from typing import List
def get_list() -> List[str]:
    lst = ["PyCon"]
    lst.append(2022)	#mypy에서는 오류지만 pytype에서는 허용
    return [str(x) for x in lst]

 

일반적인 코드 검증

  • pycodestyle, flake8 : PEP-8 표준을 위반한 모든 라인과 에러 유형 출력
    • cf ) PEP-8은 일반적인 코드의 스타일이나 구조에 관한 것을 검사할 뿐, 모든 메서드, 클래스, 모듈에 docstring을 넣도록 강제하지는 않는다. 그리고 너무 많은 파라미터를 사용하는 함수에 대해서도 아무런 불평을 하지 않는다.)
  • pylint : 가장 엄격한 수준의 검증
    • pylintrc 설정 파일로 개별적인 규칙에 대해 활성/비활성 여부 결정 가능
  • Coala : 파이썬 뿐만 아니라 다른 언어도 지원
    • 설정 파일 有, 커맨드 라인 도구 有, 에러 발생 가능성이 있는 경우 수정 가능한 코드 형식 지정

 

자동 포매팅

  • flake8: PEP-8 준수 여부 + 코드 변환
  • black : 라인 길이 제외와 같은 옵션을 허용하지 않으면서 고유하고 결정적인 방식으로 코드 형식 지정
    • Ex ) 따옴표는 항상 큰 따옴표, 파라미터 순서는 항상 동일한 구조
    • PEP-8 보다 엄격한 하위 집합 관리
    • --check를 통해 검사 가능
    • All or nothing formatting
  • yapf : 사용자 정의 가능하면서 코드의 일부분만 포매팅 가능 (적용할 줄도 지정 가능)

 

자동 검사 설정

  • 리눅스 개발 환경에서 빌드 자동화 : Makefile 사용
  • Makefile : 프로젝트를 컴파일 하고 실행하기 위한 설정을 도와주는 강력한 도구
    • 빌드 외에도 포매팅 검사나 코딩 컨벤션 검사를 자동화하기 위해 사용 가능
    • 명령어 있을 때에는 공백이 아닌 탭으로 들여쓰기를 해야 한다.
    • 테스트를 위한 각각의 target을 만들고, 이것들을 모두 실행하는 또다른 target 만들어야 한다.
.PHONY: typehint
typehint:
	mypt --ignore-missing-imports src/
    
.PHONY: test
test:
	pytest test/
    
.PHONY: lint
lint:
	pylint src/
    
.PHONY: checklist
checklist: lint typehint test

.PHONY: black
black:
	black -l 79 *.py
    
.PHONY: clean
clean:
	find . -type -f -name "*.pyc" | xargs rm -fr
    find . -type -d __pycache__ | xargs rm -fr
  • 개발 머신과 CI 빌드에서의 실행할 커맨드
    • $ make checklist
    • 1. 먼저 PEP-8 이나 black의 --check 파라미터를 사용해 코딩 가이드라인을 잘 지키고 있는지 확인
    • 2. 올바른 타입을 사용했는지 검사
    • 3. 최종적으로 테스트 실행
  •  

--> 이 중 하나라도 실패하면 전체 프로세스 실패

 

  • 장점
    • 1. 가장 많이 사용하는 반복적인 작업을 간단하게 표준화 가능
    • 2. Makefile은 프로젝트의 여러 작업을 한꺼번에 실행하는 표준화된 방법을 제공한다.

 

Reference

http://www.yes24.com/Product/Goods/114667254

Comments