개발 slecs

리뷰 조회 반환값 정규화로 금액 타입 버그 수정

목차

learn-update 스크립트의 fetch_reviews 함수 반환값을 list로 정규화했다. 겉으로는 간단한 타입 통일처럼 보이지만, 실제론 파이프라인 전체의 데이터 안정성을 확보하는 중요한 작업이었다.

어디서 터진 버그인가

금액 처리 로직에서 간헐적으로 터지던 타입 에러가 근본 원인은 fetch_reviews의 반환값이 일정하지 않았던 것이다. 함수가 상황에 따라 단일 객체를 그대로 반환하기도 하고, dict를 반환하기도 하고, list로 감싼 형태를 반환했다. 특히 금액(money) 필드를 포함한 데이터였기 때문에, 다운스트림 로직에서 금액을 누적하거나 통화 변환을 할 때 일관된 구조를 기대하는데 그렇지 않은 형태가 들어오는 순간 타입 강제 변환이 실패하거나 의도하지 않은 결과가 나왔다.

# Before: 반환값이 일관성 없음
def fetch_reviews():
    if single_review:
        return {"amount": 1000, "currency": "KRW"}  # dict
    else:
        return [{"amount": 1000}, {"amount": 2000}]  # list

# 호출처에서는?
for review in fetch_reviews():  # 경우에 따라 에러
    total += review["amount"]

# After: 항상 list 반환
def fetch_reviews():
    return [{"amount": 1000, "currency": "KRW"}]  # 0개, 1개, N개 모두 동일

데이터 계약의 중요성

이 문제를 마주하면서 느낀 건, 데이터를 다루는 함수는 명확한 계약을 지켜야 한다는 것이다. 호출하는 쪽에서는 함수가 "항상 이 형태를 반환한다"고 믿고 코드를 짠다. 그런데 실제론 케이스에 따라 다르면, 결국 호출처마다 defensive coding을 해야 한다.

# 반환값이 불명확하면 이렇게 번거로워진다
result = fetch_reviews()
if isinstance(result, list):
    reviews = result
elif isinstance(result, dict):
    reviews = [result]
else:
    reviews = []

for review in reviews:
    total += review.get("amount", 0)

이렇게 되면 코드가 지저분해지고, 팀원들이 이 함수를 제대로 이해하지 못한 채 쓸 가능성이 높다. 특히 금액 같은 민감한 데이터는 더욱 위험하다. 가격이 float일 수도, string일 수도, dict(amount + currency)일 수도 있으면, 실제 거래 처리에서 오류가 난다. 사실 이런 금액 버그는 나중에 데이터 검증 단계에서나 실제 결제까지 가서 발견되곤 한다.

데이터 파이프라인 설계할 때 주의사항

이번 경험을 바탕으로 팀과 나눌 체크리스트를 정리했다:

  • 반환값 형식은 1가지. 성공/실패는 별도 메커니즘(exception 또는 error field)으로 표현.
  • 복수형 데이터는 항상 list로. 0개, 1개, N개 모두 같은 형태. "없음"을 표현할 때 None 대신 empty list [].
  • 돈 관련 필드는 특히 조심. 단위(currency)를 항상 함께 포함하고, 타입을 엄격하게.
  • 반환값 변경은 호출처 검토 필수. grep으로 모든 호출 지점을 확인하고 영향도 평가.

이번 fix로 learn-update 흐름이 좀 더 견고해졌다. 예전엔 "이게 뭔가 불안정한데?" 싶으면서도 정확한 원인을 모를 때가 있었는데, 이제는 데이터 구조의 일관성 문제를 먼저 의심하는 습관이 생겼다. 앞으로 코드 리뷰 때도 반환값 계약이 제대로 지켜지는지 더 면밀하게 체크해야겠다는 생각이 든다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.