Почему «нет» дороже, чем «да»
Находка проверяема на месте: инструмент назвал путь и строку, открыл — увидел. За словом «не найдено» стоит развилка минимум из четырёх веток, и три из них про нас, а не про объект.
- Команда не выполнилась. Аргумент искажён, права не те, путь переписан оболочкой — вывод пуст, код возврата никто не читал.
- Спросили не тот носитель. Реестр и файловая система, список и сам объект, репозиторий и сервер — разные хранилища одного факта.
- Ответ отстал. Индекс выдачи обновляется не мгновенно: объект уже есть, а в списке его ещё нет.
- Действие не дошло. Клик, запрос, событие ушли мимо — «не сработало» относится к доставке, а не к цели.
Дальше — по одному случаю на каждую ветку, все из одного заезда.
Случай первый: оболочка переписала путь, ошибка ушла в сторону
Чтение состояния из основной ветки — базовое правило приёмки. Для путей, у которых сегмент начинается с точки, оно молча ломается: слой совместимости в терминале под Windows считает аргумент похожим на путь и переписывает его — прямые слэши в обратные, двоеточие в точку с запятой. Команда падает с «неоднозначный аргумент», вывод пуст.
Как пустота стала выводом. Сообщение об ошибке ушло в поток ошибок, а подсчёт совпадений по пустому выводу вернул 0. Из этого нуля родилось утверждение, что чат затёр чужую конфигурацию: первое сравнение шло против пустоты, второе — против устаревшего снимка старого дерева, и только третий заход дал правду. Не затёрто ничего.
Починка — одна переменная окружения, отключающая переписывание путей. Ценнее правило проверки: команда, которая по замыслу обязана вернуть непустой результат, проверяется на непустоту. Ноль строк без видимой ошибки — повод заподозрить канал, а не отсутствие файла.
Случай второй: список репозиториев врёт в сторону занижения
Аудит сохранности записал по одному из каталогов: удалённого хранилища нет, значит работа живёт в единственном экземпляре. Формально верно — запрос удалённых адресов из каталога ничего не отдавал. Фактически репозиторий существовал: параллельный чат создал его накануне вечером и залил обе ветки, но связь у локального каталога не прописал.
| Вопрос | Плохая проверка | Проверка, которая отвечает |
|---|---|---|
| Каталог забэкаплен? | Глазами в список репозиториев | Запрос веток удалённого адреса из самого каталога |
| Репозиторий существует? | Поиск по списку | Точечный запрос по владельцу и имени |
| Заливать заново? | По факту «в списке пусто» | Сверка хешей голов: совпали — работа уже там |
Вторая мина того же места: списочная команда клиента хостинга не показала репозиторий, созданный накануне, — выдача индексируется с лагом. Попытка создать его ответила «имя уже занято». Список ошибается односторонне, в сторону занижения, и по нему легко начать заводить дубль.
Случай третий: три отрицательных ответа из одного источника
Задача «закрыть свои чаты» упёрлась в то, что два чата недостижимы. Список сессий с лимитом 80 и с архивными вернул 8 записей, обоих чатов среди них нет. Запрос по идентификатору в обеих формах — «сессия не найдена». Поиск по первым фразам — «совпадений нет». Три независимых способа, один вердикт: чатов не существует.
Транскрипты при этом лежали на диске: 6,0 МБ и 9,4 МБ. Инвентарь чатов собирается обходом файлов, а инструменты закрытия работают с реестром зарегистрированных сессий. Хранилища два, и они расходятся: чат живёт в файлах и отсутствует в реестре.
Ошибка счёта, которую легко повторить. Три способа, ходящие в один источник, — это один ответ, а не три подтверждения. Уверенность росла от повторов, хотя новой информации не прибавлялось. Правило: второй способ проверки засчитывается, только если он читает другое хранилище.
Практический вывод про закрытие: достижимость проверяется до обещания закрыть, а не после. Недостижимое выносится человеку карточкой с доказательством, что закрывать безопасно. Вердикт, описанный в отчёте, закрытием не считается — человек смотрит в список чатов, а не в наш текст.
Случай четвёртый: клик не дошёл — значит, дефект в разметке
Приёмка требует проверять переходы кликами, а не чтением кода. Клик по пункту навигации не переходил четыре раза подряд, страница была свежесобранная — картина складывалась в «дефект вёрстки». Две проверки это подтвердили ложно: элемент в точке клика возвращался именно нужной ссылкой (значит, ничем не перекрыта), подсветка при наведении на снимке срабатывала.
Правду дал слушатель событий мыши на всём документе: лог пуст, событие до страницы не доходило вовсе. Клик по координатам масштабируется по последнему снимку экрана, а после перехода снимок протухает — клик физически уходит мимо. Свежий снимок, и тот же клик прошёл с первого раза. На проде повторилось один в один: три промаха, затем снимок → клик → переход.
Смежный отказ канала. Когда панель превью не показана, страница не собирает кадры, и мышиные события до неё не доходят вообще — при этом чтение страницы и выполнение скриптов отвечают нормально. Признаки: снимок падает с «панель не отображается», размер вьюпорта нулевой. Лечится явным заданием размера окна или переходом в обычный браузер.
Вывод «переход сломан» ставится только при двух условиях сразу: снимок свежий и лог событий пуст. Цена пропуска здесь измерена: полчаса на починку исправной разметки и риск «исправить» рабочий код.
Что делать у себя
- К каждому «нет» — доказательство исправности канала. Положительный контроль: та же команда на объекте, который заведомо есть. Молчит и там — сломан прибор.
- Пустой вывод не равен ответу. Код возврата и поток ошибок читаются до того, как ноль попадёт в отчёт. Подсчёт по пустоте всегда даёт ноль и всегда выглядит убедительно.
- Списки и реестры считать нижней оценкой. Отсутствие в выдаче — не отсутствие объекта: точечный запрос по имени сильнее любого поиска по списку.
- Повтор не заменяет независимость. Три ответа из одного хранилища — один ответ; второй способ обязан ходить в другое хранилище.
- Отделять «объект сломан» от «действие не дошло». Для интерфейса это слушатель событий, для сети — код ответа, для команды — её собственный код возврата.
Каждое из четырёх «нет» оказалось правдой про наше измерение и ложью про мир. Починки ни разу не потребовал объект — её потребовал способ спросить.