C.W.K.
Stream
Lesson 01 of 05 · published

보낸 명령이 곧 바뀐 상태는 아냐

~12 min · observed-state, async, optimistic-ui, state

Level 0릴 입문자
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"제출된 명령은 엔진이 확인하기 전엔 보이는 상태 변화가 아냐."

속도처럼 느껴지는 작은 거짓말

정지 버튼을 만드는 제일 빠르게-느껴지는 방법은 사용자가 클릭하는 순간 UI 를 뒤집는 거야: isPaused = true 설정하고, 그다음 엔진한테 정지하라고 말해. 즉각적으로 느껴져, 진짜 즉각적이니까 — UI 가 아무것도 안 기다렸어. 근데 방금 작은 거짓말을 했어. 엔진은 아직 정지 안 했어. 보통은 몇 밀리초 뒤에 할 거고, 아무도 안 알아채. 가끔은 안 해 — 느린 프레임, 에러, race — 그럼 이제 버튼은 한 가지를 말하고 영상은 다른 걸 해.

그걸 정지, seek, 트랙 선택, 속도, 전체화면에 걸쳐 곱하면, 컨트롤이 일어난 것의 보고가 아니라 네가 요청한 것에 대한 이야기인 플레이어를 만든 거야. 그 틈이 미치게 하는 버그가 사는 곳이야.

명령은 요청, 현실은 보고

고침은 코드이기 전에 사고방식이야: 네가 보내는 명령은 요청이고, 엔진의 관찰된 상태가 유일한 보고야. 보고 채널은 Track 2 에서 이미 만들었어 — 관찰되는 속성. 이제 진짜로 써: 요청을 보내고, 엔진 값이 실제로 바뀔 때 관찰되는 속성이 UI 를 업데이트하게 둬. UI 는 예측을 멈추고 반영을 시작해.

명령은 요청이지 결과가 절대 아냐. 상태를 참으로 만드는 유일한 건 시스템이 그걸 다시 보고하는 거야. 네가 보낸 것 말고 돌아온 것에서 UI 를 업데이트해 — 둘은 다른 이벤트고, 하나로 취급하는 게 모든 '버튼이 틀렸어' 버그의 뿌리야.

같은 기능을, 거짓말로 그리고 진실로:

낙관적 UI 도 자리가 있어 — 여긴 아냐. 싸고, 되돌릴 수 있고, 거의 확실한 동작(포스트 좋아요, 로컬 설정 토글)엔, 성공을 예측하고 실패 시 고치는 게 좋은 UX 야. 재생 진실 — 정지됐나, 그림이 어디 있나 — 엔 틀린 예측이 사용자가 지켜보는 거짓말이야. 낙관은 틀려도 싼 것에만 남겨.

Pending 은 정직한 상태야

요청과 보고 사이엔 진짜, 이름 붙일 수 있는 순간이 있어: pending. Ashen Reel 은 그걸 보여주는 데 거리낌 없어 — 동작이 진행 중이라는 짧은 힌트 — pending 은 정직하고 거짓 '완료' 는 아니니까. 중간 상태를 이름 붙이는 게 UI 가 진실을 연속으로 말하게 해줘: 요청됨, 그다음 pending, 그다음 엔진이 실제로 보고하는 뭐든. 어떤 단계도 나중 단계인 척 안 해.

Code

같은 정지 버튼, 거짓말로 그리고 진실로·swift
// BAD: optimistic. We declare the outcome before the engine acts.
func pauseNaive() {
    isPaused = true                              // UI now CLAIMS paused...
    try? mpvCommand(mpv, ["set", "pause", "yes"]) // ...but did it? we never checked.
}

// GOOD: send a request; let the observed 'pause' property report the truth.
func pause() {
    try? mpvCommand(mpv, ["set", "pause", "yes"])  // a REQUEST, nothing more
    // isPaused is updated ONLY by the observed-property handler (lesson 2.4),
    // when the ENGINE's pause flag actually flips. Until then the UI may show
    // a 'pending' hint -- never a false 'paused'.
}

// The difference isn't style. In the BAD version, isPaused and the engine
// can disagree forever. In the GOOD version, they cannot -- there's one source.

External links

Exercise

네 UI(나 API 클라이언트)에서 명령 보낸 직후 상태를 즉시 업데이트하는 곳을 찾아 — 토글, 상태 라벨, 진행 표시. 물어봐: 명령이 느리거나, 실패하거나, 시스템이 덮어쓰면 어떻게 돼? 그 동작이 싸고-되돌릴 수 있어(낙관 괜찮음), 사용자가 의존하는 진실이야(진짜 결과를 반영)? 한 케이스를 UI 가 확인된 결과에서 업데이트하고, 그 사이 정직한 'pending' 을 두게 다시 써.
Hint
모든 낙관적 업데이트에 대한 질문: '내 예측이 틀리면 얼마나 나쁘고, 사용자가 알아챌까?' 싸고 안 보임 → 낙관 괜찮음. 비싸거나 사용자가 보는 진실 → 요청 보내고, pending 보여주고, 현실이 보고할 때만 업데이트.

Progress

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

댓글 0

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

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