Например, в управлении транспортом статичные данные (например, сет за «типичный вторник») не дают протестировать систему в условиях праздника, крупной аварии, сессии у студентов, скидки 99% на Лабубу в крупном супермаркете и так далее.
Что мы сделали:
— Стали брать реальные данные с прода, которые выбиваются за стандартные представления.
— Обезличивать их.
— Использовать ML-модель для генерации сценариев, где эти данные увязываются с остальными в системе. Это типа генерации новых данных с усилением трендов и их пересечением.
То есть фактически по модели швейцарского сыра — мы имеем один статичный срез, а затем начинаем ходить в прод и искать новые дырки. Потом соединяем несколько дырок в новом слое и накладываем слои друг на друга, чтобы посмотреть, не будет ли сквозного отверстия.
Цель — не просто нагрузить систему, а протестировать жизнеспособность архитектуры в похожих на реальные условиях.

Очень упрощая, наши наборы тестов учатся нестандартным ситуациям с прода и включают их и в тестовые выборки данных, и в юнит-тесты, и такие ситуации не только покрываются как частные случаи, но и включаются в сложные сценарии, где 3 малозначимых отказа могут привести к аварии.
Я думаю, что это будущее тестирования сложных систем, и мы с командой уже затащили это в автоматический пайплайн.
Безопасники напомнили, что я не могу называть прямо особенности конкретных проектов, но это диспетчеризация городского транспорта, финансовые хайлоады и разного рода задачи, похожие по профилю на антифрод. Но поверьте, вы этим пользуетесь каждый день, если живёте в Москве, а если не в Москве — вероятно, тоже участвуете или как набор данных, или как пользователь, но пореже.
Почему старые подходы перестали работать
Всё началось с классической ситуации: к нам пришёл заказчик и сказал: «Это работает медленно, это работает плохо и непонятно, как будет работать дальше». Система — классический enterprise-хаос: многомодульная, микросервисная, омниканальная, где контекст пользователя передавался «какой-то непонятной штукой» в новый сервис, разработанный другим подрядчиком.
Никто до конца не понимал, что происходит.
Мы начали с азов: внедрили профилирование, поковырялись в базе данных, посмотрели на запросы. Нашли очевидное: где-то не было индексов, где-то использовались слишком длинные query, которые вешали систему. Но это было лечение симптомов. Заказчик спросил: «Окей, а как нам заложить в архитектуру стандарт, чтобы этого не повторялось? Как нам спрогнозировать, что будет, когда данных станет в 10 раз больше?»
Вот тут мы и упёрлись. Наши статичные моки — это был, условно, вторник 1924 года. Мы могли удвоить нагрузку, но это был тот же самый вторник, просто в двойном объёме. Заказчик смотрел на наши отчёты и говорил: «Ребята, ну это какая-то усреднённая вещь, средняя температура по больнице. А жизнь — она другая».
И он был прав.
Имитационное моделирование
На производствах с кучей переменных используется не тестирование, а имитационное моделирование. Там в систему загоняются все данные и делается WHAT IF-анализ. Чаще, правда, это WTF-анализ, особенно когда это реально крупное производство.
Наш случай с транспортом отлично это иллюстрирует. Продолжая аналогию, сначала задача была простой: считать, сколько людей вошло в автобус и вышло. Потом её усложнили: нужно было из толпы выделять женщин, мужчин, студентов, чтобы понять, почему в 8 утра пиковая нагрузка — может, рядом институт. Затем система разрослась на новые районы города, и данные оттуда в тот же самый вторник приходили совершенно другие. Эта дифференциация данных была для нас ключевой. Нам нужно было не просто фиксировать разницу, а анализировать её, чтобы строить тепловые карты и планировать новые оптимальные маршруты. Это уже не тестирование, это почти эмуляция управления полётами, где маршрут может поменяться за секунды из-за внештатной ситуации.


В смысле, да, мы строим расписание и знаем, куда сколько автобусов отправить, чтобы маршрутная сеть не сложилась. И мы помогаем принимать решения по тому, где какой нужен «запас прочности» на разные случаи. Так что если вы проклинаете кого-то, стоя в холод на остановке уже ПЯТУЮ МИНУТУ, — это либо наш кривой алгоритм, либо ресурсное ограничение. Просто знайте, что всего лет 20 назад без нашего софта вы, возможно, в такой же ситуации пошли бы пешком.
Вот для того, чтобы прогнать хитрые комбинации факторов, мы сделали ML-систему, которая генерирует реалистичные данные для тестов.
Как это работает
Несколько источников данных. Мы не полагаемся на что-то одно. Сейчас наша модель питается из трёх потоков:
1. Непрерывный поток данных из реального мира. Наш пайплайн автоматически «дёргает» из продакшена свежие срезы данных и логи. Мы ищем не типичные, а как раз аномальные, экстремальные ситуации, которые выбиваются из общей картины.
2. Умное обезличивание. Мы в силу специфики и желания путешествовать по миру очень серьёзно относимся к обезличиванию.
Система распознавания изначально создаёт обезличенный цифровой профиль пользователя (уникальный UUID). К нему привязываются неперсональные атрибуты: возраст, пол. Даже если система видит UUID, она понимает, кто это — девочка, мальчик, бабушка — без доступа к личной информации. То же самое с банковскими картами: мы гарантируем, что одна и та же карта всегда обезличивается одинаково, сохраняя все транзакционные связи, но делая невозможной обратную идентификацию.
3. Генерация «экстремальных моков». ML-модель не просто повторяет шаблоны. Мы поняли, как обогащать данные не только вертикально (меняя значения в существующих полях), но и горизонтально — добавляя новые поля и меняя саму структуру данных. Модель комбинирует реальные аномалии с прода, наши гипотезы и даже чистый рандом.
Что будет, если закроют станцию метро и тысячи людей одновременно вызовут такси? А если начнётся ярмарка и весь трафик пойдёт в обход? Модель комбинирует реальные аномалии с прода с полностью сгенерированными нами кейсами, даже с чистым рандомом, чтобы покрыть максимум неожиданных ситуаций.
Цель — набрутфорсить такой тренд, который покроет максимум неожиданных ситуаций.
Как работает пайплайн и изменились роли
Отлично работает! Всё это не вручную, а в рамках общего автоматизированного и MLOps-пайплайна.
И тут самое интересное — как изменились роли.
DevOps-инженер отвечает за инструмент, который автоматически поставляет свежие моки из прода. Но откуда он знает, как правильно их интегрировать, чтобы не сломать все?
Здесь на сцену выходит QA. В enterprise-разработке, как у нас, QA обязан участвовать в проектировании архитектуры с самого начала. Это senior-специалист, который заложил в систему правила и логику, как реагировать на разные типы данных. Фактически QA становится хранителем контекста и говорит DevOps: «Вот эти данные интегрируем так, а вот эти — вот так, потому что они влияют на такие-то модули».
И даже для нас результат каждого такого прогона — это загадка. Мы сами сидим и смотрим на тренды в реальном времени, анализируя, как система справилась с новым, сгенерированным хаосом.
Как начать такой переход?
Первое, что мы сделали, — написали скрипты для проверки их качества. В ML-проектах первая линия обороны — это именно данные.
Не нужно сразу строить космолёт. Мы начали с автоматизации простых процессов, например, переобучения модели по расписанию.
Чтобы эффективно тестировать ML-системы, нужно понимать, как они работают: что такое обучение, валидация, дрейф модели. Надо учить всех участников процесса, то есть QA.
Пришлось освоить IaC, чтобы окружения dev, staging и prod были идентичными (мы используем Terraform и Ansible), а также разобраться в observability и reproducibility (наблюдаемость и воспроизводимость).
Многие ML-проекты проваливаются не из-за плохой модели, а из-за отсутствия инженерной культуры. Мы используем DVC для версионирования данных так же, как Git для кода.
Ошибка считать, что модель готова после обучения. В реальности данные постоянно меняются (это и есть дрейф), и без контроля модель быстро теряет актуальность.
Вот наш основной инструментарий для контроля:
Great Expectations — это, по сути, набор unit-тестов для данных. QA определяет правила: нужные поля на месте, значения в правильном диапазоне, нет пустых ячеек.
Evidently AI / NannyML — наши сторожевые псы. Они следят за дрейфом данных, постоянно сравнивая новые данные с эталонными. Как только разница становится критической, они бьют тревогу. Это сигнал для QA: «Ребята, реальность изменилась, пора обновлять правила в Great Expectations». И эту задачу выполняет именно QA, а не девопсы.
Для оркестрации всего этого зоопарка используем Airflow, а для трекинга экспериментов — MLflow.

Кем становится QA
Этот подход полностью меняет роль QA. Он всё больше участвует в проектировании архитектуры, закладывает модели для обеспечения качества данных и валидации.
По сути, становится архитектором тестов, который с самого начала проектирует систему так, чтобы её можно было тестировать и поддерживать.
Его роль смещается от тестировщика к инженеру по надёжности ML-систем.
Качество перестаёт быть финальным этапом и становится встроенным свойством системы.
Наш модуль для генерации данных оказался настолько полезным, что мы стали использовать его и на других проектах — для проведения бенчмарков и тестирования систем на деградацию производительности.
Результат
Но самое главное — доказанная ценность. В одном из проектов наша трендовая система, основанная на комбинации реальных данных с прода, наших собственных сгенерированных кейсов и эталонных моделей, построила прогноз, который в точности совпал с реальным, непредсказуемым событием в будущем.
То есть мы поняли, где могут совпасть 4 дырки швейцарского сыра. И мы своими тестами подтвердили это. Именно в этот момент заказчик поверил в подход и начал доверять нашей ML-модели для стратегического планирования.