Изображение: Unsplash
Всем привет! Мы инженеры-автоматизаторы из компании Positive Technologies и занимаемся сопровождением разработки продуктов компании: поддерживаем весь сборочный конвейер от коммита строчки кода разработчиками до публикации готовых продуктов и лицензий на серверах обновлений. Неформально нас называют DevOps-инженеры. В этой статье мы хотим рассказать про технологические этапы процесса производства ПО, про то, как мы их видим и как классифицируем.
Из материала вы узнаете про сложность координации мультипродуктовой разработки, про то, что такое технологическая карта и как она помогает упорядочивать и тиражировать решения, из каких основных этапов и шагов состоит процесс разработки, как разграничены зоны ответственности между DevOps и командами в нашей компании.
Про Хаос и DevOps
Кратко отметим, что понятие DevOps включает в себя инструменты и сервисы разработки, а также методологии и лучшие практики их использования. Выделим глобальную цель от внедрения идей DevOps в нашей компании: это последовательное снижение себестоимости производства и сопровождения продуктов в количественных показателях (человеко-часах или машино-часах, CPU, RAM, Disk etc.). Самый простой и очевидный способ снижения общей себестоимости разработки на уровне всей компании — это минимизация стоимости выполнения типовых серийных задач на всех этапах производства. Но что это за этапы, как их выделить из общего процесса, из каких шагов они состоят?
Когда компания разрабатывает один продукт, все более-менее понятно: обычно есть общий роадмап и схема разработки. Но что делать, когда продуктовая линейка расширяется и продуктов становится больше? На первый взгляд, у них похожие процессы и сборочные конвейеры и начинается игра «найди Х отличий» в логах и скриптах. А если в активной разработке уже 5+ проектов и требуется поддержка нескольких версий, разработанных за несколько лет? Хотим ли мы переиспользовать максимально возможное количество решений в продуктовых конвейерах или готовы тратиться на уникальную разработку под каждый?
Как найти баланс между уникальностью и серийностью решений?
Эти вопросы стали возникать перед нами все чаще начиная с 2015 года. Количество продуктов росло, а расширять наш отдел автоматизации (DevOps), у которого на поддержке находились сборочные конвейеры этих продуктов, старались по минимуму. При этом хотелось как можно больше решений тиражировать между продуктами. В конце концов, зачем делать одно и то же в десяти продуктах разными способами?
Директор по разработке: «Парни, а мы как-то можем оценить, что делает DevOps для продуктов?»
Мы: «Не знаем, не задавались таким вопросом, а какие показатели считать нужно?»
Директор по разработке: «А кто его знает! Подумайте…»
Как в известном том фильме: «Мне в гостиницу!..» — «Э-э… А дорогу покажешь?». Подумав, мы пришли к выводу, что сначала требуется определиться с конечными состояниями продуктов; это стало нашей первой целью.
Итак, как же провести анализ десятка продуктов с достаточно крупными командами от 10 до 200 человек и определить измеримые метрики при тиражировании решений?
1:0 в пользу Хаоса, или DevOps на лопатках
Начали с попытки применить диаграммы IDEF0 и различные диаграммы бизнес-процессов из серии BPwin. Путаница началась после пятого квадратика очередного этапа очередного проекта, а квадратиков этих у каждого проекта можно нарисовать в хвост длиннющего питона под 50+ шагов. Взгрустнулось и захотелось повыть на луну — не подошло в общем.
Типовые производственные задачи
Моделирование производственных процессов — это очень сложная и кропотливая работа: нужно собрать, обработать и проанализировать множество данных по различным отделам и производственным цепочкам. Подробнее об этом вы можете прочитать в статье «Моделирование производственных процессов в ИТ-компании».
Когда мы занялись моделированием нашего производственного процесса, то преследовали конкретную цель — донести до каждого сотрудника, участвующего в разработке продуктов нашей компании, и до руководителей проектов:
- как продукты и их компоненты, начиная от коммита строчки кода, доходят до заказчика в виде инсталляторов и обновлений,
- какими ресурсами обеспечен каждый этап производства продуктов,
- какие сервисы участвуют на каждом этапе,
- как разграничены зоны ответственности для каждого этапа,
- какие контракты существуют на входе и выходе каждого этапа.
По клику картинка откроется в полном размере
Наша работа в компании разделена на несколько функциональных направлений. Направление инфраструктуры занимается оптимизацией эксплуатации всех «железных» ресурсов отдела, а также автоматизацией развертывания виртуальных машин и окружения на них. Направление мониторинга обеспечивает контроль работоспособности сервисов 24/7; также мы предоставляем мониторинг как сервис для разработчиков. Направление workflow предоставляет командам инструменты для управления процессами разработки и тестирования, анализа состояния кода, для получения аналитики по проектам. И наконец, направление webdev обеспечивает публикацию релизов на серверах обновлений GUS и FLUS, а также лицензирование продуктов при помощи сервиса LicenseLab. Для поддержки производственного конвейера мы настраиваем и сопровождаем множество различных вспомогательных сервисов для разработчиков (рассказы про некоторые из них можно послушать на старых митапах: Op!DevOps! 2016 и Op!DevOps! 2017). Также мы разрабатываем инструменты внутренней автоматизации, в том числе опенсорс-решения.
За последние пять лет в нашей работе накопилось множество однотипных и рутинных операций, а от наших разработчиков из других отделов в основном приходят так называемые типовые задачи, решение которых автоматизировано полностью или частично, не вызывает трудностей у исполнителей и не требует значительных объемов работ. Совместно с ведущими направлений мы проанализировали такие задачи и смогли выделить отдельные категории работ, или производственные этапы, этапы разбили на неделимые шаги, а из нескольких этапов складывается производственная технологическая цепочка.
Простейший пример технологической цепочки — это этапы сборки, деплоя и тестирования каждого нашего продукта внутри компании. В свою очередь, например, этап сборки состоит из множества отдельных типовых шагов: выкачивание исходников из GitLab, подготовка зависимостей и 3rd-party библиотек, юнит-тестирование и статический анализ кода, выполнение билд-сценария на GitLab CI, публикация артефактов в хранилище на Artifactory и генерация релиз-нотов через наш внутренний инструмент ChangelogBuilder.
Про типовые задачи DevOps вы можете почитать в других наших статьях на Хабре: «Личный опыт: как выглядит наша система Continuous Integration» и «Автоматизация процессов разработки: как мы в Positive Technologies внедряли идеи DevOps».
Множество типовых производственных цепочек образуют производственный процесс. Стандартный подход к описанию процессов — использовать функциональные IDEF0-модели.
Пример моделирования производственного CI-процесса
Особое внимание мы уделили разработке типовых проектов для системы непрерывной интеграции. Это позволило добиться унификации проектов, выделив так называемую релизную схему сборок с продвижениями.
Вот как это работает. Все проекты выглядят типовыми: они включают конфигурацию сборок, которые попадают в snapshot-репозиторий на Artifactory, после чего осуществляется их развертывание и тестирование на тестовых стендах, а затем продвижение в релизный репозиторий. Сервис Artifactory является единой точкой распространения всех артефактов сборки между командами и другими сервисами.
Если очень упростить и обобщить нашу релизную схему, то она включает в себя такие этапы:
- кроссплатформенная сборка продукта,
- деплой на тестовые стенды,
- запуск функциональных и иных тестов,
- продвижение протестированных сборок в релизные репозитории на Artifactory,
- публикация релизных сборок на серверы обновлений,
- доставка сборок и обновлений на продакшн,
- запуск инсталляции и обновления продукта.
Рассмотрим для примера технологическую модель этой типовой релизной схемы (далее просто — Модель) в виде функциональной IDEF0-модели. В ней отражены основные этапы нашего CI-процесса. В IDEF0-моделях используется так называемая ICOM-нотация (Input-Control-Output-Mechanism) для описания того, какие ресурсы используются на каждом этапе, на основании каких правил и требований выполняется работа, что получается на выходе и какие механизмы, сервисы или люди реализуют конкретный этап.
По клику картинка откроется в полном размере
Как правило, в функциональных моделях легче декомпозировать и детализировать описание процессов. Но с ростом числа элементов понять в них что-то становится все сложнее и сложнее. А ведь в реальной разработке есть еще и вспомогательные этапы: мониторинг, сертификация продуктов, автоматизация рабочих процессов и другие. Именно из-за проблемы масштабирования мы отказались от такого описания.
Рождение надежды
В одной книжке наткнулись на старые советские карты описания технологических процессов (которые, кстати сказать, применяются и сейчас на многих госпредприятиях и в вузах). Постойте, постойте, ведь у нас тоже технологический процесс!.. Есть этапы, результаты, метрики, требования, показатели и прочее и прочее… Почему бы не попробовать применить технологические карты и к нашим продуктовым конвейерам? Появилось чувство: «Вот оно! Мы нащупали нужную ниточку, пора за нее хорошенько потянуть!»
В простой таблице мы решили по столбцам фиксировать продукты, а по строкам — технологические этапы и шаги продуктового конвейера. Этапы — это нечто крупное, например этап сборки продукта. А шаги — это что-то более мелкое и детальное, например шаг скачивания исходного кода на сборочный сервер или шаг компиляции кода.
На пересечениях строк и столбцов карты мы проставили статусы для конкретного этапа и продукта. Для статусов определили множество состояний:
- Нет данных — или нецелесообразно. Нужно провести анализ востребованности этапа в продукте. Либо анализ уже проведен, но этап на текущий момент не нужен или экономически не обоснован.
- Отложено — или неактуально на данный момент. Этап в конвейере нужен, но сил на реализацию в этом году нет.
- Запланировано. Этап запланирован для реализации на этот год.
- Реализовано. Этап в конвейере реализован в требуемом объеме.
Заполнение таблицы начали попроектно. Вначале классифицировали этапы и шаги одного проекта и зафиксировали статусы по ним. Потом взяли следующий проект, зафиксировали статусы в нем и добавили отсутствующие в предыдущих проектах этапы и шаги. В итоге получили этапы и шаги всего нашего производственного конвейера и их статусы в конкретном проекте. Получилось нечто похожее на матрицу компетенций продуктового конвейера. Такую матрицу мы назвали технологической картой.
С помощью технологической карты мы метрологически обоснованно согласовываем с командами планы работ на год и целевые показатели, которых хотим совместно достичь: какие этапы добавляем в этом году в проект, а какие оставляем на потом. Также в процессе работы у нас могут появиться улучшения этапов, которые мы выполнили только для одного продукта. Тогда мы расширяем нашу карту и вносим это улучшение как этап или новый шаг, затем проводим анализ по каждому продукту и выясняем целесообразность тиражирования улучшения.
Нам могут возразить: «Это все, конечно, хорошо, только со временем количество шагов и этапов станет запредельно большим. Как быть?»
Мы ввели стандартные и достаточно полные описания требований для каждого этапа и шага, чтобы внутри компании они понимались всеми одинаково. Со временем, при внедрении улучшений, шаг может быть поглощен в другом этапе или шаге — тогда они «схлопнутся». При этом все требования и технологические нюансы вписываются в требования обобщающего этапа или шага.
Как оценить эффект от тиражирования решений? Мы используем крайне простой подход: начальные капитальные затраты на реализацию нового этапа мы относим на годовые общепродуктовые затраты, а затем делим на всех при тиражировании.
Части разработки уже отражены как этапы и шаги на карте. Мы можем повлиять на уменьшение стоимости продукта через внедрение автоматизации для типовых этапов. После этого считаем изменения качественных характеристик, количественных метрик и получаемый командами профит (в человеко-часах или машино-часах экономии).
Технологическая карта производственного процесса
Если взять все наши этапы и шаги, закодировать тегами и развернуть в одну цепочку, то она получится очень длинной и непонятной (как раз, тот самый «хвост питона», о котором мы говорили в начале статьи):
[Production] — [InfMonitoring] — [SourceCodeControl] — [Prepare] — [PrepareLinuxDocker] — [PrepareWinDocker] — [Build] — [PullSourceCode] — [PrepareDep] — [UnitTest] — [CodeCoverage] — [StaticAnalyze] — [BuildScenario] — [PushToSnapshot] — [ChangelogBuilder] — [Deploy] — [PrepareTestStand] — [PullTestCode] — [PrepareTestEnv] — [PullArtifact] — [DeployArtifact] — [Test] — [BVTTest] — [SmokeTest] — [FuncTest] — [LoadTest] — [IntegrityTest] — [DeliveryTest] — [MonitoringStands] — [TestManagement] — [Promote] — [QualityTag] — [MoveToRelease] — [License] — [Publish] — [PublishGUSFLUS] — [ControlVisibility] — [Install] — [LicenseActivation] — [RequestUpdates] — [PullUpdates] — [InitUpdates] — [PrepareEnv] — [InstallUpdates] — [Telemetry] — [Workflow] — [Communication] — [Certification] — [CISelfSufficiency]
Это этапы сборки продуктов [Build], их деплоя на тестовые серверы [Deploy], тестирования [Test], продвижения сборок в релизные репозитории по итогам тестирования [Promote], генерации и публикации лицензий [License], публикации [Publish] на сервере обновлений GUS и доставки до серверов обновлений FLUS, инсталляции и обновления компонентов продуктов на инфраструктуре заказчика средствами Product Configuration Management [Install], а также сбор телеметрии [Telemetry] с установленных продуктов.
Кроме них можно выделить отдельные этапы: мониторинга состояния инфраструктуры [InfMonitoring], управления версиями исходного кода [SourceCodeControl], подготовки сборочного окружения [Prepare], управления проектами [Workflow], обеспечения команд средствами коммуникации [Communication], сертификации продуктов [Certification] и обеспечения самодостаточности CI-процессов [CISelfSufficiency] (например, независимости сборок от интернета). Десятки шагов в наших процессах даже не будем рассматривать, потому что они очень специфичные.
Будет гораздо легче понять и окинуть взглядом весь производственный процесс, если представить его в виде технологической карты; это таблица, в которую по строкам записаны отдельные производственные этапы и декомпозированные шаги Модели, а по столбцам — описание того, что делается на каждом этапе или шаге. Основной акцент сделан на ресурсах, обеспечивающих каждый этап, и разграничении зон ответственности.
Карта для нас — это своеобразный классификатор. Она отражает крупные технологические части производства продуктов. Благодаря ей нашей команде автоматизаторов стало легче взаимодействовать с разработчиками и совместно планировать внедрение этапов автоматизации, а также понимать, какие трудозатраты и ресурсы (человеческие и «железные») для этого потребуются.
Внутри нашей компании карта автоматически генерируется из jinja-шаблона в виде обычного HTML-файла, а затем выкладывается на сервер GitLab Pages. Скриншот с примером полностью сгенерированной карты можно посмотреть по ссылке.
По клику картинка откроется в полном размере
Если сказать коротко, то технологическая карта — это обобщенная картина производственного процесса, где отражены четко классифицированные блоки с типовой функциональностью.
Структура нашей технологической карты
Карта состоит из нескольких частей:
- Область заголовков — здесь находится общее описание карты, вводятся базовые понятия, определяются основные ресурсы и результаты производственного процесса.
- Информационная панель — здесь можно управлять отображением данных по отдельным продуктам, приводится сводка по реализованным этапам и шагам в целом по всем продуктам.
- Технологическая карта — табличное описание технологического процесса. На карте:
- приведены все этапы, шаги и их коды;
- даны краткое и полное описания этапов;
- указаны входные ресурсы и сервисы, используемые на каждом этапе;
- указаны результаты каждого этапа и отдельного шага;
- указана зона ответственности по каждому этапу и шагу;
- определены технические ресурсы, например HDD (SSD), RAM, vCPU, и человеко-часы, необходимые для поддержки работ на данном этапе, как на текущий момент — факт, так и в будущем — план;
- для каждого продукта указано, какие технологические этапы или шаги для него реализованы, планируются к внедрению, неактуальны или не реализованы.
Принятие решений на основе технологической карты
Изучив карту, возможно предпринять некоторые действия — в зависимости от роли сотрудника в компании (руководитель разработки, менеджер продукта, разработчик или тестировщик):
- понять, какие этапы отсутствуют в реальном продукте или проекте, и оценить необходимость их внедрения;
- разграничить зоны ответственности между несколькими отделами, если они работают над разными этапами;
- договориться о контрактах на входах и выходах этапов;
- интегрировать свой этап работ в общий процесс разработки;
- точнее оценить потребность в ресурсах, обеспечивающих каждый из этапов.
Резюмируя все вышесказанное
Технологическая карта универсальна, расширяема и легко поддерживается. Разрабатывать и сопровождать описание процессов в таком виде гораздо легче, чем в строгой академичной IDEF0-модели. Кроме того, табличное описание проще, привычней и лучше структурировано, чем функциональная модель.
За техническую реализацию шагов у нас отвечает специальный внутренний инструмент CrossBuilder — инструмент-прослойка между CI-системами, сервисами и инфраструктурой. Разработчику не нужно пилить свой велосипед: в нашей CI-системе достаточно запустить один из скриптов (так называемый task) инструмента CrossBuilder, который правильно его исполнит с учетом особенностей нашей инфраструктуры.
Итоги
Статья получилась довольно длинной, но это неизбежно при описании моделирования сложных процессов. В конце хочется коротко зафиксировать наши основные идеи:
- Цель внедрения идей DevOps в нашей компании — последовательное снижение себестоимости производства и сопровождения продуктов компании в количественных показателях (человеко-часах или машино-часах, vCPU, RAM, Disk).
- Способ снижения общей себестоимости разработки — минимизация стоимости выполнения типовых серийных задач: этапов и шагов технологического процесса.
- Типовая задача — это задача, решение которой автоматизировано полностью или частично, не вызывает затруднений у исполнителей и не требует значительных трудозатрат.
- Производственный процесс состоит из этапов, этапы разбиты на неделимые шаги, которые представляют собой типовые задачи разного масштаба и объема.
- От разрозненных типовых задач мы пришли к сложным технологическим цепочкам и многоуровневым моделям производственного процесса, которые могут быть описаны функциональной IDEF0-моделью или более простой технологической картой.
- Технологическая карта — это табличное представление этапов и шагов производственного процесса. Самое главное: карта позволяет увидеть весь процесс целиком, крупными кусками с возможностью их детализации.
- На основе технологической карты можно оценить необходимость внедрения этапов в том или ином продукте, разграничить зоны ответственности, договориться о контрактах на входах и выходах этапов, более точно оценить потребность в ресурсах.
В следующих статьях мы более подробно расскажем о том, какими техническими инструментами реализуются те или иные технологические этапы на нашей карте.
Авторы статьи:
- Александр Паздников — руководитель отдела автоматизации (DevOps) компании Positive Technologies
- Тимур Гильмуллин — зам. руководителя отдела автоматизации (DevOps) компании Positive Technologies