Krong Dev.
아카이브 목록

낙관적 업데이트(Optimistic Update)


금일 수업시간에 낙관적 업데이트를 잠깐 다뤘었는데요, 낙관적 업데이트는 쉽게 말해서 ’어차피 요청은 성공할거야!’라고 긍적적인 결과를 가정하고, 서버 응답이 오기 전에 클라이언트 화면을 먼저 바꿔버리는 것입니다.

예를 들어 그런 경우가 있습니다. 대중교통 이동중에 인터넷이 매우 느린상황에, 혹은 인터넷이 안되는 상황에 카카오톡 메시지를 보내면 채팅 내용은 보내진 것 같지만 종이비행기 아이콘이 옆에 붙어서 실제로 상대방에게 전달되지 않는 상황이 있습니다. 이러한 케이스가 낙관적 업데이트의 가장 대표적인 예시입니다.

이 낙관적 업데이트가 중요한 이유는 UX 때문인데요, 사용자 입장에서 분명히 메시지 전송 버튼을 눌렀는데, 전송이 안되고 멈춘 것처럼 보이면, 카카오톡 앱이 멈춘건지, 핸드폰이 멈춘건지 알지 못합니다. 사용자는 이러한 처리에 불친절하다고 느낄 수 있죠.

오늘은 ’없어도 돌아는 가지만, 필요한 기능’인 낙관적 업데이트에 대해 알아보겠습니다.

기본적으로 서버로 요청을 보낼 때는 클라이언트 요청 -> 서버 내 비즈니스 로직 -> 서버 응답의 순서로 진행되기 때문에 서버 응답이 온 후에야 UI에 반영이 됩니다. 그래서 네트워크가 느리거나 접속 불량인 상태라면 요청은 보내지긴 하지만, 요청이 서버까지 제대로 전달되지 않을 수 있습니다. 이런 경우에는 화면이 멈추고, 사용자는 답답함을 느끼고 무한 네트워크 요청을 보내게되면 결국 서버 과부화의 문제를 야기합니다.

물론 fetching, loading 동안에 재요청을 막아버리는 것도 하나의 해결책이긴 하지만, 사용자에게 ’도대체 무슨 문제때문에 이렇게 느리지?’라는 궁금증을 해소시킬 수는 없습니다. 하지만, 낙관적 업데이트는 자기 행동에 대한 피드백을 바로 받기 때문에 앱이 매우 빠르다고 느낄 뿐만 아니라, 네트워크가 약간 느리더라도 그 지연을 체감하지 못합니다.

HCI 초기 연구자인 Robert B. Miller는 응답 시간을 대략 세 구간으로 나누어 설명했습니다. - 출처: https://www.smashingmagazine.com/2016/11/true-lies-of-optimistic-user-interfaces/

  • 0.1초 이내의 응답 : 사용자가 거의 지연을 느끼지 못하는 ‘즉각적인 반응’으로 인식됩니다.
  • 약 1초 내의 응답 : 흐름이 유지되지만 사용자가 약간의 지연을 인식하는 구간입니다.
  • 10초 이상 : 사용자는 작업에서 마음이 떠나 다른 일을 하기 시작한다고 보고했습니다.

이러한 관점에서 보면, 낙관적 업데이트는 단순한 기술 트릭이 아니라 인간이 시간을 인지하는 방식에 맞춰 인터랙션을 설계하는 전략이라고 볼 수 있습니다.

이러한 낙관적 업데이트에서도 단점이 있는데요, 바로 ’구현의 복잡성’과 ’데이터 불일치’입니다.

구현의 복잡성

낙관적 업데이트의 구현 방식은 다음과 같습니다. (‘좋아요’ 기능을 예시로 들어보겠습니다.)

  1. 이전 상태를 저장 -> 좋아요가 false인 상황을 저장
  2. 클라이언트에서 서버로 요청을 보냄 -> 좋아요를 true로 만들기 위한 서버 요청
  3. 요청을 보냄과 동시에 UI 반영 (낙관적 업데이트)
  4. 좋아요 요청이 서버로 도달하면, 서버에 true로 상태 저장
  5. 저장된 좋아요 상태를 클라이언트로 응답
  6. fulfilled(서버 요청 성공 시)클라이언트에 서버 상태 저장(유지) : 좋아요 true
  7. reject(서버 요청 실패인 경우) : 이전 상태(좋아요: false)로 롤백(rollback)

이러한 복잡한 에러상황에서 기존 상태로 롤백해야하는 복잡한 에러처리를 구현해야 하는 추가적인 로직을 구현해야 합니다.

데이터 불일치

낙관적 업데이트가 구현만 하면 다 좋을 것 같은데? 라고 할 수 있지만, 절대!! 사용하면 안되는 경우가 있습니다. 가장 대표적인 예시로는 ‘은행 결제 시스템’ 즉, 데이터 무결성이 매우 중요한 경우입니다.

금융 거래, 재고 관리 등 서버의 실제 처리 결과가 failure를 반환할 경우 클라이언트가 미리 반영한 데이터와 서버의 실제 상태가 불일치할 위험이 큽니다. 특히 여러 사용자가 동시에 같은 리소스를 대상으로 수정하게 될 경우에도 경쟁 상태(race condition)를 유발할 수 있기 때문에 피해야합니다.

위와 같은 다른 사용자와의 실시간 동기화가 중요한 서비스에서는 낙관적 업데이트를 피해야합니다.

결론적으로, 대부분의 상호작용에 대해서는 낙관적 업데이트를 사용하는 편이 체감 성능과 UX 측면에서 분명한 이점을 주지만, 구현 복잡도와 데이터 정합성(rollback, 충돌 처리, 에러 UX 등)에 대한 부담이 커지기 때문에 도메인별로 신중하게 적용 범위를 좁혀 가는 전략이 필요합니다.

  • #배움일기
  • #React