컨벤션 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

1. PEP8의 주요 규칙 요약

항목 규칙 예시
들여쓰기 4칸 공백 사용 ( 말고 스페이스)
최대 줄 길이 79자 이하 (주석은 72자 이하 권장)
줄 간격 함수/클래스 사이 2줄, 함수 내부에서는 논리 단위마다 1줄
임포트 정렬 표준 라이브러리 → 서드파티 → 로컬 모듈 (줄바꿈)
공백 사용 연산자 앞뒤에는 공백, 괄호 안쪽은 공백 ❌
이름 규칙 함수, 변수: snake_case, 클래스: PascalCase
docstring 함수/클래스에는 설명용 주석 (트리플 따옴표) 추가

a. 줄 간격 예시

def fetch_data():
    # Step 1: API 호출
    response = requests.get("https://example.com")

    # Step 2: 응답 파싱
    data = response.json()

    return data

def save_to_file(data):
    with open("data.json", "w") as f:
        json.dump(data, f)

b. 임포트 정렬 예시

# isort 기준
import os
import sys

import requests

from app.models import User

c. 공백 사용 예시

# ✅ 올바른 예
if a == b
func(x, y)

# ❌ 잘못된 예
if(a==b)
func( x , y )

d. 네이밍 컨벤션

항목 컨벤션 예시 규칙
변수/함수 snake_case get_user_info()
클래스 PascalCase UserService
상수 UPPER_SNAKE_CASE DEFAULT_TIMEOUT
모듈/파일명 snake_case.py user_service.py

가. 코딩 규칙, 함수/클래스 명명 규칙 정의

  • 함수는 동사형: get_user_info, send_email
  • 클래스는 명사형: UserService, EmailSender

e. Type hint는 필수

def get_user(user_id: int) -> Optional[User]:
    ...
  • 함수 인자, 반환값에 모두 명시
  • 타입 모호할 경우 → Any 또는 Union, Literal 등 사용
  • None 반환 가능 시 → Optional[Type] 또는 -> None

f. 주석 & Docstring 스타일

종류 용도 예시
Docstring (""") 함수/클래스/모듈의 기능, 입력, 출력 설명 def func(): """..."""
일반 주석 (#) 코드 내부의 구현 설명, 예외 처리 이유 등 # 예외 처리 로직

가. Docstring 규칙

  • """ 트리플 쿼트 사용
  • 함수/클래스 시작 부분에만 작성
  • 구현 설명은 일반 # 주석으로
  • Docstring은 Google 스타일 이용
def add(a: int, b: int) -> int:
    """
    두 수를 더합니다.

    Args:
        a (int): 첫 번째 숫자
        b (int): 두 번째 숫자

    Returns:
        int: 두 수의 합
    """

나. 주석 규칙

TAG 의미 예시
# NOTE: 중요한 참고사항 (특이점, 의도 등) # NOTE: API에서 status가 문자열로 옴
# TODO: 해야 할 작업 (아직 구현 안된 부분) # TODO: 에러 처리 추가 필요
# FIX: 버그 관련 정보, 수정 예정 또는 필요 # FIX: 간헐적으로 None 반환됨
# HACK: 임시 코드, 추후 개선 필요 # HACK: 간단한 우회로 처리함
# WARN: 경고, 주의 사항 (비용 큼, 느림 등) # WARN: 이 함수는 매우 느립니다.
일반 주석 구현 설명, 흐름 설명, 예외 처리 이유 등 # 파일이 없으면 기본값으로 생성

2. PEP8 적용 도구

a. black → 코드 자동 정리

  • 들여쓰기, 괄호 배치, 줄바꿈, 따옴표 종류 등 자동 수정

    # 원래 코드
    def foo(a,b=1): return(a+b)
    
    # black 적용 후
    def foo(a, b = 1):
        return a + b
    

b. ruff → 스타일 검사

  • 들여쓰기, 공백, 줄 길이, 괄호 사용 등 스타일 오류 잡기
  • 미사용 변수, import, 중복 변수 선언 등 불필요한 코드 제거 유도
  • 함수, 변수, 클래스가 올바른 네이밍 패턴(snake_case, PascalCase)을 따르는지 검사
  • import 순서 정렬

3. 로깅 컨벤션

a. 기본 원칙

원칙 설명
구조적 로깅 로그는 JSON 형태로, 추후 분석 및 필터링이 용이하게 구성
레벨 구분 철저 DEBUG, INFO, WARNING, ERROR, CRITICAL 단계별 역할 명확히
로거 이름 통일 __name__ 또는 모듈명 기준으로 통일
상황 중심 메시지 작성 단순 상태가 아닌 맥락 있는 설명 포함
요청 식별자 포함 필요한 경우 요청 ID 등 삽입
예외는 로그 + raise 병행 예외는 exc_info=True로 스택 트레이스 포함

b. 구조적 로깅

{
  "timestamp": "2025-04-16T09:00:00",
  "level": "ERROR",
  "message": "앨범 생성 실패",
  "name": "app.services.image_service",
  "album_id": "al_001",
  "reason": "timeout",
  "exception": "Traceback (most recent call last):\n  File \"/app/services/image_service.py\", line 42, in create_album\n    result = call_external_api()\n  File \"/app/services/api_client.py\", line 10, in call_external_api\n    raise TimeoutError(\"Request timed out\")\nTimeoutError: Request timed out"
}

c. 로깅 구조 예시

import logging

logger = logging.getLogger(__name__)

def process_image(image_id: str) -> None:
    try:
        logger.info("Start processing", extra={"image_id": image_id})
        ...
        logger.debug("Image resized", extra={"image_id": image_id, "size": (224, 224)})
    except Exception as e:
        logger.error("Image processing failed", exc_info=True, extra={"image_id": image_id})
        raise

d. 로깅 레벨 가이드

레벨 사용 시점 예시
DEBUG 디버깅용, 로직 흐름 파악 "임베딩 계산 시작", "API 응답 파싱 완료"
INFO 정상 흐름 요약, 단계 표시 "앨범 생성 완료", "유저 요청 처리 시작"
WARNING 문제 가능성 있음, 오류 아님 "입력 이미지가 작습니다", "재시도 요청 감지됨"
ERROR 실행 중 오류 발생 "DB 연결 실패", "API 요청 실패"
CRITICAL 치명적 오류, 즉시 조치 필요 "GPU 리소스 없음", "전체 서비스 중단 감지"

e. 로거 이름 통일

logger = logging.getLogger(__name__)
  • __name__은 현재 파일의 모듈명 (app.services.clustering 등)을 자동으로 참조함
  • 로그에 **출처(module 단위)**가 자동으로 찍혀서 어떤 코드에서 발생한 로그인지 추적이 쉬움
  • 이용 방식
# app/services/image_service.py
import logging

logger = logging.getLogger(__name__)

f. 로그 메시지 작성 스타일

  • 고유 명사 영어를 더 많이 쓰는 용어는 영어로(예: ControlNet, OpenCV, DB 등)
  • 행동 & 상태는 한글로 작성
  • 메시지는 행동+상태 형태로 명확히 작성
잘못된 예 개선된 예
"실패" "앨범 생성 중 DB 저장 실패"
"시작함" "인물 클러스터링 작업 시작"
"안됨" "ControlNet 추론 중 OpenCV 오류 발생"

g. 예외 처리 시 로그 + raise 병행

가. 원칙

  • 예외가 발생하면 무조건 로그를 남기고, 필요한 경우 다시 예외를 던져야 한다.
    • 단순히 raise만 하면 어디서 어떤 상황에 발생했는지 알기 어려움

    • logger.error(..., exc_info=True)스택 트레이스까지 출력하기

      • 스택 트레이스
      Traceback (most recent call last):
        File "app/image.py", line 12, in process_image
          resize_image(img)
        File "app/image.py", line 5, in resize_image
          return img.resize((0, 0))  # <- 여기서 에러 발생
      ValueError: height and width must be > 0
      

나. 예시

try:
    run_ai_pipeline()
except Exception as e:
    logger.error("AI 파이프라인 실패", exc_info=True, extra={"user_id": user_id})
    raise