Откуда берутся три ответа на один вопрос
Инструменты писались в разное время под разные задачи. Каждый решал свою — и каждый по-своему прав:
| Инструмент | Насчитал | Почему именно столько |
|---|---|---|
| Первый | 6 | берёт всё, что похоже на сумму |
| Второй | 7 | то же плюс мелкое двузначное значение |
| Третий | 3 | режет по диапазону разумных цен и схлопывает повторы |
Пока эти инструменты живут порознь, расхождение незаметно: у каждого свой отчёт, и каждый отчёт внутренне непротиворечив. Оно всплывает в тот момент, когда два отчёта кладут рядом — обычно перед клиентом.
Опасен не сам разброс, а его безымянность. «Инструменты дают разное» — повод для спора. «Первый берёт любую сумму, третий — только из диапазона цен и без повторов» — это уже спецификация: можно выбрать нужный и объяснить выбор. Разброс не исчезает, он перестаёт быть случайным.
Код, который выглядит работающим
Сплошной разбор того же конвейера дал класс, который стоит знать всем: код на месте, комментарий обещает работу, работы нет.
- Отсечка, которая ничего не отсекала. Стояло условие «пропустить значения меньше 30». Но шаблон, по которому значения вообще попадали в обработку, требовал от трёх цифр — то есть двузначное число не могло дойти до этой проверки в принципе, а трёхзначное всегда больше 30. Условие не срабатывало никогда. Комментарий рядом при этом обещал фильтрацию по реальным ценам рынка.
- Детектор, работавший по случайности. Он искал символ, которого в очищенном от разметки тексте не бывает. На странице, свёрстанной в одну строку, он не сработал бы вовсе. Завели его после настоящего случая на шестнадцати страницах — то есть проблема была реальной, а защита от неё держалась на совпадении.
- Дважды скопированный блок в одном файле — две почти одинаковые версии одной логики в тридцати строках друг от друга.
Как мы это чиним: считать по кодам правил, а не по сумме
Главный приём, который сработал, — мутационные тесты с раздельным учётом. Идея простая: берём заведомо дефектный образец, ломаем в нём одну конкретную вещь и проверяем, что покраснело именно то правило, которое за неё отвечает.
| Как считать | Что видно |
|---|---|
| Суммарно: «сработало N проверок» | отключение одного детектора маскируется срабатыванием соседнего — прибор молчит, а отчёт зелёный |
| По кодам правил отдельно | видно, какое именно правило перестало работать |
На нашей проверке это 50 тестов, все зелёные, с разбивкой по шести кодам правил. На казахской странице девять признаков проверяются поимённо — потому что условие «сработало не меньше N признаков» зеленело бы даже при полностью слепом конкретном детекторе.
И последний шаг, без которого рефакторинг не считается закрытым: сверка выходов до и после побайтово. У нас девять файлов из двенадцати изменились, три совпали — и ни одного необъяснённого изменения. Формулировка «вроде работает так же» здесь не проходит.
Что забрать себе
- Если один вопрос считают несколько инструментов — сравните их на одном образце. Не для того, чтобы выбрать победителя, а чтобы назвать разницу.
- Проверьте, доходит ли поток до ваших условий. Отсечка, стоящая после фильтра, который её обесценивает, — самый частый мёртвый код.
- Мутационные тесты считайте по правилам отдельно. Сумма скрывает выключенный детектор.
- После рефакторинга сверяйте выход побайтово и объясняйте каждое расхождение.