Помните, недавно мы рассказывали, как несколько лет создавали нашу систему управления производственными процессами (MES)? Мы бы ее еще дольше создавали (и тому были объективные причины, включая переоценку своих сил подрядчиками), если бы не он. Автодеплой нам в помощь!
Я, Куликов Алексей, являюсь техническим архитектором MES-системы, хочу рассказать о том, как мы пришли к развертыванию MES-приложения при помощи автоматизированных решений и как это оптимизировало нашу работу.
Небольшая техническая вводная про то, как была устроена MES «Северстали» в начале проекта по ее созданию
Над кодом совместно работали подрядчики и специалисты «Северсталь-инфокома» — это наш центр информационных и коммуникационных технологий. Потом подрядчики ушли, а наши специалисты продолжили творить. Система разработана на Embarcadero RAD Studio. Приложение реализовано в виде одного исполняемого EXE-файла под Windows, который представляет собой оболочку для показа интерфейсов (а до этого у нас были огромные экзешники). К нему подключаются модули в виде BPL-пакетов, которые попадают на рабочие места при старте приложения с файлового сервера посредством системы автообновления. Исходники изначально хранились в MS TFS (Team Foundation Server, сейчас он называется Azure DevOps Server, это аналог Subversion, SVN). Используемые инструменты разработки (Embarcadero RAD Studio и PL/SQL) не имеют развитых инструментов DevOps.
Основная бизнес-логика вынесена в СУБД. MES разделена по цехам предприятия. В каждом цехе — выделенная схема БД с идентичным набором таблиц и PL/SQL-объектов. При подключении нужно выбрать среду: это либо цеховая система, либо общий модуль, например, модуль ведения справочников. Функции в каждой среде имеют древовидную структуру. Выбирая конкретную функцию, вы видите ее интерфейс. Интерфейсы функций реализованы в BPL-пакетах, которые подключаются по мере необходимости.
Предпосылки к изменениям, или Как все работало до автодеплоя
Над кодом трудились около 30 разработчиков. Было разработано и дорабатывалось более 3000 объектов PL/SQL и более 500 подключаемых BPL-библиотек. В ходе проекта мы стали осознавать, что у нас есть довольно весомые технические и организационные ограничения, которые задерживают успешное развитие системы управления производственными процессами, а значит, стопорят и саму оптимизацию выпуска продукции на производстве. А она была очень нужна производствам «Северстали», об этом вы тоже можете почитать в прошлой статье. Основным организационным ограничением стала работа не с релизами, а с отдельными задачами. Дальше расскажу, как была реализована разработка.
Про задачи и блокирующий режим разработки
Работа велась (и ведется сейчас) по задачам. Цель каждой задачи — реализовать законченную часть какого-то функционала. Задачу создаёт и формулирует бизнес-аналитик, он же включает её в график и определяет приоритет разработки. После завершения разработки тестирует задачу всё тот же аналитик. Задачи выставляются в тест и продуктив по мере готовности, независимо друг от друга. Релизов нет.
До проекта у нас не было отдельной группы деплоя для сборки и выставления кода в тестовую среду и на продуктивный сервер — изменения выгружал разработчик. Один, да. Но потом мы создали группу деплоя. И разработчиков прибавилось. Они теперь работают с кодом в блокирующем режиме.
Вот что это означает: приступая к задаче, разработчик блокирует необходимые ему файлы в TFS и освобождает их после выхода задачи в продуктив (а современные инструменты — GIT, Mercurial — позволяют работать с кодом параллельно, да-с). У группы деплоя написана утилита, которая компилирует на сборочной машине EXE и BPL, относящиеся к задаче. Эта же утилита выполняет SQL-скрипты и компилирует исходники PL/SQL на выбранных схемах БД.
Процесс работы над задачей выглядит примерно так (стадии, явно замедляющие разработку и выбранные для улучшения, отмечены оранжевым):
После того, как мы расстались с неоправдавшим ожидания и затянувшим разработку MES подрядчиком, мы принялись анализировать, какие у нас есть возможности для ускорения разработки. В первую очередь решили изменить систему контроля версий и оптимизировать процесс деплоя.
Как мы сходили на GIT и Liquibase и вернулись
Когда мы попробовали использовать готовое решение, которое помогло бы нам с оптимизацией, мы исходили из точки зрения бизнеса, ведь «изобретать свой велосипед» всегда более затратно. Однако, идя по этому пути, мы пришли к тому же выводу, что и при разработке MES — не подходит. Расскажу, как это было.
Мы перешли на распределенную систему управления версиями GIT, встроенную в более новую версию MS TFS (Azure DevOps Server), чьими средствами мы планировали создать и сборочные конвейеры (пайплайн). Этим шагом мы хотели наладить параллельную работу с кодом, устранить блокировку файлов и тем самым ускорить разработку. Вместе с этим нам очень хотелось избавить деплой от рутинных операций и дать возможность разработчикам самим инициировать выставление на тест по мере готовности. То есть, перейти на автодеплой.
Казалось бы, что может быть сложного в переходе на GIT? Перенести исходный код, создать ветки и — вперёд! Но оказалось, может.
Раньше разработчики блокировали свои файлы, и работа по задачам шла последовательно. Теперь же код задачи, которая была протестирована и готова к выставлению в продуктив, смешивался с новым кодом, только что подготовленным для тестирования. Мы сделали еще хуже. Ну, хорошо, не хуже, но теперь надо разбираться еще и в этом хаосе изменений. Как это можно сделать? Разве что помечать занятые файлы и не менять их. Но ведь это не отличается от варианта с блокировкой. К счастью, мы перевели на GIT не всех разработчиков сразу, а только один модуль. И после первой же пробы вернулись обратно.
С инструментами деплоя первое свидание тоже не заладилось. Хотелось применять готовые общепринятые инструменты. И если для RAD Studio ничего кроме её компилятора и метода стандартного копирования собранных файлов на файловый сервер особо и не придумаешь, то для PL/SQL и SQL-скриптов инструменты существуют.
Мы остановили свой выбор на Liquibase. Это независимая от базы данных библиотека с открытым исходным кодом для отслеживания, управления и применения изменений схемы базы данных. Она позволяет выполнять скрипты в БД и следит за тем, чтобы код был выполнен единожды. Это очень удобно при создании систем, разворачивающихся «с нуля» и работающих с базой только как с набором таблиц, изредка их модифицируя. У нас же большинство изменений происходило в пакетах, и практически никакого выигрыша по сравнению с компиляцией через консоль SQL*Plus мы не получили. А временные затраты на написание и актуализацию скриптов добавились ко времени, выделенному на разработку.
Пришлось отказаться и от этого. Зато при внедрении Liquibase у нас сложилось понимание, что для файлов PL/SQL необходимо иметь мета-информацию о том, в какие схемы БД должен попасть объект. Тогда и стало понятно, что нужно делать что-то своё.
Этому проекту нужен QDeSnik!
Приоритетом в оптимизации был, конечно же, переход на GIT, а автодеплой планировали следующим этапом. Но, проанализировав неудачу с GIT и блокировками файлов, мы решили форсировать внедрение автодеплоя в части создания базы описания объектов деплоя. Идея заключалась в том, чтобы разработчик блокировал файлы, но не перед разработкой, а только после нее — для выставления в тест в интерфейсе самописной системы. А система сама следила бы за блокировками и разрешала выставление на тест. Так появился QDeSnik — система формирования поставок кода в тестирование.
Под рукой у нас были СУБД Oracle и RAD Studio. А ещё команда разработки, которая могла реализовать и сопровождать новую систему на этих технологиях. Именно поэтому структуры БД и основную логику мы реализовали на PL/SQL, а интерфейс пользователя — на RAD Studio. В таблицы сохранили список так называемых объектов деплоя — неделимых единиц выпуска на тест и продуктив. Так, для PL/SQL объектами стали: пакет, процедура, функция, триггер, обзор (view) и скрипт. А для Embarcadero RAD Studio — пакет BPL (не каждый отдельный пользовательский интерфейс, но и не весь исполняемый файл, так как система изначально модульная). Также сохранялась метаинформация: для объектов БД — схемы и сервера развёртывания, для пакетов BPL — путь размещения в каталоге дистрибутива.
Чтобы выставить свою задачу на тест, разработчик теперь должен был сформировать поставку: указать все объекты, которые он поменял и нажать «готово». А дальше система уже принимала решение, можно сейчас выставлять задачу или нет. Если объекты были заняты другой задачей, то разработчик ставил задачу «в ожидание» и переходил к следующей. При освобождении объектов, автомат (циклическое задание в Oracle) давал задаче «зелёный свет», о чём и уведомлял письмом. Разрешение от системы означало, что разработчик может мержить свой код в основную ветку (у нас это «test»), откуда уже производится развертывание на тестовый стенд, а затем, после проверки — в продуктив.
Тестирование нового формата работы мы опять решили провести на небольшой отдельной группе разработчиков. Скриптом загрузили в БД все объекты, с которыми работает эта группа, объяснили новые правила и стали смотреть, что получилось. И на этот раз никаких непреодолимых препятствий не возникло. Устраняли только мелкие шероховатости. В целом, новый формат работы команде понравился.
Самой большой проблемой стала синхронизация разработок команды, участвующей в пилоте, с другими командами. Это было важно, потому что периодически появлялись задачи на несколько команд или одной команде требовались файлы другой команды. Что ещё больше подстегнуло переход на новый формат.
Как задача попадает на тест
Получившаяся система точно знала, какие объекты, куда и в какой последовательности хочет выставить разработчик. Оставалось это выставление автоматизировать.
Классический сборщик после завершения запроса на слияние кода нам не подошел. В процессе перехода с TFS мы решили, что иметь один GIT под всё не слишком-то удобно. Потому что «всё» — это чуть меньше 2000 файлов на тот момент и около 4000 на текущий. Мы разделили исходники на несколько областей, а также отделили часть PL/SQL от BPL. Это позволило:
разграничить ответственность и права разных команд;
ограничить количество изменений и веток в каждом репозитории;
упростить постепенный переход на автодеплой.
Но слияние кода в test в одном репозитории не гарантировало готовности выставления кода. О том, что разработчик закончил слияние и готов идти на тест, знает только система QDeSnik. Она же хранит дополнительные скрипты БД и метаинформацию о стендах.
В итоге взяли мы за основу инструмент позадачного выставления, который уже был реализован группой деплоя. Соединили его с информацией от системы QDeSnik и запустили в виде циклического задания на сборочной машине. Таким образом, когда разработчик заканчивает работу над задачей и QDeSnik даёт ему «добро» на выставление, задача попадает на тест в течение 10 минут без участия группы деплоя.
Какой стала работа над задачей после внедрения автоматизации
В результате разработок, доработок и интеграций мы пришли к сценарию, где разработчик может сразу приступать к задаче, и только после её реализации ждать освобождения объектов. Он уже не проводит анализ и не рискует ошибиться с выбором объектов, которые ему понадобятся.
Процесс работы над задачей теперь такой:
Задача формируется аналитиком, согласуются ее сроки, к ней назначается разработчик и задача ставится в план.
Разработчик решает задачу — создаёт ветки в нужных репозиториях, пишет и отлаживает код, сохраняет изменения в ветке задачи.
Разработчик формирует «поставку» по задаче, указав все изменённые им объекты. Переводит задачу в ожидание.
Система QDeSnik периодически проверяет возможность выставления задачи на тестирование. Когда другие задачи уходят с тестирования и освобождают требуемые объекты, QDeSnik даёт разрешение на тестирование этой задачи. А разработчику поступает письмо и объекты блокируются его задачей.
Разработчик создаёт запрос на слияние в ветку test всех необходимых репозиториев, проходит ревью кода и завершает запрос. После завершения всех запросов подтверждает это в QDeSnik.
Система разворачивает все объекты, указанные разработчиком на тестовых стендах. При сбоях уведомляет разработчика. При успехе сама переводит задачу в статус «Тестирование» и назначает её на проверяющего.
После успешного тестирования и выхода задачи в продуктив система меняет статус поставки и освобождает объекты для следующих задач.
При неудаче тестирования задача возвращается на разработчика.
На схеме видно, как изменился процесс работы над задачей после внедрения автодеплоя (зелёные блоки — оптимизированы, выделенные черным контуром — изменены):
Что мы поняли на пути к автодеплою
Теперь система автодеплоя полностью удовлетворяет нашим потребностям. Множественные усилия дали хороший результат:
Разработчики стали выполнять задачи быстрее — теперь им не надо ждать заблокированных файлов. К этому мы и шли.
Большинство задач приходят на тест в автоматическом режиме примерно через 10 минут после того, как разработчик завершил изменения.
Группа деплоя теперь следит за автоматом, а вручную выставляет только что-то совсем экзотическое.
Но, совершенству нет предела, и теперь мы ищем новые возможности для ускорения своей работы. Надеемся, вам понравилась статья. Задавайте, пожалуйста, ваши вопросы в комментариях.