Анатолий Кулаков — Build as Code

Анатолий Кулаков — Build as Code01:00:15

Информация о загрузке и деталях видео Анатолий Кулаков — Build as Code

Автор:

DotNext — конференция для .NET‑разработчиков

Дата публикации:

12.04.2024

Просмотров:

2.3K

Транскрибация видео

Спикер 2

Уважаемые друзья, коллеги, участники конференции, всех вас приветствую здесь, в этом первом зале.

Меня зовут Антон Черновцев, я девелопер-адвокат в Яндекс.Клауд, и сегодня я буду вашим ведущим.

И мне хотелось бы, конечно же, начать с того, чтобы представить нашего спикера.

Ну, и вот я готовился к этой, и такой, думаю, надо же какую-нибудь цитату подобрать, чтобы вот миллионер, филантроп, вот это вот все, плейбой, да, вот это все.

И я нашел цитату от 2000 года.

Оказывается, в августе, 9 августа 2000 года Джоэл Спольский, вот тот самый миллионер, филантроп, вот это вот все, что мы любим, написал совершенно замечательный

Пост про тест Джоэла.

Если вы его не знаете, поищите в интернете.

Он очень простой, состоит из 12 пунктов.

И один из этих пунктов говорит, если вы приходите на собеседование и спрашиваете своей компании, а можете ли вы собрать свой код одной кнопкой, то это один дополнительный балл компании на собеседовании.

И мы сегодня...

С Анатолием поговорим, как же можно сейчас, в 2023 году, работать с кодом и создавать свои приложения.

Давайте поприветствуем Анатолия.

Анатолий, вся сцена твоя.

Спикер 1

Спасибо.

Именно так.

И самый большой парадокс Джоэля, который написал это в 2000-м году, то, что у нас и так это все было.

Извини, Джоэль, мы все потеряли.

Мы сейчас будем с вами учиться, как же это восстанавливать.

Прежде всего, меня еще раз зовут Анатолий Кулаков, и я занимаюсь программированием, и в том числе иногда пишу подкасты.

Вот в частности с Игорем Лабутиным мы записываем подкасты все о .NET, о инструментах, об SDK, о статьях каких-нибудь.

Если вам интересна эта тема,

Попробуйте послушать и, может, станете нашим постоянным подписчиком.

Ну и начнем все-таки о компиляторах.

Начнем мы с древних времен, когда наша земля еще была покрыта снегами, и по ней ходили маминты.

Программисты пользовались компилятором вручную.

Они писали файлики, они писали код в своих файликах, попускали это в компилятор.

Компилятор на выходе выдавал объектные файлы и библиотеки.

Мы брали какие-то заголовочки от других библиотек с помощью товарища Линкера, все это вместе как-то соединяли, и на выходе у нас получалась уже какая-то запуска библиотека, модуль или какая-нибудь новая экзешная программа.

И в принципе это был весь пайплайн, который нужно было для жизни, чтобы пользоваться и жить нормально.

Постепенно процессоры становились не такими быстрыми, а кода становилось очень-очень много, и компиляторы начали тормозить.

Они выполнялись очень-очень долго.

И поэтому была придумана такая штука, как зависимость каких-то файликов от того, что они на выходе выдают.

Таким образом появился makefile — это специальный файл конфигурации для утилиты make, который внутри себя описывал, какие файлики должны компилироваться для того, чтобы особые модули какие-то выдать.

Также в этом файле удобно было задавать какие-нибудь алиасы для программ, чтобы, например, очистить папочку от старых билдов в то время, когда вы запускаете повторную компиляцию,

пустить какой-нибудь припроцессор для того, чтобы подготовить ваши ресурсы.

Вот такие тоже удобные командники там появлялись.

И постепенно этот файл становился все сложнее и сложнее, и начали появляться прям отдельные инструменты, которые мы используем с вами до сих пор.

Те же самые MSBuild, те же самые ANT.

Maven и прочие вот такие инструменты, они как раз пронаследовали вот эти все идеи Makefile.

И постепенно эти инструменты также становились сложнее, больше, у них появлялось версионирование, несовместимость между собой, нужно было как-то патчить, инсталлировать, следить за ними, обновлять.

То есть они превращались в такие тоже большие сложные инструменты.

И у нас обычно в больших компаниях есть специальные люди, которые следят за теми инструментами, которые нужно обновлять, инсталлировать, это sysadmin.

И случилась как-то ситуация такая, когда сисадмины пробегали мимо ленивых разработчиков, а ленивые разработчики заметили, что товарищи сисадмины, вы же для того, чтобы поставить все эти инструменты, уже прочитали их документацию, уже прошерстили все формы, уже их настроили, конфигурацию посмотрели, убедились, что она работает.

Вы уже об этих инструментах знаете намного больше, чем мы, разработчики.

А давайте вы будете вместо нас пользоваться нашими инструментами и сами будете использовать то, что заинсталлировали.

Сисадмины сначала отнекивались.

Они сказали, нет, это не входит в наш профиль должности, мы вообще-то администраторы, а не операторы.

На что разработчики заявили, да блин, без проблем, давайте мы вас переименуем, а заодно помоем и побреем.

Вы хоть на людей станете похожими.

но и при этом вы будете пользоваться нашими инструментами.

Те почесались и почему-то решили, да, история умалчивает, может быть, потому что им понравилось в барбершопы ходить, может быть, потому что им зарплату X10 сделали, но они согласились, да, давайте мы тоже умеем собирать, в принципе, какие проблемы.

Проблемы на самом деле были, потому что это огромная разводка.

На самом деле DevOps это не человек, это не отдел, это не должность, это набор практик и инструментов, методологии, которые помогают людям общаться и помогают людям доносить, больше пользы бизнесу приносить, лучше с кодом управляться, лучше понимать, что мы делаем, что мы разрабатываем.

И те большие компании, которые все-таки клюнули на эту уловку и сделали у себя отдельный отдел DevOps, они постепенно начинают сталкиваться с большими проблемами.

Проблема заключается в том, что отдел DevOps постепенно откусывает домен программистов.

То есть в чем это выражается?

Давайте разберемся конкретнее.

Программисты пишут код.

Для того, чтобы этот код собрать, вам нужен DevOps.

По сути, DevOps должен догадаться, какие у вас там SDK стоят, каким версийным компилятором вы пользуетесь, на каком языке вообще вы пишете.

Это все почему-то должен догадываться DevOps.

Когда программисты пишут тесты, вам эти тесты нужно запускать в каком-то окружении, с какими-то фильтрами, с какими-то параметрами, с какими-то приатрибутами.

И обо всем об этом тоже должен догадываться DevOps, для того, чтобы правильно настроить вам pipeline тот же самый.

Дальше программисты колбасят себе какие-то артефакты.

В каком формате они это делают, что там будут за артефакты, откуда они будут выходить и почему, об этом тоже по хрустальному шару должны догадываться те же самые бедные сисадмины.

И, в общем, у них какая-то странная работа довольно получается.

То есть они половину обязанностей программистов взяли на себя.

И если вы думаете, что им это нравится, то нет, им это не нравится.

Давайте посмотрим, какие же проблемы мне сталкиваются.

Прежде всего, они должны знать, какими зависимостями, какими сборками, какими издеками собираются разработчики и пользуются разработчики.

И по сути, если у вас в компании несколько языков, несколько фреймворков, несколько версий, они должны знать это все.

Это довольно сильная когнитивная нагрузка.

Дальше они должны понимать структуру проекта, из чего он состоит, какие артефакты выдает и вообще как с ним работать, что с ним дальше делать.

Из тех артефактов, которые он выдает, они бывают разных форматов, они бывают в разных репозиториях, для них нужны разные зависимости.

В общем, тоже нужно знание о всех возможных форматах, которые существуют в компании.

Это вообще ужас просто.

И если что-то случается с CI, допустим, у вас там TeamCity покраснел, то первое, кого бросают на абразуру, это, конечно же, с админов.

Потому что они должны посмотреть, а что там случилось, не упал ли там какой-то агент или еще что-то случилось.

И если это почему-то разработчик залил какой-то плохой код, то все это пойдет через другие отделы, через тикеты, и до разработчика вернется, дай бог, на следующий день.

Что тоже очень плохо и сильно замедляет разработку.

Ну и обычно сисадмины становятся узким горлышком, потому что отдел девопса всегда маленький.

Не всегда маленький, просто программистов всегда больше.

Потому что программистов больше нужно, они больше пишут кода, и постепенно они упираются в те задачи, которые висят на девопсах.

Настроить пайплайн, поставить зависимости, настроить какие-то переменные среды окружения.

То есть такие банальные вещи, которые, казалось бы, должны уходить в секунду для того, чтобы в проект их добавить.

Но нет.

Можно, конечно, параллельно с программистами растить отдел девопсов,

Но кажется, что это тупиковый вид развития.

Если вы думаете, что разработчики счастливы от сложившейся картины, то на самом деле нет.

Ни разу они не счастливы.

Потому что у них становится очень много ограничений.

Например, они не могут уже обновить свои инструменты.

Вот вы пришли на конференцию, изучили новую технологию, хотите ее к себе принести, а вам там скажут, нет, у нас пайплайн, у нас другой отдел, давайте делайте заказ на .NET 8, через пару лет мы вам его поставим, если нам секьюрити отдел разрешит, или прочую такую странную бюрократию.

Казалось бы, товарищ, я хочу вам лучше сделать, я хочу вам перформанс увеличить и все такое.

Но нет, мы упираемся в вот эти искусственные ограничения, которые сами себе выдумали.

И постепенно разработчики деградируют.

Они даже не знают, какие артефакты выдают их проекты.

В больших компаниях вы спросите, а во что превращается ваше приложение, как оно запускается на продакшене, что оно там делает.

Большинство разработчиков вам не ответит.

Они не знают, во что компилируется, как запускается, кто такие пакеты, где лежат образы.

Во всех этих вещах они не знают.

То есть у них теряется связь с реальностью.

И разработчики даже не знают, где их проект работает.

У нас была такая интересная ситуация, когда разработчики не могли ответить на вопрос, на какой операционной системе в продакшене крутится ваше приложение.

Ну, действительно, разработчики у нас разрабатывают на Маке, заливают это все в билд-агенты, которые прогоняют тесты на Windows, а в продакшене все это крутится на Linux.

И откуда разработчики об этом должны знать, не очень понятно.

То есть из вот этой сложившейся картины неясно.

Потому что разработчики теряют связь с продуктовой разработкой.

То есть те люди, которые должны отвечать за продукт или леять его и холить, у них продукт заканчивается на коммитив мастер.

Вот они все залили, мастер-коммитули, а все там дальше разберутся.

Тестировщики потестируют, девопсы соберут, какие-нибудь там деврелы разместят это на сайтах и все прорекламируют.

К сожалению, это все влияет на качество продукта.

Не на то качество, когда вы колбасите код, а именно на то бизнес-вэлю, которое приносит ваша компания.

И разработчики теряют вот эту связь.

Они забывают о том, что такое продукт, как он развивается, какие метрики, может быть, вам нужно собирать, в общем, и прочее-прочее.

Там дальше очень много возможностей идет, которые, естественно, после коммита в мастер уже никому не видны.

И этот жизненный цикл, который существует в компании, обрубается прямо здесь.

За всем остальным могут следить девопсы, за всем остальным может следить кто угодно, но разработчики написали код и дальше ни о чем дальше не думают.

Хорошо или плохо?

Мне кажется, что плохо, потому что это напрямую влияет на качество их работы.

Они полностью не следят, они не интересуются, им не интересно, что будет дальше.

До них дальше с source-репозитория ничего не существует.

Ну и больше всего из этих отделов, знаете, кто плачет?

Больше всего плачет бизнес.

Потому что вот эти все проволочки, когда нам нужно согласовать 10 тысяч коммитов, а потом донести патч до продакшена, они напрямую влияют на time to market.

И бизнес не может себе это позволить.

У нас были много раз ситуации, когда мы запатчили критическую багу в одну минуту, и потом она пару дней ждала на пайплайне доставки до продакшена, когда дойдет до пользователя.

Но это абсолютно недопустимо, это вообще полный бред.

Хорошо, я надеюсь, я вас убедил, что текущая ситуация, которая складывается в индустрии, она какая-то провальная, она идет не туда.

Давайте подумаем, что с этим можно сделать.

Ну, прежде всего, вернемся к нашей картине, когда доменную разработки делился между двумя командами.

Опять же, нужно понимать, что эти команды разделены обычно на отделы.

То есть это разные начальники, разные процессы, бюрократия и все в этом духе.

Самое легкое, что мы можем здесь сделать, это убрать вот этот ненужный компонент и заставить разработчиков все-таки отвечать за свой собственный код.

Разработчики должны понимать, как собираются системы, как делаются тесты, как создаются артефакты.

На самом деле, если мы представим...

То есть разработчики компилируют код 500 раз на дню.

Для них нет никакой проблемы компилировать код.

Они знают, с какими SDK, каким компилятором и так далее.

Разработчики тесты запускают миллион раз на дню.

Разработчики сами знают, какие артефакты выдаст их проект, потому что они сами их программируют.

Для другого отдела эта информация абсолютно неочевидна.

Они вынуждены читать документацию по артефактам, по компиляторам, по зависимостям и все.

То есть то, что разработчики делают по 100 раз на дню, и у них...

не составит труда эти знания получить там за одну секунду, девопсы могут тратить дни для того, чтобы полностью изучить этот pipeline и как-то его применить.

То есть разница, эффективность работы, она даже не в разах, она просто в экспоненте возрастает.

Эффективность вот в той работе, которую должны были бы делать, по идее, разработчики.

Ну хорошо, сказано-сделано.

Мы, разработчики, хотим теперь правильно научиться компилировать.

Что нам для этого нужно?

Ну, прежде всего, у нас существуют такие билд-инструменты, которые помогают вам выстроить пайплайн, помогают вам каким-то образом настроить тесты, вашу компиляцию и так далее.

Одним из самых популярных инструментов у нас является TeamCity.

TeamCity – это прекрасный инструмент, на нем легкие пайплайны строятся очень легко.

Вы буквально визуально накликиваете мышкой какие-то шаги, например, забилдить приложение, откомпилировать.

Затестировать приложение, развернуть Nuget-пакеты в какой-то Nuget-репозиторий.

Все это делается легко и просто.

Проблемы начинаются тогда, когда мы вспоминаем, что мы кровавый интерпрайз.

И как любой кровавый интерпрайз, мы хотим каких-то своих хитро выдуманных процессов, которые нигде больше нет.

И мы хотим их сами запрограммировать и сами свои костыли, сами свою специфику учесть.

И когда мы хотим это учесть, TeamCity нас радостно встречает вот таким окошком и говорит «Давай, чувак, учитывай, пожалуйста.

Давай, пиши, что хочешь.

Я могу все.

Я мощный инструмент».

И вот в этом окошке вы должны выразить полностью себя как личность, как творчество и напрограммировать все, что вы там хотите.

И как приличный разработчик вот на это все смотришь и спрашиваешь, а где, а как, а что, а где версионирование, чтобы понять, что было месяц назад в этом маленьком окошке, чтобы как-то пропатчить или что-то с ним сделать.

Где вообще история изменений, чтобы там на кого-то спихнуть или посмотреть вообще, кто этот код написал, когда он написал, зачем привязал, какой джире, то есть какой май тому привязал.

Где ветвление, чтобы я мог сделать какие-то эксперименты в этом бранче, что-то поэкспериментировать, а потом вернуться обратно.

Подсветки кода нет, рефакторинга вообще забудьте, какого-нибудь интеллисенса тоже не будет.

Даже такие банальные практики, как код-ревью, дать коллеге посмотреть, оно полностью отсутствует.

Его нужно сделать в сторонних инструментах, потом каким-то образом втыкать туда, мигрировать.

Тестирование, отладка, переиспользование, все вообще забудьте.

Все это окошко сопряжено с кучей багов, которые вам нужно будет какими-то костылями обходить.

И самое главное – это вендерлог.

Как только вы осилите это окошко, напишите какие-то большие свои скрипты с помощью сторонних инструментов, с помощью сторонних тулзов, вы все равно 100% завяжетесь на конкретном инструменте, слезть с которого у вас уже не получится.

По той или иной причине вы потратите очень много времени на переделывание вашего пайплайна.

Очень дорогая разработка, даже дороже, чем писать код, в принципе.

Поэтому вендерлог – это еще одна страшная штука, к которой нас подвигают все эти инструменты, которые билдят код.

Ну хорошо, мы поняли, что в принципе там все плохо.

Вот с этими кастомизациями, с настройками, с энтерпрайзом все плохо.

Пойдемте посмотрим на другую часть, это билд-агенты.

Билд-агенты это штука, которая должна просто брать и запускать компиляцию.

Но на самом деле мы полезли и посмотрели на наши билд-агенты и ужаснулись.

Нас встретили

Растолстевшие билд-агенты.

То есть это уже не просто какая-то штука, которая запускала компиляцию, это штука, которая делала кучу всего.

Ну, например, все наши билд-агенты знали о всех проектах в компании.

То есть они с собой таскали все из ДК.

Десяти лет недавно, даже такого проекта уже давно нет, но из ДК таскается.

Ну, потому что мало ли что, вдруг что-то упадет.

Поэтому билд-агенты представляли себе такую сборную солянку со всем программным обеспечением, которое есть на планете просто.

И вот когда у вас много SDK, разных версий, естественно, версию нельзя повышать для некоторых проектов, поэтому приходится ставить рядышком несколько версий, у вас возникает куча багов.

И эти баги некоторые можно обойти апдейтом, некоторые нельзя, некоторые нужно конфиги какие-то пропатчить, некоторые переменные окружения пропатчить, которые конфликтуют уже с будущими версиями.

Всё это порождало кучу костылей, которые вокруг этих билд-агентов собирались.

И эти билд-агенты именно от этого пухли.

Также нужно помнить, что эти билд-агенты были одни на всех.

Это значит, что если вы ставите новый SDK, тот же самый .NET 8, который вам так нравится, он вполне мог внести конфликты в некоторые существующие библиотеки, и на практике уже такое не раз было, для старых приложений, которые там собираются под старые SDK, но вот инсталляция новой SDK просто не нарушала их pipeline.

И у нас в компании вполне могли поехать какие-то там сборки.

Это тоже недопустимо, это тоже очень плохо.

И все это ведет к большим-большим рискам.

Во-первых, мы не можем просто так обновлять билд-агенты, потому что как только мы что-то новое поставим, у нас есть шанс, что старые приложения попадают.

Мы не можем обновлять SDK новые ставить, потому что они могут конфликтовать между собой.

Мы не можем добавлять, ну, сложно, сложно добавлять новые шаги деплоя.

Вы должны сто раз перетестировать, сто раз перепроверить, что эти новые шаги не влияют на все те проекты, на всю эту сотню проектов, которые уже билдятся на этих агентов.

И редактирование шагов точно такая же ситуация.

Вы не можете просто так взять и поэкспериментировать, и что-то отредактировать.

У вас это все может упасть.

Именно поэтому эти агенты были такие распухшие, такие страшные, и все изменения в них вносились очень медленно и очень долго.

Для сисадминов нужен был отдельный хрустальный шар, отдельная магия, отдельные карты Таро для того, чтобы угадать, что там происходило.

Именно поэтому они...

Все эти агенты нагружали вот такими вот избыточными для них знаниями.

То есть им нужно было догадываться о правильных флагах компиляции, им нужно было восстанавливать правильные переменные окружения, с их точки зрения правильные.

Мы когда там через два года увидели, с какими переменными окружениями компилировалось наше приложение, мы очень сильно ужаснулись.

Им нужно догадывалось, какие версии SDK мы используем, и вот эти вот, опять же, про тестируемые сборки, про пакеты, которые там выдавались, про какие-то артефакты.

Все это нужно было догадываться, и они это делали на своем уровне понимания.

То есть не как мы, например, можем поменять папочку, куда наши артефакты выходят.

аутпутятся, куда они напрямую компилируются, и все, и проблема исчезла.

Нет, они не могут это поменять.

У них ситуация другая.

Они находят по всему приложению, допустим, наши аутпуты и как-то складывают их в одно место, и как-то там подсовывают какие-то файлики, какие-то новые конфиги, половину из этих файликов забывают.

В общем, такие костыли у них возрождаются каждый день.

Как раз все это потому, что они не могут владеть полностью тем доменом, которым владеют разработчики.

Для разработчиков там ничуть не лучше, потому что не очень понятно, что там происходит на этом удаленном сервере.

То есть как тестируется код и вообще где он тестируется, где работает.

Вот как раз с примером, когда у нас разработчик разрабатывал на Маке, заливал на билд-агент, а там все тестировалось под Windows.

А потом все то, что протестировалось хорошо под Windows, все тесты зеленые, оно катилось на продакшен под Linux.

И у нас под Linux на самом деле работала система, которая по факту никогда не тестировалась под Linux.

Конечно, у нас там кросс-платформенный язык, и все там должно работать одинаково под всеми операционными системами, но на самом деле это не так.

На самом деле существует очень много багов, которые вам не позволяют работать одинаково под различными операционными системами, по крайней мере, если вы это специально не программируете, не тестируете и не учитываете.

А у нас оно не учитывалось, потому что, опять же, никто не думал, как оно работает, где оно запускается.

Магия девопсов делала так, что наше приложение могло одновременно работать и под ИИСом, и под Кубернетусом, и об этом никто не знал из разработчиков, они без понятия были.

Поэтому они даже не знали, что такие тесты нужно написать.

Как я уже говорил, для разработчиков огромная боль доставляет смена SDK.

Обновление пакетов, каких-то новых зависимостей, обновление инструментария, установка новых .NET-версий.

В общем, все это шло через большую боль, потому что любое вот это изменение приводило к тому, что наши толстые билд-агенты начинали крашиться, рушиться, потому что там еще куча несовместимости было.

И еще одна интересная штука, мы теряли локальную воспроизводимость.

То есть, когда у вас баг не воспроизводится на локальной машине, но воспроизводится, допустим, на билд агенте или воспроизводится на продакшене.

Вот как его сделать так, чтобы он у меня сейчас здесь воспроизвелся?

Вот это была большая проблема, потому что операционные системы другие, зависимости другие, все другое.

И абсолютно было невозможно повторить некоторые баги, некоторые особенные такие мелкие приятные баги.

На самом деле, повторить – это очень большая тема.

У Microsoft есть отличная статья, которая называется Reproducible Build, то есть как сделать так, чтобы один и тот же код, который вы собираете, выдавал один и тот же результат.

И это вообще нетривиальная задача, если вы задумаетесь.

То есть там нас на пути ждет очень большая куча магических проблем.

Все это связано потому, что Microsoft сделал нам хорошо.

Microsoft позаботился о программистах, чтобы мы не задумывались о том, где ищутся SDK, где ищутся пакеты, какой рентайм запускается.

Все должно работать просто из коробки одной кнопочкой.

Поэтому там существует интерактивный поиск SDK.

Если мы не нашли какую-то версию, мы ищем какую-то совместимую с ней, может быть.

Не нашли ее, заглядываем в папочку с Visual Studio.

Можем оттуда какие-то библиотеки подтащить.

В Visual Studio нет, можно стырить компилятор у F-Sharp.

Такое тоже есть.

И вот что в итоге в вашем пакете положится, что в итоге запустится в вашем продакшене, вы вообще не можете ответить без контроля вот этого интеллектуального поиска SDK.

Такая же система точно с рантаймом.

Рантайм можно подменить как угодно.

Рантаймы можно взять из других версий, пропатченные, не пропатченные.

Половину версий взять оттуда, половину оттуда.

И все это делается, все это берется, если вы не контролируете ту систему, в которой это все запускается и в которой ищется.

Пути поиска тех же самых зависимостей пакетов точно так же контролируются с помощью интеллектуальной системы.

Еще есть классная оптимизация в Toolchain, когда скачивает все пакеты, он не скачивает XML-документацию.

Ну, для того, чтобы собрать вам, откопилировать проект, вам XML-документация не нужна, правда же?

Это такая хорошая оптимизация, потому что иногда XML-документации бывает много, и нормальная хорошая оптимизация.

Но проблема в том, что иногда с XML-документацией он еще не скачивает XML-конфиги.

Потому что этот сволочь определяет XML, то есть он считает XML-документацией все, что кончается там на XML.

В общем, иногда ваши конфиги тоже не могут дойти до продакшена.

В общем, таких много интересных вещей.

Вот ссылочки вниз, почитайте.

Ну и 100% на это все влияет операционная система.

Потому что весь этот интеллектуальный поиск по путям, по различным зависимостям, по различным папочкам, на это все влияет операционная система.

Даже вплоть до того, зависимая она регистрозависимая или не регистрозависимая, у вас может от этого попадать сборка.

Переменное окружение – это вообще магический камень, который способен настроить абсолютно все, что есть в .NET.

Вы можете, например, запустить свой .NET-код, а в итоге получить какой-нибудь PHP-артефакт.

Это все можно сделать с помощью переменных окружений.

Это безумная магия.

И она есть, и DevOps они знают.

Поэтому аккуратнее.

Вообще, они с ними сделают с переменным окружением просто ужасные вещи.

Флаги компиляции – это тоже такая самая близкая, наверное, самая понятная нам вещь.

В зависимости от того, как вы проекты откомпилируете, с какими флагами, точно так же он будет работать у вас на продакшене.

Очень много чего можно подменить или не учесть во время компиляции, сборки, зависимости и прочих вот этих всех шагов.

Ну и вот примерно вот такая картинка перед нами вырисовалась, когда я попытался выписать, как наше одно приложение собирает на каком-то одном билд-агенте.

Как вы можете заметить, здесь куча такая разразная соляночка.

Из башев, xml, powershell, питонов, regex, и что там только не было.

Даже какая-то отдельная скейлбаза поднималась для чего-то, для каких-то своих внутренних нужд.

И в TeamCity это все выглядело с помощью 12 шагов.

То есть нам нужно было 12 шагов сборки и плюс вот эта куча конфигурации, без которой наше приложение не могло собраться и не могло уйти на продакшн.

Естественно, все это писал не один человек.

Тут просто опыт поколений собран.

Каждый девопс, который приходил, я знаю PowerShell, я знаю Bash, я знаю Python.

И каждый решал свои проблемы на том языке, на тем инструментарием, который он владел.

Из-за чего вот и собралось такое зоопарк, с которым вообще невозможно больше работать.

Из-за этого и появились вот эти хрупкие большие билд-агенты.

Вот туда оно все идет.

Это тупиковая ветвь.

Итак.

Я думаю, что я вас убедил в том, что нельзя оставлять на произвол судьбы такое безобразие.

Нам нужно это починить.

Что же все-таки мы хотим?

Во-первых, упростить процесс разработки, сборки.

Сборка не должна быть такая сложная.

Ей не должно быть нужно тысячу конфигов, тысячу питонов, разные рантаймы, разные SDK, еще что-то.

Это слишком сложно.

В одной голове DevOps это не влезет.

Даже в целом отделе головы DevOps это не влезет.

Они в любом случае будут вылезать баги, будут вылезать костыли, и в любом случае мы упремся во что-то плохое.

Следующее.

Нам нужно уменьшить время выпуска.

Бизнес – это самый важный показатель, на который влияет вот этот pipeline.

Должно проходить где-то примерно 5 минут с тех пор, когда вы придумали имя сервиса, и ваше приложение уже на продакшене отдает первые ответы.

И все эти 5 минут должны уходить на тесты.

У нас pipeline был такой, что мы не могли месяц новое приложение, например, паблишить на продакшен.

Это, разумеется, ни в какие ворота не лезет.

Дальше нам нужно раздвижить команду сисадминов, потому что та работа, которая на них сваливается, она абсолютно неподъемная.

И притом она не того уровня, на котором они способны решить.

Они решают проблемы на слишком высоком уровне.

Нам нужно опускаться немножко ниже.

Опять же, растить команду сисадминов – это дело гиблое.

Кажется, что они делают пустую работу и сделают ее абсолютно зря.

И нельзя забывать о вовлеченности разработчиков.

Как я уже говорил, разработчик теряет связь вообще с миром, как только коммитит в мастер.

Это очень-очень плохо.

Разработчик должен думать о продукте в целом.

Как он доходит до продакшена, как им пользуется пользователь, какие метрики он с него снимает.

Получать какой-то фидбэк напрямую и улучшать продукцию.

Время улучшать продукт.

Вот в нашей бывшей системе вот эта связь, она терялась.

И нам как цель, это очень хорошая цель, мы должны туда стремиться.

Ну и вообще не самая последняя вещь ни разу, это избавление от вендерлока.

Чтобы, опять же, какая-нибудь компания, которая внезапно ушла из страны и запретила вам пользоваться их продуктами и запретила использовать их лицензии, она как бы не поставила наш, не стопанула весь наш бизнес, как бы мы могли пользоваться нашими продуктами дальше.

Как вы, наверное, догадались, все эти проблемы способны решить подход Build as Code.

И именно сейчас мы с вами посмотрим, а как же это сделать.

На самом деле подход не нов.

Он существует довольно давно.

Наши деды еще использовали батни, батфайлы, в которых собирали всякие компиляционные штуки, те же самые мейкфайлы можно вспомнить.

И в современных инструментах они тоже есть.

Вот пример Kotlin DSL, который и родной для TeamCity.

Это описание тех же самых шагов TeamCity, но на каком-то программистском языке.

Безусловно, это единственный его плюс.

Минусов намного больше.

Это чужеродный синтаксис.

Опять же, если вы Java-разработчик, которому 30 лет запрещали смотреть на сторону, то для вас Kotlin — это глоток свежего воздуха.

Но для нормального человека вот этим жить не сможет.

Этот синтаксис безумно многословен, он не подходит для ручного редактирования.

Если у вас более или менее много шагов, это все превращается в огромную портянку, которая в 10 раз больше конкурентов.

В общем, жить с этим никак нельзя.

Ну и опять же, это вендерлог.

Даже если мы освоим этот страшный язык и что-то с ним сделаем, мы всегда прибьем себя гвоздями к недружественному продукту.

Это плохо.

Вендерлог мы не хотим.

Если посмотреть шире, то в индустрии существует очень много билд-тулзов, которые сейчас есть на рынке, которые приняты разработчиками.

И в основном большинство из них сошлось на том, что прекрасный формат описания билд-конфигурации – это YAML.

Безусловно, YAML обязан быть у каждого свой.

Все эти тулзы используют YAML, но YAML с разными стайлгайдами, с разными зависимостями, с разными какими-то договоренностями, настройками.

В общем, стандарт они выработать так и не смогли.

И даже если представить, что мы можем взять какой-то из этих инструментов, поставить его локально...

выучить все вот эти конфигурации, каким-то образом под них подстроиться и сделать наши скрипты совместимыми, то мы все равно упираемся в наш пресловутый вендерлог.

Все равно этот YAML не будет совместим с любым другим, и все равно переезд на другой инструмент доставит нам кучу боли.

Самое лучшее, что мы можем сделать, это, конечно же, написать свой инструмент, который удовлетворит всем нашим целям, положит конец во всей этой ваханалии и будет как бы править миром.

Давайте этим сейчас как раз-таки и займемся.

Ну, погнали.

Прежде всего, нам нужно скомпилировать наш проект.

В современном .NET компиляция это просто.

Вы можете выполнить одну команду .NET Publish, и после этого у вас автоматически произойдет и рестор, и компиляция, и все упакуется, и розовым бантиком это все сверху повяжется, и все артефакты вам выдадутся.

.NET это достаточно, вот это .NET тулза, .NET командная строка, достаточно такой геймчейнджер в нашем мире, она зашла к нам довольно незаметно с какими-то примитивными обязанностями, типа откомпилировать, но мы раньше могли компилировать, какие проблемы.

Но на самом деле это довольно мощный поворот, потому что эта утилита является кроссплатформенная.

Она внутри себя имеет кучу плагинов, которые позволяют вам с вашим .NET проектом делать все, что угодно.

Тестировать, код каверидж смотреть, security сканеры какие-то запускать.

В общем, это хороший входной кроссплатформенный инструмент для того, чтобы сделать абсолютно все, что вам нужно просто с помощью одной команды.

Это очень круто.

В общем, вот это мы возьмем себе на вооружение.

Дальше вспомним про всю ту ваханалию, которая творилась у нас с билд-агентами.

Там нет контроля операционной системы, зависимости конфигурации, переменной версии.

Вот это все мы абсолютно не контролируем.

И это очень страшно.

По факту мы не знаем, что работает на нашем продакшене, как оно собирается, с какими зависимостями и что там делает.

Безусловно, эту проблему тоже нужно решить.

Слава богам, человечество придумало, как решать такие проблемы, и у нас есть докер, который делает то, что раньше и представить себе было невозможно.

Это он контролирует полностью, начиная все от операционной системы.

Мы раньше могли это делать на виртуальных машинах, но там слишком много проволочек, а в докере прям все становится вообще очень симпатично, очень красиво.

Давайте я вам покажу.

Вот у меня есть типичный пример докер-файла, который мы, например, создали для наших приложений.

Мы создали единый докер-файл для всех приложений, поэтому его можно было просто копировать, менять всего-навсего пару строчек, где есть имя приложения, и дальше больше ничем не загоняться.

Здесь я просто выбираю имя базовых образов, с помощью которых мы будем собираться.

Объявляю какие-то версии, какие версии наше приложение будет иметь.

И дальше запускаю стандартные команды .NET restore, .NET build, .NET test.

Кстати, заметьте, все команды запускаются с явным указанием переменных компиляций, переменных рестора.

Мы явно их задаем.

Все эти команды отлично описаны в документации Microsoft.

По ним существуют книги, статьи и так далее.

То есть никаких больше неявных командных аргументов, которые мы почему-то не захотели, их больше не существует.

В общем, все здесь описаны, их можно прийти, посмотреть.

И человек, даже не искушенный в синтаксисе докера, прочитать этот файл 100% может.

Дальше у нас запускаются тесты.

.NET Pack пакует какие-то артефакты, Publish собирает конечный образ и дальше запускается Entry Point.

То есть теперь мы видим, что наше приложение хотя бы запускается с помощью команды .NET и в качестве сборки ему передается какая-то конкретная сборка.

Теперь мы понимаем вообще, как наше приложение хотя бы запускается в продакшене.

Уже счастье.

Я здесь использую multi-stage билды.

Это значит, что когда я устанавливаю кучу SDK и компиляторов и тулзов во время компиляции, все это никак не попадает в мой финальный образ.

Мой финальный образ будет зависеть только от рентайма, никакого SDK компиляции там не будет.

Он будет чистый, красивый и очень-очень тонкий, максимально тонкий.

Здесь пару строк, которые нужно было поменять, это всего лишь навсего версии, которые у нас, в принципе, передаются через командный аргумент, и entry point, да, то есть каждая команда вставляла сюда свое собственное название проекта, и, в принципе, все, она могла переюзать этот Docker контейнер без всяких проблем.

Плюсы контейнеризации довольно очевидны.

У нас появляется предсказуемое окружение.

Как я уже сказал, параметры все у нас тут на виду, операционная система на виду, все, что есть у нас на виду.

Мы понимаем уже, как собираются артефакты, потому что мы сами вынуждены, как программисты, вынуждены их собирать и куда-то складывать.

Очень важная штука, что у нас теперь тестирование происходит в той же самой среде, в которой и оно будет работать на продакшене.

То есть под тем же самым линуксом, с теми же самыми зависимостями, пакетами, флагами, все 100% идеально то же самое.

Поэтому все тесты, которые мы запустим, они будут точности в том же самом окружении, как оно будет работать на продакшене.

И это вот сложно переоценить.

Разработчики теперь контролируют все SDK и все зависимости, которые только есть, которые только могут.

Они больше независимы от команды sysadmin.

Если я вдруг после сегодняшней конференции захочу весь мой проект поменять на .NET 9,

Я просто захожу вот сюда, ставлю вот здесь вот такие значения, и все.

И больше никакие сезонмины, никакие девопсы мне не нужны.

Вот это все, что мне нужно для того, чтобы перейти на новый язык.

И это великолепно.

Если я захочу вдруг перейти на Alpine, образ, потому что мне кажется, что чем меньше, тем лучше, то мне тоже достаточно записать здесь одно единственное слово, и никакой девопс даже об этом не узнает.

Это тоже довольно мощная интересная штука.

Также у нас после того, как заведен отдельный Docker-файл, у нас появляется отдельный контейнер для тестирования.

То есть раньше у нас, конечно, были контейнеры, но они создавались какой-то магией на стороне DevOps.

Теперь разработчики, которые отвечают за этот файл, они явно понимают, что у них в руках контейнер, что с ним можно что-то делать.

А отсюда они могут делать что-то другое интересное.

Они могут теперь поднять в Compose какую-нибудь сеть из этих контейнеров, настроить между сервисами связь и запустить end-to-end тестирование, например, между этими контейнерами, что раньше они не могли сделать, потому что вообще не понимали, как оно собирается.

Ну и теперь у нас появился локальный запуск, потому что докер носит с собой практически операционную систему.

Мы можем взять тот контейнер, который ломается на продакшене, запустить у себя локально, подключиться отладчиком и все прекрасно воспроизвести, посмотреть, починить без проблем.

У минусов.

Если мы посмотрим на минусы контейнера, то это небольшой порог входа в технологию.

Вам нужно знать, что такое Docker, базовые вещи, как он работает.

Я думаю, за последние лет десять уже все мучай прожужжали, поэтому мало ли много про Docker все знают, про Docker все слышали.

Немножко непривычный синтаксис.

Как я уже сказал, этот синтаксис специально сделан таким примитивным и банальным, чтобы его мог прочитать абсолютно каждый.

Даже если вы никогда не видели Docker контейнер, вы первый раз на него посмотрите, вы сто процентов ответите, что там происходит.

В этом синтаксисе очень сложно сделать сложные вещи.

Например, циклы всякие, условия даже сделать.

Нет, этот синтаксис более или менее декларативен.

Он вас пытается придержать к простому синтаксису и вообще очень плохо расширяется.

То есть на практике они практически его никак не изменяют, практически никак не расширяют именно для совместимости.

И это можно рассмотреть как минус, потому что язык становится более-менее ограниченным.

Вы не можете делать, опять же, те же самые циклы, процедуры, классы, к которым мы все с вами давно привыкли.

А делать их хочется, потому что на самом деле сборка состоит не просто из .NET Build.

Ей нужно нечто большее.

Например, нужно вычислять версии.

Они могут откуда-то браться, как-то считаться по каким-то определенным формулам.

Например, нужно рассчитывать пути, где мы заберем исходники, где мы заберем ресурсы, куда мы выгрузим какие-нибудь артефакты, которые выдаст наше приложение.

Этим артефактами нужно как-то управлять.

Их нужно залить в репозитории, их нужно просканировать всякими security tools, с ними нужно еще что-то делать.

И это...

Дело не укладывается в концепцию декларативного докер-файла.

Также нам нужна интеграция с системой сохранения секретов.

То есть обычно там пароли, сертификаты, их просто так не раздают.

У них есть определенный какой-то волт, где там все хранится и под роспись всем раздается.

Вот эту роспись получить сложновато будет из докер-файла.

И нам нужно интеграться с системой сборками.

Допустим, если мы хотим сообщить о статусе, там зеленый флажочек, красный, синий флажочек, показать какой-нибудь код кавериш или выдать отчет о тестировании, отчет покрытия.

Нам нужно как-то синтегрироваться с теми инструментами, которые есть в нашей компании.

Это тоже уже как-то не про докер.

И, соответственно, нам нужен инструмент, который будет над докером, который будет вот эти все задачи на себя брать, на это все делать.

На докере мы оставим чисто предсказуемую компиляцию.

Если вспомнить про наши другие приложения, про которые я говорил, практически все билд-агенты сошлись на формате YAML.

У этого формата очень много минусов.

Даже существует такое движение в интернете, которое называется No YAML.

Если интересно, погуглите, и там очень много интересных кейсов найдете.

Например, то, что у YAML есть ошибки спецификации.

То есть если мы возьмем какой-то валидный YAML-документ и его сервизуем, десервизуем обратно, и он будет уже совсем не валидным и совсем не тем, который вы изначально написали.

YAML очень хрупок.

Вы нечаянно поставите пробел где-то не в том месте, нечаянно ошибетесь с переводом строки или, не дай бог, спутаете пробелы с табами, и вы будете весь день искать ошибки.

Потому что эти ошибки невозможно просто предсказать по его выводам, где они случились, что произошло и почему оно начало вдруг падать.

То есть формат очень хрупкий, но несмотря на то, что он был разработан как какой-то упрощенный JS, он при этом стал еще очень ломающимся JS.

Естественно, это никак нельзя тестировать, вам нужно только верить линтерам на слово, и вообще не у всех есть линтеры, и вообще не про это этот формат, этот формат больше про такую прогибку и быструю набросалово.

Также нам хочется, как нормальным программистам, делать условия, функции, цикли, к чему мы привыкли.

Какие-то внешние библиотеки использовать, особенно там, где нужна какая-то интеграция с внешними системами.

Мы хотим подключить то, что уже программисты написали, то, что уже есть.

И постепенно, размышляя в этом направлении, приходишь к выводу, что CICD на самом деле это не декларативная задача.

Изначально она появлялась в виде makefile, как вот эта декларация на мерениях.

И почему-то все инструменты, большинство инструментов современных продолжают придерживаться этой парадигмы.

Тот же самый msbuild, тот же самый ant.

Они все думают, что собирать мы должны в виде декларации.

На самом деле вот это уже все давно не нужно.

Нам не нужна декларация.

Там, где нужна была декларация, мы с ней давно справились.

А вот...

CICD нам нужна что-то мощное, что-то более современное, даже не современное, да, что-то более мощное, более пауэрное.

И из пауэрных у нас есть, конечно же, PowerShell.

Давайте рассмотрим, какими инструментами мы можем решить нашу задачу.

PowerShell — это прекрасный язык.

Он создавался для системного администрирования, из-за чего у него есть куча плюсов.

Например, он идеально информирует инфраструктуру, особенно если это инфраструктура в экосистеме Микрософта.

Создать виртуальные машины, добавить пользователей, отредактировать политики — все это делается с трудными конкретами за просто одну строчку.

Очень крутая штука.

У него низкий парк входа, так как он придумался для системных администраторов, то есть люди, которые должны были быстро вникнуть в программирование, то, в принципе, синтаксис там довольно простой и хороший.

Он идеально подходит для прототипирования.

Как и любой скриптовый язык, он является скриптовым языком.

Там динамически подводятся типы, там есть куча встроенных сервизаторов, форматоров.

В общем, быстро наловать какой-то прототип в одну строчку, которая может в C-Sharp потом развернуться в 300 строк, вообще элементарно можно на PowerShell сделать.

И это родное .NET окружение.

Как ни странно, это .NET оболочка, которая, между прочим, самый распространенный в мире .NET язык, если кто не задумывался.

На каждом Windows компьютере в мире стоит PowerShell.

Поэтому, если вы вдруг запутались в синтаксисе, вы всегда можете опуститься до .NET, вызвать .NET классики, .NET методы с то, чем все мы с вами давно знакомы.

Другой инструмент, который можно рассмотреть, это PSAC.

Это надстройка над PowerShell.

Она предоставляет ту же самую мощь, которую мы говорили про PowerShell, но она оптимизирована специально для Continuous Integration.

У нее есть такие понятия, как шаги, у нее есть понятие зависимости, триггеры и так далее.

То есть те привычные инструменты, которые обычно мы и ожидаем увидеть в инструменте для сборки.

Fake – излюбленная тулза для сборки проектов на F-Sharp.

Опять же, это мощь F-Sharp, если вы ее способны обуздать.

И он оптимизирован специально для CI, точно так же там есть шаги, там есть зависимости, все это у нас тоже есть.

Кейк – это тоже интересная лза, очень безумный синтаксис, куча магии, на которой все это работает, неявные проброски контекстов, неявные какие-то строки, которые появляются из ниоткуда, отвратительная документация, которой много, но вся она автосгенерирована, ее невозможно просто читать нормальному человеку.

Отсутствует ограниченная поддержка интеллисенса, почти ограниченная поддержка раскрашивания.

И вообще такая тупиковая концепция.

Идеальная идея.

Автор Кика сказал, а давайте мы возьмем язык C-Sharp и на нем напишем pipeline.

У нас же C-Sharp программисты, все и так знают язык.

Это было бы очень удобно.

Не нужно что-то новое учить.

Можно использовать уже привычные средства разработки.

И идея была шикарная.

Вот только реализация оказалась странная.

Если посмотрите на этот синтаксис, то у него здесь отрублено абсолютно все.

Отрублена строгая типизация, отрублена поддержка IDE, те же самые рефакторингов, те же самые подсветка синтаксисов.

В общем, все это нет.

Он взял C-Sharp, сделал из него какой-то страшный обрубок и потерял все те плюсы, которые есть в концепции C-Sharp и приобрел те минусы, которых вообще нигде нет.

В общем, какая-то страшная вещь.

Если вы...

вынуждены сталкиваться с этой штукой, то обязательно надо на неё смотреть через раннер, который называется Cake Frosting.

Cake Frosting — это способ более или менее привести вот этот ужасный синтаксис уже к C-sharp, и там что-то можно интеллисенсом поиграться, уже подсветочку сделать и нормально в Visual Studio запустить.

Но каждый раз, когда вы с этим сталкиваетесь, вы вспоминаете про чужеродный синтаксис, опять же, про вот эту потерю типизации, когда у вас шаги передаются строчками.

Вы можете строчку опечататься, обронить, еще что-то с ней сделать.

В общем, каждый раз вы будете натыкаться на костыли вот этого ужасного проектирования, которое было автором, допустим, изначально.

Ну и Кейк Фрост, он довольно-таки молодой, в принципе.

Он не успел сильно захватить аудиторию.

И самая странная концепция в этом инструменте в том, что это самый популярный билд-инструмент.

Если мы отойдем от MS Build, от людей, которые зря шили, пробуют новые инструменты, в общем, они останавливаются все на кейке.

Наверное, потому что он был самым первым и захватил всю эту нишу энтузиастов, которые всю эту волну он к себе слезал.

На самом деле существует еще один шикарный инструмент, который называется Nuke.

И вот если...

Автор Кейка взял самое плохое, чего нет в C-Sharp, то автор Нюка как раз-таки наоборот.

Он взял всю мощь C-Sharp и многократно её усилил.

И это инструмент, который позволяет вам строить билд-код, билд-пайплайн ваш на C-Sharp.

Он прекрасно интегрируется, у него есть шаги, триггеры, все, как вы любите в стандартных билд-инструментах.

У него полноценная поддержка IDE, у него есть честный дебаггинг, у него есть тестирование покрытия кодом, IntelliSense.

Есть абсолютно все, что вы можете себе представить, потому что это обычное, настоящее дотнет-приложение.

Это обычное консольное дотнет-приложение, которое вы можете запустить, открыть в своей студии и сделать все, что вы делаете каждый день с кодом.

И это великолепно.

Это просто шикарно, это просто прекрасно.

Итак, вот у нас был такой вот магазин инструментов, который мы выбрали, то есть который мы на рынке увидели, который мы протестировали, посмотрели, и нам нужно теперь было понять, а какой же инструмент мы выберем.

И, как ни странно, выбрали мы PowerShell.

Не мой вопрос, почему.

Во-первых, быстрое прототипирование рулит.

Вы даже себе поверить не можете, насколько быстро можно наколбасить шикарную работающую программу, шикарный работающий пайплайн, который возьмет те сотни проектов, которые у нас копились 10 лет, возьмет те жирные агенты, которые у нас копились 10 лет, и вместе сведет их подружить.

То есть нам нужен какой-то инструмент, который очень быстро все это сделает.

Также это инструмент, который специально создавался для администрирования, и который очень сильно знаком с разработчиком.

А я напомню, что нам как раз нужно было подружить команду сисадминов и разработчиков.

И поэтому этот инструмент, его понимали и те, и те.

И это прекрасно.

И вообще это командная строка.

Весь пайплайн состоит из запуска командных утилит.

В этом составляется вся его интеграция.

А что может запускать лучше командные утилиты, чем специальная командная строка, которая была создана для запуска командных утилит?

Вообще ничего.

Так, давайте посмотрим, как выглядит у нас

Как выглядит у нас типичный билд на PowerShell?

Здесь я получаю кучу зависимостей.

Это, опять же, такой же скриптик.

Он универсальный для всех приложений нашей компании, если они поменяют там пару строчек.

Все зависимости, которые нужны, мы принимаем явно в виде командной строки.

Вот здесь у нас все зависимости, которые мы собрали за 10 лет, универсализировали.

Их, в принципе, немало, но не то, чтобы совсем много.

С ними вполне можно жить.

То есть всех этих зависимостей 100% хватит для того, чтобы забилдить любое приложение.

Вот эти строчки, которые каждое приложение должно поменять само под себя.

Указать имя проекта, где он располагается, как он запускается и, в принципе, все.

Все остальное универсально абсолютно для всех.

Мы подготавливаем какие-то аргументы, мы определяем какое-то версионирование и пошли стандартные шаги.

Вот шаг, например, который запускает наш докер-контейнер, который мы рассмотрели несколько минут назад.

Здесь, опять же, явные аргументы, все прописано четко и по полочкам.

Какие зависимости брать и откуда их вытаскивать.

Далее мы запушиваем Docker артефакт, который собрали в наш Docker репозиторий.

С этого момента его могут использовать тестировщики, реализеры и прочие люди, которые уже общаются с Docker артефактами.

После этого мы спушим NuGet пакеты.

После этого степа наши коллеги из других команд, например, могут использовать наши контракты, наши клиенты.

Здесь мы создаем билд-релиз.

В данном случае мы используем Octopus Deploy, но не суть.

Вы можете создать билд-релиз в той системе, в которой у вас настроено и что вы там делаете.

Минусы PowerShell.

Во-первых, это все-таки, как ни крути, довольно язык, который непривычен тут над разработчиком.

Поэтому...

мы встретили такое бурное желание не учить PowerShell.

Очевидная вещь.

Но на самом деле мы на это и не рассчитывали.

На самом деле наша главная задача у PowerShell – это было быстрое прототипирование.

То есть мы должны были взять как можно быстрее и наколбасить как можно больше.

И доказать, что эта концепция вообще работоспособна –

что мы способны подружить вот эти десятилетние агенты и десятилетние приложения вместе, что их можно свести, что это вообще не тупиковый ветер развития.

И с этим моментом PowerShell справился идеально.

Очень быстро мы собрали в кучу все зависимости, то, как это должно запускаться.

Мы доказали, что мы можем собирать приложения с стопроцентной гарантией, ничуть не хуже, чем другие инструменты, чем вот эти жирные билд-агенты.

Мы это доказали, мы протестировали, проверили это на нескольких проектов, и время двигаться дальше.

И дальше же, конечно, мы должны выбрать тот инструмент, с помощью которого мы будем жить дальше.

И, как я уже говорил, одна из целей была это вовлечение разработчиков в том, чтобы они полностью занимались тестированием, они полностью занимались сборкой проектов, они полностью занимались автоматизацией.

И, безусловно, разработчиков невозможно было подвинуть, если не использовать C-Sharp.

И на помощь нам пришел Nuke.

Как я уже говорил, у него...

Много всего полезного.

У него практически нет недостатков для .NET-разработчиков.

И поэтому мы все те скрипты, которые мы собрали на PowerShell, систематизировали, обговорили, стандартизировали, мы их просто один в один перенесли на Nuke и поехали жить дальше.

Давайте немножко про Nuke.

Нюк интересен тем, что его автор выступал на сцене .next и презентовал этот инструмент.

Доклад есть в интернете, можно посмотреть.

Вообще про Нюк очень много докладов в интернете, я не буду сильно углубляться, но некоторые концепции хотелось бы вам подсветить.

Во-первых, как я уже сказал, это обычное консольное приложение.

У него даже есть метод статический main, который вы можете запустить под отладчиком и посмотреть, что там внутри у него происходит.

В самом базовом случае этот метод main передает управление engine, который дальше разбирается, что делать в вашей программе.

Вся программа описывается некими шагами, то есть это атомарные какие-то блоки.

Например, откомпилировать приложение, собрать пакеты, запустить тесты, запаблишить эти докер-образы куда-то.

В общем, все это делится на такие отдельные шаги, которыми удобно управлять, которые удобно логируются, которые отсылают какие-то метрики и все такое.

У него есть очень много различных фишечек.

Вот, например, если мы объявим переменную solution, наложим на нее специальный атрибут и скажем generate project true, то во время компиляции запустится source generator, который сгенерит нам переменную, которая полностью отражает структуру нашего solution.

То есть мы можем обратиться в solution.webapplication1, и этот webapplication1 – это именно тот проект, который сейчас у меня есть в solution.

Вот он именно сейчас так назван.

Мы можем проанализировать все проекты, все solution, зависимости и так далее.

Также у него есть хорошая интеграция со всеми внешними билд-тулзами.

Не билд-тулзами, а консольными тулзами.

Огромная библиотека того, что уже написано.

То есть вы ко всем консольным тулзам обращаетесь строго типизированно.

Все параметры, которые вы в этих консольных тулзах не знаете, вам подскажет IntelliSense.

В общем, все, как мы привыкли в C-Sharp, и это прекрасно.

Для нас, как для интерпрайза, была очень важна тема переиспользования, потому что мы хотим сделать какие-то общие библиотеки, вынести какие-то общие команды в отдельные расшаренные блоки и эти блоки потом интегрировать к себе, как обычные, ну, гет-пакеты, допустим.

У Nuke есть очень крутые способы переиспользования.

Одну из них вы можете просто скомпилировать .NET-приложение, какое вам нужно, и распространять его в виде .NET Global Tools, что тоже, в принципе, для маленьких проектов является удобоваренным решением.

Но так как мы сложный интерпрайс, нам подошел другой способ.

Это способ через вот такие интерфейсы-компоненты.

То есть получается, что у нас каждый интерфейс отвечает за какую-то свою область.

То есть есть интерфейс, например, который отвечает за билды.

Интерфейс, который отвечает за publish на get-пакетов.

И в этих интерфейсах мы можем описать полностью имплементацию, то, что мы хотим, чтобы там было.

То есть мы полностью можем рассказать, каким образом в нашей компании паблишатся NuGet-пакеты.

Мы это описываем в каком-то общем компоненте, и дальше эти общие компоненты могут переиспользоваться.

То есть то целевое приложение, которое непосредственно есть в самой команде, оно должно всего лишь навсего поставить себе нюк, разумеется, и пронаследоваться от тех интерфейсов, которые мы уже задекларировали.

То есть, по сути, собрать из блоков те шаги, которые им нужны.

Им нужно запуск тестов, они просто наследуются от интерфейса и все, больше ничего не делают.

Все остальное подхватится динамически.

Нужен push-nugget пакетов, опять же, про наследующие интерфейсы и все.

И на самом деле вот эта реализация, если вы посмотрите, это default interface implementation.

Это новая фишка, которая появилась в каком-то шарпе, которая позволяет вам в интерфейсах сделать имплементацию.

Мне кажется, это первый раз, когда я вижу ее достойное применение в такой суровой жизни от Microsoft.

Если вас вдруг на собеседованиях спросят, зачем нафиг нужны default interface implementation, можете показать в Nuke.

Так, по кусочкам мы собираем это вообще как конструктор.

И вот из такого конструктора, в принципе, может состоять все наше приложение.

То есть конечный билд, он может получиться довольно-таки маленьким.

Как я уже сказал, мы не хотим вендерлоков, но мы хотим уметь с ними быстро интегрироваться.

Вот с такими системами, которые у нас поставляются.

И Nuke имеет очень много интеграций с различными билд-системами.

Давайте посмотрим на примере GitHub, что значат эти интеграции.

Например, когда мы разделили свой код на вот эти шаги, то эти шаги в GitHub будут группироваться по таким вот отдельным степам.

То есть мы уже не весь билдлог видим, а только какие-то шажки, на которых мы можем посмотреть.

Дальше мы можем использовать переменные окружения, специфичные для того build-агента, где мы запускаемся.

Вот здесь есть build-hub-action, он нам передает переменные окружения, такие как hash-set-commit, такие как имя ветки, в которой мы собираемся.

Все это можно строго типизировано использовать в вашем коде и делать на основании какие-то выводы.

Артефакты, которые мы собираем, очень удобно можно просматривать в GitHub на отдельной страничке.

В общем, Nuke тоже умеет рассказывать существующему окружению, что он выдал какие-то артефакты, и там вы их можете скачать, посмотреть, открыть.

Отдельно стоит упоминание такая прекрасная штука, как генерация конфигурации.

Чтобы полностью отвязаться от вендоров, вам нужно все-таки автоматизировать вот этот процесс, когда вы мышкой накликиваете шаги, например, в TeamCity, который единственный шаг, допустим, запустить ваш билд PS1.

Это еще полбеды.

А вот в гитхабах обычных и аффейерах вам нужно для того, чтобы интегрироваться с ними, выучить все-таки тот YAML-синтаксис, который они нам навязывают.

Мы не хотим этого учить, мы не хотим завязываться на этот синтаксис.

Инюк нам предлагает шикарное решение.

Он говорит, что вы навесите атрибуты,

Строго типизированно укажите, от какого имиджа вы хотите пронаследоваться и где вы хотите тестировать, и как вашу компиляцию по какому триггеру поджигать, а все остальное я вам сгенерирую сам.

То есть он сгенерит тот YAML-файлик, который вы можете подложить к GitHub, и GitHub автоматически запустит ваше Nuke-приложение.

Это прекрасно, мне не надо разбираться с этим синтаксисом.

Кстати, вот в этом синтаксисе он учел, что я публикую какие-то артефакты, и GitHub уже здесь рассказал, что будут вот такие артефакты вот такой папочки, и ты их не забудь подобрать.

То есть он учитывает то, что вы пишете внутри шагов, не только то, что вы написали в этом атрибуте.

Он анализирует полностью программу.

Nuke — это обычное консольное приложение.

Вы можете открывать и редактировать в любом редакторе, который вам нравится.

Но у него есть плагины, которые позволяют сделать немножко какие-то вещи более привлекательными.

Например, вы можете таргет запускать прямо из IDE, какие-то отдельные таргеты, или у вас там добавляется куча анализаторов, которые помогают вам правильно писать код.

Давайте посмотрим, как же выглядит Nuke.

В принципе, самое главное, что сделал PowerShell, это систематизировал и собрал все проблемы и все костыли.

И мы практически один в один перенесли их все в Nuke приложение.

Просто из PowerShell и все.

Как я уже сказал, мы сделали такие базовые компоненты.

У нас базовый Docker Build, который собирает Docker образ.

Вот те самые параметры командной строки, которые мы передали.

Они здесь развешаны красивыми атрибутами.

Nuke их валидирует, запускает.

И вот из кучи таких интерфейсов расшаренных состоит наша общая сборка.

Конечному же приложению нужно всего лишь навсего прорасследоваться от этих интерфейсов.

Мы сделали специально такой интерфейс iDefaultBuild, который внутри себя собрал все те интерфейсы, которые требуют наше стандартное приложение.

Приложение нашей компании должно собираться под докером, должно пушить нугет-пакеты и должно создавать релиз.

То, что делает любое приложение.

И вот если ваше приложение абсолютно стандартное, абсолютно любое, то в вашем коде, в вашем конкретном приложении, чтобы переюзать весь эту функциональность, которую мы один раз написали, достаточно вот этих строк.

И все.

То есть здесь вы определяете имя,

мажорную и минорную версию и стандартный main, который запускает стандартный pipeline.

Если ваше приложение нестандартное, вы хотите что-то там накрутить, дополнительные тесты вызвать, прекомпиляцию, то это также точно элементарно делается.

Добавляете там какой-то шаг, объявляете в nom-dependency, то есть в каком момент вы хотите, чтобы ваш триггер вызвался.

И, пожалуйста, используйте всю мощь нюка, которая вам нужна.

Если вы не хотите так извращаться, вот пять строчек, и ваше приложение собирается, интегрируется во всем нашем корпоративном pipeline, которое только существует.

Давайте еще раз, чтобы у вас в голове все это уяснилось, все это уложилось.

У нас есть билд-агент, который каким-то образом вызывает нашу сборку.

Вся задача этого билд-агента очень элементарна.

Во всех наших проектах в корне лежит файл build.ps1.

Это все, что нужно знать билд-агенту для того, чтобы запустить наше приложение.

Он ищет этот файл, запускает, все.

Он не думает, никакой проект, никакой версии, никакой язык, ничто там валяется.

Он просто запускает.

Естественно, там для линуксов лежат саши и так далее.

Как только запускается этот скрипт, этот скрипт запускает pipeline nuke.

Pipeline nuke первым делом определяет переменное окружение, рассчитывает версии, рассчитывает пути, еще там что-то рассчитывает, и запускает docker build.

В docker файл мы вынесли такую концепцию, как неинвазивность.

То есть все, что вы делаете в Docker-файле, остается в Docker-файле.

Несмотря на то, что он там паблишит кучу пакетов, собирает какие-то зависимости, собирает какие-то нугеты, он их никуда наружу не сохраняет.

Это никуда не полетит в вашей репозитории.

Он их сохраняет все локально.

Это значит, что разработчик может просто скачать этот Docker-файл, забилдить у себя локально и получить все эти артефакты, которые будут работать на продакшене.

Никуда это не уйдет снаружи.

А вот чтобы эти артефакты ушли наружу,

Если это нужно сделать.

Мы возвращаемся обратно в Nuke Build и дальше пушим Docker контейнеры, дальше пушим Nuget пакеты, дальше создаем Octopus релизы, дальше интегрируемся в систему отчетов и так далее.

Все это уже делается непосредственно в Nuke.

Плюсы, которые мы получили.

Это полное виссионирование всего.

Все, что у нас только возможно.

Переменное окружение, операционные системы,

Пакеты, зависимости, SDK, все у нас под полным контролем гита.

Мы знаем, кто, когда, зачем и так далее.

Лучшие инструменты практики, которые есть у разработчиков, с инсенталисенсом, с подсветкой, с рефакторингом, все это мы можем применять.

Полный контроль над процессом сборки.

У нас уже не будет той ситуации, когда кто-то зашел на продакшн, изменил переменку окружения в нашем контейнере, и вот только поэтому наш контейнер работает, а следующий диплой нас все развалит.

Нет, все переменки окружения, они здесь.

Никто на продакшн не заходит, никто руками ничего не меняет.

Мы получили возможность встроить в нашу pipeline security команду.

Как раньше любой sysadmin мог зайти через remote desktop куда-нибудь на машину, на продакшен, на билт-агент и там что угодно поменять.

И это недопустимо, безусловно.

Сейчас же у нас есть стандартное review.

К этому review мы можем подключать security team, и они, например, могут просмотреть, что этот pipeline валидный, он там лишних портов не открывает, он там security сканеры запускает, и все хорошо.

У нас появилась изоляция контейнеров на уровне веток.

Это очень мощная штука.

На самом деле, если вы переходите на новый .NET, допустим, вам нужно и сломать 20 коллег, которые в этот момент активно пушуют в мастер.

Обычно вам нужно было отвести ветку, там что-то перевести, что-то сделать, а дальше начинались проблемы.

Вам это нужно как-то встроить в TeamCity.

То есть там нужно сделать какие-то удобные шаги для того, чтобы они игнорировали старые ветки, перенаправили на ваши новые, каким-то образом собирать артефакты, каким-то образом отдельно их не пушить.

В общем, очень много проблем возникало с этим делом.

Сейчас же нет.

Сейчас у нас все хранится в ветке.

Если вы перевели на отдельную ветку, вы можете сделать там все, что угодно, ничего у вас не сломается, разработчики, ваши коллеги продолжают пушить в мастер, вы продолжаете в своей ветке жить, весь пайплайн в вашей ветке.

Ничего нигде не разломается.

Предсказуемость сборок.

У нас уже появилась полная предсказуемость того, что мы получим все-таки на продакшене.

И если вдруг у вас клиент, который год не обновлялся, допустим, и вы хотите воспроизвести те проблемы, которые есть у этого клиента, вы можете забрать код из вашей репозитории годичной давности.

Но вы никогда не заберете пайплайн годичной давности со стандартным подходом, потому что пайплайн постоянно живет.

Переменные окружения меняются, зависимости ставятся.

Это бесперспективно вообще.

В нашем же подходе мы вместе с кодом забираем и пайплайн.

Мы вполне воспроизводим 100% те же самые окружения, те же самые зависимости, которые у нас были год назад.

И это прекрасно.

Мы получили локальную диагностику.

Теперь любой разработчик может взять докер-контейнер, идентичный тому, который будет прокрутиться на продакшене и воспроизвести у себя на машине все, что он захочет.

У нас получилась максимальная погруженность разработчиков.

Теперь разработчики прошли вот этот этап боязни, что там происходит дальше нашего Source репозитория.

Они уже знают, как собирать, как тестировать, как покрывать код кавериджем, как запускать security анализаторы, что происходит с приложением дальше, что такое Docker контейнер, как он капакуется, куда уходит.

То есть мы проделали огромный просто шаг вперед, дальше осталось там совсем чуть-чуть до продакшена.

Самое главное, у нас больше нет никакого вендерлока.

Никто не способен нам диктовать, будет он нам продлевать лицензии или не будет он нам продлевать лицензии.

Мы ровно через 5 минут ухмыльнемся и уйдем на другую билд лзу вообще без каких-либо потерь.

Переносится все элементарно.

Даже те интеграции, которые, казалось бы, у нас остаются, типа интеграция отчета, интеграция статусов, нюк их прекрасно генерит.

Мы получили тонкие агенты.

Все вот эти десятки наших сотни тысяч шагов превратились в один.

Один шаг, который называется запусти файл, билд, который лежит в корне репозитория.

Все.

Больше агентам не нужно знать ничего.

Вот эта простота привела нас к тому, что мы их смогли универсализировать.

И у нас появился просто один шаблон для всех проектов, и все.

Билд-агенты больше ни о чем не знают.

У нас нет никакого устаревания.

Если у нас какой-то проект использовал старую версию, и потом умер...

Эта старая версия умирет вместе с ним.

Если новый проект приносит новую версию, то он опять же, эта новая версия приходит вместе с ним.

Никакого устаревания с ДК нету, никаких ненужных зависимостей нету, все чистится само собой.

Всегда рабочие билды.

Невозможно поломать билд другой команде.

Вы если что-то и поломаете, то даже не билд своей команде, вы поломаете билд просто в своей ветке.

Вы никогда не сможете заэффектить каким-то образом другие продукты или другие команды.

Минимальное внимание девопсов теперь требуется.

Все, что от них требуется, это гарантировать нам, что у нас в системе крутится куча билд-агентов.

То есть что билд-агентов хватает, что ресурсов у них хватает.

Это, в принципе, все, что нужно.

Все остальное.

И билд-агенты довольно примитивные, поэтому гарантии вот эти давать очень легко.

Билд-агенты практически ничего не знают, кроме того, как запустить PowerShell.

И нужно, конечно, чтобы они умели запускать докер.

И интеграция отчетов качества, мы уже все настроили, артефакты сборки у нас тоже уже есть, все это мы выдаем во внешние инструменты.

Вот к таким довольно хорошим результатам, по нашему мнению, мы пришли, вот переделав все наши билд-агенты, мы достигли всех тех целей, которые мы рассчитывали без каких-то снисходительств и без каких-то проблем.

Я не нашел каких-то ресурсов, которые вам можно порекомендовать, потому что эта тема почему-то очень сильно обходится компаниями, мало про нее рассказывают.

В общем, официальная документация Docker, официальная документация Nuke, это, наверное, все, что можно здесь порекомендовать.

Если вы знаете какие-то статьи или какие-то практики, или, может быть, в вашей компании тоже используются подобные подходы, то приходите, пишите, задавайте вопросы, давайте подискутируем и придумаем какие-нибудь практики, которые можно в индустрию дальше внедрять.

Моя почта всегда открыта.

С радостью приму все ваши какие-то замечания или комментарии.

На этом у меня все.

Всем большое спасибо за внимание.

Спикер 2

Спасибо.

Спасибо большое.

Очень круто.

Одной кнопкой собрали вот все, как писал Джоэл в 2000 году, только здесь и сейчас, и на современной инфраструктуре.

Так и есть.

Мы старались.

Очень круто.

Так, уважаемые коллеги, у нас есть экспертная зона, где можно будет задать огромное количество всяких разных вопросов.

Так, один вопросик возьмем здесь в зале?

Не успеем уже.

Уже не успеем.

Ну, время кончилось, поэтому все вопросы в экспертном зале.

Еще раз поблагодарим нашего докладчика.

Всем вам большое спасибо.