전에 운영하던 거래소에서 특정 회원만 수수료를 면제해야 하는 요구가 왔는데 대상이 하나였다. members 에 fee_exempt 컬럼을 하나 만들어 그날 배포했고 그때는 그것이 맞았다.
Table of contents
Open Table of contents
배경 — 하나일 때의 컬럼
예외가 하나면 컬럼이 간단하고 빠르다. 그 하나 말고는 영향을 주는 곳도 없다.
문제는 그 판단이 언제까지 유효한가였다. 하나일 때 맞는 선택이 둘이 되는 순간에도 맞으리라는 보장은 없다.
막힌 지점 — 두 번째가 부류의 신호였다
몇 달 뒤 다른 회원에 출금 한도를 따로 두는 예외가 필요해서 withdraw_limit_override 를 하나 더 만들었다. 그때도 괜찮아 보였다.
두 번째가 온다는 것은 이것이 하나짜리 예외가 아니라 부류라는 신호였고 그 시점에 갈랐어야 했다. kyc_skip 과 api_rate_override 는 그 뒤에 왔다.
원인 — 조합이 만든 읽을 수 없는 조건
컬럼이 다섯이 되자 대부분의 행에서 그 값들이 NULL 이었다. 그리고 조합 요구가 생겼다.
어떤 것은 되고 어떤 것은 안 되는데 특정 조건일 때만 예외라는 요구를 컬럼 조합으로 쓰면 WHERE 절을 읽을 수 없게 된다. 조건을 읽을 수 없다는 것은 그 조건이 맞는지 검증할 수 없다는 뜻이다.
해 본 것 — 옮기는 비용과 순서
member_exceptions 표로 옮기려니 기존 컬럼을 읽는 코드를 전부 찾아 고치고 값을 행으로 옮기고 동시 운영 기간을 둬야 했다. 두 번째에 옮겼으면 컬럼 하나와 코드 몇 줄이었을 일이 다섯 컬럼과 수십 곳이 됐다.
그래도 옮기는 쪽을 골랐다. 이유는 요구가 계속 오고 있어서 미루면 더 커진다는 것이 명확해서다. 대신 동시 운영 기간 동안 컬럼과 표 양쪽을 읽는 코드가 잠시 공존하는 것을 감수했다. 새 표를 만들고 값을 옮긴 뒤 읽는 코드와 쓰는 코드를 차례로 바꾸고 마지막에 컬럼을 지웠다.
조치 — 테이블에서 얻은 세 가지
옮기고 나서 valid_from 과 valid_to 를 적을 수 있게 됐는데 컬럼에는 기간을 못 넣어서 한시적 예외를 영구 예외로 만들 수밖에 없었다. reason 을 적을 수 있게 되어 누가 언제 왜 요청했는지가 남았다.
가장 큰 것은 현재 어떤 예외가 몇 개 있는지 GROUP BY kind 한 번의 조회로 나온다는 점이었다. 컬럼일 때는 각각을 따로 세야 해서 예외가 전부 몇 개인지 아무도 몰랐다.
정리
- 예외가 하나일 때는 컬럼이 맞다
- 하나일 때 맞는 선택이 계속 맞다는 보장은 없다
- 두 번째가 오면 그것이 부류라는 신호다
- 세 번째를 기다리지 않고 그 시점에 옮긴다
- 컬럼이 늘면 조합 조건을 읽을 수 없게 된다
- 읽을 수 없는 조건은 맞는지 검증할 수도 없다
- 테이블로 옮기면 기간과 사유와 목록을 얻는다
- 컬럼으로 시작할 때 옮길 시점을 주석에 적어 둔다