"crumb 을 언제 썼나, 그리고 어느 날에 속하나. 이건 서로 다른 두 진실이야."
두 질문, 한 칸으론 둘 다 못 답해
모든 crumb 은 시간에 대해 두 질문에 답해. 이거 실제로 언제 썼어? 네가 탭하는 순간 기기가 아는 객관적 사실이지. 그리고 이거 어느 날에 속해? 네가 내리는 판단이고, 오늘일 수도 지난 화요일일 수도 다음 달일 수도 있어. 진짜로 다른 질문이고, 날짜 칸 하나엔 답이 하나만 들어가. 뭘 저장하든 그 칸은 이제 나머지 하나에 대해 거짓말하는 거야.
쓴 순간을 저장하면 backdate 를 못 해. 지난주에 속하는 기억이 이번 주를 가리키는 데 갇혀. target 날을 저장하면 진짜 쓴 순간을 없앤 거야. 3월로 던진 crumb 이 이제 3월에 쓰였다고 우기고, 실제로 언제 그 생각을 했는지의 정직한 기록은 그냥 사라져. 이걸 피하는 영리한 단일 값은 없어. 두 진실이 서로 독립이라 칸이 두 개 필요해. Vesta 는 그걸 captured_at(안 바뀌고 기기가 매김)과 target_date(저자가 배정, 유일하게 바뀌는 날짜)로 불러.
자리채움 날짜 병
그래도 둘을 뭉치는 팀한테 뭐가 일어나는지 봐. 날짜 칸 하나는 '특정 target 날 없음' 을 표현 못 해. 그래서 누군가 자리채움 값(sentinel)을 발명해. '미정' 이나 '알 수 없음' 을 뜻하는 마법 값이지. 유닉스 epoch, 먼 미래 9999년, 쿼리 절반이 처리를 까먹는 NULL. 그러고 그 값이 새기 시작해. 모든 목록 맨 위나 아래로 정렬되고, 날짜 범위 필터를 슬쩍 빠져나가고, UI 에 '1970년 1월 1일' 로 뜨고, 하류 쿼리마다 그걸 피하려 특수 케이스를 키워. 자리채움 값은 뭉개진 모델의 흉터야. 칸 하나가 두 일을 지다 무너졌다는 증거지.
Vesta 는 자리채움 값이 절대 필요 없어. 그게 모델이 맞다는 신호야. 모든 crumb 은 진짜 captured_at 을 가져. 어떤 실제 순간에 쓰였으니까. 그리고 진짜 target_date 를 가져. 저자가 어떤 날에 놨으니까. 어느 쪽도 '알 수 없음' 이 아니라, 발명할 마법 값도 기억할 특수 케이스도 샐 것도 없어.