Почему точность важна
В повседневной речи люди используют «баг», «ошибка», «дефект» и «отказ» как синонимы. В профессиональном тестировании эти термины имеют конкретные, различные значения. Понимание разницы — не педантизм, оно определяет, исправите ли вы симптом или корневую причину.
Когда клиент сообщает «приложение упало», он описывает отказ. Когда разработчик находит NullPointerException на строке 42, он нашёл дефект. Когда команда обнаруживает, что разработчик забыл обработать случай пустого результата из БД, они идентифицировали ошибку.
Три разных вещи. Три уровня проблемы. Исправление только отказа (перезапуск приложения) или только дефекта (добавление null-проверки) без устранения ошибки (почему пустые результаты не обрабатываются системно?) гарантирует повторение проблемы.
Ошибка: человеческая оплошность
Ошибка (error, mistake) — это человеческое действие, приводящее к некорректному результату. Ошибки случаются, потому что люди несовершенны — мы неправильно понимаем требования, допускаем опечатки, забываем граничные случаи, применяем неверную логику или просто плохо себя чувствуем.
Примеры ошибок
- Разработчик неправильно читает спецификацию и реализует «больше» вместо «больше или равно»
- Дизайнер использует неверный код цвета (#FF0000 вместо #EE0000)
- Бизнес-аналитик пишет двусмысленное требование, допускающее два толкования
- DevOps-инженер вводит неверный IP-адрес в конфигурацию развёртывания
- Тестировщик пишет тест-кейс с неправильным ожидаемым результатом
Ключевой момент
Не каждая ошибка приводит к дефекту. Разработчик может допустить ментальную ошибку при кодировании, но сразу поймать её при самопроверке. Ошибка произошла (неверная мысль), но дефект не был создан (код исправлен до коммита).
Дефект: баг в артефакте
Дефект (defect, bug, fault) — это изъян в рабочем продукте — коде, документации, дизайне, конфигурации — который может привести к сбою системы. Дефект — конкретное проявление ошибки в артефакте.
Примеры дефектов
- Ошибка на единицу в цикле:
for (i = 0; i <= array.length; i++)вместоi < array.length - Отсутствие валидации отрицательных чисел в поле количества
- Некорректный SQL-запрос с неправильным соединением таблиц
- Опечатка в сообщении об ошибке: «Ваш парль неверен»
- Неправильное значение таймаута в конфигурационном файле
Ключевой момент
Не каждый дефект приводит к отказу. Дефект может находиться в коде, который никогда не выполняется, в функции, отключённой feature flag-ом, или в условии, требующем специфических (и редких) входных данных. Это спящие дефекты — они существуют, но ещё не проявились как отказы.
Отказ: наблюдаемая проблема
Отказ (failure) — это отклонение системы от ожидаемого поведения при выполнении. Это то, что пользователь видит, испытывает или сообщает. Отказ — наблюдаемое последствие активации дефекта.
Примеры отказов
- Приложение падает при отправке формы
- Страница оформления заказа показывает $0.00 для товара за $99.99
- Поиск возвращает результаты на неправильном языке
- Страница логина грузится 45 секунд
- Email для сброса пароля не отправляется
Ключевой момент
Не каждый отказ вызван дефектом в ПО. Отказы также могут быть вызваны:
- Проблемами среды: Нехватка памяти сервера, таймаут сети, переполнение диска
- Внешними зависимостями: Сторонний API недоступен, пул соединений к БД исчерпан
- Проблемами данных: Повреждённые данные в БД, неожиданный формат из интеграции
- Человеческими факторами: Пользователь вводит данные неожиданным образом
Цепочка: Ошибка → Дефект → Отказ
Человеческая оплошность] -->|создаёт| D[Дефект
Баг в коде/артефакте] D -->|может вызвать| F[Отказ
Наблюдаемая проблема] E -.->|не всегда| D D -.->|не всегда| F style E fill:#f59e0b,color:#fff style D fill:#ef4444,color:#fff style F fill:#7c3aed,color:#fff
Цепочка работает так:
- Человек совершает ошибку — разработчик неправильно понимает, что даты должны храниться в UTC
- Ошибка создаёт дефект — код хранит даты в локальном времени вместо UTC
- Дефект может вызвать отказ — пользователи в разных часовых поясах видят неправильные даты событий
Но цепочка может прерваться на любом звене:
- Ошибка может не привести к дефекту (обнаружена при code review)
- Дефект может не вызвать отказ (путь кода никогда не выполняется)
- Отказ может остаться незамеченным (происходит в редко используемой функции)
Анализ корневых причин
Понимание цепочки ошибка-дефект-отказ позволяет проводить анализ корневых причин (RCA) — практику отслеживания отказа через дефект к лежащей в основе ошибке.
Техника «Пять почему»
Простая, но мощная техника RCA — задать вопрос «Почему?» пять раз:
Отказ: Месячный отчёт показывает неверные итоги выручки.
- Почему? Потому что запрос отчёта суммирует заказы, по которым был сделан возврат.
- Почему? Потому что запрос не фильтрует возвращённые заказы.
- Почему? Потому что разработчик не знал, что возвращённые заказы остаются в таблице заказов.
- Почему? Потому что документация схемы БД не объясняет обработку возвратов.
- Почему? Потому что нет процесса документирования решений по модели данных.
Настоящее исправление — не просто обновить запрос (исправить дефект). Это создать стандарты документации модели данных (устранить корневую причину ошибки) и установить процесс ревью (предотвратить аналогичные ошибки).
Уровни RCA
| Уровень | Фокус | Пример исправления |
|---|---|---|
| Симптом | Отказ | Перезапустить сервер |
| Прямая причина | Дефект | Исправить null pointer |
| Корневая причина | Ошибка | Добавить правила null-safety в стандарты кодирования |
| Системная причина | Процессный пробел | Внедрить статический анализ, ловящий null-проблемы |
Исправление только симптома — тушение пожаров. Исправление корневой причины — инженерия. Исправление системной причины — обеспечение качества.
Практическая классификация
Полный сценарий, отслеженный через все три уровня:
Сценарий: Интернет-магазин списал деньги с клиента дважды за один заказ.
Отказ: С кредитной карты клиента списано $149.99 дважды за заказ #12847.
Дефект: Вызов API оплаты не был идемпотентным — когда таймаут сети вызвал ошибку первого вызова, повтор отправил второй запрос на оплату. API обработал оба, так как не имел механизма обнаружения дубликатов.
Ошибка: Разработчик предположил, что API оплаты идемпотентен. Он не прочитал документацию, которая явно указывает, что вызывающая сторона должна включать уникальный ID транзакции для предотвращения дублирования.
Корневая причина: Отсутствует чеклист code review для платёжных интеграций. Нет интеграционного тестирования, проверяющего идемпотентное поведение.
Упражнение: классифицируйте ошибку, дефект и отказ
Для каждого сценария определите ошибку, дефект и отказ:
Сценарий 1: Пользователь регистрируется с email “john@example.com” и получает приветственное письмо, адресованное “null”.
Сценарий 2: Система бронирования авиабилетов позволяет пассажиру забронировать место, уже забронированное другим.
Сценарий 3: Банкомат выдаёт $300, когда клиент запросил $200.
Подсказка
Для каждого сценария отследите назад: Что наблюдал пользователь (отказ)? Что не так в коде или системе (дефект)? Какая человеческая ошибка привела к дефекту (ошибка)?Решение
Сценарий 1:
- Отказ: Приветственное письмо показывает «null» вместо имени пользователя
- Дефект: Шаблон письма использует
user.firstName, но форма регистрации не собирает имя, поэтому поле равно null. Шаблон не имеет значения по умолчанию для null. - Ошибка: Разработчик шаблона предположил, что имя всегда будет доступно. Разработчик формы не согласовал с разработчиком писем обязательные поля.
Сценарий 2:
- Отказ: Два пассажира забронированы на одно место
- Дефект: Логика бронирования проверяет доступность и бронирует место двумя отдельными операциями БД без блокировки или транзакции. Между проверкой и бронированием другой запрос может забронировать то же место (состояние гонки).
- Ошибка: Разработчик не учёл конкурентный доступ при реализации потока бронирования. Он предполагал, что операции выполняются последовательно.
Сценарий 3:
- Отказ: Банкомат выдаёт $300 вместо $200
- Дефект: Алгоритм выдачи наличных неправильно подбирает купюры — считает купюры по $50 как купюры по $20.
- Ошибка: Разработчик перепутал константы номиналов, задав
BILL_50 = 20вместоBILL_50 = 50. Вероятно, это ошибка копирования-вставки при определении номиналов.
Профессиональные советы
Совет 1: Всегда отслеживайте до корневой причины. Найдя дефект, не просто создавайте баг-репорт и идите дальше. Спросите: «Какая ошибка привела к этому дефекту?» и «Могут ли аналогичные ошибки создать другие дефекты?» Найденный дефект может быть одним из многих, вызванных одной корневой причиной.
Совет 2: Дефекты могут существовать в любом артефакте. Большинство думает о дефектах как о багах в коде. Но дефекты могут быть в документах требований, спецификациях дизайна, тест-кейсах, конфигурационных файлах и документации. Неверное требование — тоже дефект.
Совет 3: Отслеживайте цепочку ошибка-дефект-отказ в баг-репортах. Вместо описания только отказа («страница падает»), описывайте все три уровня, когда возможно. Это даёт разработчикам контекст для исправления корневой причины, а не только симптома.
Ключевые выводы
- Ошибка — человеческая оплошность; дефект — изъян в артефакте; отказ — наблюдаемое некорректное поведение
- Цепочка: Ошибка → Дефект → Отказ, но может прерваться на любом звене
- Не все ошибки создают дефекты, и не все дефекты вызывают отказы
- Анализ корневых причин отслеживает отказы до лежащих в основе ошибок
- Исправление симптомов (отказов) без устранения корневых причин (ошибок) гарантирует повторение
- Техника «Пять почему» — простой, но мощный инструмент анализа корневых причин