본문 바로가기
C.W.K.
Stream
Lesson 02 of 05 · published

현금은 지키는 값이지, 계산하는 값이 아냐

~10 min · ground-truth, authoritative-data, fallback-discipline, data-model

Level 0Open Gate
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"어떤 숫자는 계산해서 얻고, 어떤 숫자는 그냥 전해 들어. 현금은 전해 듣는 쪽이야. 그러니 믿어. 다시 계산하려 들지 말고."

모델을 정직하게 지키는 구분 하나

Keep 에서 owner 의 stored cash 잔고는 ground truth 야. 사람이 직접 입력한 권위 있는 값이고, Keep 는 그걸 그 사안의 진실로 취급해. 'seed 금액에서 포지션 총 cost 를 빼면 되잖아' 라고 슬쩍 재구성하지 않아. 그 재구성이 꽤 유혹적이긴 해. 숫자가 대개는 맞아떨어지거든. 근데 현금을 저장하는 대신 계산하는 순간, 현금은 모든 포지션 row 가 빠짐없이 정확해야만 성립하는 파생값이 돼 버려. cost 하나만 빠져도, 불완전한 과거 row 하나만 있어도, 계산된 현금은 거짓말을 시작해.

ground truth 와 파생값, 이 구분이 왜 중요한가

시스템의 모든 값은 둘 중 하나야. ground truth 는 누군가 사실이라고 선언한 값이라 선언 자체로 권위를 가져. 파생값은 다른 값들에서 계산돼 나오니까 입력이 온전할 때만 권위를 갖고. 현금은 ground truth 야. 직접 지키는 값이고, 충돌이 나면 이 값이 이겨. Family 총합은 파생값이지. owner 들한테서 계산돼 나오니까(앞 트랙에서 봤지). 실력이란 어느 값이 어느 쪽인지 아는 거야. 그리고 공식이 '대개 맞으니까' 라는 이유로 ground truth 를 슬그머니 파생값으로 강등시키지 않는 거고.

권위 있게 전해 들은 값을 다시 계산하지 마. 사실로 입력된 값이라면, 저장해 두고 믿는 게 '같은 답이 나와야 하는' 공식으로 유도하는 것보다 옳아. 공식은 입력이 온전해야 성립하지만 저장된 사실은 그렇지 않거든. 둘이 어긋난다면, 그 어긋남 자체가 네가 발견하고 싶었던 버그야. 덮을 게 아니라.

표시 붙은 fallback, 단 하나의 예외를 시끄럽게

seed 빼기 cost 가 허용되는 경우는 딱 하나야. stored cash 가 기록된 적 없는 불완전한 과거 row. 그 한 경우에만 Keep 는 계산된 추정치로 물러설 수 있는데, 그때도 추정치라는 표시가 또렷하게 붙어. 호환용 fallback 이라고 자백하지, 진짜 저장값인 척은 절대 안 해. fallback 은 조용히 숨지 않고 눈에 보여. 그래서 지금 보는 현금이 전해 들은 값인지, 옛 row 에서 추측해 낸 값인지 언제나 구분할 수 있어.

fallback 은 자백하게 만들어. 진짜 데이터 자리를 말없이 메우는 fallback 이야말로 '대충 맞음' 을 '틀렸는데 믿어짐' 으로 바꾸는 지름길이야. 'seed 빼기 cost 로 추정, 원본 현금 기록 없음' 이라고 스스로 라벨을 다는 fallback 은 읽는 사람이 무게를 제대로 달게 해 줘. 정직한 fallback 의 조건은 하나야. 자기가 fallback 이라고 인정하는 것.
owner 마다 ticker 당 포지션 하나. 스냅샷의 나머지도 똑같이 평평해. owner 마다 ticker 당 row 딱 하나. 서로 상계해야 할 lot 더미 같은 건 없어. 이 평평함이 스냅샷을 스냅샷답게 만들어. 지키는 사실은 stored cash 와 ticker 당 포지션 하나, 이 둘뿐이고 나머지는 전부 그 위에서 계산돼.

Code

stored cash 가 이기고, fallback 은 자백한다·python
def owner_cash(owner):
    row = cash_row(owner)
    if row is not None and row.balance is not None:
        # Ground truth: 사람이 알려준 값이야. 믿어.
        return {"amount": row.balance, "source": "stored"}

    # 불완전한 과거 row 에만 허용되는 표시 붙은 추정치.
    # 진짜인 척 조용히 흘려보내는 일은 없어.
    est = seed(owner) - total_cost(owner)
    return {"amount": est, "source": "estimated:seed-minus-cost"}

# 호출자는 자기가 받은 숫자가 어느 쪽인지 항상 알 수 있어.
# 'stored' 는 믿고, 'estimated:*' 는 라벨 달린 fallback 으로 보여줘.

External links

Exercise

네가 아는 시스템에서, 어떨 땐 저장돼 있고 어떨 땐 공식으로 계산되는 값을 하나 찾아 봐. 잔고든 카운트든 총합이든. 어느 쪽이 ground truth 여야 하는지 정한 다음, '표시 붙은 fallback' 버전을 써 봐. 저장값이 없으면 추정치를 계산하되, 추정이라는 걸 호출자가 알 수 있게 태그를 다는 거야. 조용한 버전과 나란히 놓고, 조용한 쪽이 숨기게 될 구체적인 버그를 짚어 봐.
Hint
위험한 패턴은 '저장값 없으면 그냥 계산해서 똑같이 리턴' 이야. 그러면 호출자가 믿을 값과 추측한 값을 구분할 길이 없어. source 태그 하나만 달아 봐. 'stored' 와 'estimated'. 그 순간부터 downstream 의 모든 소비자가 이 숫자를 얼마나 믿을지 스스로 정할 수 있게 돼.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.