본문 바로가기

기술 인사이트 정리/Clean Code

[좋은 코드] 코테 스타일 가이드

✅ 조건문 표현 스타일 기준 5가지

1. 현재 기준 변수는 좌측에 둔다

  • 원칙: 현재 비교하고 있는 값(=기준)은 좌측에 배치
  • 이유: 조건을 읽을 때 **"지금 값이 ~한가?"**를 자연스럽게 읽기 위함

예시:

# ❌ (덜 직관적)
if freq[stack[-1]] <= freq[current]:

# ✅ (더 직관적)
if freq[current] >= freq[stack[-1]]:

2. 숫자 상수(리터럴)는 우측에 둔다

  • 사람 눈은 좌측에 변수, 우측에 상수를 배치했을 때 더 빠르게 해석 가능

예시:

# ❌
if 100 < score:

# ✅
if score > 100:
  • 오른쪽의 상수가 기준처럼 보이는 것이 일반적 읽기 순서에 맞음

3. 의미 있는 순서대로 정렬하라 (작은 → 큰)

  • 조건식은 왼쪽이 작고, 오른쪽이 큰 형태로 정렬되면 이해가 빠름

예시:

# ❌
if 100 >= x and x >= 0:

# ✅
if 0 <= x <= 100:
  • 이렇게 삼단 비교(0 <= x <= 100)는 Python이 지원하므로 적극 활용하면 좋음

4. not 사용은 최소화하고, 긍정 조건을 우선으로

  • 부정 조건은 뇌가 한 번 더 해석해야 해서 인지 부하가 있음

예시:

# ❌
if not is_valid:

# ✅
if is_invalid:

 

물론, 경우에 따라선 not이 더 자연스러운 조건일 수도 있음
핵심은 "읽는 사람이 한 번에 이해 가능한 방향"으로 쓰는 것

5. 조건은 최대한 간결하게 유지 (논리 추상화)

  • 복잡한 조건은 미리 변수로 빼거나 함수화

예시:

# ❌
if user.age >= 18 and user.role == 'admin' and user.is_active:

# ✅
is_adult_admin = user.age >= 18 and user.role == 'admin'
if is_adult_admin and user.is_active:

 

 

✅ 실무에서 자주 쓰는 조건문 설계 패턴 6가지


1. Guard Clause 패턴 (방어절)

→ 불필요한 중첩을 없애고, 일찍 리턴한다

# ❌ 중첩된 if
def process(user):
    if user is not None:
        if user.is_active:
            return user.name
    return None

# ✅ guard clause
def process(user):
    if user is None or not user.is_active:
        return None
    return user.name

조건이 만족되지 않으면 바로 빠지는 방식
→ 코드 흐름이 위에서 아래로 깔끔하게 읽힘


2. 삼항 연산자 for 단순 조건 분기

# ✅ 변수 할당에 조건 적용
discount = 0.2 if user.is_premium else 0.05
  • 단순한 if-else를 한 줄로 표현할 때 좋음
  • 다만, 복잡해질 경우 삼항연산자는 피해야 함

3. 명확한 불리언 체크

# ❌
if not len(items):
    ...

# ✅
if not items:  # 파이썬스러운 방식
    ...
  • len(items)보다 그냥 items를 사용하는 것이 더 명확하고 간결
  • Python에서는 [], None, '', 0 등은 모두 False로 평가됨

4. 의미 있는 변수로 조건 추상화

# ❌
if user.age >= 18 and user.status == 'active':
    ...

# ✅
is_adult_active = user.age >= 18 and user.status == 'active'
if is_adult_active:
    ...
  • 의미 있는 이름으로 조건을 추상화하면 읽는 사람이 맥락을 더 쉽게 이해할 수 있음

5. 딕셔너리를 조건 분기 처리에 활용

# ✅ 딕셔너리를 switch처럼 활용
def handle(status):
    return {
        'pending': process_pending,
        'approved': process_approved,
        'rejected': process_rejected
    }.get(status, process_unknown)()
  • if-elif-else가 길어질 경우 딕셔너리 매핑으로 처리하면 깔끔함
  • 특히 함수 분기할 때 유용

6. 리스트/튜플 포함 여부로 간결하게

# ❌
if x == 'a' or x == 'b' or x == 'c':
    ...

# ✅
if x in ('a', 'b', 'c'):
    ...
  • 값이 여러 개일 경우 in 연산자로 훨씬 읽기 쉬움

✅ 좋은 함수란?

짧고 명확하며, 하나의 역할만 수행하는 함수.
읽는 순간 "아, 이 함수는 이거 하나 하려고 만든 거구나"가 바로 이해돼야 한다.

 

🎯 좋은 함수 5가지 기준

1. 함수는 **하나의 책임(One Responsibility)**만 가져야 한다

  • 하나의 함수는 하나의 "논리적 기능"만 해야 한다.
  • 여러 개의 기능을 섞어놓으면 수정/확장할 때 터진다.

❌ 나쁜 예

def process_user(user):
    validate_user(user)
    save_user(user)
    send_welcome_email(user)
  • 검증 + 저장 + 이메일 발송 = 서로 다른 책임이 섞여 있음

✅ 좋은 예

def validate_user(user):
    ...

def save_user(user):
    ...

def send_welcome_email(user):
    ...
  • 각각 독립적인 함수로 분리

2. 함수는 짧아야 한다

  • 한눈에 전체를 이해할 수 있을 만큼 짧아야 한다.
  • 실무 기준으로는 보통 20줄 이하, 가능하면 10줄 이하로 유지한다.

"스크롤을 내려야 이해할 수 있는 함수는 나쁜 함수다."


3. 함수 이름은 행동(동사) + **대상(명사)**로 짓는다

  • 함수는 무엇을 하는지 분명히 보여야 한다.

예시

  • calculate_total_price()
  • fetch_user_profile()
  • send_email_notification()

함수 이름만 보고 대충 무슨 일을 하는지 알 수 있어야 해.


4. 함수는 입력(Input)과 출력(Output)이 명확해야 한다

  • 어떤 값을 넣으면, 어떤 값을 돌려주는지 분명해야 한다.
  • 부수효과(Side Effect)는 최소화한다.

❌ 나쁜 예

def update_user_info(user):
    global DB
    DB.append(user)
  • 함수가 외부 상태(DB)를 직접 수정 → 추적하기 어렵다.

✅ 좋은 예

def create_user(user_data):
    return User(user_data)
  • 입력받아서 객체를 리턴 → 예측 가능

5. 함수 내부는 일관된 추상화 레벨을 유지한다

  • 함수 안에는 비슷한 레벨의 작업만 들어가야 한다.
  • 고수준 작업과 저수준 작업을 섞으면 읽기가 매우 힘들어진다.

❌ 나쁜 예

def create_user_account(user_data):
    validate_email(user_data['email'])
    if '@' not in user_data['email']:
        raise ValueError('Invalid email')
    send_email(user_data['email'])
  • 고수준 작업(create_user_account) + 저수준 작업('@' not in email) 섞여 있음.

✅ 좋은 예

 
def create_user_account(user_data):
    validate_user_data(user_data)
    send_welcome_email(user_data['email'])

def validate_user_data(user_data):
    if '@' not in user_data['email']:
        raise ValueError('Invalid email')
  • 추상화 레벨을 함수마다 맞춰서 정리

📌 요약 표

기준설명
하나의 책임 한 가지 기능만 수행
짧은 길이 한눈에 이해 가능 (20줄 이하)
의미 있는 이름 동사+명사 조합으로 의도 표현
명확한 입력과 출력 외부 상태에 의존하지 않음
일관된 추상화 수준 유지 한 함수 안에는 같은 레벨의 작업만

🎯 마무리

"좋은 함수는 짧고, 읽기 쉽고, 하나의 목적만 가지고, 입력과 출력이 명확하며, 일정한 수준의 작업만 담고 있다."

🔥 "이 함수는 하나의 역할을 하는가?" "이름만 보고 알 수 있는가?" "입출력이 명확한가?" 를 항상 체크