Development/Python
파이썬 클린코드
위풍당당 가리비
2024. 5. 5. 17:22
반응형
코드 포맷팅
- PEP8 : 파이썬 코드 포맷 기준 https://peps.python.org/pep-0008/
- Linter : PEP8을 따르는 지 검사할 수 있는 라이브러리. lint = 보풀, linter = 코드의 보풀을 제거하는 장치.
- Pylint
- Flake8 : 코드 스타일 강제화와 강제 변환이 없음.
- Black : 코드 스타일 강제 변환.
- Flake8 + Black 조합이면 괜찮은 것 같음.
Pythonic 코드 작성법
- Pythonic code의 장점
- 일반적으로 더 좋은 성능을 낸다.
- 여러명이 작업하기 편해지고 실수를 줄일 수 있다.
- 음수 인덱싱, 슬라이싱
- C에는 없는 파이썬 고유 기능.
- Context manager
- 파일, 소켓 연결 후에 자동으로 리소스를 해제해주는 기능.
- 리소스 해제를 고민할 필요없음.
- 리소스 해제 뿐만 아니라, 독립적으로 유지되어야하는 코드를 분리하는 좋은 방법임.
-
더보기예를 들어서 DB를 백업해야한다고 할 때 이미 실행되고 있는 DB를 껐다가 백업하고 다시 켜야하고, 백업하는 과정에서 오류가 발생하더라도 DB는 다시 시작되어야한다. 이때 에러 났을 때마다 하나하나 다 DB를 키는 코드를 추가하기 보다는 context manager를 사용하면 가독성 좋게 코드를 짤 수 있다.
그리고 contextlib를 사용하면 데코레이터 형태로도 내가 구현을 할 수 있다.
- contextlib.contextmanager
- contextlib.ContextDecorator
위 두개 사용해서 custom context manager를 만들 수 있음.
-
- Example
-
더보기
## not pythonic fd = open(filename) try: process_file(fd) finally: fd.close() # 수작업으로 닫아줘야한다. ## pythonic code with open(filename) as fd: # 자동으로 닫아준다. process_file(fd)
-
- Property
- Python은 모든 메소드와 멤버 변수는 public이다. Private, protected라는 개념이 없음. 그래서 밑줄 한개0로 구분함.
- 밑줄 X : Public
- _ : Private (강제는 아님.)
- _ _ : 네임 맹글링
- 외부에서 멤버 변수의 접근을 어렵하게 하기 위해서 "__<변수이름>" ☞ ☞ "_<클래스 이름>__<변수 이름>" 으로 바꿔버림. ※주의 : 접근이 아예 불가능한거는 아님.
- 원래 여러번 상속되는 클래스에서 오버라이딩할 때 이름이 겹치는 문제를 회피하기 위한 기능이라서 private 용도로 사용하는 건 X.
- 그 외에도 책에 더 많이 나와있는데 이거 다보다가는 시간이 없을 듯.
좋은 코드의 일반적인 특징
- 클린 코드의 궁극적인 목표 : 1) 견고하고, 2) 결함을 최소화하며, 3) 명확히 이해할 수 있도록 하는 것.
- 조금 더 풀어서 설명하면,
- 견고한 소프트웨어 = 프로그램이 예상치 못한 상황에서도 중단되지 않아야함.
- 잘못된 데이터를 쉽게 다룬다.
- 요구사항이 바뀌더라도 유지보수가 쉬운 소프트웨어 설계
- 재사용 가능
- 생산성을 높이는 효율적인 코드 작성
- 조금 더 풀어서 설명하면,
- 계약(Contract)에 의한 디자인
- 코드를 실행하려면 원하는 바를 명확히 정하고 계약을 어겼을 경우에는 예외를 발생시켜서 코드가 실행되지 않도록 해야한다.
- Input, Output에 대해서 조건을 무조건 작성하고 사전에 약속된 형태가 맞는 지 확인하는 코드가 들어가야함. 이런 확인코드가 들어감으로써 누구의 잘못인지를 정확하게 파악할 수 있다.
- Precondition : 함수가 제대로 동작하기 위해서 보장해야하는 모든 것들. 변수 타입뿐만 아니라 값까지 확인이 되어야함.
- Postcondition : 함수의 output이 원하는 값인지를 확인. 클라이언트가 필요로하는 모든 것을 검사한다.
- 방어적 프로그래밍
- 예상할 수 있는 오류(error handling)나 발생하지 않아야할 오류(=assertion)를 처리하는 방법.
- 에러 핸들링
- 오류가 발생하기 쉬운 상황에서 에러 핸들링 프로시저를 사용.
- 주로 입력 데이터 확인할 때 사용.
- 에러 핸들링의 주목적은 예상되는 에러를 처리해서 다음 코드를 실행할지, 아니면 프로그램을 중단할지를 결정하는 것.
- 에러 핸들링은 주로 3가지 방법으로 가능
- 값 대체 = 디폴트 값 사용.
- 에러 로깅
- 예외 처리 = 예외상황을 처리하는 것, (try-except 구문 같은 상황) 그렇지만 예외처리가 많다는 것은 해당 함수가 너무 많은 책임을 가지고 있다는 것이다. 예외가 너무 많이 발생하면 함수를 나눠야하는 신호로 생각해라. 예외는 오직 한가지 일을 하는 함수의 한 부분이어야한다. 예외 처리는 해당 기능을 하는 함수 내에서 해야한다. 바깥에서 하는게 아니다!
- Assertion
- 그냥 프로그램 종료. 발생하지 않아야할 오류는 다른 대체 코드를 실행하면 안된다.
- 관심사 분리
- 책임이 다르면 컴포넌트, 계층, 모듈로 분리되어야한다. 프로그램의 각 부분은 자기 기능만 책임을 지며, 나머지 부분에 대해서는 알 필요 없다.
- 이렇게 관심사를 구분하는 이유는 파급 효과를 최소화하여 유지보수성을 향상시키는 것.
- 컴포넌트 : 실행되는 가장 작은 하나의 단위. 아래 내용들과 같은 개념으로 묶이는 것이 아님.
- 라이브러리 : 여러 패키지와 모듈을 모아둔 것.
- 패키지 : 특정 기능을 위해 여러 모듈을 모아둔 것.
- 모듈 : 실행과 관계없이 어떤 기능들을 모아둔 것.
- 응집력과 결합력
- 응집력 : 객체가 작고 잘 정의된 목적을 가져야 응집력이 높다고 함. 응집력이 높으면 재사용성이 높아짐.
- 결합력 : 두 개 이상의 객체가 어떻게 의존하는지를 나타냄. 낮을 수록 좋다.
- 관련 내용
- 개발 지침 약어
- 개발할 때 중요한 것들을 슬로건처럼 약어로 축약한 용어들이 있음.
- DRY (Do not Repeat Yourself) / OAOO (Once And Only Once)
- 코드를 중복해서 작성하지 말아라. 여기저기에 똑같은 함수를 만들어두지 마라.
- YANGNI (You Ain't Gonna Need It)
- 미래의 모든 요구사항을 염두에 두고 코드를 복잡하게 짜지 말아라. 현재 필요한 만큼만 짜라.
- KIS (Kepp It Simple)
- 과잉 엔지니어링을 하지말고, 최대한 간단하게 짜라.
- 간단하게 짤수록 유지보수가 쉽다.
- EAFP (Easier to Ask Forgiveness than Permission) / LBYL (Look Before You Leap)
- EAFP : 일단 코드 실행하고 동작하지 않을 경우에 대응. try - except
- LBYL : 예를 들어서 파일을 불러오기 전에 그 파일이 있는지부터 확인.
- 파이썬스러운 코드는 EAFP라고 함. 근데 굳이 따라야할 필요가 있나 싶음.
- 컴포지션과 상속
- 컴포지션 (Has-A 관계) : 합성, 상속받지 않고 하나의 멤버변수로 상속받으려는 클래스를 포함하는 것. 인터페이스로만 접근하기 때문에 상속에 비해 결합력을 많이 낮출 수 있다. 상속보다 권장하는 방법.
- 상속 (Is-A 관계): 부모 클래스를 상속받아서 새로운 클래스를 만드는 것. 좋은 기능이지만 코드의 결합력을 높이는 문제가 있다.
- 상속을 사용해도 되는 경우 : Is-A + 행동호환성 (하는 행동이 똑같은 경우).
반응형