로토님께서 강의에서 언급하시고 Todo List에서 구현해본 ‘낙관적 업데이트(Optimistic Update)’에 대해 좀 더 알아보자.
+ 2022년 웹 트렌드로 optimistic design이 소개되었다고 함!
낙관적 업데이트란?
API 요청의 성공/실패와 상관없이 사용자에게 성공한 모습을 먼저 보여주는 것이다.
일반적으로 SNS의 좋아요 기능 등에 적용한다.
송금, 결제, 주식 체결 등 민감한 기능의 경우 실패 시 사용자에게 치명적인 영향을 줄 수 있으므로 적절하지 않다.
React에서는 react-query의 useMutation으로 구현한다.
웹 2.0 이전
아주 오래 전의 웹 인터페이스는 있는 그대로의 과정을 보여줬다. 액션의 성공을 예측할 수 있는 힌트가 없었다.
예. 버튼 인터랙션 과정 사용자가 버튼을 클릭한다. → 버튼이 비활성화 상태로 바뀐다. → 서버에 요청을 보내면 서버에서는 페이지로 응답을 보낸다. → 응답 결과를 보여주는 페이지가 새로 로딩된다.
이런 인터랙션은 오류가 발생할 가능성이 적다. 비활성화된 버튼을 통해 서버로 신호를 보낸 걸 사용자에게 알려주고, 서버가 응답을 하면 페이지가 업데이트되면서 액션이 끝났다는 것을 확실하게 보여준다.
하지만…
- 사용자의 인내심이 필요하다. 서버의 최소 응답 시간이 페이지뿐만 아니라 서비스의 이미지에 부정적인 영향을 미친다.
- 새로운 페이지가 로딩되는 것은 작업 중인 사용자의 맥락을 끊고 몰입을 방해한다.
웹 2.0 이후
XMLHttpRequest와 AJAX를 통해 서버에서 응답을 받은 후 페이지를 다시 로딩하지 않고도 이미 만들어진 페이지의 일부를 업데이트할 수 있다. 스피너(spinner)를 통해 사용자에게 시스템이 작업을 진행하는 중임을 알려줄 수 있다.

예. 버튼 인터랙션 과정 사용자가 버튼을 클릭한다. → 버튼이 비활성화되면서 스피너로 시스템이 작업 중임을 알려준다. → 서버에 요청을 보내고 서버에서 페이지로 응답을 보낸다. → 응답에 따라 버튼과 페이지가 업데이트된다.
페이지를 다시 로딩하지 않아도 되기 때문에 사용자가 맥락을 유지하면서 인터랙션에 몰입하기 훨씬 좋아졌다!
하지만 역시…
사용자는 여전히 서버로부터의 응답을 기다려야 한다. 아무리 응답 속도가 빠르더라도 사용자는 애초에 기다리는 것을 싫어하고
스피너 = 시스템의 느린 정도를 보여주는 것
으로 인식한다.(스피너가 도는 동안 아무것도 할 수 없고 기다리기만 해야 함..! 아 답답해ㅐ)
낙관적 UI
API가 안정적이고 프론트엔드에서 UI를 잘 조작한다면 사용자의 액션에 대한 응답으로 오류가 뜰 확률은 상당히 낮을 것이다. 97-99%의 경우 웹 사이트에서 버튼을 클릭했을 때 서버의 응답은 오류 없이 성공적으로 돌아올 것이다.
응답에 대한 확신이 있다면 기다리게 하지 말고 바로 인터랙션의 결과를 보여주는 건 어떨까?
예. 버튼 인터랙션 과정 사용자가 버튼을 클릭한다. → 바로 성공 상태를 볼 수 있게 된다!
대부분 서버에서 보낸 응답이 성공적일 것이다.
SNS에서 좋아요 버튼을 클릭하면 바로 성공을 알리는 시각적 상태로 바뀐다(e.g. 빈 하트 → 채워진 하트). 실제로는 서버 요청이 진행되는 중이지만, 서버 응답을 받기 전에 바로 UI를 변경하여 사용자가 대기 시간을 인지하지 않고 방해받지 않게 된다.
그래도 1-3%의 확률로 서버가 오류를 응답으로 보내거나, 사용자가 오프라인 상태일 수 있다. 낙관적 UI에서 가장 중요한 건 오류를 어떻게 대응하냐가 아니라, 언제 대응하냐이다. 인터랙션에 몰입한 상태에서 2초 안에는 실패를 알려줘야 자연스럽다.
트위터의 경우 응답 실패 시 버튼의 상태를 슬쩍- 원래 상태로 되돌리는 방식으로 대응한다.
사용자에게 오류가 발생했다고 직접 알릴 수는 있겠지만, 갑자기 알림을 보내면 결국 또다른 맥락을 만들어버리게 된다..! 큰 규모의 웹 사이트에서는 적절할 수 있겠지만, 좋아요 버튼을 누르는 것처럼 단순한 액션에 대해서는 과한 대처일 수 있다.
(마찬가지로 Todo List에서 삭선 처리나 삭제 버튼을 누르는 것도 단순한 액션이라고 보고 낙관적 업데이트로 처리했던 것이다.)
의미있는 낙관적 업데이트를 위해 고려할 점
- API가 안정적이고 예측할 수 있는 결과 값을 보여주는지 확인해야 한다.
- API의 응답시간을 알아야 한다. 응답 시간이 항상 2초 미만이라면 낙관적인 업데이트를 적용해도 좋다.
- UI 요소가 간단할수록 낙관적 업데이트를 간단히 적용할 수 있다.
- 버튼 클릭뿐만 아니라 페이지의 라이프사이클 동안 발생하는 다양한 인터랙션과 이벤트에 적용할 수 있다.