Frontend
응답 속도가 빨라서 깜빡여 보이는 UI 해결하기
이력서 내용을 작성할 수 있는 기능을 구현하다가 고민했던 문제다.
이력서를 작성하는 Form에는 이력서의 제목, 직무, 자기소개, 프로젝트 등 여러가지 내용을 입력할 수 있도록 개발해야 했다. 하나의 이력서 파일은 새 이력서를 생성하는 버튼으로 생성되도록 했고, 이력서를 생성하면 DB에서는 이력서의
id
값으로 이력서를 구분한다. 사용자는 기본 값으로 생성되는 제목을 통해 구분하도록 구현되어 있다.내 이력서 목록
* 신입 프론트엔드 개발자 @@@입니다.
* 새 이력서 - 기본 값으로 생성되는 이력서 제목
* 새 이력서(1) - 기본 값으로 생성되는 이력서 제목
* 새 이력서(2) - 기본 값으로 생성되는 이력서 제목
게다가 이력서 아이템 하나에는 내부에 많은 Form을 가지고 있으면서 각 Form에 대한 저장 버튼이 있어야 한다. 문제는 이력서 제목에는 자동 저장을 사용하고 있다는 점인데, 여기에 자동 저장되었음을 나타내는 UI를 넣어주었다.
- 이력서 내부 각각의 Form (업무경험, 프로젝트 등)에는 저장 버튼이 있다.
- 주로 이력서를 작성할 때는 ‘각 잡고 시간을 들여서’ 하는 경우가 많으므로 각 항목에 대한 중요도가 높을 것이라고 판단했다.
- 이력서 제목을 작성하거나 수정한 뒤, 버튼을 통해 저장하는 방식은 누를 버튼이 너무 많아지기 때문에 불편할 것이라고 판단했다.
- 아니 제목까지 저장 버튼을 누르게 하는 건 좀 아니잖아? 라고 생각했다.
여러 회의를 통해서 이러한 방식으로 이력서 작성 페이지의 작동 방식이 결정되었는데, 일단 이 포스트에서 하고 싶은 얘기는 이런 방식이 효율적인지에 대한 고민은 아니다.
API 응답 시간이 달라서 깜빡여보인다.
제목 작성/수정 API 요청에 대한 응답이 항상 일정한 속도를 유지했으면 좋겠지만 이건 바람일 뿐이다. 어떨 때는 아주 짧은 시간(300ms) 내로 응답하다가 가끔 느려지거나 사용자의 네트워크 속도가 느릴 때(1000ms 이상)를 상정했다.
데이터가 저장되지 않은 상태로 사용자가 브라우저를 종료하거나 페이지에서 이탈할 가능성이 있을 것 같다. 이력서에는 작성할 내용이 많은 만큼 데이터가 저장되지 않거나 날아가 버린다면 열 받은 사용자는 이 서비스를 절대 사용하지 않을 것이 분명하다. 일단 사용자에게 API 요청과 응답이 있다는 것을 알리는 것부터 시작해보자.
…는 마음가짐으로 Progress Indicator를 하나 만들었다.
API 요청에 디바운스를 걸어 제목 값이 기존 값과 다르면서 사용자의 입력이 끊긴 후에 API 요청을 진행하게 하고 API 요청 후 응답을 받기 전에는 작은 Spinner UI가 돌아가도록 했다.
제목의 내용이 변경되면 POST 요청과 함께 Spinner가 돌아간다.
- 제목 자동 저장이 정상적으로 되었다면 초록색의 체크 아이콘을 표시한다.
- 에러가 발생하면 빨간색의 X 아이콘을 표시하도록 했다.
응답이 빠르니까 깜빡여 보인다.
API 응답 시간이 어느 정도 걸리는 경우 부드럽게 동작하는 것처럼 보였다. 하지만 API 응답 시간이 짧은 경우가 문제였다. 돌아가는 Spinner가 너무 순식간이라, 사용자가 Spinner 아이콘을 인식하지 못하고 거의 깜빡거리는 수준으로 UI가 덜컥거려 보이는 것이었다.
- 깜빡임 때문에 부자연스럽다.
- 제목 수정을 시도했는데 에러가 발생해서 다시 시도한 경우, 수정 요청이 다시 제대로 갔는지 사용자가 확인하기 어렵다.
깜빡임을 해결해보자.
고민1. 과감하게 Indicator를 제거하는 것도 한 방법이 될 수 있다.
Indicator가 없다는 가정 하에 시나리오를 하나 생각해본다.
만약에 사용자가 알뜰폰을 사용하는데 데이터를 다 사용하고 느려터진 3mbps 속도로 이력서를 작성하는 사람에게는 Indicator가 있는 게 더 낫지 않을까? 혹시나 사용자에게 갑작스러운 네트워크 에러가 발생해서 요청이 제대로 가지 않았다면? 자동 저장도 안되었는데 저장된 줄 알고 있다면?
Form 데이터를 브라우저에 저장해두고 날아가지 않게 하던가 하면 용서해주지 않을까? ⇒ 사용자일 때의 ‘나’는 보통 용서하지 않는 편이므로 기각
열심히 작성했는데 저장되지 않았더라는 시나리오가 더 열 받을 것이라고 생각해서 제거하지 않는 것으로 결정했다.
고민2. Spinner가 돌아가는 최소 시간을 주면 되지 않을까?
Spinner가 돌아가는 최소 시간을 줘보는 건 어떨까?
그렇다면 Spinner가 돌아가는 최소 시간을 얼마나 줘야 부드러운 사용자 경험을 줄 수 있을까? 대충 몇 ms를 넣어보고 ‘이 정도면 됐군’ 하지 말고 조금 더 근거가 있는 객관적 시간이 없을까 찾아봤다.
열심히 찾아보니 흡사한 고민이 담겨있는 글을 발견했다.
스켈레톤 UI라는 점이 다르지만, Progress Indicator의 목적을 가지고 동작한다는 점에서 내 고민과 비슷한 것 같다. 해당 글에서는 응답 평균 시간을 60ms 전후로 잡고, API 응답 시간이 짧은 경우에는 스켈레톤이 보여지지 않게끔 처리했다.
근거로는 UX 리서치 그룹 닐슨 노먼의 Progress Indicator에 대한 지침에 대한 포스트였는데, 필요한 내용만 발췌했다.
‘Progress Indicators Make a Slow System Less Insufferable’에서
- 약 1초 이상 걸리는 작업에는 Progress Indicator를 사용
- Loop Animation은 빠른 동작에만 사용
- Precent-done Animation은 10초 이상 걸리는 작업에 사용
- Static Indicator는 사용하지 말 것
- Don’t-click-again 주의는 사용하지 말 것
로드하는데 1초 미만이 소요되는 모든 항목의 경우 반복되는 애니메이션을 사용하면 주의가 산만해짐. 사용자는 화면에서 어떤 일이 발생했는지 따라갈 수 없고, 화면에 깜빡이는 내용에 대해 불안함을 느낄 수 있음.
“약 1초 이상 걸리는 작업에는 Progress Indicator를 사용”
역으로 생각하면 1초 미만으로 소요되는 작업에는 Progress Indicator를 사용하지 않는 것이 좋다는 말이다. 서비스 사용자들이 소요되는 시간에 대한 평균을 낼 수 있다면 좋겠지만, 현재 그럴 수가 없으니 평균 300ms을 생각하고 ‘1초 동안은 무조건 보여준다’를 기준으로 잡아보았다.
네트워크 속도가 빠른 사용자도, 느린 사용자도 API가 요청을 시작할 때 Spinner가 무조건 1초 이상 돌기 시작한 뒤에 받은 응답의 결과를 보여주면 문제 해결?
적용도 하지 않고 단점부터 생각해보자면, 응답 속도가 양호한 사용자 또한 요청에 대한 UI 피드백을 1초 이후로 강제한다는 점인데, 애초에 응답 속도가 양호한 사용자가 다수이지 않을까? 깜빡이는 느낌을 없애기 위해 다수의 사용자들에게 불편함을 줄 수 있을 것 같다.
고민3. 특정 시간 이상 응답이 오지 않을 때만 보여주는건 어떨까
그냥 응답 속도가 빠르면 Spinner를 보여주지 않으면 될 것 아닐까? 응답 속도가 느린 사용자에게만 Spinner가 1초 이상 도는 것이다. 그런데 응답 속도가 빠르거나 느린 건 사전에 알 수 없는데 어떻게 구현할 수 있을까?
특정 시간 이상 응답이 오지 않으면 Spinner를 띄우면 되지 않을까? 미약한 개발 실력으로 코드를 상상해본다. 응답이 1000ms 이내로 오지 않으면 Spinner를 띄운다.
(특정 시간 내로 응답이 오면 Spinner가 돌아가지 않고 바로 결과를 보여준다.)
좋다. 깜빡거리는 느낌이 없이 부드러워 보인다.
1000ms 이내로 응답이 오면 Spinner 없이 바로 결과 UI (저장 성공, 실패)가 보여진다.
기존에는 이전 응답에 대한 UI가 남아 있도록 구현되어 있어서, 만약 직전 요청이 실패한 상황이면 제목 입력 폼에 빨간 줄과 인디케이터에 빨간 X 표시가 그대로 남아 있다. 이 부분을 수정해서 입력이 다시 시작되면 입력 폼 UI를 처음으로 돌린다.
이 방식의 단점을 또 생각해본다.
응답이 1200ms로 오면 200ms 동안 Spinner가 도니까 깜빡임이랑 다를 바가 없잖아?
(젠장) 깜빡임을 없애고 사용자 경험을 개선하려고 시도한 작업인데, 또 다른 문제가 발생한다. 애매하게 1000ms를 기준으로 잡아서 그런건가? 하지만 그렇다고 정확한 응답 속도의 기준이 있는 것 같지도 않다. 2000ms를 기준으로 한다고 2200ms의 속도로 응답을 받은 사용자는 결국 깜빡임이 생긴다는 말이니까. 이걸 무시할 수가 없다. 문제에 대한 해결이 똑같은 문제를 낳는 모양새다 보니까 무한 쯔꾸요미에 빠진다.
결론
결국 2번 1000ms의 최소 로딩 시간을 주기로 결정
어찌저찌 이번 사건도 해결한 것처럼 보이지만, 문제를 근원(깜빡임을 없애자!)이 사라졌음에도 찝찝하다. 애초에 잘못 설계한 UI가 아니었을까? 에러가 발생했을 때만 알려주면 해결될 문제 아닐까? 완벽한 해결책은 없고 항상 트레이드 오프가 있다는 것이 담당 교수님의 가르침이었는데, 아직 장단점의 무게를 저울질하기에는 내공이 부족하다. 결국 희생되는 것이 있다는 점이 마음을 무겁게 한다.
이력서 제목 입력에 자동 저장 기능을 넣은 가장 큰 이유는 이력서 문서의 세부 사항이 각자 다른 form이기 때문에 저장 버튼이 많아지는데, 이력서의 제목을 입력하는 곳까지 저장 버튼이 생기는 것이 어색했기 때문이다. 기획이나 설계 단계에서 더 나은 방식을 생각할 수도 있었을 것 같다.
서버의 DB 구조가 더 효율적이어서 이력서의 세부 사항을 하나 하나 저장해야 하는 방식이 아니었다면 이런 UI에 대한 고민을 덜 수도 있지 않았을까? 애초에 Form을 사용자가 작성하기 더 편리하게 만들어서 자동 저장이니 하는 기능 없이도 저장 방식이 무진장 직관적이어서 불편함이 없게 했다면 좋았겠다.
UI/UX로 사용자의 불편을 잡아보려고 해도, 애초에 페이지의 설계와 성능이 뛰어나다면 굳이 화려한 것들을 집어넣을 필요가 없지 않을까. Notion은 전부 자동 저장되는데 따로 이를 알려주는 인디케이터 UI가 없다.
결국 로딩 시간이 길어지거나 오류가 자주 발생하는 애플리케이션에는 UI고 UX고… 말짱 꽝이 아닐까. 겉으로 보았을 때만 유려해 보이는 UI가 아니라 정말 사용자 경험을 위한 정순하면서도 겉으로 보기에도 아름다운 UI를 개발하고 싶다.
좋은 서비스를 만들기는 너무 어려워-!
하지만 깊게 고민한 과정으로 구현된 결과물을 보는 것은 즐겁다.