GrabDuck

Continuous Integration для PHP. Проясните принцип работы

:

Постоянная интеграция призвана решать много проблем сразу:

  • Исключение человеческого фактора из повторяемых процессов, и, собственно, повторяемость и воспроизводимость этих процессов. Если разработчик может случайно вывалить на продакшен конкретную версию приложения со своими изменениями или забыть в исправленный код отдельной ветке, то постоянная интеграция не дает разработчику это сделать - она устанавливает набор правил и позволяет разработчику пропустить через эти правила свой код, чтобы дать добро на выкладку или отрицательный фидбэк в связи с ошибкой.
  • Предыдущий пункт выливается в то, что постоянная интеграция не способна забыть какие-либо вещи. В то время как в голове у разработчика умещаются плюс-минус последние две недели, интеграция будет сообщать о проблеме все то время, пока проблема существует.
  • Тестирование (с которого, как правило, она начинается). Пока код выкладывается на продакшен без тестирования, никто не может сказать, работает ли он.
  • Превращение кодовой базы в артефакт. Кодовая база - это просто текстовые файлы, артефакт - это готовое к работе приложение. В случае с PHP разница между двумя состояниями может быть минимальна и незаметна, но если вы, например, делаете phar-приложение, то непосредственно подготовкой этого phar-архива будет заниматься CI-сервер. Разработчик может несколько раз за день собирать этот архив, но финальную версию собирает машина, и именно она дает гарантии работоспособности архива.
  • Автоматизацию процесса релиза проекта до одной кнопки. Разница с предыдущем пунктом тоже может быть не очень хорошо заметна, но артефакт - это просто какая-то сборка приложения, в то время как релиз - это конкретная версия приложения с каким-то функционалом. Сборка артефакта и прогонка тестов гарантируют, что приложение работает, но такой артефакт не обязательно содержит в себе весь функционал, который можно выложить, это может быть промежуточная версия - так, если руководитель запланировал в следующей версии веб-сайта новую админку и интеграцию с какой-нибудь соцсетью, то промежуточный артефакт может содержать что-то одно, а в релиз уходит только такой артефакт, который содержит все запланированное. Кроме того (!sic), релиз может состоять и из нескольких артефактов. Сам по себе релиз может быть и автоматическим.
  • Полную автоматизацию процесса от выкладки кода в репозитории до выкладки артефактов в продакшен; в отличие от предыдущего пункта, человек полностью исключается из всей цепочки, а каждая успешная сборка автоматом становится релизом.
  • Дополнительные артефакты, такие, как автоматическая документация (пресловутый PHPDoc), подписи артефактов (чтобы конечный получатель мог убедиться в том, что информация о сборке артефактов соотстветствует действительности).
  • Дополнительный анализ кода. Тесты - это хорошо, но они говорят исключительно то, работает ли тот код, который был протестирован; они ничего не говорят о том, сколько кода было протестировано и насколько хорош этот код. Поэтому интеграция может включать в себя еще и дополнительные отчеты, например:
    • Общее покрытие кода тестами (e.g. 65% кода покрыто)
    • Отчет о покрытии конкретных файлов, строк, логических ветвей и выражений. Здесь начинается самая мякотка, которая может выглядеть вот так - вы просто физически видите, какие строки и в каких тестах были покрыты. Более того, такие отчеты отлично интегрируются с IDE, что позволяет вам отслеживать подобные штуки на своей машине (оставляя CI для мониторинга общего тренда - покрытие растет или падает)
    • Человекочитаемые отчеты о тестах. Когда вы тестируете код, вы формализуете проблему до сравнения реального результат с желаемым, и ошибка 'Failed asserting that 42 is true' или 'Failed asserting that server returned 200' вам ничего не скажет. Однако есть специальные фреймворки, позволяющие вам сгенерировать еще более вкусную мякотку с человеческими описаниями тестами (что мы тестируем? почему появился этот тест? что происходило во время теста? какой use-case проверяется в ходе этого теста?), прикладывать к ним аттачменты, мерять скорость выполнения тестов (если какой-то из них подвисает, то хорошо знать какой, верно? этакий test-insght). Конкретно сейчас я описываю мой любимый allure, но кроме него наверняка есть еще непочатый край утилит. Не пожалейте времени, сходите по ссылке - представляете, насколько вы упростите жизнь в сложном проекте, если к каждому проваленному тесту будет прилагаться (sic!) скриншот страницы, на которой не удалось совершить ожидаемые действия, список шагов, которые должны были быдь пройдены в тесте, конкретный браузер, в котором появились проблемы, и, наконец, какая-нибудь несмешная шутка?
    • Отчеты о статическом анализе кода. Это очередная мякотка, которая надает вам по рукам, если вы строите слишком сложные циклы или пишете нечитаемый код. В то время как анализ реализации логики - это AI-complete задача (после решения которой программисты не очень и нужны, потому что логику может писать сама система), анализ правильно расставленных отступов, повторяемого кода и количества комментариев - это вполне разрешимая задача. Чтобы еще раз впечатлить вас, оставлю очередную ссылку, а чуть позже вернусь к этой теме.
    • Автоматические ченджлоги и отчеты о вкладе команды в проект. Это уже очень специфичная и сложная тема, которой я не касался.
    • Нагрузочное и прочее тестирование, приближенное к реальной жизни и не тестирующее код напрямую (в нетфликсе, например, не пропускают релизы, которые по показателям производительности хуже предыдущих и намеренно убивают серверы, чтобы проверить жизнеспособность системы в критических ситуациях). Если нас интересует конечный продукт, то почему бы не автоматизировать еще и проверку того, что он будет соответствовать нашим ожиданиям скорости?
  • Проверку возможности слияния двух источников кода до реального слияния
  • И, наконец, постоянная интеграция легко интегрируется (pun intended) с различными способами оповещения разработчиков. Следить за процессом билда - утомительное и ненужное дело, поэтому постоянную интеграцию можно настроить на уведомление только в тех случаях, когда изменения что-то ломают; в этом случае молчание системы автоматически означает, что либо все работает, либо интеграция тупо сдохла (это решается мониторингом, который я не буду здесь затрагивать).

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

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

  • В продакшен ушел битый релиз с багами. В ходе разработки новых фич разработчики затронули старый код и все сломали. Кто виноват? Кто внес баг? Кто пропустил этот баг?
  • Разработчики говорят, что нужен срочный рефакторинг. Как оценить, насколько он нужен, как расставить приоритеты при рефакторинге, где находятся наиболее горячие места?
  • Разработчики говорят, что проект недопокрыт тестами и грозятся рисками выкатки нерабочего релиза. Как определить, правда ли это?
  • Разработчики говорят, что у нас в целом ухудшается кодовая база. Опять клянчат рефакторинг, или все действительно идет по наклонной?
  • Другие ситуации, для которых иссякла моя фантазия

Суммируя все вышенаписанное, CI дает вам возможность автоматизировать все рутинные процессы, перенести основные задачи тестирования на машину, нормализовать диалог между менеджерами / разработчиками / отделом качества продукта и проанализировать кодовую базу буквально что изнутри. Пока у вас нет этой штуки, вы не знаете, в каком состоянии текущий продукт, поэтому берете на себя все риски выпуска нерабочего продукта, внезапно открывшейся необходимости рефакторинга, траты времени на бэктрейс багов, возникающих в системах со сложной логикой. Безусловно, это не панацея, и баги, на которые не были написаны тесты, все равно уйдут в продакшен, но без всей этой штуки вы вообще не можете заглянуть внутрь и отследить техническое (и, возможно, не только) качество продукта.

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

  • Каков объем кодовой базы? Если мы берем нового разработчика, с каким объемом кода ему придется ознакомиться, чтобы начать работать?
  • Сколько у нас глобальных констант? Не работают ли у нас макаки?
  • Что у нас с цикломатической сложностью? Корректно ли у нас разносится логика в коде?

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

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