Говори, когда больно: как ошибки становятся частью UX

Когда в продукте появляется ошибка, пользователь не думает о том, что "не прошёл валидацию payload" или "сервер вернул 422". Он думает одно: "Что-то пошло не так. И, скорее всего, это я криворукий. А вообще это сервис кривой."

И тут есть развилка: либо мы оставляем его наедине с этим ощущением (читай — он уходит и не возвращается), либо мы объясняем, что произошло, что делать и почему это вообще случилось.

Ошибки — это не побочный продукт разработки. Это часть интерфейса, как кнопки, поля и текст. Только в отличие от кнопок, ошибки проявляют себя в худший момент. И именно в этот момент они показывают, насколько вы вообще думаете о пользователе. Сегодня прольем цифровой чай на вопрос о котором очень мало кто думает.

Говори, когда больно: как ошибки становятся частью UX

Почему ошибки — это важный UX-инструмент

В отчёте NN Group за 2024 год говорится: "Poor error messages are one of the top 3 causes of user frustration and task abandonment in digital products."

Само собой лучше когда ошибки не появляются на пути пользователя и все идет гладко. Но если ошибки имеют место быть, то ошибки оформленные правильно, дают продукту:

  • Прозрачность — объясняют, что происходит и кто виноват.
  • Контроль — возвращают ощущение, что "ситуация под контролем".
  • Обратную связь — помогают быстрее достичь цели (даже если пользователь ошибся).
  • Рост конверсии — в форме, где ошибки объяснены, пользователей меньше уходит.
  • Меньше поддержки — когда всё понятно, писать в саппорт нет смысла.

Где ошибки живут и кто за них отвечает

В любой системе существуют два типа ошибок валидации:

1. Frontend-валидация

Это ошибки, которые происходят на клиенте — до отправки данных на сервер. Данный тип ошибок “зашивается“ в компонент. Они обеспечивают быстрый отклик и предотвращают очевидные ошибки:

  • Пустое поле
  • Неверный формат email
  • Превышение допустимой длины и т.д.

2. Backend-валидация

Это ошибки, которые возвращает сервер после проверки данных. Данный тип ошибок косвенно связан с компонентом, но поставляется в него в виде переменной. Они учитывают бизнес-логику, доступы, связи между сущностями и пр.:

  • Email уже зарегистрирован
  • Пользователь не имеет права загружать файл
  • Неверный код верификации
  • Недопустимая комбинация данных

Есть еще третий тип, но я не буду намеренно его выделять в список. Ошибка сети/системы — пользователь без интернета, истёк токен, не отвечает база.

И все эти ошибки в итоге вываливаются пользователю. Не команде. Не QA. Не разработчику. А реальному человеку, который пытается оплатить, зарегистрироваться, нажать “отправить” и, вообще-то, хочет просто пользоваться продуктом.

Почему нужна систематизация

Ошибки — это как официанты в ресторане: не все их замечают, пока всё идёт хорошо, но стоит что-то пойти не так — и ты сразу понимаешь, насколько здесь вообще умеют работать с людьми.

Теперь представим типичный цифровой ресторан, то есть наш продукт. Пользователь заходит, хочет «заказать» — допустим, зарегистрироваться или оплатить. А ему в ответ: «Что-то пошло не так» «422: Validation failed» «Invalid email» «Такой email уже существует»

Каждое сообщение — как будто из другой эпохи, команды и вселенной. Одно на английском, другое на русском, третье — вообще из лога сервера, случайно вывалившегося в UI. Если бы продукт был человеком, он бы разговаривал голосами трёх незнакомцев с разными акцентами и уровнем вежливости.

Вот почему нужна систематизация. Потому что ошибки — это тоже интерфейс. И если они выглядят как мусорная свалка из случайных сообщений, пользователь будет чувствовать себя на этой самой свалке. Неуверенность, раздражение, ощущение, что никто не контролирует ситуацию — и ты уже не регистрируешься, не платишь, не продолжаешь.

Имхо, систематизация ошибок — это способ сказать: “Да, у нас тоже бывает фигово. Но мы хотя бы умеем об этом нормально поговорить.”

Когда у продукта есть чёткая система: категории ошибок, ключи сообщений, единый стиль текста, предсказуемое отображение — всё становится проще. Ошибки перестают быть катастрофой. Они становятся инструкцией: что случилось, где именно, и как это исправить. И главное — всё это написано языком, который отражает личность продукта, а не автогенератор документации из 2005 года.

Так что да: ошибки — это лицо продукта. Просто не в момент, когда всё хорошо, а в момент, когда правда важнее красоты. И если у тебя это лицо кривое, злое и говорит на латыни — подумай, что пользователь запомнит в итоге.

Что такое tone of voice в ошибках

Tone of voice (TOV) — это характер продукта. Он должен быть во всём: в подписях, в кнопках, и как ты понимаешь логично продолжать линию общения с клиентом в ошибках.

Плохой TOV:

  • “Required field”
  • “Minimum length 6 characters”

Хороший TOV:

  • “Пожалуйста, заполните поле”
  • “Пароль должен быть от 6 символов — без пробелов”

Вообще говоря, тут поле для экспериментов с tone of voice становится только шире. Представь формулировки ошибок заточенные под молодежный сленг или узкую специализацию профессиональную. Пользователь кайфанет не только от нормальной работы продукта, но и от того, как он решает сложные ситуации. Пользователь запомнит и полюбит тебя.

Как это делают в нормальных системах

Немного тошноты в студию. Думаю про формулировки и проработки ошибок уже все поняли. Сейчас о том, как делают одни из лучших:

Shopify Polaris: каждая ошибка — это key, например, errors.email.invalid; компонент InlineError сам достаёт локализованный текст.

Atlassian: ошибки приходят с кодом и мапятся в flag или inline message. Компонент сам решает, как показать.

Salesforce: маппинг сообщений идёт через специальную структуру JSON, по модели errors.models.USER.EMAIL.TAKEN.

Уже достаточно инфы, что бы немного погуглить, если не слышали о таком. Вот вам еще один пунктик на разобраться. Этакий Zod.

Проблема с Zod: он не знает, что у вас tone of voice

Для начала, Zod — это современная TypeScript-библиотека для описания схем валидации данных. Она позволяет декларативно описывать, какие данные ожидаются от пользователя (или от API), и автоматически проверяет их на соответствие. По сути, это как JSON Schema, только без боли, и с типами «из коробки».

Используется в React, Next.js, Node и везде, где хочется держать логику валидации рядом с кодом, а не на стороне сервера. Это то что распакует вам разраб и скажет у меня все готово про ошибки. По факту и да и нет.

Работает быстро, пишется просто. Но вот беда:

  • По умолчанию ошибки у него машинные. Типа: “Ошибка поля”. Ты серьезно? Какое поле, о чем ты, почему?
  • Если не задать сообщение вручную — будет выводить дефолт.
  • Эти дефолты не локализуются, не стандартизируются, не брендируются.

Что делать (и как дизайнеру не превратиться в жертву Zod'а)

Хорошие ошибки не появляются сами. Увы, ни Zod, ни бэкенд, ни разработчики не обязаны думать о тоне, стиле и контексте. Они просто отдают то, что есть. А если продукт начинает говорить с пользователем как оператор терминала DOS, виноват будет не разработчик. А вы — дизайнер. Потому что интерфейс — это ваша территория.

Так что давайте разберёмся, что именно нужно сделать, чтобы ошибки выглядели как часть интерфейса, а не как сбой в Матрице. Погнали, записываем:

1. Создайте библиотеку ошибок с человеческим лицом

Начните с простого документа — например, в Figma, Notion или в виде таблицы. В нём:

  • Придумайте ключи ошибок: validation.required, auth.emailTaken, network.timeout.
  • Для каждого ключа напишите понятное, дружелюбное сообщение. Желательно в стиле продукта, а не Google Translate: "Invalid input" → "Пожалуйста, заполните поле", "Too short" → "Минимум 6 символов — без пробелов"
  • Добавьте текст для перевода, если планируете локализацию.

Это будет вашим tone-of-voice-словарём ошибок — основа для всего, что происходит дальше.

2. Определите, где и как должны появляться ошибки

Одна и та же ошибка может выглядеть по-разному в зависимости от контекста. Пример:

  • Поле не заполнено → inline-сообщение под полем.
  • Не удалось оплатить → toast или баннер сверху.
  • Сбой сервера → модальное окно с кнопкой "Повторить".

Дизайнер должен задать правила отображения ошибок:

  • Какие компоненты для чего используются?
  • Где они появляются?
  • Как они выглядят: цвет, иконка, отступы, анимация.

Пропишите это в гайдлайне дизайн-системы. Компоненты ошибок — такие же важные кирпичи интерфейса, как поля и кнопки.

3. Работайте с разработчиками, а не вместо них

Моя любимая фраза: двигаем стул к разработчику. Обсудите с фронт-командой:

  • Можно ли централизованно подключить тексты ошибок?
  • Как связать код ошибки и ключ сообщения?
  • Что делать, если сообщение приходит с бэка, но его нужно показать по-человечески?

Например, пусть фронт-форма не показывает "422: Validation failed", а обращается к ключу validation.required и берёт текст из вашей таблицы. Вы даёте стиль — разработчик даёт реализацию.

4. Прототипируйте ошибки как часть интерфейса

В макетах, wireframes и user flow всегда закладывайте состояния с ошибками. Покажите, как выглядит форма при:

  • Пустом поле
  • Некорректном вводе
  • Системной ошибке

Если ошибок нет в макетах — их выдумает фронт. И чаще всего — не в лучшую сторону.

5. Создайте визуальный реестр ошибок

Ну и наконец, хороший ход — собрать все виды ошибок в одном месте:

  • Как выглядят inline-ошибки под полем
  • Как выглядит toast с ошибкой оплаты
  • Какой стиль у баннеров и модалок
  • Что видит пользователь при ошибке 500

Это можно сделать в Figma как страницу "Error system" или в Storybook. Тогда каждый, кто делает интерфейс, будет знать, как правильно “ломаться”. И да, тогда туда придут и возьмут, что-то что готово и проверено, а не как обычно на коленке по быстрому прикинуто лишь бы задачу закрыть.

Ошибки — ваша зона ответственности

Дизайнер не обязан писать регулярки и думать, что там у Zod внутри. Но дизайнер обязан сделать так, чтобы продукт не выглядел как терминал техподдержки. А для этого нужны:

  • Таблица ошибок с ключами и текстами.
  • Визуальные паттерны отображения.
  • Гайд по компонентам ошибок.
  • Совместная работа с фронтом.

Если вы это сделаете — ошибки перестанут быть “отвалами” и начнут работать на продукт. Потому что в момент, когда всё идёт не так — именно ошибка показывает, насколько вы вообще умеете общаться с пользователями.

Как всегда, добра 🦫

1
2 комментария