Pull to refresh

Comments 35

То неловкое чувство, когда понимаешь, что за 10+ лет энтерпрайз-легаси ты видел это всё, да еще и не по одному разу.
Видел все, знаю единственный рецепт от боли: налаживать связи с адекватными людьми на проктах.

Ну вот по поводу общей базы данных: когда каждая система имеет свою копию, относящуюся к одной бизнес сущности, возникает вопрос синхронизации данных и кто является изначальным владельцем. Многие запускают ночные процессы синхронизаций, которые наутро выдают огромные портянки неконсистентных данных (это в лучшем случае), некоторые пробуют онлайн синхронизацию. Но в большинстве случаев никто не заморачивается и просто дают dblink к своей базе — типа сами ищите там все, что вам нужно.

Про базу там почти все утверждения, мягко говоря, спорные. Какие-то приложения А, которые собираются столбцы в общей базе переименовывать, вместо того, чтобы переименовать поля своих объектов и успокоиться, призывы к дублированию данных, стоны, нытьё, боль и тлен.
Такой опытный дядя и, видимо, ни разу не попадал в ситуацию объединения клиентского справочника из M баз, в которых каждый клиент заведен N раз.

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

Не буду говорить за энтерпрайз, но в Web-разработке очень многие информационные системы (не буду называть их веб-сайтами, потому что там бывает довольно сложная серверная логика) грешат тем, что в них модели данных из БД и модели предметной области — это одно и то же. Слоя бизнес-логики как такового нет, бизнес-логика размазана по коду модели и контроллера: в модели обычно правила валидации и описание структуры полей хранилища, в контроллере — извлечение нужной модели из хранилища, манипуляции с ней в зависимости от юзкейса, отдача данных клиенту и сохранение обратно в хранилище. Это де-факто стандартная практика, паттерн MVC. То есть объект извлекается из БД (в случае реляционной БД — с помощью какого-нибудь ORM-решения, в случае какого-нибудь MongoDB — напрямую из BSON) и затем используется «как есть» по всему программному коду, а затем, после необходимых изменений, сохраняется обратно в БД.

В этом случае нельзя просто так взять и поменять имя поля в объекте, потому что каждое поле модели напрямую проецируется в поле соответствующей записи в базе данных. Переименовали поле в модели? Получите ошибку, что в соответствующей таблице нет такого столбца. И наоборот, нельзя просто взять и переименовать поле в базе данных: посыпется с ошибками весь код, где используется значение соответствующего поля. База данных и код оказываются зацеплены. И хорошо еще, если код и БД полностью в вашем распоряжении — можно просто аккуратно изменить и то, и другое, и выкатить релиз с аккуратной миграцией. Но все особенно плохо, если такое приложение не одно, и команды разработки у приложений разные (как раз тот случай, что описан автором). В этом случае вам либо придется идти по описанному в статье пути, либо добавить-таки в свою программу слой бизнес-логики, который позволит вам отвязаться от структуры полей, навязанной общей базой данных.
Первая ситуация: есть слой между ORM и бизнес-логикой. Структура хранилища и структура бизнес-сущьностей не связана. Есть «слой конвертации» одного в другое и наоборот. Мы поменяли имя поля в БД — «конвертер» сломался. Мы поменяли имя свойства домен-объекта — «конвертер» сломался.

Вторая ситуация: прямое отображение домен-объекта в БД и наоборот, без DTO/DTA. Абсолютно анологично: смена контракта только с одной стороны все ломает.

Что в том что в том случае «что-то нужно менять», причем синхронно. Да, согласен, что если есть «прослойка», то это нужно сделать только в одном месте одной программы. Но речь ведь о совместном доступе к хранилищу нескольких разных програм.
Видел подобный кейс, там в описанном сценарии (общая база данных на несколько независимо разрабатываемых приложений) изменения типа «а давайте переименуем вот этот столбец, а то имя неудачное» просто перестали происходить: во-первых, любое такое изменение роняет все остальные приложения; во-вторых, объем работы по переименованию соответствующего поля в коде, помноженный на количество приложений, где это необходимо сделать, да плюс требование выкатить все эти правки быстро, синхронно и без ошибок… нет, давайте просто оставим все как есть. Просто опишем подробно в документации, что в поле с именем «номер автомобиля» на самом деле хранится номер двигателя; впрочем, это и так все в компании знают… В результате структура базы данных стала открыта для расширения, но закрыта для изменения: можно расширять существующие поля и добавлять новые, но нельзя ничего удалять, переименовывать и изменять.
Я к тому, что при любом подходе изменения нужно делать синхронно. Даже если используется подход «одна БД — одно приложение». Случай «одна БД — одно приложение», как было замечено Throwable и fukkit, ведет к денормализации данных и проблеме их синхронизации… Мне кажется тут вопрос усилий и здравого смысла: что чаще/больше нужно — синхронные данные (читай удобство использования десятками пользователей по сотне раз на дню — теми, для которых весь сыр-бор и заваривался) или как можно легче вносить правки (удобство пользования несколькими пользователями может быть раз за время жизни комплекса — программистами). А так, что бы и волки сыты и овцы целы, я пока не встречал, буду искренне рад, если кто подскажет.
И еще замечание: "… структура базы данных стала открыта для расширения, но закрыта для изменения ..." это стандартная ситуация, причем не только для БД но и для любого компонента любого уровня (класс, библиотека, API, любой иной интерфейс/контракт), где нужно сохранить обратную совместимость.
В случае, когда нужно сохранить обратную совместимость API, можно просто добавить версионирование этого API: вот у нас старая версия, в ней поле называется surname, а вот более новая версия, в ней поле называется last_name. А как оно там хранится в БД, нам вообще не важно. А вот если база данных используется совместно (то есть приложений, которые лезут в нее напрямую, больше одного), такое версионирование не сделаешь (ну, кроме костыля с двумя полями).
С определенными ограничениями и оговорками, но, может быть, представления (view)?
Да, возможно. Но если каким-то из view начнут пользоваться более одного приложения, проблемы будут те же самые: нельзя лишний раз трогать ни view, ни код.
Можете подробнее описать, из-за чего появляются портянки неконсистентных данных? И как именно происходит синхронизация баз данных — мимо соответствующих приложений и их бизнес-логики, напрямую, как при репликации? В примере из статьи единственное, что связывает две базы данных — это идентификатор автомобиля. Вся остальная информация в базах данных приложений А и Б — разная: у приложения А это данные о ремонтах, механике, поломках и т.п. У приложения Б — заявки на ремонт. Соответственно, не очень понял, как может возникнуть портянка из неконсистентных записей.
ИМХО очень сомнительно утверждение про систему управления правилами, которое в принципе можно расширить на любую систему находящуюся выше кода( как пример BPMN и подобные ).
У подобных систем есть очень большой плюс, и дело не в изменяемости, дело в читаемости на уровне бизнеса, а не на уровне кода.
Если все в коде, то необходимо, что бы программисты идеально разбирались в предметной области, заменить такого программиста практически невозможно.
Если же бизнес правила находятся выше кода, поведение системы в целом становиться более прозрачным( именно с точки зрения бизнеса, а не программиста, программисту это добавляет сложности ), чтобы понять что происходит, не надо перечитать половину проекта на java.
Получается, что программисты не очень сильно разбираются в предметной области, и поэтому вместо конкретной информационной системы, которая нужна заказчику, пишут некий универсальный абстрактный конструктор, с помощью которого заказчик сам создаст (а точнее, настроит) нужную конкретно ему систему: с необходимыми сущностями, полями, связями, операциями, правилами валидации и т.п. Так?

Это мечта любого заказчика — ты мне дай такой внятный конструктор, на котором я бы смог в любой момент поменять параметр, подправить мышкой бизнес-логику — и все без всяких этих ваших джав, девопсов и прочей фигни. Реально же получается, что заказчику под видом архитектуры задвигают кучу всякого пропиетарного и дорогого барахла типа BPMN, потом он судорожно ищет дорогого специалиста, кто бы мог это все поднять дело и запустить. А затем, не осилив BPMN и Rules Engine, жестко подседает на провайдера, который не стесняется заламывать цены, ибо на рынке всего полтора специалиста по данной системе. И это еще самый оптимистичный сценарий.


И, да, хорошие программисты идеально разбираются в предметной области, зачастую лучше, чем сам заказчик. Понимают специфику работы, нужды заказчика, и сами предлагают оптимальные решения для бизнеса. И да, заменить такого программиста сложно, и это нормально — потеря квалифицированных кадров в любой отрасли негативно отражается на производстве.

У вас есть альтернатива?
BPMN у вас дорогое барахло, которое ни один нормальный, а не безумно дорого специалист осилить не может. Умолчим, что есть открытые BPMN и их техническую часть спокойно запустить любой java мид.
Видимо альтернатива самописный самолет который за чашку риса пишут джуны?

Идея конструктора без программиста пока ни у кого не взлетела, любая подобная система, будь то BPMN или другая, это попытка использования решений для общих проблем различных систем, чтобы не писать своего монстра. Чаще всего это получается дешевле и лучше.

А так ли нужен монстр? Практически всегда бизнес логика достаточно простая, а процессы по большей части линейны, потому как клиент редко успешно оперирует сложными моделями. Имеет ли смысл притягивать за уши BPMS там, систему собрать из стандартных компонентов, коих в экосистеме полно — слава богу не в пустыне живем, и всю логику быстро и без напрягов наклепать вручную.


Кроме того, BPMN — это всего лишь стандарт, для того, чтобы он завертелся, необходима какая-никакакя платформа, содержащая в себе визуальные средства разработки, отладки, мониторинга, компоненты интеграции с внешними системами, компоненты работы с моделью данных, мепперы, бизнес-правила, языки сценариев, API для работы сценариев, средства разработки пользовательских интерфейсов (формочек), система управления пользователями, пользовательский портал, etc, etc… Какой-нибудь SOA Suite. Более-менее рабочий продукт, содержащий все вышеперечисленное, будет обязательно пропиетарным. И разработка под него станет ни чем не выгоднее, чем без оного. Это такой красивый швейцарский нож: вроде бы все есть, все как бы можно сделать, но чего не коснись — все неудобно и плохо: ни хлеб нормально не порезать, ни ногти постричь, ни винт открутить, ни вино откупорить.

Если бизнес логика достаточно проста, а процессы по большей части линейны и стабильны, при это модели придельно просты, то нет смысла в собственной разработке и собственной команде разработчиков.
Если коробка или коробка с доработками от вендора дешевле 10млн.рублей, то заниматься своей разработкой бессмысленно.
При типовых процессах и простой логике берите любой продукт по выбору от желтой фирмы.

По второй части, BPMN это нотация, как правило даже в ее приделах совместимости не наблюдается. Все перечисленные вами проблемы будут и без BPMS и их решение будет не проще и не сложнее. Только к ним у вас добавиться( в случае BPMS, если ее не использовать ) значительно усложнение кода отвечающего за бизнес логику и повышение его связности.
Если говорить шире, любая платформа для разработки ПО, будь то BPMS( которая сама готовым ПО не является ) или 1С, или hybris и т.д. Это попытка упростить разработку конечного продукта за счет решения задач которые встречаются в большинстве продуктов подобного класса на уровне платформы. Да, часть эти продуктов представляют из себя неподъемных монстров, взять хотя бы тот же SAP или Navision, но без них получается долгое и очень дорогое хождение по граблям, которое еще и обладает рядом недостатков в случае привлечения внешних денег.

Если коробка или коробка с доработками от вендора дешевле 10млн.рублей, то заниматься своей разработкой бессмысленно.

Совершенно верно. Это если мы говорим о продукте, который покрывает конкретную, хорошо определенную и достаточно типовую область бизнес логики. И тем не менее даже здесь встают проблемы, когда сценарии клиента не соответствуют заложенным в продукте, а реализовать эти сценарии в ограниченном продукте не представляется возможным, либо связано с огромными расходами ввиду недостаточной гибкости продукта. Тут начинают появляться всякого рода велосипеды, приставленные сбоку. Другой проблемой всегда является интеграция с экосистемой клиента: здесь уже появляется слово заумное слово "архитектура", все вышеперечисленные автором проблемы и еще больше самопальных велосипедов.


Я же имею ввиду именно платформы-конструкторы как какой-нибудь Roga&Kopyta BPM SOA Suite, которые вообще не покрывают ни один из бизнес кейсов, но позиционируют себя как платформу для разработки и интеграции любых бизнес сценариев. Сомнительное утверждение, что при помощи подобного самолета можно дешевле и быстрее реализовать бизнес логику, нежели в голом коде. Тем более что от самолета там только красивая панель управления — все остальное также приходится педалить. Какие конкретно


значительно усложнение кода отвечающего за бизнес логику и повышение его связности

Это все абстрактно и надумано. Конечный автомат с персистенцией в базу данных сможет реализовать любой джун. Более того, когда логика процесса изменится, всегда есть возможность контролировать состояние уже запущенных процессов, тогда как в BPMS напрямую к состоянию процесса доступа нет (проблема версионирования).
За все время работы с BPMS я не видел ни одного реально сложного бизнес-процесса. Вся сложность возникала из-за ограниченности аналиста и неумения разделить на функциональные блоки, а также потому, что в BPMN-нотации фактически присутствует "оператор goto", быстро превращающий всю схему в кашу. Там же, где сценарий требовал действительно нетривиальных вещей, таких как синхронизация со временем (realtime), раннее завершение процесса, синхронизацию процессов (race condition), каскадное завершение… — все то, что быстро реализуется в коде, но BPMS не предлагал абсолютно никаких средств, а провайдер предложил купить дополнительный продукт (ESB), который реализует эти самые "Enterprise Integration Patterns".

Сомнительное утверждение, что при помощи подобного самолета можно дешевле и быстрее реализовать бизнес логику, нежели в голом коде.


Однократно реализовать логику в голом коде часто дешевле. Но ее нужно поддерживать, изменять, тестировать, согласовывать с бизнес требованиями и проверять на соответствие вновь появившимся бизнес процессам.
Когда у вас логика в коде, то внесение даже незначительных изменений в поведение может от вас потребовать перелопатить весь продукт, чтобы понять, что нигде ничего не пойдет не так. И я сейчас не говорю о ситуации когда у вас технически, что-то развалилось, это в той или иной степени решают тесты. Я говорю о ситуации валидного кода, позволяющего реализовать не валидный с точки зрения бизнес процесс. Как гипотетический пример, отправить на доставку отмененный не оплаченный заказ, через изменение адреса доставки.
Просто Петя, писавший интеграцию со службой доставки, получил задание не проверять оплату заказ, поскольку часть заказов может доставляться клиентам до оплаты( например крупные безнальные заказчики ). А Вася писавший модуль оплаты и принятия решения, не думал, что доставку заказа смогут заказать из-за пределов его модуля. А человек который видел в голове всю систему в целом давно уволился.

онечный автомат с персистенцией в базу данных сможет реализовать любой джун.


А потом в конечно автомате появляются проверки условий, ветвления, шина событий и сигналов, откат транзакций, обработка ошибок, rest интерфейс, синхронизация веток исполнения, таймеры… и вот человек написал свой BPMS на коленке. Только зачем не понятно.
Не говоря уже, что без gui инструмента разбираться в сериализованном в базу конечном автомате еще то удовольствие если у него больше пары состояний.

тогда как в BPMS напрямую к состоянию процесса доступа нет (проблема версионирования).


Есть. Хоть через базу, хоть через rest, хоть через gui.

а также потому, что в BPMN-нотации фактически присутствует «оператор goto», быстро превращающий всю схему в кашу.


goto есть в с++ и в с#, но они от этого кашей не становятся.

(realtime)


Это точно бизнес процессы, а не технологические?

race condition


Вполне успешно блокируется движком, не допуская развертывание процесса с ошибками в параллельном исполнении.

каскадное завершение


Можно сделать или в рамках процессора через события, но нужно смотреть по ситуации, является ли она именно частью бизнес процесса. Если нет, можно напрямую через rest сделать.

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

Это совершенно не зависит от способа реализации. В любой системе есть возможность написать невалидный рабочий код. И если нет человека, который контролирует всю бизнес логику, то о чем мы говорим — логика сама себя не напишет.


А потом в конечно автомате появляются проверки условий

Все это уже доступно из коробки, например в том же Spring. Поставил одну аннотацию — получил транзакцию. Поставил пару других — вот и rest заработал. Вся эта требуха не относится напрямую к задаче BPM, или бизнес логике. И фреймворков различных для этого написано огромное количество, и кроме того любая BPMS всегда стоит поверх какой-то платформы/фреймворка: SCA, JavaEE, Spring, etc… BPM — это сугубо задача асинхронного выполнения логики с возможностью сохранения/восстановления состояния. И есть также десятки способов реализовать это. Акторы, корутины, execution graphs, etc...


Есть. Хоть через базу, хоть через rest, хоть через gui.

Мы о какой-то конкретной системе говорим? Во всех пропиетарных системах, что я видел, состояние процесса сохраняется во внутренних таблицах, к коим не предусматривается сторонний доступ. Есть консистентный, но очень ограниченный API, который иногда позволяет манипулировать переменными процесса извне, но не контролировать само выполнение процесса.


Это точно бизнес процессы, а не технологические?

Именно бизнес процессы, синхронизированные со временем. У стороннего сервиса есть техническое окно в котором можно оперировать. Есть планировщик, который позволяет выставлять процессам приоритет для доступа к сервису, согласно критериям. Если процесс не удается завершить по истечении окна, его нужно перепланировать на следующий день. Кроме того там много логики, касающейся SLA как с нашей стороны, так и со стороны сервисов: ответ должен быть гарантирован втечение установленного времени — если нет, то налагаются штрафы. Ну и естественно по приближении дедлайна система должна выдавать всевозможные алармы. Вобщем, на BPMS логику реализовать не осилили — пришлось писать свой модуль.

Это совершенно не зависит от способа реализации. В любой системе есть возможность написать невалидный рабочий код. И если нет человека, который контролирует всю бизнес логику, то о чем мы говорим — логика сама себя не напишет.


BPM делает систему самодокументируемой. Т.е. бизнес процесс описан, он присутствует в виде схемы( документации ), он же в среде исполнения.
Важно, что документация и процесс при таком подходе не могут разойтись. Плюс подобная документация позволяет быстро и точно оценить процесс целиком, что в коде сделать практически невозможно.

Все это уже доступно из коробки, например в том же Spring. Поставил одну аннотацию — получил транзакцию. Поставил пару других — вот и rest заработал.


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

Мы о какой-то конкретной системе говорим? Во всех пропиетарных системах, что я видел, состояние процесса сохраняется во внутренних таблицах, к коим не предусматривается сторонний доступ. Есть консистентный, но очень ограниченный API, который иногда позволяет манипулировать переменными процесса извне, но не контролировать само выполнение процесса.


Работал с несколькими открытыми системами( как пример Camunda ). Доступ к базе в открытых системах есть, что очевидно. API позволяет делать практически все. Контролировать выполнение процесса очень абстрактная фраза, выполнение в принципе можно контролировать только в отладчике, а контролировать состояние можно. Если очень нужно вокруг можно прикрутить свой код который плотно взаимодействует с движком. Плюс практически все можно расширить.

Именно бизнес процессы, синхронизированные со временем. У стороннего сервиса есть техническое окно в котором можно оперировать.


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

Вот с этим на все 200% не согласен. Это никогда не работает, сколько я видел систем. У всех производителей BPMS есть эта красивая идея сотрудничества: типа бизнес-бог определяет требования и расставляет на схеме мышкой ящички и стрелочки, а черти-программеры в этой же схеме уже подтягивают интерфейсы, делают меппинг данных, формочки, etc… Иногда для этого используется два разных набора тулзов, но идея, чтобы у них обоих отображался один и тот же процесс. Так вот, сколько я BPM систем ни видел, это нигде не работает. Всегда есть одна версия процесса, написанная аналистом и используемая для исключительно для документации, и есть другая, "рабочая" версия, которая порой абсолютно не похожа на изначальную, и которая написана программерами в соответствие с изначальными требованиями. И проблемы здесь начинаются не с кривых рук или глючного софта, а с порочности самой идеи: когда при реализации вылезают определенные детали, то бизнес-бог не особо слушает рекомендации чертей-программеров и черта-с-два изменит что-то на своей схеме — он птица высокого полета и не должен думать о деталях. А дьявол всегда кроется в деталях.


Работал с несколькими открытыми системами( как пример Camunda ). Доступ к базе в открытых системах есть, что очевидно.

Есть задача — пропатчить бизнес-логику, не завершая запущенные процессы. Юзал Activiti и jBPM — там есть описание структуры таблиц, и можно разобраться с состоянием процессов, на то он и OpenSource. Но точно также крайне сложно сделать корректный патч, который не порушит запущенные процессы (хотя зависит от характера изменений), и также приходится следить за всеми дельтами. И тут BPMS никак не поможет — они предлагают задеплоить новую версию для новых процессов, пока старые завершатся по-старому. А в пропиетарных BPMS вообще нет способа патчинга (все состояние закрыто семью печатями), а в некоторых и версионирование криво работает. Так что за мою деятельность у меня столько юзкейсов скопилось, которые ни одна BPMS не решает, а наоборот, мешает, что потребуется целая статья (начиная от "просто добавить поле").


Если речь идет не о долях секунды, то это не реалтайм

Если следовать определению, это именно реалтайм — процессы, синхронизированные со временем и, как частный случай, имеющие гарантированное время отклика.

И проблемы здесь начинаются не с кривых рук или глючного софта, а с порочности самой идеи: когда при реализации вылезают определенные детали, то бизнес-бог не особо слушает рекомендации чертей-программеров и черта-с-два изменит что-то на своей схеме — он птица высокого полета и не должен думать о деталях. А дьявол всегда кроется в деталях.


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

У себя мы прогоняем процесс через несколько итерации.
В каждой из которых участвуют и разработчики.
Бумага, обсуждение, первая версия BPM, обсуждение, правки, вторая версия BPM, обсуждение, правки, тесты, дальше или третья версия BPM, если на тестах вылезли проблемы реализации или разработка «мяса». Обычно в конце по обратной связи еще небольшие правки BPM.

Есть задача — пропатчить бизнес-логику, не завершая запущенные процессы.


Можно ждать завершения старых версии процессов, можно руками сделать миграцию по отдельным процессам, можно сделать массовую миграцию( batch ) в gui( обычно в платных редакциях ), можно сделать миграцию через код, можно сделать миграцию через базу.

Чем больше разница между исходным и целевым процессом, тем это сложнее, именно по этому, лучше двигаться малыми итерациями.
Процесс в обязательном порядке покрывается тестами.
Я бы сказал, это проще, чем перетаскивать процессы реализованные в самописном велосипеде.

а наоборот, мешает, что потребуется целая статья (начиная от «просто добавить поле»).


Добавить поле как правило вообще на процесс не влияет и изменений в BPM не требует.

Да, все описанные ситуации неприятные. Но в большинстве случаев альтернатива еще хуже. Нередко — гораздо хуже.

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

Зависимость от конкретного софта, вендор которого не хочет делать все безумные хотелки заказчика. Альтернатива — доработка софта своими или аутсорсинговыми силами. Вот после нескольких лет такой доработки и нескольких смен команд сладкие дни работы с одним вендором будут пределом мечтаний.

Зависимость от кода проверяется хотя бы статически. А проблемы с миллионом rest микросервисов не протестировать никаким способом. И проблема версионирования микросервисов в практике эксплуатации более проблематична (хотя бы потому, что существенная часть проблем вылезет не при сборке или тестах, а только при продакшене). Собственно, проблема существует еще с мейнфреймов (rpc, ipc и пр.), придумано, реализовано и забыто множество технологий, но принципиального решения все еще нет и даже не предполагается.

Про ETL для бизнес правил vs кодирование бизнес логики даже говорить не надо. Либо спецпрограммисты от бизнеса, либо спецпрограммисты для бизнеса. Разницы никакой. Сложные задачи, что характерно, обычно не имеют простых решений. Вспомним, например, что SQL создавался как простой пользовательский язык управления данными.
Если говорить о единой БД, которую трудно изменить… Если уж возникла необходимость иметь несколько приложений, каждое из которых хранит данные в собственной БД, то частичная несогласованность данных — это норма. Данные в этих БД синхронизируются не напрямую, а через соответствующие приложения, с использованием event-driven архитектуры и бизнес-логики в коде соответствующих приложений. Пример, описанный в статье: в базу данных приложения Б добавляется новая запись — требуется ремонт автомобиля с номером «А001ВЕ» модели «ВАЗ-2107». Приложение Б испускает событие «новая заявка на ремонт», на которое подписано приложение А (через какой-нибудь брокер событий). В приложении А реакция на это событие — завести в своей БД новую карточку на автомобиль с таким идентификатором и моделью или повторно открыть уже существующую (если ремонт данного авто уже производился). По завершению технических работ по автомобилю приложение А испускает другое событие, на которое подписано приложение Б. В приложении Б реакция на это событие — закрыть соответствующую заявку по ремонту. Очень схематично, но в чем проблема такого подхода? Это ведь не две копии одной и той же БД у разных приложений, которые как-то синхронизируются в фоне или ночами, минуя бизнес-логику, это две разные БД, каждая со своей структурой, наполняемые и изменяемые только своими приложениями.

А проблема в том, что в одной базе содержатся все марки автомобилей, которую допустим поддерживает головной офис, а в базе филиала Мухосранска локально содержатся все ремонты. Внезапно в головном офисе обнаруживается, что одна и та же модель в базе продублирована как "ВАЗ-2107" и, скажем, "ТАЗ-2107". Везде для карточки клиента использовали первый вариант, и только в Мухосранске сделали второй. Головной офис решил по-тихому расстаться с ТАЗов в модельном ряду и грохнул запись. В итоге ночью тихонько зафейлился скрипт апдейта базы Мухосранского отделения, но этого никто не заметил. Заметили через три месяца, когда система головного офиса не захотела принимать отчет с неизвестной моделью.


А вот реальная история: система сбора информации с сетки (Network Reconciliation). Ночью синхронизировались с GIS для получения новых станций и апаратов. Затем поступали данные от EMS со всеми текущими параметрами станций. В один прекрасный день образовалось несколько гигабайт зафейлившихся логов. Причина проста: GIS и наша система внезамно перешли на зимнее время, тогда как EMS всегда стоят по UTC, и в итоге начинали лить данные со станций раньше, чем мы синхронизировались с GIS, чтобы получить новый список станций. И это еще не затрагивая самой логики data reconcilliation.


Так что синхронизация баз данных — это ужасно. Тут нет универсальных решений, все что можно придумать — все плохо.

Если несколько филиалов пользуются общим справочником данных (в вашем примере это список моделей), то пусть либо пользуются общей базой данных (с шардингом заявок по филиалам, например), либо пусть филиалы получают этот справочник от головного офиса, через API — в real-time или же, в целях ускорения, с периодической синхронизацией (например, раз в сутки). Плюс, конечно же, очень желательно предусмотреть случаи, когда данные начинают рассогласовываться по вине той или другой стороны:
  • записи о моделях в базе данных головного офиса не должны удаляться, а только помечаться как удаленные — это общий сценарий для сохранения согласованности данных в связанных справочниках; такие записи пропадают из всех списков, но в случае объединения они обеспечивают корректную работу с устаревшими записями из региональных филиалов (в вашем примере — когда из региона придет заявка с моделью «ТАЗ-2107», а в БД головного офиса ее уже пометили как удаленную)
  • если регион может прислать неизвестную для головного офиса модель — приложение головного офиса должно уметь обработать эту ситуацию: записать заявку как «Неизвестная модель» и отправить модератору, или добавить новую модель в свой справочник, или еще что-то — зависит от бизнес-процесса, вопрос не в плоскости программирования;
  • если у регионов есть возможность добавлять свои модели, то эти модели должны попадать в общий справочник головного офиса;
  • возможно, головной офис просто должен быть умнее всех регионов и обеспечить распознавание нескольких разных моделей как одной и той же (регион А вводит «ТАЗ-2107», регион Б — «ВАЗ-7», а головной офис все их приводит к «ВАЗ-2107»)
  • прекратить порочную практику копания в базах данных напрямую (через какой-нибудь phpMyAdmin, mongo-shell и т.п.), т.е. когда данные изменяются мимо бизнес-логики, правил валидации и т.п. (например, когда кто-то в регионе берет и вручную правит название модели в локальной БД, а потом в головном офисе заявки не импортируются, потому что неизвестная модель)

Да, это много дополнительной работы по проектированию и кодингу, но в распределенных системах без этого не обойтись. А паттерн «shared database», на мой взгляд, — это такая фальшивая децентрализация: вроде бы приложения разные и даже лежат на разных серверах (почти микросервисы!), но раз база данных у них общая, то если с ней что-то случится — ломается абсолютно все.
Плюс, конечно же, очень желательно предусмотреть случаи, когда данные начинают рассогласовываться по вине той или другой стороны:

Ну вот. И теперь смотрите, насколько усложнилась задача для синхронизации одной лишь сущности. Если у вас есть несколько сущностей, или еще хуже, некая реляционная модель, связывающая их всех, то сложность процесса синхронизации увеличивается на порядки. Например, приходится производить многопроходную актуализацию, зачастую приходится отключать всяческие constraints (которые потом обратно не всегда включаются). А в некоторых случаях задача корректной синхронизации вообще неразрешима.


А паттерн «shared database», на мой взгляд, — это такая фальшивая децентрализация

Тем не менее только он гарантирует постоянную консистентность всех данных. Другое дело, что не во всех кейсах это так необходимо.


P.S. не туда :(

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

Но бывают ситуации, когда этот процесс непрерывного изменения и совершенствования продукта сильно затрудняется или даже замораживается определенными архитектурными решениями, заложенными в проект на заре его становления.
Shared database — один из таких архитектурных антипаттернов. Да, база данных может быть спроектирована безобразно: каша в именах полей, отсутствие гайдлайнов по именованию, семантические ошибки, кривая схема, денормализация, и т.п… Это может быть серьезной проблемой. Но еще хуже то, что если у вас shared database, то вы очень сильно ограничены в решении этой проблемы, потому что к схеме общей БД привязано целое множество других приложений, кроме вашего, и хорошо еще, если у вас на руках есть полный их список.
Эта проблема, в общем случае, не имеет решения вовсе. Правда её можно поменять на другую проблему — проблему синхронизации множества экземпляров. Как говорят в Одессе: «Обе хуже».
В каком-то смысле shared database очень схожа с другим «табу» разработки — использованием глобальных переменных. В случае глобальных переменных ответственность за данные не ограничена областью видимости переменной, а «размазана» тонким слоем по всему коду проекта: в любом месте переменную могут не просто прочитать, но еще и перезаписать. В случае shared database все даже хуже: ответственность за БД размазана по коду множества различных проектов, к многим из которых у вас даже может не быть доступа.
Sign up to leave a comment.

Articles