C.W.K.
Stream
Lesson 04 of 04 · published

지도는 자기 걸 하나도 안 저장해

~9 min · map, pure-projection, lazy-load, cheap-to-add

Level 0식은 화로
0 XP0/34 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"지도는 자기 걸 하나도 안 저장해."

시스템에서 가장 순수한 projection

Map 은 트랙 전체 규율의 가장 명료한 예야, 데이터를 절대 하나도 안 소유하니까. crumb 에 이미 있는 captured 와 intended 위치를 읽어, 점으로 그리고, 그 밖엔 아무것도 안 쥐어. '지도 DB' 도, 캐시된 핀 테이블도, 물건이 어디 있는지의 별개 사본도 없어. crumb 을 옮기고, re-file 하고, intended 위치를 고쳐도, Map 은 다음 읽기에서 그냥 변화를 반영해 — sync 어긋날 자기 버전이 애초에 없었으니까. Map 은 렌즈고, 렌즈는 아무것도 저장 안 해 — 진짜 거기 있는 하나에서 오는 빛을 굽힐 뿐이야.

구체적으론 열린 타일 소스 위 MapLibre GL 이고, 이미 아는 두-진실 우선순위 — intended 먼저, captured 둘째 — 를 쓰고, 좌표-우선이야 — Vesta 의 위치는 지명 geocoding 이 아니라 점이야. 근데 중요한 아키텍처는 경계야 — Map 이 보이는 모든 점이 crumb store 에서 오고, Map 이 하는 아무것도 거기로 되쓰지 않아. 위치 없는 crumb 은 그냥 안 나타나 — Map 은 아무것도 지어내지 않아.

가장 안전한 view 는 데이터를 안 소유하는 거야. 아무것도 저장 안 하는 projection 은 절대 drift 할 수 없고, 마이그레이션 필요 없고, 원천을 반박 안 하고, 아무것도 안 잃고 삭제될 수 있어. view 를 canonical store 위 순수 읽기로 표현할 수 있으면 그렇게 해 — 정확성을 공짜로 얻고 일관성 유지에 지속 비용을 안 내. view 의 저장은 부채고, 렌즈가 덜 소유할수록 더 믿을 만해.

구조상 lazy: Map 은 캡처에 절대 세금 안 매겨

데이터를 안 소유하는 건 Map 이 가장 중요한 것 — 캡처 — 의 길을 비켜 있게도 해. 지도 라이브러리와 타일은 lazy 하게 chunk 돼서, 앱을 열어 crumb 떨어뜨리는 게 청하지도 않은 지도를 절대 다운로드 안 해. 캡처 경로는 깃털처럼 가볍게 남고, 지리적 projection 은 네가 실제로 보러 갈 때만 로드돼. 이게 하나의-store 규율이 두 번째 배당을 내는 거야 — Map 이 필요할 때 읽는 자족적 렌즈니까, 통째로 미뤄질 수 있고, 5초 캡처 루프가 절대 그 무게를 안 져.

왜 projection 더하기가 계속 싸

물러서면 트랙 전체가 한 속성으로 풀려 — canonical store 가 하나 있고 모든 view 가 그 위 읽기니까, 새로 보는 방식을 더하는 게 구조상 싸. 어디서 가장 많이 쓰는지 히트맵, 단어-빈도 view, 월별-crumb 통계 페이지 원해? 각각 같은 crumb 위 새 쿼리야 — 새 렌즈지 새 store 가 아냐. 두 번째 진실 원천을 못 만들고, drift 할 수 없고, 데이터를 안 건드리고 더하거나 뺄 수 있어. 그게 one-state-many-projections 의 조용한 초능력이야 — 모델은 작고 canonical 하게 남고, 그걸 보는 방식의 수는 무한히 자랄 수 있어, 하나하나가 사본-당-view 설계가 매 쓰기에 매길 동기화 세금에서 자유롭게.

Code

Map: 순수 읽기, 열릴 때까지 미뤄짐·typescript
// the Map owns NO data — it reads crumbs and draws points
function mapPoints(crumbs: Crumb[]): Point[] {
  return crumbs
    .map(c => c.intended_location ?? c.captured_location) // precedence
    .filter(Boolean)                                       // no loc -> no point
    .map(toPoint);
  // nothing is written back; a crumb with no location simply isn't shown
}

// lazy-chunked: the capture path never pulls the map library/tiles
const Map = lazy(() => import("./MapView")); // loads only when you open Map

// adding a projection = another pure read, never a new store:
const heatmap = crumbs => bucketByWeek(crumbs);   // free to add, free to drop

External links

Exercise

네가 아는 시스템의 view 를 감사하고 각각 라벨링해 — 저장된 데이터를 소유해, 아니면 canonical 원천 위 순수 읽기야? 사본을 소유하는 view 마다, 대신 순수 projection 으로 만들려면 뭐가 필요할지, 어떤 부류의 sync 버그를 은퇴시킬지 물어봐. 그다음 완전 새 view 를 더한다고 상상해 — 싸(또 하나의 읽기), 아니면 비싸(sync 맞출 또 하나의 store)? 답이 모델이 얼마나 건강한지 알려줘.
Hint
순수-읽기 view 가 건강한 거야 — drift 없고, 마이그레이션 없고, 손실 없이 삭제 가능. 사본을 소유하는 view 는 지속 sync 비용이 있는 부채야. 좋은 모델의 신호는 새로 보는 방식을 더하는 게 사소하다는 거야 — 모든 새 view 가 동기화할 또 하나의 store 를 뜻하면, canonical-store 규율이 상류 어딘가에서 잃혔어.

Progress

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

댓글 0

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

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