company_banner

Как мы строим DevOps в команде из 125 разработчиков

    Всем привет.

    Меня зовут Александр Черников, я руководитель разработки в дивизионе «Цифровой Корпоративный Банк» Сбербанка и Сбертеха.

    Расскажу вам сегодня про DevOps в Сбербанк Бизнес Онлайн (СББОЛ), который мы выстроили в немаленькой команде (125 разработчиков) с большим Review (75 ПРов в день). Теперь отлаженный процесс CD(CI) на pull-requests (далее PR) — это неотъемлемая часть работы и наша гордость.



    Итак, что же мы сделали:

    1. Написали специальный плагин для Bitbucket — «Мega Plugin»
    2. Научили его взаимодействовать с Jenkins
    3. Прикрутили так называемые PrCheck (сборка, тесты Selenium, линтеры)

    Процесс в картинке


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

    Что с develop, чувак?


    Когда-то наш develop постоянно ломался из-за каких-то мелких ошибок, которые просмотрели на code-review. Это были ошибки JS runtime, ошибки компиляции Typescript, глобальные ошибки стилей приложения (когда вся страница «разъехалась») и пр. В чате постоянно звучали всем знакомые вопросы: «develop не сломан? Можно обновиться?», «У кого еще develop не собирается? Или у меня одного так?" и другие. Тогда команда была из 10 человек. И на горизонте начали маячить планы вырасти до 10-15 скрам-команд по 9-10 человек. Наши суперАдмины и эксперты (ревьюеры) загрустили.

    Думали решить проблему стабильности через git pre-push hook, но этот подход тоже не заработал по двум причинам:

    1. стабильности не может быть там, где есть человеческий фактор;
    2. жестоко было заставлять всех разработчиков перед push ждать полной сборки проекта, прогона линтеров и других проверок (тогда еще не было тестов Selenium). К тому же большой простой по времени.

    Начали думать в сторону барьера на этапе PR.

    Операция «Jenkins impossible»


    В первых реализациях запуск job делался этим плагином. Т.е. он через каждые 15 мин (cron) обходил PR с новыми комментариями test this please или новые PR, и просто запускал job. После сборки мы в shell скрипте писали коммент в PR (успех/неудача). Эксперты смотрели код, ставили свои апрувы (за англицизмы не судите строго, хорошего синонима не нашёл).

    НО вливать код могли только избранные, god mode. Обычно это был один человек на репозиторий, которому нужно было убедиться в успешной сборке, найти «BUILD SUCCESS», посчитать количество апрувов и только после этого нажать кнопку Merge. И я вам скажу, по опыту, морально это очень тяжело. Вроде и апрувы есть, и «чеки» прошли, а вливаешь всё равно ты, и ответственный тоже ты. Никто из наших больше трех недель не выдерживал. Начались дежурства :) И с точки зрения процесса это все равно было узким горлышком, потому что даже после того, как все требования выполнены, команде нужно было найти того, кто нажмет кнопку. В итоге от 1 часа до целого дня, а порой и неделями команды не могли найти этого «избранного», забившегося в угол Главного Разработчика.

    Стоит упомянуть, что у Bitbucket есть стандартная опция — отображать статус сборки. И ещё merge checklist: минимальное число апрувов, хотя бы одна успешная сборка, все замечания разрешены (галочки) и др. Но нам этого было мало.

    Потом уже только родилась идея плагина, быстро накидали минимальные требования к нему и приступили к разработке. Всего один человек МаратСадретдинов, который ни разу не писал ничего для Bitbucket и не работал с его api, дал нам рабочий прототип уже через месяц (писал в свободное время). Самым приоритетным было требование: получить список PRов, готовых к влитию. Какие критерии мы установили:

    1. сборка прошла успешно;
    2. нужные эксперты поставили апрув (в будущем объединили это в лейблы, о чем расскажу ниже).

    Как это работало:
    Создается PR >> Пишется комментарий test this please >> Наш плагин блокирует кнопку Merge, а github plugin мониторит комменты и запускает job на Jenkins >> Jenkins по окончании присылает успех/неуспех >> Плагин активирует кнопку Merge, если все критерии успешны >> «God mode user» вливает код, каждый раз немножечко постарев.

    Всё. Одна-две недели на отладку, исправление багов, задержек между Jenkins & Bitbucket (каждую секунду опрашивать все PRы было тяжело, потому что плагин сканировал все комментарии). И ура! Вопросы про сломанный develop пропали.

    Но потом всё стало еще интереснее, руководители разработки и жадные разработчики захотели «жира».

    1. Давайте уберем фразу test this please и будем запускать автоматом.
    2. А что, если человек обновил свой PR, надо предыдущую сборку грохать, запускать новую.
    3. А в какой последовательности ее запускать, там же уже очередь на Jenkins, значит он будет вставать в самый конец очереди?
    4. Давайте вливать автоматом! Не руками нажимать.
    5. Давайте создадим лейблы, которые по разным правилам навешиваются на PR, изначально жёлтые. Как только они все становятся зелёными — PR вливается.
    6. Давайте экспертам в Телеграм писать, если у них новый PR или не вливается больше двух дней и т.д.
    7. Не запускать сборку до тех пор, пока все апрувы не собраны
    8. Если сборка прошла, но очень давно (неделя или больше), т.е. «старый» PR, то нужно сбрасывать лейбл успешности.

    Много чего хотели, давайте я расскажу, что же у нас в итоге получилось.

    Labels


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

    team.
    Лейбл твоей команды. Выставляется минимальное число апрувов от твоей команды. Это не обязательно должен быть разработчик, или js-ник, если PR в UI. Главная цель, чтобы команда подтвердила, что разработка движется в том направлении, которое они запланировали. Иногда это могли быть более опытные разработчики, которые до экспертов выставляли замечаниями своему коллеге.

    arch
    Мы себе придумали такой лейбл, когда менялись ядро, общие компоненты, утилиты. Каждый такой PR обычно затрагивал очень многие формы и страницы, и мог существенно поломать функционал. Определялся он обычной регуляркой по структуре проекта (папка src/Core, src/Common и т.п.)

    prCheck
    Самый главный технический лейбл. Гарант надежности. В UI репозитории это tslint, lesslint, jsonlint, typescript, webpack, одно время даже e2e тесты на groovy. На бэке — компиляция, интеграционные тесты API. Всё в докере.

    oracle, security, admin, devops
    Узкоспециализированные эксперты в своих областях.

    sonar
    Это Сонар, на бэке. Сканирует код, заводит таски на правила, которые вы приняли на проекте.

    predvnedrezh
    Специальный лейбл для поры «Предвнедрежа», когда внедрение на носу (одна-две недели), и вливать ничего нельзя. И мы ничего не вливаем. Почти. Ну вы поняли ;)

    not_task, not_story, not_bug, not_test
    Лейблы с приветом от Jira. У PRа всегда есть связи с задачами из Jira, потому что commit без указания номера задачи сделать нельзя (я думаю многие на сервере ставят себе такие git hooks). Плагин просто смотрит тип таски в Jira. Так вот этот лейбл говорит о том, что код правит что-то другое, не то, что вы ожидаете.

    css
    Говорит о том, что в PRе есть файлы стилей, нужен гуру по стилям, верстке и дизайну.

    На этом месте мог бы быть ваш Label

    Также реализовали возможность ручного добавления лейблов (если какие-то правила нельзя регламентировать), автор PR или сам эксперт мог добавить еще экспертов (еще больше экспертов!).

    Еще лейблы можно делать опциональными, они не блокируют кнопку Merge.

    Default Reviewers


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

    Вы спросите, зачем вообще выбирать двух-трех экспертов на PR? Почему бы не назначать весь список на каждый PR? Кто сможет — тот и посмотрит. Но, как говорится, «общее — значит ничье». В битбакете есть колокольчик с уведомлениями, и если у нас в день 50 PRов, то каждому эксперту (допустим, их 10), приходилось постоянно «гнать» этот счётчик к нулю. Это было почти невозможно (учитывая, что эксперты тоже пишут код), опять встал вопрос деморализации команды. Плагин нас всех спас.

    Потом мы добавили возможность отключения эксперта (отпуск, болезнь), и введения личного графика работы. Некоторые команды и эксперты сидят в других городах. Но когда плагин это не учитывал, получалось так, что разработчик в 5 утра МСК создавал PR, и ему назначались 2 москвича, которые приходили к 10 МСК. Хотя были эксперты, которые могли бы посмотреть этот PR сразу же.

    Приоритеты апрувов или как бороться с кумовством


    В одном из репозиториев сервера захотели такую примочку, как приоритеты (или вес) апрувов. Что это такое?

    У вас есть эксперт (допустим Mario), который в команде (допустим Nintendo). Коллега выставляет PR, а Mario апрувит и зеленит сразу два лейбла — nintendo_team & expert. Вроде нормально, он же эксперт. Отвечает за этот код, но всё же подозрения есть. Мы в своём репозитории решили не заморачиваться, а в другом — захотели. Выставили командному лейблу приоритет выше, и следовательно эксперты этой команды не могут позеленить expert. Это забавно, но проблему кумовства между командами (какие-нибудь 2 команды Nintendo & Dendy), так и не решили :) А может ее и нет…

    Клуб зависимых pull-requests


    Еще у нас есть, да и не только у нас, такая потребность — выставлять зависимые PRы на UI & Back сразу, с одновременными правками api например, и проверкой всего приложения на уже новом коде. Для этого придумали доработку плагина «Зависимые PR и их одновременное влитие». В PRе ставишь ссылку, какой PR в другом репозитории тебе нужен, и сборка будет собираться одновременно с твоей ветки и ветки зависимого PRа. Это очень выручает, когда ты меняешь модель api одновременно на клиент+сервер, допустим, был

    //до
    Dog: {age: number, id: string}
    //после
    Dog: {age: string, guid: string}
    

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

    @FindBy("//button[text()="Сохранить"]")
    class MyButton
    

    а в UI коде она по-старому:

    <button>Подтвердить</button>

    тогда тебе надо править опять в двух репозиториях.

    Различные кнопки-команды


    Есть кнопки Restart, которая перезапускает чеки, если вдруг что-то пошло не так.
    Есть кнопка Recalculate, Recycle, если нужно скинуть все лейблы и просчитать заново.
    Есть кнопка «Too long review» для тех, кто любит пожаловаться. Отправляется письмо «куда следует». Возможно, скоро добавим кнопочку «Поменять экспертов», «Пожертвовать 50 руб» или еще что-нибудь важное и интересное.

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

    Спасибо за внимание, пишите вопросы. Надеюсь, наш интересный опыт пригодится вам в работе.

    Сбербанк

    196,00

    Компания

    Поделиться публикацией
    Комментарии 8
      +6
      Очень печалят подобные статьи.

      Во-первых, знатно навелосипедили там, где вполне можно было обойтись стандартным набором функций. (Я, конечно, максимум на 40 человек процесс CI/CD масштабировал, но не думаю, что проект на всего в три раза большую команду как-то сильно сложнее в этом плане.)

      Также, не стоит продвигать плохие практики. Для «зависимых» PR в разных репозиториях обычно поддерживают версионность API и обратно совместимые протоколы. Это нормально, а вот то что вы делаете — это какая-то дичь.

      Наконец, если одной из решаемых проблем является «кумовство», то у меня плохие новости. Проблемы подобного рода нельзя в принципе решать техническими средствами, только административными регламентами, и повышением общей культуры разработки. Есть такая штука как «мотивация», например. И если разработчик не отвечает за качество кода перед собственной совестью прежде всего, то это плохой разработчик, его надо увольнять, а не обвешивать PR кнопочками.
        +1
        можно было обойтись стандартным набором функций

        это вы про Битбакет? вы же понимаете, если бы нам было достаточно возможностей битбакета, мы бы не придумывали плагин ;)
        Для «зависимых» PR в разных репозиториях обычно поддерживают версионность API и обратно совместимые протоколы.

        Мы, конечно, знаем про версионность, обратную совместимость и пр. Представьте у вас есть репозиторий кода (ui) и репозиторий тестов (selenium). Каким способом вы будете править одновременно разметку в html и PageObjects в тестах? Расскажите, интересно послушать ваш опыт в команде из 40 человек.
        не стоит продвигать плохие практики

        мы не заставляем людей уходить от версионности API и лучших практик, а переходить к связанным PR. Просто в нашем проекте версионностью не решишь все проблемы.
        если одной из решаемых проблем является «кумовство»

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

        а может подробнее рассказать, как вы оцениваете команду разработчиков на качество кода + производительность (объем доработок)? Вы просто так пишите про мотивацию, увольнению плохих разработчиков, как будто для вас это ерундовая задача.
          +3
          1) Я юзал и GHE, и ББ, когда он ещё назывался Stash. Как-то сумел обойтись без плагинов в обоих случаях. Максимум тупенький скрипт на крон вешал, чтобы дёргать через штатный REST targeted builds (+deployments) по различным токенам в комментах. Интегрировался не с Дженкинсом, а с Тимсити, но это в целом без разницы.

          2) Править надо в рамках одного коммита. Любое изменение должно быть атомарное, и это догма, нарушать нельзя. Разработчик правит разметку — значит он автоматически обязан поправить и тест ДО того как тот упадёт на CI. А если вы оторвали тесты от кода (и уж тем более разнесли по разным репозиториям и отдали их разным людям) — у меня для вас опять плохие новости. Так нельзя делать, потому что это ересьвыстрел в ногу. В обе ноги.

          3) Ваш проект не уникален, даже если вам так кажется. И уж тем более не является чем-то исключительным по меркам индустрии (потому что таких вообще нет, всё украдено задолго до нас). Вполне можно юзать опыт товарищей из действительно промышленных контор, которые собаку на этом съели. Вот что Мозилла, что Майкрософт весьма подробно описывают в блогах, как они рулят своими проектами. Просто нужно потратить немного (вру, довольно много) времени, чтобы правильно врубиться. Синдром NIH опасен, он хоронит проекты. Я это видел вживую и даже участвовал пару раз. С тех пор учусь на чужих ошибках, а то на своих слишком дорого.

          4) Эт у вас прозвучало как-то совсем не смешно :/

          5) Нет ничего проще, чем уволить плохого разработчика. Но, скорее всего, он сам уйдёт после третьего подряд разгромного ревью кода, особенно если провести таковое в присутствии коллег. Либо ему придётся браться за ум и расти до уровня старших товарищей. И таковые должны не сидеть в своём углу и делать что-то непонятное, а общаться с остальными на постоянной основе, и задавать некий правильный тон в коллективе. Это отнимает время и стоит дорого, но оно в самом деле того стоит.

          Насчёт оценок. Ну… я имею наглость считать себя экспертом (почти два десятка лет код пишу всё-таки, вдобавок, ещё и читаю в гораздо больших объёмах, чем пишу), поэтому очень субъективен, крайне пристрастен, и исхожу из эстетических критериев. Качественный код с моей точки зрения выглядит прилично, опрятен, прост, минималистичен, бездушен, полностью лишён индивидуальных черт, и какого-либо влияния автора. Написан с расчётом на то, чтобы его в любой момент можно было отдать любому другому члену команды. Желательно, делает ровно то, что написано в ТЗ. И если я, глядя на экран кода, не могу понять за пять минут, как он это делает, я его скорее всего заверну. Также меня мало волнует производительность разработчика в строках за день (потому что это вообще не показатель), меня волнует, чтобы фича была реализована корректно. А сколько итераций она пройдёт в процессе — вопрос для отдельного согласования. Как-то так.
            0

            1) Я же написал про подобные плагины (типа гитхаб), который мы тоже пробовали, и скрипты по Крону с тригерами в комментах. Но это все не то. Небо и земля, по сравнению с нашим плагином.
            Давайте так, напишите мне, пожалуйста, каким образом решить главную нашу боль — default reviewers и их распределение? (Это в защиту нашего велосипеда)


            Про команду в 40 человек вопрос — это 40 человек разработчиков или вместе с аналитиками и тестировщиками, и др?
            5) Я бы с радостью прислушался к вашим советам, но в них мало конкретики. Эту теорию мы и сами знаем. Вы случаем не аджайл-коуч сейчас?

        +3
        Фигня какая-то, если честно.
        Вместо веток релизов, в которые вливаются ветки задач и нормального интеграционного тестирования на стендах релизов, придумали какую-то безумную историю с пулл-реквестами. Откуда куда? Из feature-branch'а сразу в master?
        Вы про git flow читали когда-нибудь? Рекомендую.
          +2
          Вместо веток релизов

          зачем же так сразу :) Никаких веток вместо, весь процесс разработки из feature > release > master, как обычно. Я нигде не писал, что у нас одна ветка на все случаи жизни.
          Плагин настраивается для ваших основных веток, допустим release-*, hotfix-*. Остальные ПРы если ребятам надо, выставляют в свои ветки, всей командой могут работать в одной ветке feature.
          нормального интеграционного тестирования на стендах релизов

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

          Так должно было быть или что-то пропустили при копипасте?

          sonar
          Сканирует код, заводит таски на правила

          Я так понимаю, sonar — это какой то скрипт на бэке который запускается по какому-то событию? Он какие-то ключеые слова или файлы ищет в новом релизе или он работает по какому-то другому принципу?
            +1
            что-то пропустили при копипасте?

            спасибо, поправил.

            sonar — это какой то скрипт на бэке который запускается по какому-то событию?

            SonarQube — инструмент статического анализа кода. Вообще насколько я понял, изначально он создавался для построения разных отчетов, но потом у него появились разные инструменты для анализа кода на копипасту, логические ошибки и прочие (подробнее смотрите в наборе правил sonar rules list)

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

          Самое читаемое