본문 바로가기
C.W.K.
Stream
Lesson 01 of 04 · published

네트워크는 저장이 아냐

~12 min · local-first, critical-path, durability, anti-pattern

Level 0신호 없음
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"전송 버튼이랑 저장 버튼은 똑같이 생겼어. 이 둘을 한 동작에 묶어버린 게, 사라진 메시지 수천 개의 진범이야."

입력이 날아가는 자리엔 늘 이 혼동이 있어

'앱이 내 메시지 먹었어' 하는 사연은 거의 다 뿌리가 같아. 앱이 전송저장으로 다룬 거야. 타이핑하고 버튼 눌렀는데, 그 순간 네 말이 존재하는 데라곤 네트워크 위를 날아가는 중인 패킷뿐이었던 거지. 그 요청이 실패하면, 터널이든 타임아웃이든 앱이 백그라운드로 밀렸든, 돌아갈 데가 없어. 미리 적어둔 게 아무것도 없었으니까.

캡처 먼저는 그걸 거부해. 하나로 보이던 동작을 순서가 정해진 둘로 쪼개. 로컬에 커밋하고, 그다음에 보내기. 저장은 로컬에서 바로 끝나는, 안 없어지는 쓰기야. 전송은 그렇게 저장된 걸 읽어다 보내는 별개의 시도고, 몇 번이든 다시 할 수 있어. 네트워크는 저장 경로엔 절대 안 껴. 배달 경로에만 끼고.

임계 저장 경로

사용자가 뭘 하려는 마음이랑 그게 안 없어지는 상태 사이에 뭐가 끼어 있냐, 그 규칙이라고 생각하면 돼. 임계 저장 경로(critical save path)는 사용자 입력이 안전해지려면 반드시 성공해야 하는 단계 전부야. 네트워크가 그 경로에 끼어 있으면, 입력이 안 없어질 확률은 딱 연결이 버텨줄 확률만큼이고. 기차에선 그냥 동전 던지기지. 캡처 먼저는 네트워크를 그 경로에서 아예 .

  • 사용자 제출 → 로컬 저장소에 쓰기 → 끝. 입력은 안전.
  • 그거랑 별개로, sync 워커가 저장소를 읽어서 배달을 시도해. 지금이든, 나중이든, 앱 다시 켠 다음이든.

패킷이 폰을 떠날 때쯤이면 질문은 이미 잃을 수가 없어. 배달은 실컷 실패해도 돼. 네 말을 데려가진 못하니까.

순서가 전부야

마법은 전부 순서에 있어. await commitLocally()fetch() 를 부르기 전에 끝나야 해. 순서를 뒤집거나 둘을 같이 돌려놓고 잘되기를 바라면, 네트워크를 슬그머니 저장 경로에 도로 갖다 놓은 거야. 로컬 우선이라고 해놓고 사실은 아닌 경우가 제일 흔하게 이런 모양이야. 로컬 쓰기가 있긴 한데 전송 뒤에 붙어 있어서, 영영 안 올지도 모를 성공을 캐시하는 역할밖에 못 하는 거.

Code

맞는 순서 vs 틀린 순서·typescript
// 틀림: 네트워크가 저장 경로에 있음.
async function submitWrong(turn: PippaGoTurn) {
  const res = await fetch("/api/ask", { method: "POST", body: encode(turn) });
  await saveLocally(turn); // 너무 늦음 — fetch 가 던지면 여기 못 옴
}

// 맞음: 로컬에 먼저 커밋, 그다음 운송.
async function submit(turn: PippaGoTurn) {
  await commitLocally(turn);        // 입력은 이제 잃을 수 없음
  turn.syncStatus = "pending";
  await enqueueForDelivery(turn);   // 지금/나중/재시작 후 실행 가능
}

// 순서는 스타일 선택이 아냐. '내구 후 배달' 이랑
// '배달되거나 잃거나' 의 차이야.

External links

Exercise

메시지 제출을 의사코드로 두 번 써 봐. 하나는 로컬 저장을 네트워크 호출 뒤에 두고, 하나는 앞에 두고. 네트워크 호출이 예외를 던졌을 때 사용자한테 뭐가 남는지 각각 따라가 봐. 그 차이가 캡처 먼저의 가치 전부야. 아무것도 안 남느냐, 다시 보낼 수 있는 pending 메시지가 남느냐. 다섯 줄이면 보여.
Hint
네트워크가 앞인 쪽은 예외가 저장을 통째로 건너뛰어. 네트워크가 뒤인 쪽은 저장이 이미 끝나 있으니까 예외가 메시지를 failed 상태로 남기고 끝나. 다시 보내면 되는 상태로. 기능은 같은데 신뢰성은 정반대야.

Progress

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

댓글 0

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

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