Оптимистичная архитектура: дал слово — держи!
Сегодня будет сказ про оптимистичную архитектуру. В нём можно разглядеть себя или своих знакомых. Основано на реальных событиях, но все совпадения случайны!
Однажды перед разработчиками встала задача — разработать микроядро для хранения документов клиента. Функциональность подразумевала создание CRUD-сервиса и сервиса поиска. Поиск должен был предоставлять возможность находить документы выбранного клиента по произвольному фильтру, который строился на основе атрибутов документа.
Архитекторы решили не ограничивать API поиска, предоставив будущему пользователю абсолютную свободу действий. Сейчас уже и не найдешь истинной причины такого оптимистичного решения. Возможно, используемая реляционная база и ORM натолкнули на такую мысль; возможно, не хотелось в будущем менять контракт взаимодействия. Так или иначе, для существующих и будущих интеграций API поиска позволял указать предикат любой сложности.
Время шло, проект развивался, вокруг него выстроилась целая плеяда систем. В связи с этим база документов выросла до значительных размеров, и с каждым годом этот рост только ускорялся. Поначалу всё шло хорошо. API поиска использовался так, как было задумано: поиск сводился к фильтрации документов выбранного клиента. Однако после пользователи API смекнули, что искать можно как угодно! И понеслось...
"Верни мне документы, которые удовлетворяют <этим> критериям, а из найденного я возьму только один-единственный атрибут"; "Найди все документы <этого> типа за всю историю существования системы, а я возьму только их количество"; "Найди <подобные> документы у всех клиентов" и т.д.
Подобные запросы были редкими, но крайне неприятными. Они провоцировали повышенную загрузку ресурсов и выполнялись крайне медленно. А что делают пользователи в этом случае? Правильно, идут жаловаться на поставщика услуги! И правильно делают, ведь они используют официально предоставленный публичный контракт.
Выяснилось, что подобные запросы — это попытки внешних систем сделать какую-либо аналитику (OLAP) на основе исходных данных (OLTP). Однако микроядро по своей сути задумывалось как OLTP-фасад с функцией фильтрации документов внутри агрегата клиента. Однако благодаря оптимистично-многообещающему API поиска ситуация начала выходить из-под контроля.
Пользователи требовали быстрый поиск, команда микроядра делала его оптимизацию, затаскивая в проект всё новые и новые частные прикладные сценарии...
Думаю, что история ясна и пора перейти к капитанским советам:
- Не давай обещания, которые не собираешься выполнять. Предоставь ровно ту функциональность, которая требуется. Если нужно заложить точки роста, заложи, но в рамках здравого смысла и понимания перспектив развития. Если кому-то понадобится "больше", то он придёт и заявит об этом явно. Так процесс развития станет прозрачным и понятным каждому участнику интеграции.
- Не соглашайся с навязыванием условий. В тот момент, когда сервис начали использовать не по назначению, поднимай красный флаг. Выясни причины, определи и запланируй возможные шаги для исправления. Иногда данный вопрос может быть решён административно.
- Отделяй общее от частного. Проанализируй запросы, возможно, что часть подсистем нуждается в какой-то общей функциональности, а часть должна быть реализована на местах. Например, некоторым подсистемам нужен один и тот же срез данных, а другие должны самостоятельно организовать специфичные витрины данных.
- Универсальных моделей не бывает. Модель данных должна соответствовать характеру её использования. Мы не можем игнорировать этот аспект, в том числе и на уровне API. Если строим аналитику и отчётность на базе сырых данных, то важно помнить, что это может создать риски в будущем.
А вы попадали в похожую долговую яму? ;-)
P.s. Посмею напомнить, что у меня есть Telegram-канал "Архитектоника в ИТ", где я публикую материал на похожие темы примерно раз в неделю. Подписчики меня мотивируют, но ещё больше мотивируют живые дискуссии, ведь именно в них рождается истина. Поэтому подписывайтесь на канал или на мой блог здесь. Будем обмениваться опытом и мнениями. ;-)