Skip to main content

인포메이트 5주차 공유(UX)

· 21 min read

인포메이트 5주차 공유(UX) 모음입니다.

쉽게 놓칠 수 있는 더 나은 로그인/회원가입 UX 팁 - 곽승주
사용자 친화적인 에러 처리하기 - 윤해진
로딩 시간에 따른 다른 사용자 경험 처리 - 김하나

Intro

지금까지 정말 많은 로그인, 회원가입을 해오셨을텐데, 그 과정에서 자신도 모르게 불편했던 경험이나 편했던 경험이 있으셨을 것입니다. 엄청 큰 차이는 없어 느끼지 못하셨을 수도 있지만, 사소한 차이를 통해 사용자가 더 빠르게 혹은 편리하게 로그인, 회원가입을 할 수 있게 도와주는 팁을 알려드리려고 합니다.

1. 첫 번째 필드에 autofocus

로그인 페이지나 회원가입 페이지로 이동하면 보통은 첫 칸을 선택해 입력하기 마련입니다. 그러기 위해서는 그 칸을 클릭해야하는데 그런 수고없이 자동으로 그 칸을 선택해준다면 편리하지 않을까요? 그 방법으로는 input 태그의 autofocus 속성을 사용하면 됩니다.(리액트에서는 autoFocus 사용)

<input placeholder="아이디를 입력하세요" autoFocus />

※참고: eslint에서는 접근성 관련 우려로 autofocus 사용을 금지합니다. The autoFocus prop should not be used, as it can reduce usability and accessibility for users. eslint[(jsx-a11y/no-autofocus)](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/no-autofocus.md)

2. 모바일용 특수 키보드 설정하기

모바일의 경우에서 입력 칸을 선택 시에 키보드가 생성되는데 입력할 값만 들어있는 키보드가 있다면 정말 편리할 것입니다. 예를 들면 학번이나 전화번호 같은 경우 숫자만 필요한데, 문자도 키보드에 들어있어서 숫자 패드가 작아지는 경우에는 숫자를 터치하기 불편할 것입니다. 이를 해결하기 위해, input 태그의 type 속성을 num, tel, email로 하여 특수 모바일 키보드가 나오게 할 수 있습니다. numtel의 경우는 숫자만 나오게 되고, email의 경우 기존 키보드에는 없었던 @ 또는 .com이 나오게 됩니다.

이미지

3. 비밀번호 요구사항 표시

회원가입 시 보안을 위해 비밀번호에 특수문자 하나 이상, 숫자 하나 이상, 전체 8글자 이상 등의 요구를 할 것입니다. 따라서 그 요구사항을 알려주기 위해 비밀번호 입력칸 아래에 조건을 보여줘야 합니다. 만약 그 조건을 만족했다면 조건을 만족했다는 표시를 하거나, 조건 표시를 없애는 것은 사용자가 잘 입력했는지 확인할 수 있는 방법이 됩니다.

4. 비밀번호 확인

회원가입 시 사용자가 비밀번호를 올바르게 쳤는지 확인하기 위해 비밀번호를 두 번 입력하게 할 수 있습니다. 하지만 사용자 입장에서는 자신이 입력한 비밀번호를 볼 수 있게 하는 것이 비밀번호를 두 번 입력하는 것보다 덜 번거로울 것입니다. 그 방법으로는 input의 type 속성password로 되어있는 것을 text로만 바꾸면 됩니다. 그 방법은 아래와 같습니다.

  const [isShowPwChecked, setShowPwChecked] = useState(false);

const handleShowPwChecked = () => {
const { password } = loginRef.current;
if (password === null) return;

setShowPwChecked(!isShowPwChecked);
if (!isShowPwChecked) {
password.type = 'text';
} else {
password.type = 'password';
}
};

그리고 아래 요소를 넣어주면 다음과 같이 나타낼 수 있습니다.

<div className="show_password_button">
<label>
<input type="checkbox" onChange={handleShowPwChecked} />
<span className="show_password_title">비밀번호 보기</span>
</label>
</div>
이미지

5. Sign-in과 Sign-up 같이 사용하지 말기

Log in과 같은 의미인 Sign in을 회원가입을 뜻하는 Sign up과 같이 보여주게 되면 사용자 입장에서는 헷갈릴 수 있습니다. 영문이 익숙치 않은 한국인에게는 더더욱 헷갈릴 수 있습니다. 따라서 우리나라 말로는 ‘로그인 / 회원가입’ 이라는 말로 대체할 수 있고, 만약 영문으로 표현해야한다면 Register / Sign in, Create account / Log in, Sign up / Log in 등으로 표현할 수 있습니다.

6. 로그인 창과 회원가입 창 간 쉬운 이동

만약 로그인 버튼이나 회원가입 버튼을 잘못 눌러서 페이지 이동이 되었다면 사용자는 뒤로가기를 하고 다시 원하는 버튼을 클릭해야할 것입니다. 이런 번거로움을 방지하기 위해 로그인 페이지에서는 회원가입 페이지로 이동할 수 있게, 회원가입 페이지에서는 로그인 페이지로 이동할 수 있게 하면 좋을 것입니다. 예를 들어, 회원가입 페이지에서는 이미 계정이 있으신가요? **Log in** 이라 표시할 수 있고, 로그인 페이지에서는 계정이 없으신가요? **Sign up**이라 표시할 수 있습니다. 아니면 간단하게 아이디 찾기 | 비밀번호 찾기 | 회원가입으로 나타낼 수도 있습니다.

사용자 친화적인 에러 처리하기 - 윤해진

들어가는 말

사이트를 이용을 하며 어떠한 에러를 직면하는 상황은 많이 겪어보셨을 것이라고 생각합니다.

여기서 에러가 났을 때의 적절한 사이트의 대응에 따라 사용자 경험의 차이가 있을 것입니다. 또한 이것은 사이트의 완성도에도 영향을 미칠 것이라 생각합니다.

사용자가 해결을 할 수 있음과 없음, 의도가 된, 되지 않은 에러의 차이점에 대해 이야기해 보고 BCSD의 서비스에서는 어떠한 방향으로 사용해 볼 수 있을지 적어보려 합니다.

1) 어떤 에러가 발생할 수 있을까요? :

크게 나누어 환경, 사용자와의 에러로 나누고 세부적으로는 두 타입으로 나눌 수 있습니다.

[환경과 에러]

  1. 의도가 된 에러(예상 가능한 에러)

  2. 의도가 되지 않은 에러(예상하지 못한 에러)


[사용자와 에러]

  1. 사용자가 해결할 수 있는 에러

  2. 사용자가 해결하지 못하는 에러

예시를 들어 위 에러를 설명해보겠습니다.

  • 의도가 된 에러(예상 가능한 에러):

    로그인을 하지 않아 인증이 되지 않은 계정으로 로그인이 필요한 페이지에 접근을 할 때에는 서버에서 401 Error를 내곤 합니다.

    또한 잘못된 접근을 시도했을 땐 403 Error를 내곤 합니다.

    그 외에도 도메인 특성에 따라 사전에 조율이 되어있는 에러가 있을 수 있습니다.

  • 의도 되지 않은 에러(예상하지 못한 에러):

    서버에서 내는 500대의 error는 의도 되지 않은 에러라 판단할 수 있습니다.

    언제 어디서 나타날지도 모르고 어느 부분에서 일지 예측 불가능하기 때문입니다.

    그리고 사용자의 네트워크 환경에 따라 발생할 수 있는 에러, 사용자의 브라우저 환경에서 발생할 수 있는 에러는 예측하기 어렵기 때문에 의도 되지 않은(예측할 수 없는 에러)로 분리할 수 있습니다.

  • 사용자가 해결할 수 있는 에러:

    만약 로그인이 필요한 페이지에 로그인이 되지 않은 상태에서 접근을 하게 되었다면 사용자는 401 과 관련된 에러를 마주할 것입니다. 이때는 로그인을 함으로 해당 에러를 처리할 수 있을 것입니다.

    또한 네트워크가 좋지 않은 것에 대한 이슈라면 네트워크 설정을 확인한다 등으로 사용자의 액션을 통해 에러가 해결 가능할 수 있습니다.

  • 사용자가 해결할 수 없는 에러:

    그러나 사용자에게 어떤한 에러 상황인지를 말해주어도 액션을 취할 수 없는 경우가 있습니다.

    사용자가 사용하는 기기에서는 지원하지 않는 상황 혹은 더 이상 해당 기능을 제공하지 않는 경우 등이 있을 것입니다.

이미지

출처: https://www.jbee.io/articles/react/클라이언트의 사용자 중심 예외 처리

위의 사진이 앞서 설명한 에러의 경우에 대해서 보기 좋게 표현하고 있습니다.

2) 어떤 방식으로 사용자에게 친절한 에러를 표현할 수 있을까요?

  • 예상할 수 없고, 해결 방법이 있는 에러

    예시로 네트워크 에러의 경우를 들 수 있습니다.

    이의 경우 네트워크 환경을 확인하라는 안내 문구를 제시하는 방향으로 사용자의 에러에 대한 원인과 액션을 제안할 수 있습니다.

  • 예상할 수 없고, 해결 방법이 없는 에러

    이 부분은 개발 단계에서 꼼꼼히 체크하여 사용자가 위와 같은 에러를 직면하지 않게 하는 것이 제일 좋은 대응법일 것입니다.

    그럼에도 불구하고 위와 같은 에러를 사용자가 보았을 경우에는 고객 센터 및 문의 채널 진입로를 안내하는 액션을 취할 수 있을 것입니다.

  • 예상할 수 있고, 해결 방법이 있는 에러

    이는 기획 파트에서 설계된 부분일 것입니다.

    위의 경우에는 에러의 경우에 맞게 설계된 로직을 따르면 될 것입니다.

    -로그인 필요한 401 ⇒ 로그인 페이지로 이동

    -잘못된 페이지 접근 404 ⇒ 메인 혹은 랜딩 페이지로 이동

  • 예상할 수 있고, 해결 방법이 없는 에러

    예상은 할 수 있지만 해결할 방법이 없다는 것은 기획 개발단에서 놓친 에러가 있다는 것이라 할 수 있습니다. 혹은 사용자가 고의적으로 비정상적인 접근을 한 경우로도 파악할 수 있습니다. 따라서 해당 에러는 보안상의 허점 및 에러 경우의 수를 보완해야 할 것입니다.

이미지

출처: https://www.jbee.io/articles/react/클라이언트의 사용자 중심 예외 처리

3) 우리 서비스에 어떤 식으로 녹여볼 수 있을까요?

**Koin(코인)**으로 예시를 들어보겠습니다.

  • 버스/교통 PART

    만약 버스/교통 부분에서 API의 500 ERROR가 오고 있는 경우에 어떤 식으로 위 방법을 활용할 수 있을까요?

    제 생각에는 이는 예상하지 못한 그리고 사용자가 해결하지 못하는 에러일 것입니다.

    따라서 서버 error가 오는 API를 활용하는 부분에 Error Boundaries 등을 활용하여 “서버에 에러가 발생하였다 빠르게 수정하겠다.”라는 내용을 담은 안내 문구를 띄우는 방식으로 보다 사용자에게 확실한 전달을 할 수 있을 것이라고 판단됩니다.

  • 시간표 PART

    만약 시간표에 새로운 기능이 추가되었다는 가정을 해봅시다.

    그러나 해당 기능에서는 무조건 적인 회원만 접근 가능하다는 기획입니다.

    이 경우에 로그인을 하지 않은 사용자가 해당 페이지 혹은 기능에 접근하려고 하였다면 이는 예상 가능한, 사용자가 해결 가능한 에러일 것입니다.

    따라서 접근을 하였을 때 로그인이 필요한 기능이다. 로그인 혹은 회원가입을 해라. 와 같은 플로우로 사용자를 유도하는 액션이 필요할 것입니다.

요약

  • 에러를 크게 분류하자면 아래와 같다.

    1. 의도가 된 에러(예상 가능한 에러)

    2. 의도가 되지 않은 에러(예상하지 못한 에러)

    3. 사용자가 해결할 수 있는 에러

    4. 사용자가 해결하지 못하는 에러

  • 각각의 에러 상황에 맞게 적절한 사용자의 액션 유도가 필요하다.

참고 글

https://toss.tech/article/how-to-write-error-message

https://www.jbee.io/articles/react/클라이언트의 사용자 중심 예외 처리

로딩 시간에 따른 다른 사용자 경험 처리 - 김하나

프로그래스 바나 로딩 스피너와 같은 UI 요소는 사용자가 현재 작업 상태를 파악하고 불확실성을 줄여주어 프로세스를 더 쉽게 이해할 수 있도록 도와줍니다. 이로써 사용자는 더욱 만족스러운 경험을 할 수 있게 됩니다.

저희 서비스에서도 데이터 Fetching 시 걸리는 시간을 보여주기 위해 Suspense를 사용하고 있습니다. 하지만 이러한 방법이 실제로 사용자 경험을 향상시키고 있는지 의문입니다.

##Progress Indicator 에 관한 리서치

세계적인 UX 연구자 닐슨 놀먼의 지침을 살펴보면 다음과 같습니다.

  • 1초 이상 걸리는 작업에는 Progress Indicator를 사용합니다. 작업이 1초 미만에 완료되는 경우 반복되는 애니메이션은 사용하지 않는 것이 좋습니다.
  • 로딩 스피너와 같은 요소는 2~9초의 지연 시에만 사용합니다.
  • 완료율 애니메이션은 10초 이상 소요되는 작업에 사용합니다.
  • 빠른 응답이 가장 이상적이지만, 서버 업그레이드로 인해 시스템 속도가 느려질 수 있습니다. 따라서 작업이 10초 이상 소요될 경우 사용자에게 완료 예상 시간을 표시해야 합니다.
  • 정적인 진행률 표시는 피하는 것이 좋습니다. (예: 화면에 단순히 "...로드 중" 텍스트만 표시)

이러한 지침을 고려하면 로딩 시간에 따라 다른 로딩 경험을 제공하는 것이 바람직합니다.

또한, 모든 경우가 아닌 1초 이상 지연될 경우에만 로딩 스피너를 사용하는 것이 좋습니다.

##React Suspense 를 이용하여 로딩 경험 개선

현재 저희는 대부분의 경우 Suspense를 이용하여 child component를 감싸 로딩 스피너를 보여주고 있습니다.

// example
<div className={styles.page__depart}>
<React.Suspense fallback={<LoadingSpinner />}>
<DeptListbox />
</React.Suspense>
</div>

이를 로딩 시간에 따라 다른 UX를 제공할 수 있도록 유틸성 컴포넌트를 활용해 변경할 수 있습니다.

예를 들어, 1초까지는 아무런 UX를 제공하지 않다가 1초 이상 로딩이 지연된다면 그때 로딩 스피너를 보여주는 컴포넌트를 만들 수 있습니다. 아래는 카카오에서 제시한 유틸 컴포넌트 설계입니다.

const DeferredComponent = ({ children }: PropsWithChildren<{}>) => {
const [isDeferred, setIsDeferred] = useState(false);

useEffect(() => {
// 200ms 지난 후 children Render
const timeoutId = setTimeout(() => {
setIsDeferred(true);
}, 200);
return () => clearTimeout(timeoutId);
}, []);

if (!isDeferred) {
return null;
}

return <>{children}</>;
};

**DeferredComponent**는 children을 Props로 받고, 200ms 이전에는 children을 렌더링하지 않습니다.

따라서 기존의 로딩 스피너에 이 **DeferredComponent**를 적용하면 특정 시점부터 로딩 스피너가 보여지게 됩니다.

<div className={styles.page__depart}>
<React.Suspense
fallback={
<DeferredComponent>
<LoadingSpinner />
</DeferredComponent>
}>
<DeptListbox />
</React.Suspense>
</div>

우리는 사용자 경험을 향상시키기 위해 항상 Progress Indicator(=Skeleton)을 사용하고 있습니다. 그러나 빠른 인터넷 환경에서는 오히려 선택적으로 Progress Indicator를 제공하는 것이 더 나은 사용자 경험을 제공할 수 있습니다.

resource