Все программисты — оптимисты. Возможно, эта современная разновидность колдовства особенно привлекательна для тех, кто верит в хэппи-энды и добрых фей. Возможно, сотни неудач отталкивают всех, кроме тех, кто привык сосредоточиваться на конечной цели. А может быть, дело всего лишь в том, что компьютеры и программисты молоды, а молодости свойствен оптимизм. Как бы то ни было, в результате одно: «На этот раз она точно пойдет!» Или : «Я только что выявил последнюю ошибку!»
"Мифический человеко-месяц", Ф.Брукс
Не сосчитать сколько раз я сам и мои коллеги спотыкались о проблему, описанную Бруксом. В последнее время появилась полезная привычка остановиться и подумать над тем, что делаешь. Не как раньше кидаться на проблему с шашкой на перевес. Видимо 7 лет в разработке ПО наталкивают на новые схемы восприятия проблем. Хочу, чтобы этот пост был маячком, который заставит вас в нужный момент задуматься о том, как сделать правильно, без спешки.
Я выбрал 3 задачи из практики, с которыми скорее всего сталкивался каждый разработчик. Многие разработчики делали эти задачи и ленились, как и я, сначала придумать как измерить успешность задачи. До начала надо ответить на вопрос: "Как я могу узнать, что сделал всё правильно?". Обо всем по порядку.
1. Миграция БД
Каждый делал миграции из старой БД в новую. Как обычно построен этот процесс в идеальном мире? Мы изучаем схему БД, связи в таблицах, пишем миграционный скрипт и запускаем. Дальше данные оказываются в новой БД и старую можно отключать.
Недавно на проете, который нам достался от другой команды, была сделана миграция из MSSQL в Couchbase. Весь проект переделывали под NoSQL с целью простой масштабируемости. Миграция из реляционной БД в NoSQL не такая простая процедура, т.к. меняется структура данных и само понятие связей. В результате было потеряно множество данных, включая оплаты у пользователей, купленные подарки и купленные аккаунты. Выяснилось, что в миграциях были ошибки, только когда систему выпустили в релиз. В БД было около 500 тыс. активных пользователей, поэтому QA не смогли сделать полную проверку с нужным качеством вручную.
Как должна была проходить миграция? Сначала у нас есть новая пустая БД и надо определить как мы поймём, что в новой БД есть все данные и связи из прошлой? Это нетривиальная задача, но без ее решения, что мы вообще делаем? Надеемся на удачу!
2. Обработка и денормализация данных
В одном из проектов, эволюцию которого я недавно описывал, была следующая проблема. Данные приходят через репликацию из сторонней БД. Эти данные надо отправить через триггеры в очередь СУБД, обработать, отправить в очередь RabbitMQ, в конце сохранить в денормализованные таблицы. По ходу развития проекта всплыло много нюансов. Например, триггер мог не сработать и не отправить какое-то изменение в очередь. При обработке изменения из очереди могла произойти ошибка. Любая ошибка давала неверную картинку для аналитики.
Только через 3 месяца после начала проекта были созданы процедуры, которые могли определить полноту и правильность переноса данных. Как нужно было сделать? Нужно было изначально определить и реализовать эти процедуры, набрать цифры и метрики для измерения качества переноса, а потом уже заниматься переносом.
3. Краулинг
История краулинга данных в одном из проектов очень поучительна для меня самого. Сначала одна команда билась за полноту и точность краулинга данных почти год. Потом наша команда взяла проект и только через 4 месяца разработки были созданы анализаторы, которые показывали отставания краулинга, его полноту и точность.
Как нужно было поступить? Сначала настроить мониторинг источников, задать индикаторы полноты и качества данных, а потом уже начинать делать краулинг. В крайнем случае заниматься этим параллельно.
Общий вывод
Подобных историй можно вспомнить множество. Уверен, что каждый из вас может вспомнить парочку проеков, где надежда на удачу с первого захода обламывала и заставляла делать уже нормально. Что объединяет эти истории? Мне кажется, выводы о том, как должно было быть напоминают Acceptance testing. Сам подход вылитый TDD в масштабе большой задачи, а не отдельного модуля, прям ATDD.
Для описания приемочного теста до реализации функционала кто-то использует Fitness, кто-то Selenium с Cucumber и т.п. инструменты. Возможно, в вашем случае нужны специальные проекты по сбору и анализу нужных данных.
В следующий раз, перед тем как что-то начинать делать, я предлагаю остановится и ответить для себя и заказчика на вопрос: "Как мы поймем, что добились нужных результатов с нужным качеством? Как можно измерить, что мы делаем систему/модуль/алгоритм лучше, а не хуже?" Ответив на эти вопросы, мы заложим фундамент для результативной работы.
Я был на проектах из п. 2 и п. 3. Саша привел очень правильную аналогию с TDD и термин ATDD мне нравится. В целом весь процесс разработки какой-либо сложной функциональности надо начинать с некоего "assert". Другой вопрос, что этот "assert" может быть очень масштабным и инфраструктура для поддержания его работы может показаться избыточной, но в итоге это окупается. Конечно, встает очень забавный вопрос - как определить правильность работы самого "assert"'a, если он у нас такой комплексный. И тут важно не переборщить и использовать для проверки те параметры, которые наиболее оптимальны по соотношению охват/простота. В таком случае весьма удобными могут быть проверки по принципу последовательного каскада исходя из прицнипа необходимых и достаточных условий.
ОтветитьУдалитьНапример, если речь идет о краулинге, то для начала мы проверяем общую полноту простым каунтером, затем проверяем общее число за временной период и т.д.
Сергей, спасибо за дополнения, про Change Data Capture не слышал, надо будет посмотреть.
ОтветитьУдалитьВообще сейчас от ServiceBroker уже ушли, т.к. эта "очередь" не работает как надо. Теперь триггеры шлют данные в таблицу, которая выполняет роль очереди. Надежность повысилась в разы.
Второй вариант не подойдет, т.к. логики при денормализации очень много, не просто преобразовать данные, но спасибо за идею.
Саша, а идея подключить всю цепочку от первичного источника через rabbit mq в итоге умерла?
ОтветитьУдалитьВ итоге политика победила здравыйс смысл. Репликация жила, живет и будет жить :)
ОтветитьУдалитьпрочитал, статью и комментарии и тоже подумал о использовании:
ОтветитьУдалитьпозволяет делать репликацию близкую к real-time без нагрузки на БД-источник
Microsoft CDC http://technet.microsoft.com/en-us/library/bb522489%28v=sql.105%29.aspx
однако обратите внимание решение microsoft CDC доступено только для Enterprise Edition
Александр, почему таблица в роли очереди, а не rabbit mq отдельным экземпляром?
ОтветитьУдалитьшаблон: тригер > MQ > обработка событий изменений > MQ > другой сервер
Алексей, так работала реализация Версия 2.0. Проблема описана ниже "Дело было в том, что CLR-функции довольно медленно отправляли данные из MSSQL в RabbitMQ"
ОтветитьУдалитьВызовы CLR в связке с RabbitMQ не давали высокой надежности и скорости, поэтому из триггеров пришлось убрать вызовы отправки в очередь.
Вставка в таблицу и выборка из нее очень быстро и главное надежно работает, без каких-либо потерь.