이 글은 구글에서 작성된 Writing Helpful Error Messages 을 정리한 내용입니다.
에러 메세지는 왜 중요한가?
여러 상황에서 오류 메세지는 사용자의 잘못된 입력 또는 의도하지 않은 활용에 대한 경고와 예외처리 또는 제품의 결함 등으로 발생하기 때문에 사용자가 직접 해결할 수 있도록 돕는 역할을 한다. 때문에 에러 메세지는 예상하지 못한 작동 상황에서 사용자로 하여금 문제를 해결할 수 있는 가장 첫번째 이정표이자 개발자와의 상호작용 역할을 수행한다고 볼 수 있다.
좋은 오류메세지는 다음과 같은 특징을 갖는다.
- 긍정적인 사용자 경험 제공
- 쉽게 접근하여 실제로 실행 가능하다
- 문제 해결을 위한 지원 작업을 줄이고 사용자가 직접 해결할 수 있도록 함
공통 오류 처리 규칙
실패 상황을 넘어가선 안된다.
Failure 는 어떠한 상황에서든 발생할 수 있기에 100% 성공은 언제나 보장 할 수 없다. 만약 실패한 상황을 reporting 하지 않고 넘어간다면 2가지 문제를 야기한다.
첫째, 사용자는 문제 원인을 정확히 파악할 수 없다.
둘째, 고객 지원팀도 문제의 원인을 정확히 파악할 수 없다.
고객이 본인의 문제 상황을 정확히 파악할 수 없기 때문에 지원요청의 내용만으로는 문제를 명확히 파악할 수 없다. 나아가 실패 상황을 기록하지 않고 넘어간다는 것은 어떠한 기록(log) 에도 해당 상황에 대한 정보가 없다는 것을 의미 하기 때문에 개발자 입장에서도 문제 재현에 어려움을 겪을 수 밖에 없다.
각 언어별 가이드라인을 명확히 지킨다
Python, go, java, java script 등 다양한 언어들은 각 언어마다 개발 규칙이 있다. 이러한 문서에 에러 처리에 대한 규칙이 명시되어 있으므로 이것을 지키도록 노력한다.
근본 원인을 무시하도록 해선 안된다.
API 형태의 구현은 단순히 사용자 코드의 문제를 넘어 백엔드상에서 발생할 수 있는 근본적 원인이 존재할 수 있다. 예를 들어 “서버 오류” 라고 불리는 에러 내부에는 네트워크 끊김, 권한 문제, 서비스 실패 등이 있다. 이러한 상황에서 단순히 “서버 오류” 라고 표기하는 것은 사용자가 문제를 이해하고 수정하기 위해서는 지나치게 일반화 되어 있다고 볼 수 있다. 각 에러 상황 마다 추가적인 정보를 반드시 제공하도록 한다.
에러를 모델링 한다
여러 오류 상황을 일반화하고 그 하위에 세부적인 오류 항목이 포함된 에러 모델링은 사용자와 고객 지원 모든 상황에서 유용하다. 각각의 에러를 코드화하여 관리하고 각각의 구조와 상속관계를 문서화하여 제공한다면 훨씬 효율적인 오류 처리가 가능하다.
오류는 모두 즉시 발생시킨다
오류의 경중에 상관 없이 발생하면 바로 발생시킨다. 시스템에 미치는 영향이 적은 오류라고 하여 발생시키지 않고 넘어간다면 오히려 디버깅에 더 큰 어려움을 줄 수 있다.
좋은 오류 메세지의 기본
명확한 원인을 전달한다
Invalid field 'picture'.
picture 필드가 잘못되었습니다.
The 'picture' field can only appear once on the command line; this command line contains the 'picture' field <N> times.
Note: Prior to version 2.1, you could specify the 'picture' field more than once, but more recent versions no longer support this.
picture 필드는 1회만 호출됩니다. 해당 명령줄에는 picture 필드가 n번 포함되어 있습니다.
참고 : 2.1버전 이전에는 picture 필드를 2번 이상 지정할 수 있었으나 최신 버전에서는 더 이상 지원하지 않습니다.
위 두 메세지는 모두 picture 필드의 오용을 지적하고 있으나 후자가 에러에 대해 훨씬 소상하고 즉시 조치 가능하도록 알려주고 있는 것을 볼 수 있다. 좋은 오류 메세지는 아래와 같이 명확하게 원인을 전달하여야 한다.
사용자의 잘못된 입력을 명확히 전달하고 예제를 전달한다
Invalid input "bid"
지정된 입찰가가 잘못되었습니다.
The specified bid ($5) is below the minimum bid ($8).
지정된 입찰가($5)가 최소 입찰가($8)보다 낮습니다.
Invalid input
입력이 잘못되었습니다.
Enter the pathname of a Windows executable file. An executable file ordinarily ends with the .exe suffix. For example: C:\Program Files\Custom Utilities\StringFinder.exe
Windows 실행 파일을 경로 이름으로 입력하십시오. 실행 파일은 일반적으로 .exe 접미사로 끝납니다. 예: C:\Program Files\Custom Utilities\StringFinder.exe
오류 메세지에 사용자가 입력하거나 수정할 수 있는 값이 있다면 오류 메세지에 이를 반드시 표기해주는게 오류 처리에 큰 도움이 된다. 위와 같이 사용자가 지정한 입력이 유효하지 않은 이유를 명확히 전달하고 해결 방법을 예제로 보충 설명해주면 사용자가 즉각적인 오류 처리가 가능하다.
만약 잘못된 입력이 여러줄에 걸쳐서 나타난다면 잘못된 입력을 점진적으로 제공하거나 중요한 부분만 유지하고 잘못된 입력을 잘라서 보여주는 것이 좋다.
요구 사항과 제약 조건을 명확히 지정해준다
Permission denied.
권한이 없습니다.
Permission denied. Only users in <group name> have access. [Details about adding users to the group.]
권한이 없습니다. <그룹 이름> 의 사용자만 접근할 수 있습니다. [그룹에 사용자를 추가하는 세부정보]
오류가 발생했을 때 사용자는 시스템이 요구하는 조건을 아예 모르고 있음을 가정하고 오류 메세지를 작성한다. 시스템이 요구하는 사항과 제약하는 상황을 명확히 알려주는 것이 좋다.
사용자가 실행 가능한 오류 메세지를 제안합니다
The client app on your device is no longer supported.
장치의 클라이언트 앱은 더이상 지원되지 않습니다.
The client app on your device is no longer supported. To update the client app, click the Update app button.
장치의 클라이언트 앱은 더이상 지원되지 않습니다. 클라이언트 앱을 업데이트하려면 업데이트 버튼을 클릭합니다.
단순히 문제의 원인을 기술하는 것을 넘어서 사용자가 해당 문제를 해결하기 위해 실제로 실행 가능한 방법을 함께 설명한다.
일관된 용어로 작성합니다..
Can't connect to cluster at 127.0.0.1:56. Check whether minikube is running.
127.0.0.1:56 에서 클러스터에 연결할 수 없습니다. minikube가 실행중인지 확인하세요.
Can't connect to minikube at 127.0.0.1:56. Check whether minikube is running.
127.0.0.1:56 에서 minikube에 연결할 수 없습니다. minikube가 실행중인지 확인하세요.
단일 제품에 대해서 모든 오류 메세지에 일관된 용어를 사용하는 것이 좋다. 개발자 입장에서 두 단어가 같은 제품을 의미하더라도 사용자 역시 그렇게 이해할 것으로 생각해선 안된다
적절한 톤 앤 매너로 작성합니다.
메세지를 작성하는 어조에 따라 사용자가 받아들이는 방식에 큰 영향을 미칠 수 있다.
되도록 긍정문을 활용한다
You didn't enter a name. 이름을 입력하지 않았습니다. Enter a name. 이름을 입력하세요.
무언가를 잘못했다고 지적하는 것보다 해결 방법을 알리는데 집중한다.
유머는 자제합니다.
Is the server running? Better go catch it :D.
서버가 실행 중(달리는 중)입니까? 잡으러 가세요ㅋㅋㅋㅋ
The server is temporarily unavailable. Try again in a few minutes.
일시적으로 서버를 사용할 수 없습니다. 몇 분 후에 다시 시도하십시오.
유머러스한 오류 메세지는 오류 메세지의 목적을 손상시키고 사용자로 하여금 불쾌감을 느끼게 할 수 있다.
가독성을 높이는 오류 메세지 형식
아무리 좋은 정보를 담고 있어도 오류 메세지에 불필요한 텍스트가 많고 길다면 사용자는 중요한 부분을 찾지 못하고 집중력을 잃을 수 밖에 없다.
불필요한 텍스트를 제거합니다.
Unable to establish connection to the SQL database. [Explanation of how to fix the issue.]
Can't connect to the SQL database. [Explanation of how to fix the issue.]
에러 메세지는 최대한 쉬운 단어로 짧게 작성될수록 효과적이다. 둘은 같은 의미의 문장이지만 아래 문장이 훨씬 간결하다.
수동태보다 능동태를 사용합니다.
The Froobus operation is no longer supported by the Frambus app.
Froobus 작업은 Frambus 앱에서 더이상 지원되지 않습니다.
The Frambus app no longer supports the Froobus operation.
Frambus 앱은 더이상 Froobus 작업을 지원하지 않습니다.
한국어와 다르게 영어는 수동태로 작성될 때 문장 구조가 훨씬 복잡하고 길어진다. 되도록 능동형으로 표현하여 문장을 단순하게 만드는게 좋다.
이중 부정을 피합니다.
The App Engine service account must have permissions on the image, except the Storage Object Viewer role, unless the Storage Object Admin role is available.
Storage Object Admin 역할을 사용할 수 있는 경우가 아니면 App Engine 서비스 계정에 Storage Object Viewer 역할을 제외하고 이미지에 대한 권한이 있어야 합니다.
The App Engine service account must have one of the following roles:
* Storage Object Admin
* Storage Object Creator
App Engine 서비스 계정에는 다음 역할 중 하나가 있어야 합니다.
* 저장소 개체 관리자
* 저장소 개체 생성자
not, no (can’t, won’t 와 같은 단어 포함) 를 2개 이상 포함하는 문장을 피한다. 이는 독자에게 이중 부정이 부정을 강조하기 위한 목적인지, 부정의 부정이 되어 긍정을 의미하는 것인지 혼란스럽게 만든다. 이중 부정을 피하는 것 만으로도 오류 메세지를 훨씬 명확하고 간결하게 바꿀 수 있다.
사과 표현은 피합니다.
We're sorry, a server error occurred and we're temporarily unable to load your spreadsheet. We apologize for the inconvenience. Please wait a while and try again.
죄송합니다. 서버 오류가 발생하여 일시적으로 스프레드시트를 로드할 수 없습니다. 불편을 끼쳐드려 죄송합니다. 잠시 기다린 후 다시 시도하십시오.
Google Docs is temporarily unable to open your spreadsheet. In the meantime, try right-clicking the spreadsheet in the doc list to download it.
Google 문서도구에서 일시적으로 스프레드시트를 열 수 없습니다. 그동안 문서 목록에서 스프레드시트를 마우스 오른쪽 버튼으로 클릭하여 다운로드해 보세요.
이는 대상자의 특성(문화적 차이)에 영향을 받지만 일반적으로는 사과의 표현보다 문제와 해결방안에 집중하는 것이 효과적이다. 사용자는 지금 당장 문제를 회피하는 것이 가장 중요하기 때문이다. 또한 사과 표현은 오류 메세지를 필연적으로 길어지게 만든다.
자세한 정보는 링크를 통해 리디렉션합니다.
Post contains unsafe information.
게시물에 안전하지 않은 정보가 포함되어 있습니다.
Post contains unsafe information. Learn more about safety at <link to documentation>.
게시물에 안전하지 않은 정보가 포함되어 있습니다. <문서 링크>에서 안전에 대해 자세히 알아보세요.
오류에 대해 긴 설명이 필요하거나 이미 적절한 설명서가 있는 경우 이를 에러 메세지에 모두 표현하기 보다 해당 링크를 제공하여 사용자가 보다 자세한 설명서를 볼 수 있도록 리디렉션 하는게 유용하다.
적절한 접어두기 사용하기
TextField widgets require a Material widget ancestor, but none were located. In material design, most widgets are conceptually “printed” on a sheet of material. To introduce a Material widget, either directly include one or use a widget that contains a material itself.
TextField widgets require a Material widget ancestor, but none were located.
...(Click to see more.)
>> In material design, most widgets are conceptually "printed" on a sheet of material. To introduce a Material widget, either directly include one or use a widget that contains a material itself.
일부 오류 메세지는 문제의 원인과 해결 방법을 설명하는 데 어쩔 수 없이 긴 텍스트가 필요할 수 있다. 이러한 경우 앞서 설명한 링크를 통한 리디렉션을 고려할 수 있지만 모든 상황에서 다 가능하지는 않다. 이 때 오류 메세지의 요약 버전을 표시한 다음 전체 내용을 보기 위한 옵션을 제공하는 것이 좋은 대안이 될 수 있다.