Наша команда отвечает за эксплуатацию и развитие большого корпоративного продукта.
В начале 2017 года, передохнув от крупного внедрения и перечитав "lessons learned", мы твердо решили пересмотреть процесс разработки и доставки нашего приложения. Нас беспокоила низкая скорость и качество доставки, не позволяя нам обеспечивать уровень сервиса, который от нас ожидают заказчики.  Пора было переходить от слов к делу — менять процессы. В этой статье будет кратко рассказано о том с чего мы начинали, что делали, какая ситуация сейчас, с какими трудностями столкнулись, что пришлось пока оставить за скобками, что ещё планируем делать. Приложение представляет собой классический пример монолитного энтерпрайз приложения "архитектурного разлива 2000-х годов": Доставка проводится в рамках ежемесячных релизов (как он у нас устроен я рассказывал раньше здесь). Отсутствие контроля Трудоемкость и ошибки Ограничения В начале проекта мы ставили перед собой очевидные цели, призванные решить обозначенные выше проблемы. Дополнительно, используя решения полученные при достижении первых двух целей, мы рассчитывали: Первый шаг: проанализировать существующий процесс разработки подрядчика. Это помогло спланировать изменения так, чтобы, по возможности, не прерывать работу. К сожалению, знакомство с процессом разработки показало, что в понимании IT отрасли настоящего времени — процесс отсутствовал. Зависимость от платформ MS и корпоративные стандарты предопределяли выбор среды для разработки — Team Foundation Server.
Однако, к моменту когда мы непосредственно начинали проект (апрель 2017) как раз вышла версия Visual Studio Team Services. Продукт показался очень интересным, был обозначен как стратегическое направление для MS, предлагал репозитории git, сборку и развертывание для on-prem и cloud.  Корпоративный on-prem TFS отставал по версии и функционалу от VSTS, миграция на новую версию была только в процессе обсуждения. Мы не хотели ждать. Мы решили сразу переходить на VSTS, поскольку это снижало наши накладные расходы на поддержку платформы и предоставляло нам полный контроль над тем как и что мы делаем.  На момент начала изменений у команды разработки был опыт работы с TFSVC, код приложения хранился в таком репозитории. С другой стороны, GIT давно фактически стал стандартом для ИТ сообщества — заказчик и сторонние консультанты рекомендовали перейти на эту систему.
Нам хотелось чтобы команда разработки была вовлечена в принятие решения о новой системе контроля версий, и сделала осознанный выбор. Мы развернули в VSTS два проекта с разными репозиториями — TFSVC и GIT. Были определены набор сценариев, который предлагалось протестировать и оценить удобство работы в каждой из систем.  Среди оцениваемых сценариев были: В результате, ожидаемо, был выбран GIT, и пока никто об этом не жалел. В качестве процесса мы начали использовать GitFlow. Этот процесс предоставлял достаточно контроля за изменениями и позволял проводить доставку релизами, как мы уже привыкли. Приложение представляло собой большое количество сборок, сотни решений. Как выяснилось в ходе аудита процессов, все это собиралось отдельно и "вручную".
Мы решили на первом этапе не переделывать все "с нуля" (чтобы не останавливать существующую доставку), а "обернуть" сборку в набор сценариев msbuild — один сценарий на компонент.
Таким образом мы достаточно быстро получили сценарии, которые проводили все необходимые промежуточные артефакты, и в конце — готовый продукт. Отдельная история — проект базы данных. К сожалению, система содержит несколько CLR компонентов, которые были не очень хорошо структурированы. Зависимости не позволяют простой развернуть базу с содержимым. На данный момент это решается pre-deployment скриптом.
Кроме того, из-за неровного системного ландшафта (на разных точках были установлены SQL Server версий 2008 и 2014) пришлось организовывать сборку проекта базы для .Net версий 2.0 и 4.0. После того как все сценарии были готовы и протестированы, они были использованы в build сценарии VSTS. Непосредственно перед началом сборки версии всех продуктов обновлялись на общий стандартный номер, включающий сквозной номер билда. Такой же номер сохранялся в скрипте post-deployment. Таким образом все компоненты: база данных и все клиентские приложения, — выходили согласованными и одинаково пронумерованными. После того, как первичной версия процесса сборки была завершена, мы приступили к подготовке сценария рпзвертывания. Ожидаемо, больше всего хлопот доставила база данных.  Развертывание "поверх" копии реальной базы показало множество конфликтов между сборкой и состоянием реальных систем: Об этом, конечно, странно говорить и, тем более — писать здесь, но самой серьезным изменением для разработчиков стало введение принцип "если этого нет в git — этого не существует". Раньше код комитился "для отчётности перед заказчиком". Теперь — без этого невозможно доставить ничего. Сложнее всего было с кодом базы данных. После перехода на развертывание базы данных из репозитория, через сборку и развертывание с помощью sqlpackage, "delta" подход был заменен подходом "desired state". Пакеты уходили в прошлое, все должно было деплоиться автоматически. Но! До момента полного перехода на новый процесс развертывания — все ещё нужно было доставлять изменения. И делать это нужно было по старинке -"дельта обновлениями".  Перед нами встала задача обеспечить полную и постоянную согласованность состояния системы при доставке дельта пакетами, и содержания репозитория. Для этого мы организовали следующий процесс: Таки образом, с помощью автоматического контроля удалось относительно быстро привести код базы данных продукта в git а актуальному состоянию и поддерживать его без дополнительных усилий со стороны проектной команды. Одновременно, разработчики стали привыкать к необходимости корректно и своевременно комитить код в репозиторий.  После завершения предыдущего этапа мы перешли непосредственно к развертыванию приложения на тестовом окружении. Мы полностью прекратили применение дельта-пакетов к тестовым системам и перешли на автоматическое развертывание средствами VSTS. Именно с этого момента вся команда начала получать первые плоды от затраченных ранее усилий: развертывание проходило без каких-либо дополнительных усилий. Закомиченный код автоматически собирался, развертывания и тестировался. К сожалению, как мы поняли потом, проведенное "выравнивание репозитория" привело к тому что у нас появилась версия стабильно поддерживаемая версия "develop", но версия "production" была все также недоступна. И поэтому дальше тестового окружения — на QAS и PRD идти было не с чем. Код приложения на стороне БД можно было сравнить с продуктивным и понять различия. Сравнивать клиентские приложения было не с чем — существовала только актуальная продуктивная версия в виде набора исполняемых файлов, а из чего они были собраны достоверно сказать было нельзя. После изменения подхода к сборке продукт пришлось подверкнуть большому регрессионному тестированию. Нужно было убедиться, что приложение работает и ничего не потеряно.
При тестировании как раз проще получилось с функционалом, размещенным на стороне БД. К счатью у нас был в наработан значительный набор автотестов, покрывающий критические области. А вот для С# тестов не было — поэтому проверялось все руками. Это был значительный объем работы, и проверка заняла какое-то время. Несмотря на проведенное тестирование, развертывать на продуктиве в первый раз было страшно. Нам повезло — у нас как раз был запланирован очередное развертывание системы на новой площадке. И мы решили использовать этот шанс для пилотного развертывания.
Пользователи не видели, возможные ошибкиновой сборки было просто исправить, реальной продуктивной работы еще не началось. Мы развернули систему, и несколько недель она была в режиме пред-продуктивного использования (низкая нагрузка, определенный патерн использования, который в продуктиве можно пропустить). За это время вскрылось несколько пропущенных при тестировании дефектов. Они исправялись по мере нахождения, и новая версия сразу же выкатывалась для пповерки. После официально запуска и неделю пос-стартовой поддержки мы объявили, что это первый экземпляр собранный и доставленный "по новому".  Эта версия сборки стала первой стабильной версией ветки master, была обвешана праздничными тагами "fisrt_deployment" (значков с хэшем комита мы, правда, не заказали). Как говорил Джеймс Бонд: "второй раз — гораздо проще". После успеха пилотного развертывания мы довольно быстро подключили остальные экземпляры систем аналогичного типа.  Но система имеет несколько типов использования — одна функциональность может использоваться для одного типа, и не использоваться в других случаях. Соответственно, функциональность проверенная на внедрении первого типа не обязательно гарантировала успех для других случаев. Для проверки функционала оставшихся типов использования мы начали использовать активные проекты, которые находились в разработке. Идея была сходной и первым развертыванием — мы начали использовать автоматические сборки, "подсовывая" их пользователям вместе с проектной функциональностью. Таким образом, пользователи, работая с "проектной" версией продукта заодно проверяли и старую функциональность. Само по себе масштабирование выявило неожиданные технические проблемы: Неоднородный системный ландшафт
Помимо непосредственно развертывания приложения пришлось сначала позаботиться чтобы везде все было одинаково — версии .Net, Powershell и модули. Это все заняло изрядное время. Сетевое соединение
На некоторых площадках сетевое соединение просто не позволяло прокачивать все компоненты сборки. Шли таймауты, повреждения в процессе передачи. Много чего проверяли и пробовали — не очень успешно. Пришлось остановиться на следующем решении: сценарий сборки доработали так чтобы все результаты упаковывались в один большой архив, который потом нарезался на маленькие фрагменты (по 2 мб). Доработали сценарий развертывания чтобы исключить параллелизм при скачивании артифактов, принимали все 2-х мегабайтные фрагменты и восстанавливали из них то что уже можно разворачивать.  Конфликт с антивирусом
Еще одна странная проблема с которой мы столкнулись — конфликт антивирусного ПО и одно из шагов развертывания: когда из архивов артифактов начинают извлекаться всякие "подозрительные" файлы, типа .js, .dll, то антивирус начинает в них пристально смотреть. И самое странное — антивирус начинает бросаться на файл еще до окончания распаковки и процесс распаковки падает сообщением "файл занят другим процессом". Пока боремся с этим исключая из сканирования локальную папку с артифактами — не очень хорошо, но больше ничего не придумали. После стабилизации процессов сборки и развертывания, мы перешли к "пошивке сапогов для сапожников" — улучшение внутренних процессов. Общая продолжительность — 14 мес Длительнось, особенно на финальном этапе, во многом определялась координацией, и согласованным календарем обслуживания систем. Общие затраты вовлеченных сотрудников заказчика и подрядной организации на все работы, связанные с изменением — примерно 250 человек * дней. Бизнес-анализ, управление проектами, разработка