Приемочное тестирование как производственная необходимость

24 января 2014 г.

Все программисты — оптимисты. Возможно, эта современная разновидность колдовства особенно привлекательна для тех, кто верит в хэппи-энды и добрых фей. Возможно, сотни неудач отталкивают всех, кроме тех, кто привык сосредоточиваться на конечной цели. А может быть, дело всего лишь в том, что компьютеры и программисты молоды, а молодости свойствен оптимизм. Как бы то ни было, в результате одно: «На этот раз она точно пойдет!» Или : «Я только что выявил последнюю ошибку!»
"Мифический человеко-месяц", Ф.Брукс

Не сосчитать сколько раз я сам и мои коллеги спотыкались о проблему, описанную Бруксом. В последнее время появилась полезная привычка остановиться и подумать над тем, что делаешь. Не как раньше кидаться на проблему с шашкой на перевес. Видимо 7 лет в разработке ПО наталкивают на новые схемы восприятия проблем. Хочу, чтобы этот пост был маячком, который заставит вас в нужный момент задуматься о том, как сделать правильно, без спешки.

Я выбрал 3 задачи из практики, с которыми скорее всего сталкивался каждый разработчик. Многие разработчики делали эти задачи и ленились, как и я, сначала придумать как измерить успешность задачи. До начала надо ответить на вопрос: "Как я могу узнать, что сделал всё правильно?". Обо всем по порядку.

1. Миграция БД

Каждый делал миграции из старой БД в новую. Как обычно построен этот процесс в идеальном мире? Мы изучаем схему БД, связи в таблицах, пишем миграционный скрипт и запускаем. Дальше данные оказываются в новой БД и старую можно отключать.

Недавно на проете, который нам достался от другой команды, была сделана миграция из MSSQL в Couchbase. Весь проект переделывали под NoSQL с целью простой масштабируемости. Миграция из реляционной БД в NoSQL не такая простая процедура, т.к. меняется структура данных и само понятие связей. В результате было потеряно множество данных, включая оплаты у пользователей, купленные подарки и купленные аккаунты. Выяснилось, что в миграциях были ошибки, только когда систему выпустили в релиз. В БД было около 500 тыс. активных пользователей, поэтому QA не смогли сделать полную проверку с нужным качеством вручную.

Как должна была проходить миграция? Сначала у нас есть новая пустая БД и надо определить как мы поймём, что в новой БД есть все данные и связи из прошлой? Это нетривиальная задача, но без ее решения, что мы вообще делаем? Надеемся на удачу!

2. Обработка и денормализация данных

В одном из проектов, эволюцию которого я недавно описывал, была следующая проблема. Данные приходят через репликацию из сторонней БД. Эти данные надо отправить через триггеры в очередь СУБД, обработать, отправить в очередь RabbitMQ, в конце сохранить в денормализованные таблицы. По ходу развития проекта всплыло много нюансов. Например, триггер мог не сработать и не отправить какое-то изменение в очередь. При обработке изменения из очереди могла произойти ошибка. Любая ошибка давала неверную картинку для аналитики.

Только через 3 месяца после начала проекта были созданы процедуры, которые могли определить полноту и правильность переноса данных. Как нужно было сделать? Нужно было изначально определить и реализовать эти процедуры, набрать цифры и метрики для измерения качества переноса, а потом уже заниматься переносом.

3. Краулинг

История краулинга данных в одном из проектов очень поучительна для меня самого. Сначала одна команда билась за полноту и точность краулинга данных почти год. Потом наша команда взяла проект и только через 4 месяца разработки были созданы анализаторы, которые показывали отставания краулинга, его полноту и точность.

Как нужно было поступить? Сначала настроить мониторинг источников, задать индикаторы полноты и качества данных, а потом уже начинать делать краулинг. В крайнем случае заниматься этим параллельно.

Общий вывод

Подобных историй можно вспомнить множество. Уверен, что каждый из вас может вспомнить парочку проеков, где надежда на удачу с первого захода обламывала и заставляла делать уже нормально. Что объединяет эти истории? Мне кажется, выводы о том, как должно было быть напоминают Acceptance testing. Сам подход вылитый TDD в масштабе большой задачи, а не отдельного модуля, прям ATDD.

Для описания приемочного теста до реализации функционала кто-то использует Fitness, кто-то Selenium с Cucumber и т.п. инструменты. Возможно, в вашем случае нужны специальные проекты по сбору и анализу нужных данных.

В следующий раз, перед тем как что-то начинать делать, я предлагаю остановится и ответить для себя и заказчика на вопрос: "Как мы поймем, что добились нужных результатов с нужным качеством? Как можно измерить, что мы делаем систему/модуль/алгоритм лучше, а не хуже?" Ответив на эти вопросы, мы заложим фундамент для результативной работы.

7 комментариев:

  1. Я был на проектах из п. 2 и п. 3. Саша привел очень правильную аналогию с TDD и термин ATDD мне нравится. В целом весь процесс разработки какой-либо сложной функциональности надо начинать с некоего "assert". Другой вопрос, что этот "assert" может быть очень масштабным и инфраструктура для поддержания его работы может показаться избыточной, но в итоге это окупается. Конечно, встает очень забавный вопрос - как определить правильность работы самого "assert"'a, если он у нас такой комплексный. И тут важно не переборщить и использовать для проверки те параметры, которые наиболее оптимальны по соотношению охват/простота. В таком случае весьма удобными могут быть проверки по принципу последовательного каскада исходя из прицнипа необходимых и достаточных условий.

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

    ОтветитьУдалить
  2. Сергей, спасибо за дополнения, про Change Data Capture не слышал, надо будет посмотреть.
    Вообще сейчас от ServiceBroker уже ушли, т.к. эта "очередь" не работает как надо. Теперь триггеры шлют данные в таблицу, которая выполняет роль очереди. Надежность повысилась в разы.

    Второй вариант не подойдет, т.к. логики при денормализации очень много, не просто преобразовать данные, но спасибо за идею.

    ОтветитьУдалить
  3. Саша, а идея подключить всю цепочку от первичного источника через rabbit mq в итоге умерла?

    ОтветитьУдалить
  4. В итоге политика победила здравыйс смысл. Репликация жила, живет и будет жить :)

    ОтветитьУдалить
  5. прочитал, статью и комментарии и тоже подумал о использовании:
    позволяет делать репликацию близкую к real-time без нагрузки на БД-источник
    Microsoft CDC http://technet.microsoft.com/en-us/library/bb522489%28v=sql.105%29.aspx
    однако обратите внимание решение microsoft CDC доступено только для Enterprise Edition

    ОтветитьУдалить
  6. Александр, почему таблица в роли очереди, а не rabbit mq отдельным экземпляром?
    шаблон: тригер > MQ > обработка событий изменений > MQ > другой сервер

    ОтветитьУдалить
  7. Алексей, так работала реализация Версия 2.0. Проблема описана ниже "Дело было в том, что CLR-функции довольно медленно отправляли данные из MSSQL в RabbitMQ"


    Вызовы CLR в связке с RabbitMQ не давали высокой надежности и скорости, поэтому из триггеров пришлось убрать вызовы отправки в очередь.


    Вставка в таблицу и выборка из нее очень быстро и главное надежно работает, без каких-либо потерь.

    ОтветитьУдалить

Моя книга «Антихрупкость в IT»

Как достигать результатов в IT-проектах в условиях неопределённости. Подробнее...