/code-review medium 2회차 · Claude Code · Opus 5.5 · 클로드의 마지막 답 원문 · 목록
points.py에서 실제 버그 7개와 정리할 점 3개를 찾았습니다. 이번 리뷰는 검증 단계 없이 진행해서 일부는 오탐일 수 있습니다. 가장 심각한 건 앞의 세 개로, 모두 돈과 직결됩니다.
- 생일 적립률이 계속 쌓임: 생일에
self.rate를 직접 2배로 바꿔서 그 값이 남습니다. 생일에 두 번째 결제는 20%, 생일 다음 날에도 10%로 적립됩니다. - 포인트를 쓰면 하루 한도가 다시 풀림: 한도 계산이 그날 적립한 양이 아니라 남은 포인트를 더합니다. 그래서 쓰고 나면 같은 날 또 5,000까지 적립할 수 있습니다.
- 만료된 포인트부터 차감:
use()가 만료 여부를 보지 않아서, 1,000을 써도 잔액이 그대로 1,000으로 남는 경우가 생깁니다.
나머지 버그는 use()에 음수를 넣으면 포인트가 생기는 문제, 만료일이 하루 빨리 처리되는 문제(새로 생긴 버그는 아니지만 use()가 이 판정을 씁니다), 2월 29일 생일자가 평년에 2배 적립을 못 받는 문제 등입니다. 정리할 점과 테스트가 없다는 지적까지 포함한 전체 목록은 리뷰 결과에 있습니다.
찾은 문제 목록 (ReportFindings 도구로 넘긴 원문, 10건)
| # | 위치 | 분류 | 요약 | 일어나는 상황 |
|---|---|---|---|---|
| 1 | points.py:35 | 정확성(버그) | 생일 적립률이 영구 누적됨 생일에 `self.rate`를 직접 2배로 바꿔서 그 값이 영구히 남습니다. 생일에 결제할 때마다 다시 2배가 되고, 생일이 지나도 원래 비율로 돌아오지 않습니다. | 생일에 결제를 2번 하면 첫 결제는 10%, 둘째는 20%로 적립됩니다. 다음 날 10,000원을 결제하면 500 대신 2,000포인트가 쌓이고, 생일이 돌아올 때마다 비율이 계속 2배가 됩니다. |
| 2 | points.py:37 | 정확성(버그) | 포인트 사용 후 하루 한도가 다시 풀림 하루 한도 계산이 그날 적립한 양이 아니라 남은 포인트(entry[1])를 더합니다. `use()`가 이 값을 깎기 때문에, 포인트를 쓰고 나면 같은 날 다시 적립할 수 있게 됩니다. | 같은 날 5,000을 적립하고 5,000을 쓰면 earned_today가 0이 됩니다. 그 뒤 또 5,000을 적립할 수 있어서 하루 한도를 계속 넘을 수 있습니다. |
| 3 | points.py:54 | 정확성(버그) | use()가 만료된 적립분부터 차감함 `use()`가 만료 여부를 보지 않고 가장 오래된 적립분부터 깎습니다. 그래서 이미 만료된 포인트가 먼저 차감되고, 유효한 포인트는 그대로 남습니다. | 400일 전에 1,000(만료), 오늘 1,000(유효)을 적립했다고 하면 balance는 1,000입니다. use(1000)을 하면 만료분만 0이 되고 오늘 적립분 1,000은 그대로라서, 1,000을 쓴 뒤에도 잔액이 1,000으로 남습니다. |
| 4 | points.py:51 | 정확성(버그) | use()에 음수를 넣으면 포인트가 생겨남 `use()`가 음수나 0을 막지 않습니다. 음수를 넣으면 take가 음수가 되어 적립분에 포인트가 더해집니다. | use(-1000, today)를 호출하면 잔액 검사를 통과하고, 첫 entry에서 take=-1000이 되어 entry[1]이 1,000 늘어납니다. 포인트를 공짜로 만들 수 있습니다. |
| 5 | points.py:45 | 정확성(버그) | 만료 판정이 하루 빠름 만료 조건 `< EXPIRE_DAYS - 1`이 하루 짧습니다. 적립일을 1일째로 치면 365일째는 days==364인데, 이 조건에서는 그날 포인트가 빠집니다. 이 판정을 `use()`도 그대로 씁니다. | 1월 1일에 적립한 포인트는 365일째 되는 날까지 써야 하는데, 그날 balance에서 빠지고 use()에서는 '포인트가 부족합니다'가 납니다. 조건은 `< EXPIRE_DAYS`여야 합니다. |
| 6 | points.py:29 | 정확성(버그) | 2월 29일 생일자는 평년에 2배 적립 없음 2월 29일 생일은 윤년이 아닌 해에 (month, day)가 맞는 날이 없어서 생일 2배 적립을 받지 못합니다. | birthday=date(2000,2,29)인 손님은 2025~2027년에 2배 적립을 한 번도 받지 못합니다. 2/28이나 3/1로 대신 처리하는 규칙이 필요합니다. |
| 7 | points.py:38 | 정확성(버그) | 한도 도달 후 0/음수 entry가 쌓임 하루 한도에 이미 도달했어도 0포인트짜리 entry가 계속 추가됩니다. 또 earned_today가 어떤 이유로든 한도를 넘으면 음수 포인트가 기록될 수 있는데, 이를 막는 하한(max 0)이 없습니다. | 한도에 도달한 날 결제할 때마다 [today, 0]이 쌓여서 entries가 불필요하게 커지고 이후 계산마다 그만큼 더 순회합니다. 한도 상수를 낮추면 기존 적립분 때문에 음수 적립이 생길 수 있습니다. |
| 8 | points.py:23 | 단순화 | rate를 인스턴스 상태로 둘 필요 없음 `self.rate`는 상수에서 계산할 수 있는 값인데 인스턴스 상태로 들고 있습니다. `earn()` 안에서 지역 변수로 `rate = POINT_RATE * (2 if 생일 else 1)`을 쓰면 됩니다. | 필요 없는 가변 상태 때문에 1번 버그(비율 누적)가 생겼습니다. 지역 변수로 바꾸면 이런 종류의 버그가 생길 여지가 없어집니다. |
| 9 | points.py:54 | 효율 | use()에서 불필요한 정렬과 이중 순회 `use()`가 매번 balance()로 전체를 한 번 돌고, 다시 전체를 정렬합니다. entries는 append 순서대로 이미 날짜순이라 정렬할 필요가 없습니다. | 적립 내역이 많은 손님은 결제/사용할 때마다 O(n log n) 작업을 합니다. 순서대로 한 번만 돌면서 유효분만 차감하면 만료 버그도 같이 고쳐집니다. |
| 10 | points.py:49 | 테스트 | 새 규칙 테스트 없음 생일 2배, 하루 한도, 오래된 순 차감 같은 새 규칙에 대한 테스트가 하나도 없습니다. | 생일에 두 번 결제하기, 쓰고 나서 다시 적립하기, 만료분이 섞인 상태에서 사용하기 같은 경우를 테스트했다면 위 버그들이 바로 드러났을 것입니다. |