Комментарии 42
Из личного опыта (и той методологии, в которой сейчас работаем) схема немного сложнее.
То, что хочет заказчик, называется BRD - бизнес-требования. Они согласуются с заказчиком. Все, что делается дальше, уже является внутренними документами исполнителя.
На основе BRD сначала разрабатывается архитектурное решение - там уже архитектура, дробление на модули, связь между модулями и т.д. и т.п. Это работа архитектора.
На основе архитектурного решения разрабатывается FSD - это уже ТЗ для конкретного исполнителя (разработчика). Разработкой FSD занимается аналитик (возможно, совместно с разработчиком, если уровень разработчика позволяет). Там уже описываются технические подробности реализации.
Как оформлять каждый из документов - это уже зависит от контекста, предметной области и много чего. Где-то удобнее использовать модель данных, где-то функциональную модель. Но суть примерно такова - есть документ который согласуется с заказчиком, есть внутренние документы исполнителя. И это разные документы, он "на разных языках" пишутся и с разными целями. Заказчику важно получить функционал, закрыть свои потребности. И ему совершенно не важно какие там алгоритмы будут реализованы.
Конечному исполнителю (разработчику) важно не только в каком виде должен быть представлен результат, но и как его получить (например, какие таблицы по каким условиям связать для получения выборки, как обработать полученную выборку и т.п.)
Представлять все это в виде одного документа неудобно никому - ни заказчику (там будет слишком много технических подробностей), ни исполнителю (там будет много того, что ему, в общем-то, не нужно).
схема немного сложнее
Как говорил один серьезный Заказчик, "Для того, чтобы что-то упростить - надо сначала это усложнить!"
Заказчику важно получить функционал
Именно, и тот, который он ожидал. При этом важно понять даже невнятное изложение требований - мои рассуждения в статье больше о том, как понять такие.
При этом важно понять даже невнятное изложение требований
Дело в том, что вам это изложение требований кажется "невнятным". А для заказчика все это понятно и естественно. А все, что вы ему говорите в ответ про "движки" и "фреймворки" для него птичий язык. И тут речь не о том что
Для того, чтобы что-то упростить - надо сначала это усложнить!
а о том, что разнести по разным уровням так, чтобы каждый из них был максимально понятен для того, кто с ним работает.
Лично мне представляется, что разработка какой-то персонифицированной для заказчика системы фактически означает разработку некоторого «движка» для бизнес-процесса заказчика на выбранном наборе фреймворков, поэтому нужно в итоге обсуждений с заказчиком прийти к тому, что его бизнес-требования будут описываться в терминах этого «движка». Всем от этого будет легче - заказчик понимает, что он может хотеть от такой системы в краткосрочной и долгосрочной перспективе, разработка становится более прозрачной для всех - и для заказчика и для исполнителя. Код движка от заказчика может быть закрыт, но тут как договориться участники. У меня был пример, когда в итоге общение с заказчиком свелось к таблицам параметров - они присылали таблицы параметров или изменения в таблицах, мы выставляли счёт, он оплачивал, мы делали. Все были довольны. Отступления от такой схемы рассматривались отдельно.
Это я к тому, что просто набор нарисованный прямоугольников, который никак не связан с программным кодом всё равно не удобен. Он может быть удобен администрации, но для непосредственных исполнителей в итоге почти бесполезен.
Ну, тут есть отличие в том, что речь идет не только о программном коде. И акцент идет, действительно, в большей степени на "администрацию". Для исполнителя, если речь вести только о программном коде, конечно есть другие варианты представления требований.
Можно и просто их оформить, сформулировать, и сложно. Use Case, User Stories, просто постановка задач на разработку функций "на вход то-то, на выходе то-то". Разные варианты.
По графическому представлению - Use Case (опять таки по мне) - рулит!
Заказчик живет в рамках своей предметной области. И разговаривает на своем языке. И ему все эти "движки", "фреймворки" глубоко безразличны - у него есть бизнес-процесс и он хочет его автоматизировать. И вот для ее автоматизации он и составляет BRD - Business Requirements Document. Вот его он понимает. А все что глубже ему не интересно.
И да, это будет как раз "набор прямоугольников, который никак не связан с программным кодом". Это описание бизнес-процесса заказчика. Как его связать с программным кодом - это уже задача архитектора и аналитика. И это внутренняя задача, заказчик в ее решении и обсуждении уже участия не принимает с того момента как BRD согласовано и принято к реализации и до того момента, как результат будет выкачен на уровень бизнес-тестирования на соответствие BRD.
Связь "набора прямоугольников" программным кодом описывается аналитиком в FSD (Functional Specifications Document). Это совсем другой документ и там используется совсем другая терминология - терминология разработчика. Там уже и "движки" и "фреймворки" и все вот это вот. Аналитик в данном случае выступает в качестве переводчика с языка заказчика на язык разработчика.
Здесь классическая цепочка - "заказчик - организатор - исполнитель" в которой крайние звенья (заказчик и исполнитель) между собой не общаются и друг друга не знают, они связаны только через организатора, роль которого выполняет аналитик.
Да, ок.
В понятийном аппарате PMI, документу BRD соответствует Паспорт проекта. Он логичный, содержательный, но... опять таки - сложноватый и весьма формальный.
На подобные документы, такова жизнь, забивают болт... Особенно в цейтноте.
На подобные документы, такова жизнь, забивают болт... Особенно в цейтноте.
И ничего хорошего из этого не выходит. Ладно если это разовый проект - спихнул заказчику, взял деньги и свалил в даль светлую. А что там дальше - трава не расти.
А вот если система сложная, постоянно развивающаяся и модифицируемая, требующая поддержки... Тут такие подходы быстро выходят боком и заказчику и исполнителю.
Паспорт проекта это точно, не BRD. На самом высоком уровне Business Case описывает, что хочет бизнес, а потом это детализируется, но не в Паспорте проекта
Аналитик в данном случае выступает в качестве переводчика с языка заказчика на язык разработчика
Вот это и есть тонкий момент во всей этой системе. Переводчик - это тоже условный термин и вот тут я с этим не очень согласен. Я бы сказал так - «толкователь». Потому что нет каких-то строгих и чётких правил перевода. Этот человек и является очень слабым звеном в этой системе. По хорошему он должен работать на то, чтобы устранить себя из этой системы и это очень противоречивая ситуация для него. Можно было бы предложить получать процент от работы по такому договору в случае изменений с его участием или без. Тогда он может быть заинтересован как можно быстрее настроить систему так, чтобы она работала без него, а он получал пассивный доход.
Переводчик в том смысле, что он владеет как терминологией заказчика (и понимает бизнес-логику), так и исполнителя - знает как эта логика проецируется на конкретную реализацию.
Отсутствие такого человека в системе накладывает на исполнителя (разработчика) требования глубокого понимания предметной области заказчика. А она может быть очень непростой и на вникание в нее могут потребоваться годы (если это, конечно, не формошлепство в виде красивого раскидывания кнопочек и формочек по страничке).
если это, конечно, не формошлепство в виде красивого раскидывания кнопочек и формочек по страничке
По моему именно к такой форме работы и надо стремиться в каждом конкретном проекте. Не начинать с него, а идти к нему. А как вы считаете?
По моему именно к такой форме работы и надо стремиться в каждом конкретном проекте
А представьте, что задача заключается в разработке модуля с достаточно сложной логикой, но совершенно без интерфейса... Например, поиск совпадений между элементами одной БД (5-6 таблиц, ~50млн записей) и другой БД (7-8 таблиц, ~300тыс записей) по 5-6 параметрам с формированием списка связей (какие элементы по каким параметрам совпали). Причем, не просто вывести, а проанализировать - что было, но сейчас нет, чего не было, но сейчас появилось, что было, но изменилось...
Запускается все это по определенному событию. Плюс есть жесткие рамки - временное окно, в которое нужно уложиться и максимально допустимая нагрузка на процессор в рамках временного окна.
Или контроль платежей. Там порядка десятка проверок на основании которых выносится решение о том, пропустить платеж или отправить его на ручной контроль в финмон. Порядок, параметры и состав комплекса проверок определяется исходя из типа платежа (входящий, исходящий, внутренний) и типов плательщика и получателя (ФЛ, ЮЛ, ИП...). Причем, все это должно быть организовано так, чтобы порядок проверок, их настройки для каждого конкретного случая можно было легко настраивать без изменения кода.
А с учетом того, что количество платежей в сутки легко может уйти за 100млн, то все это должно работать не просто быстро, а очень быстро.
Такие вот задачки приходится решать. И без аналитиков тут никак. Чтобы разработчик был в курсе предметной области настолько чтобы быть способным реализовать всю эту логику без аналитиков, он должен много лет проработать тут. А заказчик (бизнес), как правило не сильно в курсе как все это организовано внутри. Они на другом уровне работают, у них свои сущности и понятия.
Так что ИТ - оно не ограничивается сайтами и мобильными приложениями. Есть много отраслей, где приходится работать со сложной логикой, большими объемами данных.
А представьте, что задача заключается в разработке модуля с достаточно сложной логикой, но совершенно без интерфейса...
Представляю и не вижу противоречий. Я и не говорю, что без аналитиков никак, только настаиваю, что аналитик должен стремиться к самоустранению.
Я не очень понимаю что такое "стремится к самоустранению".
У нас аналитик избавляет разработчика от общения с бизнесом (сталкивался с ситуациями когда разработчик напрямую пытается с бизнесом общаться - они просто не понимают друг друга). Помогает разработчику в предметной области. Занимается компонентным тестированием (первая стадия - тестирование поставки на соответствие FSD).
Да, он не пишет ТЗ "до псевдокода" - выбор наиболее эффективного решения всегда за разработчиком. Но описать dataflow - это задача аналитика.
Аналитик ведет задачи в Jira (разработчик только меняет статусы на Dev и потом на Dev Done). Занимается актуализацией FSD, которая одновременно является технической документацией по задаче (ее же потом еще надо сопровождать, вносить изменения если изменился бизнес-процесс или какие-то условия - законодательство, требования регулятора...). Также для решения одной задачи может потребоваться создание каких-то подзадач (те же витрины, например). Для решения задачи может потребоваться проектирование БД - это тоже работа аналитика...
Аналитик вообще незаменимый человек в процессе. Он и предметную область должен знать и обладать некоторыми навыками алгоритмизации.
В целом хороший аналитик очень сильно облегчает жизнь разработчику и позволяет ощутимо ускорить процесс разработки.
Эта роль называется Product Owner. Хороший PO часто знает бизнес заказчика лучше заказчика, потому что общается не только с начальством, но и конечными пользователями. За красивыми BPMN можно скрыть любой ад.
Мне кажется - это статья, классический пример тяжеловесного аналитика, который скорее утомит всех своим ТЗ, чем его кто-то поймет
Во-первых, люди НЕ БУДУТ менять свой словарь ради аналитика. Мы разошлем термины, согласуем в начале, всех заставим говорить на одном языке - это видимость работы и мина замедленого действия. Заказчик понимает свой язык и имеет на то право, так как он платит деньги. Учи его, говори на нем, пиши на нем, если ты входишь в число членом команды, кто общается с ним.
Разработчики не понимают ... да, роль аналитика выступить переводчиком и разъяснить. А не попробовать нагнуть всех и заставить всех общаться на том языке, который понятен аналитику.
Заказчик имеет деньги, разработчик пишет код. Остальные - обслуга и должны максимально создать комфортные условия первым и вторым, беря на аебя сложности перевода.
Можно как писали выше, заказчику один документ, команде - сторьки во внутреннем формате. Все равно их декомпозировать технически. Простейший пример, одно требование из ТЗ, хочештили нет, разделится на отдельные требования фронту и бэку. Между которыми API. Не всегда конечно, но очень часто.
Пример "Современная модель оборудования - модель оборудования, выпущенная не ранее января 2022 года и доступная к приобретению на потребительском рынке, при этом рейтинг модели должен быть не ниже 4 по оценке сайта market.yandex.ru или аналогичного." - это жесть и за такое надо бить. Поясню. Требования к аппаратной части идут от ее свойств, к примеру. Минимальной версии браузера или операционной системы смартфона. Это и есть требованик, техническое. Потому что с изменением версии чего то там отпало в API, и так далее. А за такое, повторюсь, аналитик должен немедлено получить пистон и вымарать этот абзац навсегда.
Но я теперь понимаю, откуда проблема. Там и другие схожие примеры. Вместо наполнения ТЗ требованиями, льем воду и провоцируем дискуссии на тему, как лучше эту воду лить. Аналитик, если уж пишет ТЗ, должен обладать достаточными техничкскими знаниями, либо это рукоблудие.
Мне кажется - это статья, классический пример тяжеловесного аналитика, который скорее утомит всех своим ТЗ, чем его кто-то поймет
Мне кажется, это классический коммент теоретика, который не сталкивался с реальной реализацией сложных проектов, но книжки читал!
Ну в целом это то, что пытаюсь донести... ТЗ с точки зрения заказчика - это одно. С точки зрения разработчика - другое. Задача аналитика - свести все это воедино. Не в один документ, а минимум в два - согласованные требования заказчика и описание из реализации для разработчика.
Не будет аналитика - заказчик с разработчиком будут выносить друг другу мозги, разговаривая каждый на своем языке и все равно останутся разногласия - "я подразумевал что это будет так", "а я это понял этак".
Ну, если писать небольшими сторьками - то проблем нет. Так как они маленькие, и даже если там будут и тех. детали, и бизнес язык - не проблема. Связывание и прочее реализуется в условной Jira линками, иерархией и тэгами.
Получаете сразу все в одном. Постановку, трекинг, картинку большую и маленькую. И нет проблемы большого документа и страданий на тему, как его писать
Если же надо большой документ, то все идет от контракта и условий приемки. Ну реально, если приемка по требованиям - то все будут смотреть туда. Если по ТЗ - то туда. А вот уже потом для команды можно и какие-то детали описать вне конктратного документа
Заказчик с разработчиками вообще не общается по хорошему :)
Ну, если писать небольшими сторьками - то проблем нет.
Это когда заказчик не выкатывает сразу большую логику, раздробить которую при всем желании не получится.
Я понимаю, что у меня "профдеформация" - всю свою жизнь в разработке (а это 30+ лет) я практически не занимался интерфейсами, зато очень много реализацией логики разной степени мудрености, которая работает преимущественно в виде фоновых процессов. И там не получалось сделать маленький кусочек и показать заказчику. Оно или работает целиком, или не работает вообще.
Это когда заказчик не выкатывает сразу большую логику, раздробить которую при всем желании не получится.
Эх, а я вот как раз этим 10+ лет занимаюсь... Картинки (мне) помогают. Собственно и статья то была отчасти про это. Про способы наглядно представить нечто труднодробимое. Ну да ладно, спасибо за комментарии!
Ну так же ж почти никогда не бывает. Примеры реальной монолитной логик и - ну напиши, правда интересно
Тут скорее проблема в том, что сначала "заходит" архитектор со знанием и декомпозирует решение, а потом уже в рамках декомпозиции детализируются требования
Ну например, из последнего моего. Чисто фоновый процесс, data pipeline. Тут из названия очевидно, что разбивается на изи.
Из старого - биллинг оператора связи. Процесс идет дни, но декомпозиция очевидна на много кусочков
Платежный роутер - тоже режется без проблем.
Ну правда, напиши свой кейс, или пару
Ну вот из того, с чем до сих пор работаю. "Списки комплаенс".
Росфин присылает списки всяких злодеев-бармалеев. Из 5 штук разных:
ППТ - список подозреваемых в пособничестве терроризму
ПЭ - список подозреваемых в экстремизме
ПРОМУ - список подозреваемых в распространении оружия массового уничтожения
РС - список решений суда
СБ ООН - список совета безопасности ООН
Они все в разных форматах (похожие, но есть отличия). Например, в каких-то списках, если субъект исключается, то явно приходит уведомление что он теперь не списке. А в каких-то он просто не приходит (т.е. если в очередной версии списка его нет, нужно исключить его из БД).
Плюс нужно предусмотреть возможность "отката последнего списка" на случай "ой, вчера вам прислали неправильный список, вот правильный" - нужно откатить все изменения по последнему списку и вкатить новый.
Все это должно быть разложено по нашей БД так, чтобы потом со всем этим можно было работать. А поскольку это нехорошие люди, то там может быть
она же Анна Ефидоренко, она же Элла Кацнельбоген, она же Людмила Огуренкова, она же Изольда Меньшова, она же Валентина Панеяд (с)
Т.е. у субъекта может быть несколько имен, ДУЛов (документ, удостоверяющий личность), адресов и т.п.
Субъекты могут быть ФЛ (ФИО, ДР - день рождения, ДУЛ, ИНН) или ЮЛ (наименование, ИНН).
Все это раскладывается по нескольким таблицам - данные ФЛ (ИНН, ДР...), данные ЮЛ (ИНН), ФИО ФЛ, наименования ЮД, ДУЛы ФЛ, адреса (их несколько типов - рождения, национальность, проживания и т.п.). Плюс таблица заголовков списков (версия, дата, загружен полностью, откатывался, маркер списка...) Плюс таблица субъектов (типа "оглавления" - идентификатор, тип списка, тип субъекта, активен/не активен), плюс лог изменений по субъектам, плюс еще несколько вспомогательных, плюс на каждую основную таблицу еще "архивная" куда переносится предыдущая версия записи для возможного отката. Плюс есть "основная запись" и есть "остальные". В некоторых списках они разделены явно, в некоторых приходится первую считать основной, следующие "остальными"
При раскладке необходимо распарсить данные (XML, форматы все разные, для каждого списка свой), разложить по таблицам (с учетом того что там уже есть т.е. смотри что есть, смотрим что пришло, сравниваем, вносим изменения - что-то добавляем, что-то "деактивируем", что-то корректируем). Выглядит все это так - сначала парсим и приводим к единообразному виду (с учетом "основных" и "остальных" записей), потом все это раскладываем по таблицам.
Это первая часть задачи. ТЗ с описанием всех форматов и правил раскладки где-то страниц на 150. Кода (не считая описания таблиц в DDS) - под мегабайт. Поставка содержит порядка 180 объектов (программные модули, таблицы, индексы). И эта часть не дробится никак.
Вторая часть - сверка. Надо сверить всех клиентов (~50млн) со всеми субъектами списков (~300тыс), выявить совпадения (для ФЛ это ФИО+ДР или ИНН или адрес, для ЮЛ - ИНН или наименование, или адрес). Еще надо сверить "субъектов клиентов" (доверенные, уполномоченные лица, представители не являющиеся сами по себе клиентами банка) - у некоторых клиентов таких до десятка может быть. Это дробится легче - сверка по клиентам отдельно, сверка по субъектам клиентов отдельно, сверка по адресам клиентов отдельно, сверка по адресам субъектов отдельно. Плюс каждая сверка еще делится пополам - одна часть запускается каждый день и идет "от клиента к субъекту" с выборкой только тех клиентов, у которых были изменения в данных за прошлый день, вторая часть - "от субъекта к клиенту" - она запускается после загрузки очередной версии списка с выборкой тех субъектов, у которых были изменения. Т.е. один раз прогоняем всех со всеми, дальше работаем по дельте. Тут еще отпочковывается задача по витрине ключевых слов для поиска по ФИО, наименованиям и адресам - чтобы не сравнивать длинные строки, для каждой выбираем "ключевое слово" из строки (с учетом частотного словаря) чтобы по нему можно было делать высокоселективную предвыборку для детального сравнения. Отдельная задача - заполнение витрины (порядка 400млн записей). Дальнейшее ведение витрины уже включается в раскладку при обработке списка.
Результат сверки заносятся в т.н. "стоплисты" - таблицы связей клиент-субъект списка с указанием по каким параметром найдено совпадение. Тут алгоритм примерно такой - взяли клиента (или субъекта), провели поиск совпадений, составили список "новых свопадений" (может быть пустой), прошли по стоплисту, собрали список "старых совпадений" (тоже может быть пустой), сравнили эти два списка, внесли изменения в стоплист (что-то было, но сейчас нет, чего-то не было, сейчас появилось, чтобы было, есть, но поменялось, что-то осталось без изменений). Стоплисты потом будут использоваться, например, в контроле платежей в системе расчетов (но это уже другая команда).
Третья часть - комплекс комплаенс проверок. Это поиск совпадений с БД по клиентским данным. Пришел человек - вот его ФИО, ДР, ДУЛ, ИНН... Оператор в ККО заводит клиента, данные автоматом улетают в модуль комплаенс проверок и оттуда приходит "оп-па, он по ФИО+ДР бьется в известным международным террористом...".
Или кто-то отправляет платёж куда-то - получатель пробивается по БД и приходит отказ - этому нельзя переводить деньги, будет спонсирование терроризма, за такое регулятор может навалять по самое немогу.
По этим проверкам алгоритм поиска совпадений немного иной чем при составлении стоплистов - там есть "частичные" и "полные" совпадения. Плюс проверка имен/наименований идет с учетом "словоформ" (падежи, транслитерация...).
Ну и вишенка на торте (четвертая часть) - анкета 499П (уж не помню куда она идет, но это из разряда обязательной отчетности). Там есть блок "история совпадений клиента со списками комплаенс" - вся история когда и по каким параметрам он попадал в стоплисты и по какому списку.
Такая вот история... Первая и вторая части достаточно объемные Вторая и третья - очень критичные по производительности (там приходится мозг наизнанку выворачивать с алгоритмами чтобы все это работало предельно быстро - тупые решения "в лоб" не проходят - без всех наших наворотов сверка может растянуться на 12-15 часов что недопустимо).
По комплаенс-проверкам (старая версия, еще до нас была) как-то вот такое пришло от сопровождения
Коллеги, сервис *** за последние 5 недель увеличил потребление процессорных ресурсов в 3 раза!!!
Он уже является 2-м по величине сервисом после *****.
В качестве альтернативы мы рассматриваем перенос запуска сервиса на резервный сервер, но там есть лаг по отставанию до 10 мин.
Заказчикам сервиса это может не понравиться :(
Неделю голову ломал как это дело оптимизировать. Но победил в конечном итоге (со второго раза).
Спасибо!
Уже утром видим очень хороший результат!!!
Доработка сокращает потребление процессорных ресурсов почти в 10 раз!
Но там реально мозголомные алгоритмы получились. С учетом всех особенностей использования этого сервиса (кеширование всего чего только можно закешировать, полное избавление от любого оверкода и т.п.)
Новую версию уже по образу и подобию делал.
ТЗ с описанием всех форматов и правил раскладки где-то страниц на 150.
И это на пять списков? Ничего себе...
PostgreSQL используете?
PostgreSQL используете?
DB2 for i. Причем, все изменения в БД у нас делаются не скулем, а специальными модулями (на каждую таблицу три модуля - внешний ввод, валидация данных, запись в таблицу) с журналированием (на каждую таблицу ведется журнал где все изменения - скажем, меняем запись - пишется два образа - до изменения и после изменения.
А здесь еще архивные таблицы и эти модули обслуживают и их тоже - если идет изменение записи и при этом поменялся маркер списка, то старая запись из основной таблицы переносится в архивную (журналы тут не проходят т.к. они не для долгосрочного хранения), а модуль это поддерживает дополнительную операцию "восстановление из архива" на случай отката списка.
И это на пять списков? Ничего себе...
Там не так все просто. В одних списках "деактивация" субъекта приходит в явном виде - признак что субъект не активен. Тогда его сразу деактивируем в процессе обработки.
В других - приходится сначала прогрузить весь список, потом посмотреть какие из субъектов были в БД, но не пришли в этой версии списка и деактивировать их отдельно (т.е. отдельная операция после загрузки списка).
В каких-то списках теги русские, в каких-то латинские. В каких-то все более-менее стройно, в каких-то полный разброд и шатание (та же ДР может приходить как тегом DATE_OF_BIRTH внутри тега INDIVIDUAL_ALIAS, так и тегом DATE внутри тега INDIVIDUAL_DATE_OF_BIRTH, а имя как клеиться из тегов FIRST_NAME ... FOURTH_NAME, так и браться из тега ALIAS_NAME внутри тега INDIVIDUAL_ALIAS).
Набор данных по разным спискам тоже может отличаться - в каких-то есть всякие данные типа "номер решения", "дата включения", в других нет...
Короче, там фактически на каждый тип списка свой парсер и при раскладке потом тоже куча условных веток по разным типам списков.
И это не считая всяких нормализаций (имена, адреса, ДУЛы), если тип ДУЛ - паспорт РФ (а это тоже нужно определить по ряду признаков - не везде это явно указывается), то еще парсинг паспорта - серия, номер, кем выдан и т.п.
Плюс "коды маркировки" обозначающие всякие "ненормальности":
Дата рождения/регистрации не заполнена
ИНН ФЛ не 12 символов
СНИЛС ФЛ не 12 символов
ИНН ЮЛ не 5 и не 10 символов
ОГРН ЮЛ не 13 символов
ФИО содержит больше 3х слов
Присутствуют подозрительные символы
Не определен тип ДУЛ
Не заполнены серия и номер
ДУЛ занесен не полностью
Адрес занесен не полностью
ФИО внесено не полностью
Наименование внесено не полностью
ФИО содержит меньше 3х слов
Есть история изменений по субъектам - субъект добавлен, у субъекта изменился список адресов, список наименования, список ДУЛов и т.п.
Плюс данные по субъекту могут быть изменены руками (потом уже что-то подправлено) - такие записи тоже отдельно обрабатываются. Например, пришло три имени в списке. Положили в БД. Потом одно из них поправили. В следующий раз опять пришло три имени - два совпадают, их не трогаем. А вот третье не совпадает. По идее, должны удалить старое и добавить новое. Но на старом стоит флаг ручного изменения - значит его нельзя удалять...
Короче, там не просто их XML БД раскидать. Там логики накручено по самые помидоры. В целом - собрать список новых записей, собрать список старых записей, сравнить их и понять что со всем этим теперь делать.
Короче, это долго описывать все... Наворочено там преизрядно.
Мда, это адский ад. Странно, что, вроде бы, "официальные источники" не нормируют свои списки.
Похожую задачу я делал с использованием MongoDB, не настолько мудрено, чтобы там сохранять логи и историю (нет нужды просто). А для внесения и считывания данных у меня реализованы парсеры, которые на основе регулярных выражений определяют заполненность полей и всякие там ненормальности.
В некоторых случаях, это эффективнее работает, чем нормирование исходных данных перед загрузкой.
Ну такие себе "источники" - росфинмониторинг...
Тут все надо - и история и возможность отката... Парсеры на регулярках будут работать безумно (по нашим понятиям) долго. Да и регулярки там забодаешься писать.
Как примеры:
ППТ
<PPT_CATALOG>
<FileDate>16.10.2017</FileDate>
<LastMessage>0</LastMessage>
<СписокРешений xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<ВерсияФормата>1.0</ВерсияФормата>
<ДатаСписка>2017-10-16</ДатаСписка>
<СписокАктуальныхРешений>
<Решение>
<ТипРешения>
<Идентификатор>3</Идентификатор>
<Наименование>Решение МВК</Наименование>
</ТипРешения>
<НомерРешения>7-дсп</НомерРешения>
<ДатаРешения>2017-03-14</ДатаРешения>
<Орган>Межведомственная комиссия по противодействию финансированию терроризма</Орган>
<ВидРешения>
<Идентификатор>1</Идентификатор>
<Наименование>Решение на приостановление (заморозка)</Наименование>
</ВидРешения>
<СписокСубъектов>
<Субъект>
<ИдСубъекта>8349984888</ИдСубъекта>
<ТипСубъекта>
<Идентификатор>2</Идентификатор>
<Наименование>Физическое лицо</Наименование>
</ТипСубъекта>
<ФЛ>
<ФИО>МОЛЧАНОВ МУРАД АНДРЕЕВИЧ</ФИО>
<Фамилия>МОЛЧАНОВ</Фамилия>
<Имя>МУРАД</Имя>
<Отчество>АНДРЕЕВИЧ</Отчество>
<ФИОЛат>MOLCHANOV MURAD ANDREEVICH</ФИОЛат>
<ДатаРождения>1993-08-15</ДатаРождения>
<ГодРождения>1993</ГодРождения>
<МестоРождения>Г. АДЫГЕЙСК ТЕУЧЕЖСКОГО РАЙОНА РЕСПУБЛИКИ АДЫГЕЯ</МестоРождения>
<ИНН>010701070387</ИНН>
<СписокДокументов>
<Документ>
<ТипДокумента>
<Идентификатор>1631726</Идентификатор>
<Наименование>ПАСПОРТ РФ</Наименование>
</ТипДокумента>
<Серия>7907</Серия>
<Номер>503236</Номер>
<ОрганВыдачи>ВЫДАН ТП ОФМС ПО РЕСПУБЛИКЕ АДЫГЕЯ В ТЕУЧЕЖСКОМ РАЙОНЕ РЕСПУБЛИКИ АДЫГЕЯ</ОрганВыдачи>
<ДатаВыдачи>2007-09-11</ДатаВыдачи>
</Документ>
</СписокДокументов>
</ФЛ>
<СписокАдресов>
<Адрес>
<ТипАдреса>
<Идентификатор>6</Идентификатор>
<Наименование>Гражданство</Наименование>
</ТипАдреса>
<ТекстАдреса>РОССИЙСКАЯ ФЕДЕРАЦИЯ</ТекстАдреса>
</Адрес>
<Адрес>
<ТипАдреса>
<Идентификатор>2</Идентификатор>
<Наименование>Адрес места регистрации</Наименование>
</ТипАдреса>
<ТекстАдреса>РЕСП АДЫГЕЯ, Г АДЫГЕЙСК, УЛ ЛЕНИНА, Д 24, КВ 14</ТекстАдреса>
<Страна>
<Наименование>РОССИЙСКАЯ ФЕДЕРАЦИЯ</Наименование>
<Код>643</Код>
</Страна>
<ОКАТО>79403000000</ОКАТО>
</Адрес>
<Адрес>
<ТипАдреса>
<Идентификатор>5</Идентификатор>
<Наименование>Адрес местонахождения</Наименование>
</ТипАдреса>
<ТекстАдреса>РЕСП АДЫГЕЯ, Г АДЫГЕЙСК, УЛ ЛЕНИНА, Д 24, КВ 14</ТекстАдреса>
<Страна>
<Наименование>РОССИЙСКАЯ ФЕДЕРАЦИЯ</Наименование>
<Код>643</Код>
</Страна>
<ОКАТО>79403000000</ОКАТО>
</Адрес>
</СписокАдресов>
<РешениеПоСубъекту>Осуществить замораживание (блокирование) денежных средств и иного имущества, принадлежащих указанному лицу, гуманитарное пособие не назначать.</РешениеПоСубъекту>
</Субъект>
</СписокСубъектов>
</Решение>
</СписокАктуальныхРешений>
</СписокРешений>
</PPT_CATALOG>
Этот самый внятный из всех
ПЭ
<TERRORISTS_CATALOG>
<FileName>01.01.2020</FileName>
<NUM>362ПЭ</NUM>
<DATE>01.01.2020</DATE>
<ID>3758452944></ID>
<LastMessage>0</LastMessage>
<TERRORISTS>
<TERRORISTS_NAME><![CDATA[СУЛТАНОВ ЛЕЧИ РАСУЛОВИЧ* (Mounir el Moutassadeq;Pahlawan Shamsuddin)]]></TERRORISTS_NAME>
<ID_NEW>5639</ID_NEW>
<PERSON_TYPE>4</PERSON_TYPE>
<IS_TERRORIST>1</IS_TERRORIST>
<INN></INN>
<BIRTH_DATE><![CDATA[20.08.1981]]></BIRTH_DATE>
<DESCRIPTION><![CDATA[В РОЗЫСКЕ]]></DESCRIPTION>
<ADDRESS><![CDATA[IN PRISON IN GERMANY; IN PRISON IN GERMANY]]></ADDRESS>
<TERRORISTS_RESOLUTION><![CDATA[]]></TERRORISTS_RESOLUTION>
<BIRTH_PLACE><![CDATA[СТ. ОРДЖОНИКИДЗЕВСКАЯ СУНЖЕНСКОГО РАЙОНА ЧИАССР]]></BIRTH_PLACE>
<PASSPORT><![CDATA[ПАСПОРТ РФ: 8303 596899 ВЫДАН БАКСАН РОВД 27.01.2004,ПАСПОРТ РФ: 8309 964133 03.08.2009,ПАСПОРТ РФ: 8314 255832 ВЫДАН ОТДЕЛОМ УФМС РОССИИ ПО КАБАРДИНО-БАЛКАРСКОЙ РЕСПУБЛИКЕ В БАКСАНСКОМ РАЙОНЕ 06.03.2015,]]></PASSPORT>
</TERRORISTS>
</TERRORISTS_CATALOG>
Тут нет отдельно серии-номера паспорта - парсим регуляркой.
ОМУ
<OMU_CATALOG>
<FileDate>07.11.2018</FileDate>
<LastMessage>0</LastMessage>
<СписокОМУ xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<ВерсияФормата>1.0</ВерсияФормата>
<ДатаСписка>2018-11-07</ДатаСписка>
<ДатаПредыдущегоСписка>2018-09-07</ДатаПредыдущегоСписка>
<АктуальныйСписок>
<Субъект>
<ИдСубъекта>3569309339</ИдСубъекта>
<УНС>IRi.003</УНС>
<ТипСубъекта>
<Идентификатор>2</Идентификатор>
<Наименование>Физическое лицо</Наименование>
</ТипСубъекта>
<История>
<ДатаВключения>2012-04-18</ДатаВключения>
</История>
<ФЛ>
<ФИО>AGHAJANI AZIM</ФИО>
<Фамилия>AGHAJANI AZIM</Фамилия>
<ФИОЛат>AGHAJANI AZIM</ФИОЛат>
<СписокДокументов>
<Документ>
<ТипДокумента>
<Идентификатор>746140005</Идентификатор>
<Наименование>PASSPORT</Наименование>
</ТипДокумента>
<Номер>6620505</Номер>
<ОрганВыдачи>Iran (Islamic Republic of)</ОрганВыдачи>
</Документ>
<Документ>
<ТипДокумента>
<Идентификатор>746140005</Идентификатор>
<Наименование>PASSPORT</Наименование>
</ТипДокумента>
<Номер>9003213</Номер>
<ОрганВыдачи>Iran (Islamic Republic of)</ОрганВыдачи>
</Документ>
</СписокДокументов>
<СписокДрНаименований>
<ДрНаименование>
<ФИО>Azim Adhajani; Azim Agha-Jani</ФИО>
</ДрНаименование>
</СписокДрНаименований>
<СписокГражданств>
<Гражданство>Iran (Islamic Republic of)</Гражданство>
</СписокГражданств>
</ФЛ>
<Примечание>Facilitated a breach of paragraph 5 of resolution 1747 (2007) prohibiting the export of arms and related materiel from Iran. [Old Reference #I.AC.50.18.04.12.(1)]</Примечание>
</Субъект>
</АктуальныйСписок>
</СписокОМУ>
</OMU_CATALOG>
Тут несколько имен в одном теге -
<СписокДрНаименований>
<ДрНаименование>
<ФИО>Azim Adhajani; Azim Agha-Jani</ФИО>
</ДрНаименование>
</СписокДрНаименований>
Их приходится раскручивать в список из строки. Ладно у нас язык позволяет:
for-each name in %split(string: ';');
ООН
<UNL_CATALOG>
<FileDate>2023-05-28</FileDate>
<LastMessage>0</LastMessage>
<INDIVIDUAL>
<DATAID>2762998</DATAID>
<VERSIONNUM>1</VERSIONNUM>
<FIRST_NAME>NAJMUDDIN</FIRST_NAME>
<SECOND_NAME>FARAJ</SECOND_NAME>
<THIRD_NAME>AHMAD</THIRD_NAME>
<UN_LIST_TYPE>Al-Qaida</UN_LIST_TYPE>
<REFERENCE_NUMBER>QDi.226</REFERENCE_NUMBER>
<LISTED_ON>2006-12-07</LISTED_ON>
<COMMENTS1>Mother`s name: Masouma Abd al-Rahman. Photo available for inclusion in the
INTERPOL-UN Security Council Special Notice. Review pursuant to Security Council resolution
1822 (2008) was concluded on 20 May 2010.Review pursuant to Security Council resolution 2368
(2017) was concluded on 24 November 2020. INTERPOL-UN Security Council Special Notice web
link: https://www.interpol.int/en/How-we-work/Notices/View-UN-Notices-Individuals</COMMENTS1>
<NATIONALITY>
<VALUE>Iraq</VALUE>
</NATIONALITY>
<LIST_TYPE>
<VALUE>UN List</VALUE>
</LIST_TYPE>
<LAST_DAY_UPDATED>
<VALUE>2015-12-10</VALUE>
<VALUE>2020-11-24</VALUE>
</LAST_DAY_UPDATED>
<INDIVIDUAL_ALIAS>
<QUALITY>Good</QUALITY>
<ALIAS_NAME>Mullah Krekar</ALIAS_NAME>
</INDIVIDUAL_ALIAS>
<INDIVIDUAL_ALIAS>
<QUALITY>Good</QUALITY>
<ALIAS_NAME>Fateh Najm Eddine Farraj</ALIAS_NAME>
</INDIVIDUAL_ALIAS>
<INDIVIDUAL_ALIAS>
<QUALITY>Good</QUALITY>
<ALIAS_NAME>Faraj Ahmad Najmuddin</ALIAS_NAME>
</INDIVIDUAL_ALIAS>
<INDIVIDUAL_ALIAS>
<QUALITY />
<ALIAS_NAME />
</INDIVIDUAL_ALIAS>
<INDIVIDUAL_ALIAS>
<QUALITY />
<ALIAS_NAME>НАДЖМУДДИН ФАРАДЖ АХМАД</ALIAS_NAME>
</INDIVIDUAL_ALIAS>
<INDIVIDUAL_ADDRESS>
<STREET>Heimdalsgate 36-V</STREET>
<CITY>Oslo</CITY>
<ZIP_CODE>0578</ZIP_CODE>
<COUNTRY>Norway</COUNTRY>
</INDIVIDUAL_ADDRESS>
<INDIVIDUAL_DATE_OF_BIRTH>
<TYPE_OF_DATE>EXACT</TYPE_OF_DATE>
<DATE>1956-07-07</DATE>
</INDIVIDUAL_DATE_OF_BIRTH>
<INDIVIDUAL_DATE_OF_BIRTH>
<TYPE_OF_DATE>EXACT</TYPE_OF_DATE>
<DATE>1963-06-17</DATE>
</INDIVIDUAL_DATE_OF_BIRTH>
<INDIVIDUAL_PLACE_OF_BIRTH>
<CITY>Olaqloo Sharbajer</CITY>
<STATE_PROVINCE>Al-Sulaymaniyah Governorate</STATE_PROVINCE>
<COUNTRY>Iraq</COUNTRY>
</INDIVIDUAL_PLACE_OF_BIRTH>
<INDIVIDUAL_DOCUMENT>
<TYPE_OF_DOCUMENT>National Identification Number</TYPE_OF_DOCUMENT>
<TYPE_OF_DOCUMENT2>Ration card no.</TYPE_OF_DOCUMENT2>
<NUMBER>0075258</NUMBER>
</INDIVIDUAL_DOCUMENT>
<SORT_KEY />
<SORT_KEY_LAST_MOD />
</INDIVIDUAL>
</UNL_CATALOG>
Тут просто жесть - все вперемешку, приходится в два этапа разбирать - сначала все по спискам (имена, ДР, ДУЛы...), потом уже формировать "основная запись" + список "других записей" чтобы не писать для него отдельный раскладчик по БД.
Для решений суда под рукой нет, но там тоже что-то свое...
Для парсинга есть xml-sax - очень быстрый (быстрее чем DOM т.к. потоковый), хотя и работать с ним муторно.
Жесть, согласен. :)
Парсеры на регулярках будут работать безумно (по нашим понятиям) долго.
Это если все целиком засасывать. А если сначала добраться до полей простым парсингом хорошо структурированного XML, а потом, на основе предварительно собранной (у вас же богатая ретроспектива?) статистики значений именно этого поля, причем, возможно даже в разных списках/источниках продумать регулярки и нормализаторы (ну, банально, мусор, пробелы убрать, регистр подправить,...), то выцеплять данные быстро должно. А если еще словари какие-то прицепить, ну, типа эээ... "радужных таблиц" для быстрого сопоставления данных чему-то уже ранее нормализованному, то должно быстро работать.
Впрочем, тут надо полностью контекст решения задачи и состав данных знать, может в вашей задаче это вообще не подходит.
У меня на сотнях неструктурированных таблиц до полумиллиарда записей - нормально работает. :)))
Это если все целиком засасывать. А если сначала добраться до полей простым парсингом хорошо структурированного XML
Я описал ниже как работает XML-SAX у нас.
Подробнее можно тут:
RPGLE XML Parser - XML-SAX and XML-INTO sample code Part 1
RPGLE XML Parser - XML-SAX and XML-INTO sample code Part 2
XML-INTO штука мощная, но там куча ограничений. Хотя на простых по структуре XML работает. На сложных мне не удалось ее завести.
А SAX универсален, хотя и требует больше кода. Но, как написал уже - там все равно какой именно список пришел. Хендлер может быть один на все :-)
статистики значений именно этого поля, причем, возможно даже в разных списках/источниках продумать регулярки и нормализаторы (ну, банально, мусор, пробелы убрать, регистр подправить,...)
Там непонятно куда и зачем все это... Есть нормализаторы - для строки, для ДУЛ, для ИНН.
Нормализатор строки, например, удаляет лишние пробелы, приводит все к верхнему регистру, заменяет Ё на Е (бизнес так захотел - их право), удаляет "плохие" символы (по списку из настроек). Все это работает быстро, за один проход строки.
Для каждой отдельной опрерации, конечно, есть в языке спецсредства. Например, удаление лишних пробелов:
str = %concatarr(%split(str));
Для замены Ё на Е
str = %xlat('Ёё': 'Ее': str);
для регистра - %upper / %lower
для удаления символов - %scanrpl,
но елозить несколько раз по одной строке когда все можно сделать за один проход как-то неправославно :-)
В общем, эта задача решена уже (почти, сейчас осталось доделать сверку по адресам и по субъектам клиентов) И как-бы там нет загадок. Все работает, быстро, по нагрузке у сопровождения претензий нет.
Большие объемы данных (та же сверка) у нас распараллеливается на несколько заданий.
У нас удобнее работать именно с заданиями - job, а не с потоками внутри одного задания - это и сопровождению проще и безопаснее т.к. задания изолированы друг от друга и в случае падения одного (ошибка) остальные не затрагиваются совсем. Да и мониторить состояние задания проще чем поток - на то есть системные апишки для контроля за статусом (активно, завершило работу, выпало в ошибку и т.п.).
Есть головное задание - оно запускает нужное количество заданий-обработчиков, затем делает выборку данных для обработки и выкладывает их пачками на "конвейер". Обработчики подхватывают пачки с конвейера и обрабатывают их (каждый свою пачку). В качестве конвейера можно использовать, например, очередь (есть на нашей платформе такие системные объекты - Data Queue, User Queue) - как раз под это дело. Головное задание кладет в очередь данные, обработчики разбирают их оттуда.
Весьма грамотный подход, надо бы мне тоже в своей системе попробовать распараллеливание.
У нас применяется достаточно широко т.к. операций, где требуется обработка больших объемов данных и при этом каждый элемент этих данных обрабатывается независимо от остальных у нас достаточно много.
Как пример. Ежегодная актуализация клиентов. Запускается автоматически раз в год где-то в середине декабря. Под актуализацию попадают клиенты для которых выполняется ряд условий как то:
с момента последней актуализации прошло больше года т.е. он не актуализировался вручную в этом году;
это клиент ФЛ или ИП;
есть еще ряд условий (на самом деле там 5 SQL выборок последовательно, можно в одну запихать, но получится слишком сложно и оно будет работать дольше чем 5 более простых а результат тот же)
Для каждого отобранного клиента выполняется ряд проверок - корректность заполнения адреса, срок действия ДУЛ и т.п. Если все прошло, в специальной таблице обновляется дата последней актуализации - все ок. Если что-то не ок, пишется в отчет "у такого-то клиента не прошла проверка по такому-то параметру" - это уже на ручной разбор потом уходит.
Есть два модуля:
головная часть (master)
обработчик (worker)
Для запуска процесса достаточно запустить мастера. Дальше он уже все делет сам
создает конвейер
запускает нужное количество обработчиков, каждый из которых в отдельном задании (у нас это или системная команда SBMJOB - SuBMit JOB - запуск программы в отдельном фоновом задании, или при помощи С-шной функции spawn - ровно то же самое).
когда все обработчики запустились, мастер начинает процесс отбора. Чтобы не перегружать конвейер, туда выкладываются не все данные (это очень объемно), а только референсы - ПИНы клиентов, подлежащих обработке. У нас ПИН 9 символов. ПИНы объединяются в пакеты, например по 100 штук и пакет уже выкладывается на конвейер.
в процессе работы мастер мониторит состояние заданий обработчиков - чтобы все активны были, не выпали в ошибку и т.п. Что делать с ошибками - тут уже логика задачи. Можно принудительно прибивать задание и вместо него запускать новое, можно еще как-то.
также желательно отслеживать состояние конвейера - с одной стороны не валить туда "стремительным домкратом" чтобы он не переполнялся, с другой - поддерживать там некоторое постоянное количество данных чтобы обработчики не "голодали".
по окончании выборок мастер выкладывает на конвейер "терминаторы" - специальные пакеты что данных больше нет (количество терминаторов равно количество обработчиков).
дальше просто стоим и ждем пока все обработчики завершат работу и фоновые задания закроются (если что - можем и прибить принудительно, суть в том, что раз мы их фоном запустили, мы же и отвечаем за то, чтобы они в конце концов завершились)
У обработчика все просто - взяли пакет с конвейера, если не терминатор - обрабатываем ПИНы из пакета.
Если терминатор - завершаем работу.
Единственная нештатная ситуация - конвейер пустой, но терминаторов не было. Есть подозрение что что-то с мастером. Тут просто подождать и завершить работу.
Конвейер отдельная тема. Можно (универсально) использовать пайпы. Но там скорее всего потребуется два (как минимум) пайпа - один для данных, второй для служебных сообщений (можно без него, но будут некоторые неудобства).
Основной минус пайпа - он не контролируем. Вы не можете сказать сколько там сейчас сообщений. Придется как-то это отслеживать отдельно (чтобы пайп с одной стороны не переполнился, с другой не опустел).
Кроме того, пайпы суть потоковый транспорт - вам придется заранее устанавливать жесткий размер пакета (блока) чтобы все писали и читали блоками именно такого размера (чтобы не перепутать блоки)
К счастью, на нашей платформе есть более удобные инструменты - очереди. Есть Data Queue и аналогичная ей (но более быстрая и легкая) User Queue.
У очередей есть ряд преимуществ:
очередь суть датаграммный транспорт. Т.е. данные там лежат в виде сообщений. будь оно 10 байт или 100 байт - это одно сообщение и прочитано за один раз оно будет целиком, но только оно одно.
очередь может быть FIFO, LIFO или KEYED. Последнее наиболее интересное - каждое сообщение может быть снабжено ключом и читать можно как "первое в очереди", так и "первое с заданным значением ключа". Это позволяет в одной очереди размещать как данные (например, с ключом DTA), так и команды (например, с ключом CMD, возможно еще и с идентификатором конкретного задания для которого эта команда предназначена).
очередь может быть "материализована" - можно в любой момент получить информацию о ее емкости (максимальное количество сообщений в ней) и текущем количество сообщений в очереди. Это позволяет регулировать скорость раздачи данных со стороны мастера (если сообщений слишком много - притормозим раздачу пока не рассосется). Более, того, это позволяет производить "динамическую балансировку" - мастер оценивает состояние очереди и если видит, что обработка пакетом медленнее чем раздача, может запустить еще один обработчик. Если быстрее - послать одному из обработчиков команду на завершение, уменьшив тем самым количество обработчиков.
Также это упрощает процесс завершения обработки - мастер выложил терминаторы и уходит в цикл мониторинга очереди - пока количество сообщений стабильно уменьшается - все ок - обработчики работают. Как очередь опустела - все обработчики получили команды на завершение - переходим в цикл ожидания завершения заданий.
Естественно, что все проблемы совместного доступа к конвейеру регулируются системой. Разработчику про это думать не надо.
Естественно, что чтение с конвейера является удаляющим - прочитанное одним обработчиком сообщение сразу же удаляется с конвейера автоматически.
По большому счету, скорость конвейера в такой задаче не является определяющей - основное время это обработка данных.
У нас разработаны некоторые "фреймворки" для подобных вещей где реализована вся работа с конвейером. Разработчику нужно написать только свою логику - отбор для мастера и обработку для обработчиков. Т.е. такие задачи для нас являются типовыми и используются достаточно широко.
Ну смотри, Дробим на лету
Часть первая:
У тебя есть 5 источников данных, значит уже 5 ОТДЕЛЬНЫХ лоадеров, каждый из которых парсит свой входной формат и заливает в общий staging area c единой структурой. 5 компонент уже есть :) Пилить можно абсолютно независимо, как только определена структура stage area.
Слой историчных данных, переливает из stage к себе, решая вопросы откатов, перезаливок и т.д.
Слой "сведения" в единую модель с бизнес правилами определяющими как быть с данными одного субъекта из разных источников. Переливает из "историчекого" слоя в свой
По итогу имеет готовую "каноническую" модель з "вычищенными" данными для использования в логике транзакций. Я насчитали минимум 8 компонент, которые минимально зависят другоот друга и могут пилиться независимо, или почти независимо. Более того, при адекватной архитектуре и выбранном стеке все это будет легковестное, масштабируемое и вообще - приятное глазу :)
Вторая часть: по сути надстройка над "канонической" моделью. Ты ее и сам порезал. Представь себе задачу в виде набора зависимых или независимых data area c перекладкой/трансформацией и т.д. Понятно, что физически это может быть как физические таблицы, так и view/materialized view. Но тут надо детали смотреть
Третья часть: независимые микросервисы проверок, которые при необходимости можно оркестровать в некотором Decision making module, c настраиваемой логикой. Тут может даже low-code зайти, таких решений валом, в отм числе open source
Итого, ну честно. Ничего монолитного в фин. моне нет :) С одной стороны - заливка данных их источников, которая разбивается просто в силу слоей приороды на этапы. Главное не стесняться это делать, так как место на дисках - самый дешевый ресурс как капекс, так и опекс.
Сервисы же проверки легко встраиваются в поток транзакций, так как там идеологически сразу закладывается такая опция, если проектировщик знаком с доменом
--------------
Просто ключ в том, что сначала пишется модель данных послойно, а потом переходы между слоями можно раскидывать между командами/технологиями
Не так просто.
У тебя есть 5 источников данных, значит уже 5 ОТДЕЛЬНЫХ лоадеров
Источник данных один - очередь. И лоадер (который получает данные из очереди) тоже один.
Дальше 5 парсеров. А дальше один раскладчик по БД. Потому алгоритм раскладки одинаковый для всех типов списков и хранится все это в одной БД единообразно.
Т.е. задача парсеров - привести все к одному знаменателю - некоемоу единому набору структур, которые потом будут раскиданы по БД.
Слой историчных данных, переливает из stage к себе
И получаем отлуп с нагрузочного тестирования - слишком много ресурсов потребляет. Почти наверняка.
независимые микросервисы проверок, которые при необходимости можно оркестровать в некотором Decision making module, c настраиваемой логикой.
Угу. Именно от этого ушли и получили 10-кратный прирост производительности при сокращении ресурсопотребления
Надеюсь, есть понимание того, что все это работает не на отдельно выделенной машине, а в некоем временном окне и в условиях жесткого ограничения ресурсов, в первую очередь CPU? Потому что это всего лишь одна небольшая задачка из тысяч (если не десятков тысяч) одновременно работающих на сервере. И плотность вызовов тех же проверок крайне высока. И что там выморщить даже +5% к производительности - это уже очень хороший результат. Любой ценой.
Так что все что делается, делается прежде всего из соображений скорости работы и эффективности потребления ресурсов. А не "концептуальности" и "красивости" кода.
Источник данных один — очередь. И лоадер (который получает данные из очереди) тоже один.
Дальше 5 парсеров. А дальше один раскладчик по БД. Потому алгоритм раскладки одинаковый для всех типов списков и хранится все это в одной БД единообразно.
Ну видиш, 6-7 независимых компонент :)
И получаем отлуп с нагрузочного тестирования - слишком много ресурсов потребляет. Почти наверняка.
Не, деление на стейджи обычно не приводит к значительному увеличению, но позволяет сэкономить на времени разработки. Условно, если одна "единица" стоит 5 штук в месяц, но часто это выгоднее. Да и с чего дольше?
Ты просто декомпозировал работу на несколько элементов, повысив в разы прозрачность кода и его сопровождаемость. Это схоже на "микросервисы" vs "монолит", только для data pipeline. Накладные расходы на микросервисный подход обычно компенсируются с лихвой более эффективной разработкой.
Да и оптимизировать по частям проще.
Угу. Именно от этого ушли и получили 10-кратный прирост производительности при сокращении ресурсопотребления
Обычно выигрыш в 10 раз получается по другой причине. Нашли эпичный косяк и пофиксили. У меня на последнем проекте тоже кстати стейджинги сначала работали долго. Правильный подход к data engineer ("молоко" или "мясо"), вкупе с конструктивными идеями дал свои плоды. Кстати выигрыш тоже получился на порядок :)
Надеюсь, есть понимание того, что все это работает не на отдельно выделенной машине, а в некоем временном окне и в условиях жесткого ограничения ресурсов, в первую очередь CPU?
Не, так не работает. Точнее работает, до первого сбоя. Ну подумай сам. Условно есть задача и к ней требования по RTO около 0. Даже без внесения в условия Disaster Recovery - это минимум наличие двух нод, при этом каждая из нод, в случае сбоя доложна тянуть всю нагрузку. Либо ваша задача - сто двадцать пятое колесо в телеге и вам выдали по минимуму, что маловероятно.
Короче не верю :) Тем более, если это на IBM железе, нет никакой проблемы нарезать задачам отдельные пулы :)
В любом случае, оптимизация декомпозированной задачи выполняется быстрее. Тем более .. ну камон. У тебя задача загрузки, которую явно можно гонять в не бизнес время. Новые данные явно не поток от IoT, а скорее всего раз в день или около того. Найти окно вне бизнес времени изи. Остается "вылизать" в идеал только ту часть, где критичнен response time. И тут как раз максимально подготовленное представление данных заходит на ура, вплоть до использования альтернативной технологии.
Опять же, имено микросервисы дают возможность более гранулировано управлять нагрузкой, тем более что вы живете на решении с довольно таки продвинутой виртуализацией.
Но это ваше дело, в конце концов. Нравится героически презнемогать обстоятельства, частично вызванные вашими же решениями - ну ОК.
Ну видиш, 6-7 независимых компонент :)
Давайте еще раз.
Есть очередь - MQ
На ней висит движок HMQ который мониторит очередь и выдергивает оттуда сообщения. Тип сообщения определяется по информации из заголовка. Дальше по типу сообщения в таблице настроек ищется обработчик который запускается с передачей ему тела сообщения.
Теоретически. HMQ может запускать несколько экземпляров одного обработчика в разных заданиях. Например, пришло 10 сообщений одного типа - запустилось 10 задний с одним обработчиком и все 10 сообщений обработались параллельно (если логика такое позволяет). Это все через настройки регулируется.
Мы пишем только сам обработчик и прописываем его в настройках HMQ.
В обработчике в данном конкретном случае две основные части - вытащить из XML нужные данные, сформировать их в виде структуры и разложить по БД. Т.е.
формирование структуры
раскладка ее по БД
Структура одинаковая вне зависимости от типа списка - набор данных там всегда одинаковый (плюс-минус). Т.е. процедура раскладки одна на любой список.
разбор XML делается встроенным средством языка - XML-SAX
// Разбор сообщения
xml-sax(e) %handler(XMLHandler : dsCommArea) %xml(uMsgBody : 'ccsid=ucs2');
где XMLHandler - callback процедура обработки событий XML, dsCommArea - блок данных, передаваемый в эту процедуру (там как раз и лежит заполняемая данными структура).
DCL-PROC XMLHandler export;
DCL-PI *N int(10);
CommArea likeds(t_CommArea);
event int(10) value;
string pointer value;
stringLen int(20) value;
exceptionId int(10) value;
END-PI ;
Разборщик работает по принципу конечного автомата - вызывает XMLHandler с кодом события и строкой контекста этого события. Т.е. это потоковый обработчик, он не строит в памяти никаких деревьев, не требует их обхода... Он тупо идет по XML и дергает обработчик событий, передавая ему контекст. Быстро и с минимальными затратами.
Например, для
<FileDate>2023-05-28</FileDate>
будет три вызова XMLHandler:
event = *XML_START_ELEMENT, strring = 'FileDate'
event = *XML_CHARS, strring = '2023-05-28'
event = *XML_END_ELEMENT, strring = 'FileDate'
Поскольку выходная структура всегда одинаковая (t_CommArea), нет никакой необходимости плодить лишние сущности - достаточно описать один обработчик на все списки.
Действительно, мы знаем что есть пришел тег <UNL_CATALOG> - это список ООН. Если <TERRORISTS_CATALOG> - список ПЭ, <PPT_CATALOG> - ППТ, <OMU_CATALOG> - ОМУ.
Идентификатор субъекта приходит в тегах
<ИдСубъекта> для списков ОМУ и ППТ или
<ID_NEW> для списка ПЭ или
<DATAID> для списка ООН
Аналогично для всех остальных интересующих полей.
Фактически, меня даже не интересует что там "вообще". Интересует только в каких тегах лежит нужная информация - из какого тега в какое поле структуры ее перенести.
Не, деление на стейджи обычно не приводит к значительному увеличению, но позволяет сэкономить на времени разработки. Условно, если одна "единица" стоит 5 штук в месяц, но часто это выгоднее. Да и с чего дольше?
На чем тут экономия времени разработки? В данном случае один обработчик на все - это тупо "меньше букв".
А дольше с того, что каждый новый уровень абстракции - это лишний уровень стека, лишний вызов, лишняя передача параметров. Это кажется что все это мелочи, но когда плотность вызовов зашкаливает, это все превращается во вполне осязаемый цифры.
Вообще, у нас есть замечательный инструмент PEX - Performance EXplorer. Прогоняешь через него задачу, получаешь статистики и все сразу видно - где вызовы лишние, где лишние обращения к БД, какая процедура сколько процессорного времени отъедает и т.п. И все критичные поставки в рамках НТ прогоняются через PEX.
Это все бывает нужно и разумно объяснимо там, где это диктуется логикой работы. Но избегать лишних абстракций - это уже следующий уровень разработчика.
Не, так не работает. Точнее работает, до первого сбоя.
Удивительно, но это работает. Без сбоев.
Тем более, если это на IBM железе, нет никакой проблемы нарезать задачам отдельные пулы
Это напоминает притчу про портного заказчика и шапки:
Можно из этого куска материи шапку сшить?
Можно
А две можно?
Можно и две...
А три?
Да хоть десять...
Давай десять!
И получил заказчик 10 шапок. Только маленьких. Таких, что разве что на палец лезут.
Так и тут - нарезать можно 100500 пулов. Но сервер-то один... И все они будут на одном физическом процессоре работать... И с одной физической памятью.
У тебя задача загрузки, которую явно можно гонять в не бизнес время.
Банк работает 24/7. Какое время там не бизнес? У нас АБС "реального времени" - это значит что даже во время процесса EOD (закрытие опердня и перехода на следующий день), все банковские процессы продолжают работать (платежи обрабатываются и т.п.) в т.н. "юните ночного ввода" (который потом "вкатывается" в новый день). Тут нет такого время, когда машина пустая и ничего не делает. А списки должны загружаться сразу как только пришли т.к. эта информация сразу используется в комплаенс-процессах - лишние лаги тут недопустимы.
Опять же, имено микросервисы дают возможность более гранулировано управлять нагрузкой
Это все хорошо для процессов, которые не являются mission critical. Т.е. "хочу сейчас делаю, не хочу потом как-нибудь". У нас таких процессов не так много (ну по крайней мере на уронвне центральных серверов). Разве что отчетность какая...
И не надо думать, что АБС банка это монолит. Это очень сильно не монолит. Но это и не набор бессмысленных (по отдельности) микросервисов, каждый из которых выполняет маленький, логический не законченный кусочек задачи и в отдельности ничего цельного не делает (зато активно распаковывет и запаковывает джейсоны с тем, чтобы отдать их другому микросервису, который опять распакует и опять запакует).
Наша система ближе к модели акторов - процессов, которые запускаются по времени или событию и каждый из которых выполняет свою, логически завершенную, задачу.
Обычно выигрыш в 10 раз получается по другой причине. Нашли эпичный косяк и пофиксили.
"Эпичный косяк" был как раз в неоправденном дроблении. Некий "художник концептуалист" в свое время разделил проверку на три части - ФИО + ДР, ДУЛ и ИНН. Но беда в том, что в каждой из частей есть некоторая "базовая процедура", которая сама по себе дает только промежуточный результат, для бизнеса абсолютно бессмысленный и бесполезный, но является достаточно тяжелой.
В результате чтобы проверить нового клиента вызывалось три проверки. И каждая каждый раз дергала эту самую тяжелую базовую функцию.
Объединение трех проверок в одну (тем более, что основной сценарий вызова как раз с полным блоком данных - ФИО + ДР + ДУЛ + ИНН) с однократным вызовом тяжелой функции и дал такой вот результат. Плюс сахар в виде кеширования - если вызываем 5 раз с одними значениями ФИО, ДР, ИНН но разными значениями ДУЛ (что тоже входит в список распестренных сценариев), вызов базовой функции и проверок ФИО + ДР и ИНН будет проводиться только в первый раз, все остальные разы будет проводиться только проверка очередного ДУЛ с использование закешированных ранее результатов (в т.ч. и базовой функции).
Все эти, как сейчас говорят, "паттерны", формировались не год и не два, лет десять минимум, на основе огромного количества кода и PEX статистик. И все это оформлено в виде "нефункциональных требований" как к архитектуре, так и к коду. И требования эти модифицируются и дополняются на основе новых статистик и опыта использования и сопровождения.
Лайк!
Можно уточнить, что такое
методологии PMI
в части управления требованиями? Про РМ ВоК я знаю, но там про другое. А требования?
В таких методологиях подробно расписаны подходы к выявлению требований, их сортировке, выделению приоритетов, противоречий, способов согласования, уточнения и так далее.
PMI - Институт управления проектами, у него до чертиков методологий и PMBoK "Книга знаний по управлению проектами" - это только один сборник.
Есть отдельные книжки у них про сбор требований, про управление рисками, про управление ресурсами, про планирование - я их имел в виду.
Если зарегистрироваться на сайте у них, там взнос какой-то был, и иметь действующую сертификацию PMP - то там большая библиотека будет доступна.
Но это все не тема данной статьи...
Техническое задание в картинках?