"재구축할 수 있으면, 절대 수리하지 마. 재구축 못 하면, 그건 파생물이 아냐 — 그리고 넌 그걸 알아야 해."
두 종류의 상태, 그리고 어느 건지 알아야 해
Recall 의 행은 전부 둘 중 하나야. 유지보수 이야기 전체가 어느 쪽인지 말할 수 있느냐에 달려 있고.
- durable 상태 — 지우면 진짜로 잃는 것들. 영상 record, 불변 run, release, 교정, job 이력. 이게 진실이야. 한 번 authored 되고, 버전이 있고, 다른 어디서도 다시 만들어낼 수 없어.
- 파생 상태 — durable 한 진실에서 계산해낸 투영. 전문 index, 품질 지표, 언젠가 붙을 vector index. 뭘 지워도 잃는 게 없어. 다시 계산하면 되니까.
이 분류는 사소한 bookkeeping 이 아냐. 수리 절차를 결정하는 거야. 여기서 틀리면 시스템이 썩기 시작하고.
파생 상태의 수리는 딱 하나: 재구축
검색 index 가 release 랑 어긋났다고 해보자. 투영 중에 크래시가 났든, 옛 버전에 버그가 있었든. 경험 있는 엔지니어는 다들 reconciliation 스크립트에 손을 뻗어. index 를 release 와 diff 하고, 차이를 찾고, patch 하는 거지. 수술처럼 정교하고 효율적으로 느껴지거든. 틀린 수야. Recall 은 그걸 대놓고 금지해.
이유는 이래. 그 patch 스크립트는 투영의 두 번째 구현이거든. index 에 뭐가 있어야 하는지 정하는 새 코드가, 이미 그걸 정하고 있는 진짜 투영 코드 옆에 하나 더 생기는 거야. 진실 하나에 구현이 둘. 그리고 언젠가 갈라져. 투영이 바뀔 때 아무도 reconciler 를 같이 안 고치니까. 그럼 조용히 살짝 틀린 행을 써놓고 고쳤다고 말하는 수리 도구가 하나 생기는 거야. 버그는 patch 에서 살아.
맞는 수는 더 단순하고 지루해. 영향받은 파생 행을 purge 하고 durable 소스에서 replay 해. index 가 어때야 하는지 아는 건 이미 있는 투영 코드 하나뿐이야. 그걸 다시 돌려. diff 도 없고, 두 번째 구현도 없고, 갈라질 일도 없어. 이게 딱 materialized view 야. 손으로 편집하는 테이블이 아니라 refresh 하는 cache. 형제 두뇌도 같은 규율을 따라. 파생 mirror 가 어긋나면 자기 append-only 진실에서 purge 하고 replay 하지, reconcile 하지 않거든.
널 정직하게 유지하는 테스트
그러니까 네가 소유한 상태마다 던져볼 질문은 이거야. 이걸 통째로 지우면 durable 한 뭔가에서 다시 지을 수 있어?
- 있다 → 파생물이야. patch 하지 마. 수리는 purge 하고 replay 하는 것 하나뿐이고, 언제든 마음 내킬 때 돌릴 수 있어야 해.
- 없다 → durable 이야. 네가 그러려고 했든 아니든. 그동안 버려도 되는 cache 로 다뤄왔다면, 아무 생각 없이 지울 물건 안에 선언 안 된 진실이 앉아 있는 거고.
두 번째 경우가 위험한 놈이고, 놀랄 만큼 흔해. 아무도 다시 계산 못 하는 계산된 field, 어떤 것의 유일한 사본을 쥐고 있는 cache, 소스에는 더 이상 없는 행을 품고 있는 index. 그런 걸 찾아내서 둘 중 하나를 고르게 만들어. 제대로 durable 하고 버전 있게 만들든지, 제대로 다시 지을 수 있게 만들든지. 안 되는 건 그 중간에 두는 거야. 어중간한 상태는 누군가 그걸 cache 로 취급하는 첫날 사라질 진실이니까.