Как мы разрабатывали кроссплатформенную BPMS
Всем привет!
В НОРБИТ мы занимаемся SRM-решениями. Сегодня расскажем про особенный для нашей команды проект — разработку BPMS-платформы NBT. Мы не просто создали бизнес-решение для заказчика, а разработали собственный продукт с нуля, — всё это подразумевает совершенно другой подход к проектированию, разработке, управлению командой, организации процессов доставки изменений и планирования выпусков.
В общем, в статье не только красивая КДПВ. Ещё вы узнаете:
- про наш опыт проектирования микросервисной архитектуры (выбор инструментов, подходов к использованию этих инструментов, а именно абстрагирование их использования);
- про разработку конструктора бизнес-объектов и внедрение в решение конструктора бизнес-процессов для обеспечения подхода Low-code development;
- про то, как мы организовали работу над проектом и избавили разработчиков от некоторых рутинных или отвлекающих их аспектов при работе над системой (абстрактные межсервисные взаимодействия, автогенерация кода, атмосфера в команде);
- и про то, какой мем помогал нам в сложные периоды.
Источник
Наше подразделение в компании НОРБИТ занимается преимущественно автоматизацией закупочных процессов, для чего создает разного рода решения на платформе .Net.
Разработка таких решений начиналась еще на ASP.NET WebForms, затем новые версии этих решений создавались уже на базе ASP.NET MVC. Помимо разработок на .NET у нас были и есть другие проекты и решения, но все же разработки на .NET составляют около 80% от всех проектов подразделения.
Ограничения как ASP.NET WebForms, так и ASP.NET MVC предполагают, что для функционирования решений на этих платформах обязательно требовалось развертывание на ОС семейства Windows Server, а на стороне БД (базы данных) был реализован объем логики, не позволявший быстро и безболезненно перейти на СУБД, отличные от MS SQL Server. Это не предусматривало каких-то препятствий и сложностей до начала массового перехода на отечественное ПО.
Начиная с 2014–2015 годов, ИТ-рынок очень серьезно стал двигаться в сторону импортозамещения, и перед нами достаточно остро встал вопрос развертывания наших систем на операционных системах и СУБД, которые бы подходили под новые требования. По сути это стало вопросом № 1, который нам потребовалось решить, чтобы наши решения могли закрывать требования потенциальных заказчиков в долгосрочной перспективе.
При этом, имея сильные компетенции и достаточно большую команду .NET-разработчиков, начинать разработку нового кроссплатформенного ядра не на .NET не представлялось рациональным. Выход платформы .NET Core с открытым исходным кодом для нас оказался весьма кстати, в том числе из-за его совместимости с такими операционными системами, как Windows, Linux и macOS.
Вопрос № 2, который нам потребовалось решить, состоял в том, что большинство созданных ранее решений предполагали обязательное программирование для добавления атрибутов бизнес-объектов или изменения бизнес-процессов в системе.
Связан он с двумя аспектами.
- Для кастомизации наших решений в проектах мы обычно разделяли уровень ядра (базового решения) и какие-то особенности, связанные с конкретными внедрениями, запросами от заказчиков, выносили на уровень настроек. Но при этом реализация этих отличий, например, наличие отдельных атрибутов или бизнес-правил в том или ином объекте системы, все равно требовала написания отдельного кода, вынесение в настройки этих атрибутов или бизнес-правил.
- В последние годы все больше и больше набирает популярность подход Low-code development, по сути, встроенных в разного рода решения конструкторов, позволяющих «на лету» создавать и настраивать бизнес-объекты и бизнес-процессы.
И вопрос № 3, с которым мы сталкиваемся на протяжении многих лет, состоит в несовершенстве архитектур создаваемых систем, не позволяющих быстро переписать какую-то часть без необходимости переписывания отдельных модулей, или создающую достаточно высокий порог входа для программистов, аналитиков и тестировщиков при подключении к проектам.
Вопросов и проблем на входе в проект, о котором речь пойдет далее, было гораздо больше. Но эти три (импортозамещение и open-source, Low-code, низкий порог входа и быстрая скорость погружения новых членов команд) мы считаем ключевыми, которые нам предстояло решить.
Проектирование
Обдумывание этих вопросов привело нас к осознанию того, что нам нужен некий конструктор, в который смогут «играть» аналитики и конструировать систему (бизнес-объекты и бизнес-процессы) под потребности заказчика. Звучит дерзко, но ведь это намного интереснее, чем написать очередную систему для заказчика. По сути, мы решили сделать свой продукт в виде конструктора и развивать его.
Мы определенно не придумали ничего революционного, и на рынке есть достаточно много подобных продуктов, но для нас было принципиально важно решить свои накопившиеся вопросы, тем более, что по обозначенным ранее причинам идти по пути рефакторинга существующих систем для нас было, мягко говоря, затруднительно.
На этапе проектирования нам пришлось переосмыслить тот факт, что мы не всегда знаем заранее, кто наш потенциальный заказчик, большой он или маленький, требовательный или лояльный, какие у него бизнес-процессы, какая инфраструктура. Часть требований к будущей системе начали всплывать сами собой: нужно масштабирование, нужна кроссплатформенность, нужна гибкая и быстрая настройка бизнес-объектов/бизнес-процессов, интерфейса, вероятно, «вагон и маленькая тележка» интеграций. Стало страшно, очень страшно.
Наша любимая картинка
Но, как говорит один из наших тимлидов: «Слона нужно есть по кусочкам, начиная с лапки». Мы поставили на этом этапе перед собой две задачи: выбор микросервисной архитектуры и выбор инструментов. Да, именно сразу микросервисной (Мартин Фаулер рекомендует MonolithFirst, но мы его решили ослушаться), потому что с монолитами мы уже давно на «ты» и пришло время принять вызов двигаться дальше. А если серьезно, то одного только требования горизонтального масштабирования системы вполне достаточно, на наш взгляд.
Выбор архитектуры и инструментов
При проектировании архитектуры мы преследовали несколько целей:
- абстрагирование используемых инструментов для того, чтобы была возможность в любой момент заменить неподходящий инструмент на другой;
- абстрагирование межсервисного взаимодействия (сервис должен иметь контракт взаимодействия с ним, и другие сервисы при необходимости руководствуются только этим контрактом);
- низкий порог входа для разработчиков, особенно вновь подключаемых к проекту.
Поскольку наша команда специализируется на технологиях Microsoft, в качестве платформы для реализации был выбран .NET Core версии 2.1. На тот момент, когда начиналась разработка нашего продукта, эта версия была LTS (long term support), и для нас это было важным критерием, так как некоторые отечественные ОС (на которых мы потенциально могли бы развертывать систему) поддерживают только .NET Core версии LTS.
Frontend решили делать на React + TypeScript, так как он прост в изучении. Мы решили пропагандировать подход full stack разработчиков.
Межсервисное взаимодействие мы решили сделать синхронное, потому что цепочки вызовов у нас предполагались недлинные, а межсервисное взаимодействие всё равно абстрагировано. Сервис вызывает другой сервис через абстрактный proxy. А в нем может быть любая логика. В нашем случае — это вызов другого сервиса по http через Service Discovery. Подобная конструкция позволила нам, с одной стороны, упростить жизнь разработчикам (они могут просто использовать интерфейс сервиса для того, чтобы его вызвать, но на самом деле в контейнере служб ASP.NET Core зарегистрированная реализация этого интерфейса — тот самый Proxy), а с другой — обеспечить горизонтальное масштабирование системы автоматически, так как мы всегда спрашиваем у Service Discovery, как вызвать сервис, а тот, в свою очередь, может отдать один из запущенных инстансов этого сервиса.
В какой-то момент структура сервиса стала типовой, и мы сделали расширения для Visual Studio, которое при добавлении нового проекта в решение генерирует структуру проектов с минимальной реализацией сервиса, опять же, чтобы разработчики не занимались этой рутиной. Вдобавок к этому сделали несколько скриптов для запуска всей системы легким движением руки (позже мы задумались о таком же быстром развертывании легковесного оркестратора у разработчика).
Процесс выбора инструментов был тоже достаточно интересным. Нам предстояло решить — какой функционал мы пишем сами, а какой берем «из коробки» (речь о существующих инструментах), но, конечно, абстрагировав всё взаимодействие с ним, чтобы при необходимости была возможность заменить этот инструмент или библиотеку на другую реализацию. Нам были нужны следующие инструменты: поисковый движок, движок бизнес-процессов (BPMN Engine), протокол обнаружения сервисов (Service Discovery), планировщик. Критерии были разные: лицензии, скорость работы, скорость погружения проектной команды и т.д. В результате получился следующий список: Elasticsearch, Camunda, Consul, Hangfire.
Сразу же заложили поддержку как минимум PostgreSQL и SQL Server, но ориентировались в основном на PostgreSQL и на развертывание под Linux. Свободное ПО, ну вы понимаете. В связи с этим произошла курьезная история. Поддержку SQL Server мы заложили на ранних этапах, но особо не рассчитывали, что кто-то из наших потенциальных заказчиков заинтересуется развертыванием на Windows + SQL Server, поэтому отложили тестирование этой конфигурации на потом (ведь всегда заранее известно, какая среда у заказчика?!). И вот однажды, делая очередной тестовый стенд для потенциального заказчика, мы уже были готовы как обычно развернуть AltLinux + PostgreSQL, но неожиданно узнаем, что заказчик все же передумал и решил развертываться на Windows + SQL Server, и у нас есть два дня, чтобы всё подготовить. К счастью, пригодился давно написанный и забытый код, который эту поддержку нам обеспечивал с небольшими доработками, и мы успели подготовить всё вовремя, и система заработала как ни в чем ни бывало (слава .NET Core).
Реализация бизнес-идей
К реализации мы подошли с подготовленным списком этапов работ, и самым принципиальным из них был получение в ближайшей перспективе MVP (minimum viable product — минимально жизнеспособный продукт). Мы практически с первых итераций начали работать с акцентом на как можно более быстрое получение прототипа с визуальной частью, которую можно демонстрировать заказчикам (коими вначале были наши руководители) периодически. Этот подход ожидаемо способствовал переосмыслению некоторых задуманных ранее концепций. Удалось выловить несколько противоречий и побороться с ними заблаговременно. Речь идет о проектировании Web API для взаимодействия frontend и backend.
Конструктор бизнес-объектов
Выше уже упоминалось, что одной из ключевых идей продукта является возможность создания структуры бизнес-объекта пользователем-конфигуратором. С реализации конструктора бизнес-объектов мы собственно и начали. Первые версии, конечно, были больше концептуальными, но они впоследствии дали нам богатую пищу для размышлений. Некогда простенькие бизнес-объекты с парочкой простых полей впоследствии эволюционировали в многоуровневые многофункциональные юниты с широким спектром всевозможных настроек. Мы научились настраивать не только простые поля, но и поля с выбором из иерархических справочников, связанные коллекции объектов с фильтрацией, и так далее.
Рождаемый мышкой конфигуратора бизнес-объект имеет достаточно метаданных, чтобы можно было собирать настраиваемые реестры с поиском и формы с различным представлением.
Создание нового бизнес-объекта (шаблона). Поля бывают разных типов
Заполнение свойств поля. Состав свойств изменяется в зависимости от типа поля
Реестр и фильтр — строятся на основе метаданных, заполненных при создании структуры бизнес-объекта
Реестр событий
Нас не обошел стороной и вопрос валидации бизнес-объектов. Мы быстро обнаружили, что валидация не может не сопровождаться бизнес-логикой, которая требуется на этапе наполнения бизнес-объекта данными. «Если «поле 1» имеет «значение 1», то «поле 2» нужно спрятать» или «Поле 1 является суммой поля 2 и поля 3» — это лишь парочка простейших примеров, которые можно привести. Долго ли коротко ли, и у нас появился движок событий, в котором подобное поведение можно настраивать. События можно тоже настраивать мышкой. Много вариантов уже реализовано, в том числе сложные вычисления. Но это тема отдельного разговора. Напишите, пожалуйста, в комментариях если вы решали подобную задачу, было бы интересно обменяться ощущениями.
Настройка события для поля (это может быть валидация, условие или вычисление)
Конструктор бизнес-процессов
Как мы любим повторять: «Кому нужны бизнес-объекты без бизнес-процессов?». Сказано-сделано. Мы, конечно, знали заранее, что наступит момент, когда нужно будет решать и вопрос бизнес-процессов, и эта задача наводила ужас была чем-то загадочным и мистическим ровно до тех пор, как мы не взялись за нее. Посетив несколько митапов, прочитав и попробовав пару инструментов, мистика развеялась. Было решено использовать движок Camunda (конечно, выполнив все наши процедуры по абстрагированию доступа к этому инструменту). Это замечательный инструмент, который мы всё ещё продолжаем познавать и наращивать варианты его использования.
Текущее положение бизнес-объекта в бизнес-процессе
Результаты
С момента старта проекта прошло полтора года. Команда увеличилась в десять раз, количество седых волос в бороде тоже, были решены тысячи задач, проведены сотни daily-митингов, влиты тысячи Pull Request-ов, но похвастаться хочется не этим, а вот чем.
Первое, что кажется мегаклассным, — это тот факт, что чем больше мы делаем функционала, тем больше идей появляется. Такое чувство, что мы движемся не от начала проекта к его завершению, а просто от начала и дальше — это важный аспект. После многих лет, проведенных на поддержке готовых решений (а это случается очень часто в жизни IT-специалиста), такое положение дел очень мотивирует.
Второе мегаощущение — наблюдать за такой мотивированной командой и находиться внутри нее. Процесс создания нового продукта — это не только последовательность задач и этапов. Это, в первую очередь, атмосфера. Атмосфера того, что ты очень часто занимаешься тем, чем никогда до этого не занимался, хотя и участвовал в десятках проектов. Ей дышит каждый член команды и в какой-то момент понимает, что покинул зону комфорта после первого же вдоха. И самая сложная и главная задача — сделать эту атмосферу свежей, комфортной и интересной. Нам не спрятаться от багов, дэдлайнов и т. д., но куда более разрушительным может стать отсутствие благоприятной среды, в которой все мы находимся.
Мы стараемся уделять процессу разработки нашего продукта особое внимание. Этот процесс не статичный. Он претерпевает изменения, если это необходимо, но он дает возможность комфортно решать свои задачи и помогать делать это своим коллегам.
P.S. Сложно в одной статье описать всё детально, поэтому она получилась больше обзорной. Очень надеемся, что вы нашли в ней что-то интересное, и мы с удовольствием ответим на возникшие вопросы в комментариях, или опишем какой-нибудь аспект нашей системы более подробно в отдельной статье.