Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

Что такое непрерывная интеграция?


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

Условия: В динамическом проекте 3 разработчика и мы работаем по Git Flow. Разработчик
создают свою ветку от ветки develop, а через некоторое время (от 3 дней до 3 недель
в зависимости от сложности задачи) вливают в неё изменения. Возможны глобальные и перекрестны
изменения.

Задача: минимизировать затраты времени на интеграцию изменений разработчиков в ветк
develop.

Из опробованных средств было соглашение о стремлении к частому вливанию изменени
в develop. Это, определенно, не помогло. По идее сервер непрерывной интеграции долже
решать эту проблему, но я не могу понять каким образом. В данный момент у нас есть TeamCity
который я развернул для того чтобы он запускал тесты при каждом коммите. И я полага
что всё-таки не это является основной обязанностью сервера непрерывной интеграции :)

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

Я хочу услышать как в ваших проектах организована работа с сервером непрерывной интеграции
Как вы бы организовали нашу работу исходя из текущих условий?
    


Ответы

Ответ 1



Непрерывная Интеграция - это процесс объединения копий нескольких разработчиков общую ветвь несколько раз в день. Continuous integration Trunk (software) Хотя распределенные системы контроля версий позволяют не иметь центрального репозитория именно из-за наличия общих ветвей, объединяющих изменения, основной компонент инфраструктур непрерывной интеграции это прежде всего центральный репозиторий, развернутый на сервер (Github, Bitbucket, Gitlab). В дополнение к этому, часто применяются серверы Continuous Integration, основна функция которых - осуществлять сборку и проверку проекта, например TeamCity. Сервер Continuous Integration никак не поможет с техническими конфликтами систем контроля версий, но он может выявить часть логических конфликтов, например - некомпилирующийс проект, или поломанный тест даже после бесконфликтного с точки зрения системы контрол версий слияния. В некоторый случаях сервер CI может выявить конфликты слияния, например - с помощь функции Automatic Merge в TeamCity (начиная с версии 8.1). Незаменимая вещь - отчет сборке, включая результаты автоматических тестов на кажду фиксацию изменения в Trunk, а так же в других опубликованных ветвях. Это позволяет увидеть если кто-то влил изменения, ломающие тест. У нас собираются все опубликованные feature-ветви, поэтому можно даже отследить как поломанный неделю назад в чьей-то ветке тест мигрировал в trunk, и попросить этог разработчика срочно пофиксить тест. Проблемы объединения изменений возникают, когда разработчик слишком долго не объединя изменения, и сильно "разломал" свою ветвь. При этом проблема больше не в том, что разработчи не публиковал изменения, которые еще не готовы, а в том, что он не "подливал" себе чужи изменения. Не случайно идеология Git - Pull, don't push. Тех, кто делает только pus и редко делает pull даже называли "пушистиками" в русском сообществе программистов. Небольшой пример - я взялся рефакторить некоторый класс A, удалил из него публичны метод GetX, и заменил в 10 местах использование этого метода на другой, GetY. Предположим, что никто из разработчиков в своих ветвях не пытается вносить изменени в класс A. Это хорошо, потому что даже если мои изменения затронули 10 мест по всем решению, Git имеет шанс разрулить конфликты этих 10 файлов. Кто-то редактировал некоторы из этих файлов, но не трогал ту строку, где вы скоро замените GetX на GetY. Зато один из разработчиков привнес новое использование публичного метода GetX, потом что он не знал, что этого метода уже как бы нет, и уже интегрировал это изменение Trunk. Это уже настоящий конфликт, который Git никогда не сможет разрулить. Мало тог - Git может и не сообщить об этом логическом конфликте, потому что с точки зрения контрол версий файлов конфликта нет! Этот конфликт обнаружится на этапе компиляции, а некоторы другие логические конфликты и на этапе компиляции не обнаруживаются, и здесь становитс ясна роль сервера CI, который выдаст отчет о тестах. Так вот - если вы подливаете себе новые изменения других разработчиков часто, т вы тут же обнаружите этот конфликт, и тут же в своей ветке замените этот GetX на GetY поговорите с другими, чтобы они по возможности не делали этого, и все окей - продолжайт дальше "ломать". Еще один момент - компилируете ли вы перед тем, как сделать merge своей ветви в trunk А что, сделали pull прямо перед push, и все окей, гит доволен. Все сделали pull, и вс ругаются, что у них не собирается проект. Вот для этого и нужен сервер Continuous Integration, в который вы можете опубликоват свою ветвь, сделать pull request, увидеть что сборка прошла, потом уже делаете merge. У нас TeamCity шлет письма всем разработчикам, если не прошел билд, или упали тесты Это очень помогает: сам не заметишь - другие тут же сообщат. Поэтому публикуйте сво ветви, и настройте TeamCity чтобы он собирал буквально все, и гонял по возможности тесты У нас на каждый коммит гоняются только некоторый набор тестов, так, чтобы билд укладывалс в 7 минут примерно. Ночью на транке тестируется билд с полным набором тестов, включа базу данных - это несколько часов. Есть и несколько других методов, как можно уменьшить количество конфликтов. Во-первых, постарайтесь разбить задачу на мелкие шаги, которые меняют решение поэтапно Иногда изменение реализации можно сделать отдельно от изменения API. В первую очеред идут изменения, которые затрагивают API классов, потому что из этих изменений возникае большинство конфликтов. Предупредите других о таких изменениях во всеуслышание, согласуйт и как можно быстрее добейтесь объединения таких изменений, потом убедитесь, что вс сделали pull этих ваших изменений. Здесь помогает утренний скрам, так как другие могут вовремя узнать о том, что в планируете делать, и посоветовать, как обеспечить "бесконфликтность". Иногда можно реализовать изменение так, что новая фича, даже будучи не до конца реализованной не поломает приложения. Например - у нас с десяток интеграций с однотипными партнерами и добавление партнера - это два-четыре месяца. Никто не ныряет в бранч - фича прост присутствует в коде в отключенном на уровне конфигурации режиме. Первый этап, которы подразумевает некоторый рефакторинг API, добавление какого-то базового класса, каких-т значений в справочники - производится по возможности быстро, и интегрируется в trunk возможно это даже будет некий аврал, но такие вещи делаются задолго до следующего релиза После этого можно перейти к постоянной интеграции, и спокойно "пилить" хоть год. Другой вариант - если фича, ради которой разработчики уходят в свой бранч на неделю затрагивает публичные интерфейсы существующих классов, то можно выделить задачу по изменени API в отдельный бранч, интегрировать его часто, и в основном бранче фичи подливать себ эти изменения так же, как его подливают себе остальные. Хорошо что Git позволяет практическ мгновенно переключаться между ветвями. У нас предусмотрены ветки обслуживания релизов. Например - все основные изменения интегрируются в транк часто, а в ветку релиза ничег никогда не интегрируется. Там делаются только небольшие, точечные изменения, направленны на устранение критических ошибок. Никакого форматирования кода, никакого рефакторинга Все эти изменения подливаются в trunk сразу же, и уже там находится лучшее решение исправляющее ошибку более обстоятельно для следующего релиза. Это позволяет избежат конфликтов интеграции этих ветвей практически полностью. Естественно, есть и неотъемлемые свойства самого проекта, которые могут косвенн влиять на количество конфликтов - это принципы SOLID, о которых уже упомянули в други ответах, при нарушении которых приходится делать изменения сразу в нескольких местах.

Ответ 2



Процитирую принципы из книги «Непрерывная Интеграция», Пол М. Дюваль, Стивен Матиас Эндрю Гловер. Принципы в качестве заголовоков, текст — мои собственные комментарии. 1. Передавайте код часто Это означает, что инфраструктура должна позволять делать частые коммиты и часты мержи в основную ветку, а разработчик должен пользоваться этой возможностью. Хорошо, когда разработчик может взять коммит с небольшими изменениями и на этом коммит запустить функциональные и интеграционные тесты. Если где-то есть ошибка, он замети ее сразу же. При этом юнит-тестов может быть недостаточно, т.к. код может отлично отрабатыват в изолированном окружении, но сломается где-то выше, на уровне интеграции с другим компонентами. Чем более сложен программный продукт, тем интеграция сложнее и тем важне это требование. Для этого нужна СDCI-инфраструктура, которая позволяет на каждом коммите не тольк проводить юнит-тесты, но и создавать приближенное к боевому окружение, на котором можн проводить тесты — как автоматические, так и ручные. Ещё один аспект — это одна ветка на одну фичу. Чем меньшими порциями вносятся изменения тем легче их отслеживать. достаточно крупное изменение будет означать может только один коммит в пару дней. через некоторое время (от 3 дней до 3 недель, в зависимости от сложности задачи вливают в неё изменения Над чем здесь можно работать: Фичи меньшего размера. 3 недели это достаточно долго. Более частые коммиты. Коммит != фича. (Я вообще воспринимаю коммиты как сохраненк в опасной стрелялке и делаю коммит перед каждой дверью в темном углу). Чтобы любой промежуточный коммит можно было запустить в псевдо-боевом окружении прогнать все тесты, включая интеграционные. 2. Не передавайте сбойный код Тут всё достаточно просто. Если регрессионная проверка показывает, что новые изменени вносят баг, эти изменения не нужно сливать в dev. Вроде бы очевидно, но очень неосмотрительн будет предполагать, что 1) все тесты точно пройдены и 2) если они не пройдены, то разработчи не будет сливать свою ветку. Система должна явным образом заставлять проходить все тесты и запрещать передач сбойного кода. Все системы CI также умеют оповещать разработчика о неуспешном построении. Если я сливаю изменения с develop моя текущая работа влияет на работу другого разработчик (или это даже плюс?) Не то чтобы плюс или минус, просто реальность. Подумайте о том, чтобы сливать develo и текущую фичу в каком-то отдельном месте. Возможно, для тестирования интеграции ва понадобится слить сразу несколько фич от разных разработчиков. Либо, если интеграци не на уровне кода, а на уровне отдельных компонент (например, вы пишете сервер, а коллег пишет клиент), то поднимайте полное окружение, в котором компоненты будут построен из ваших веток с фичами. Только когда вы убедились, что в тестовой ветке интеграция успешна, сливайте результа в develop. 3. Ликвидируйте проблемы построения немедленно Чинить ошибки построения — очень приоритетная задача. Если где-то сломался скрип построения, или упал сервер интеграции, или устарели тесты — нужно идти и чинить. Тако вот ограничение непрерывной интеграции. Если построение выполняется правильно, но ошибки есть в коде — та же ситуация. Задач не считается выполненной, пока не выполнены все проверки и не проведена успешная интеграци (как слияние в dev, так и развертывание на боевом окружении). 4. Пишите автоматизированные проверки разработки Автоматизированные проверки (тесты) требуют человеческих ресурсов только на создани и поддержку, но не на проведение. Поэтому вы сможете проводить их сколь угодно част (а нужно часто, см. пункт 1). Чем чаще проводятся проверки, тем быстрее обнаруживаютс ошибки и тем ниже общая стоимость каждой проверки. Мануальные проверки тоже можно автоматизировать в части управления. Если какая-т часть системы требует ручного тестирования, возможным решением будет при запуске автоматизированног построения создавать задачу на ручное — либо в системе управления тестированием, либ в трекере задач. Отчет в системе управления тестированием выглядит примерно так (это testrail): Автоматизированные проверки — это не только функциональные тесты в каком-нибудь xUni и не обязательно каждая проверка отвечает на вопрос "да/нет". Можно автоматизироват и производить: Построение под все платформы, для которых вы производите свой продукт. Включает себя создание установочных пакетов и их успешную установку через стандартные механизм распространения (Google Play, .msi/.exe, репозиторий с deb-пакетами, скрипт для развертывани сайта...) Создание и проверку резервных копий. Ага, бэкапы нужно проверять. Бывают битые бэкапы бывает что система дает сбой и перестает делать бэкапы. Нагрузочное тестирование, если у вас сайт или сервис с API. Полученную статистик нужно как-то анализировать. Можно встраивать проверки на соответствие SLA. 5. Все проверки и инспекции должны быть пройдены Это можно понять двумя способами: Акцент на слово «пройдены». Достаточно очевидное правило — если тесты не проходят значит код ошибочный (или сломались тесты). Акцент на слово «все». Может так случиться, что разработчик просто закомментируе тест, который не проходит, если обнаруживаемую ошибку он пока что не собирается править. Страховкой от таких ситуаций служат инструменты оценки покрытия кода. Оценка покрыти должна быть обязательным этапом автоматизированного построения. Тогда можно будет увидеть что, например, все тесты проходят, но покрытие уменьшилось либо просто недостаточное. Если вы практикуете TDD (а автор вопроса практикует, я точно знаю), то пункт 2 расширяетс написанием новых тестов. Если тесты и тестируемый код отделены друг от друга, позаботьтес о том, чтобы система CI брала то и другое из нужных веток. 6. Выполняйте закрытое построение Под закрытым понимается интеграционное построение для целей тестирования. Автор книги имеют в виду построение на своей рабочей машине, но нередко используется специально тестовое окружение. Например, если вы пишете клиент-серверное приложение, то можно использоват специально выделенный сервер, на котором развертывается тестируемая версия. В идеале построение производится на каждый коммит разработчика (а коммиты происходя часто). Это реализуется за счет связи между системой контроля версий и системой непрерывно интеграции (например, Jenkins или TeamCity). При обнаружении новой версии в вашей рабоче ветке система должна автоматически запускать построение (в это входит и компиляция и когда необходимо, развертывание на тестовом контуре), следом за которым идут различны тесты. Сервер непрерывной интеграции должен быть достаточно мощным, чтобы отрабатывать компиляци хотя бы не медленнее, чем на собственной машине разработчика. Некоторые задачи в принцип нереализуемы на рабочей машине, например нагрузочное тестирование через WiFi тестируе только сам WiFi. Это также снимает распространенную проблему, когда код компилируетс очень долго, а разработчик уходит гулять/есть/спать/домой. 7. Избегайте получения сбойного кода Если коллега слил в dev сбойный код — не используйте его для дальнейшей работы (код не коллегу). Если вы возьмете этот код и будете его дальше переделывать, вам обеспечен море веселья и какие-нибудь многосторонние слияния, когда коллега исправит ошибку вам нужно будет интегрировать исправления в свой код. Не используйте сбойный код даже если он общается с вашим кодом через какой-то интерфейс Может оказаться, что вы написали какую-то заплатку для компенсации ошибки на той стороне Потом ошибка будет исправлена и придется вырезать заплатку. Конечно, это достаточно идеалистичное требование. Бывает, что ошибка обнаружена уж на бою, все о ней знают, но немедленной правки не предвидится. Тогда вам нужно буде писать заплатку, а потом договариваться об одновременных изменениях на разных сторонах.

Ответ 3



Непрерывная интеграция подразумевает только сборку билдов. Мержи она никак не оговаривает. У вас проблема совсем не не в том, что вы редко вливаете изменения в develop. У ва несколько смежных проблем, которые приводят к последствиям в виде крупных мержей. Ваши разработчики редко вливают изменения из develop в feature branch-и. Т.е. вы не решаете мерж-конфликты между двумя ветками по мере их появления, а откладывает "на потом". Вот это "потом" и вылазит при попытке смержить. Не обязательно физически мержит изменения - git rerere умеет записывать результаты мержа без коммита. Вы заводите ветки не по фичам, а по людям. У вас три девелопера, и они одновременн пишут три фичи? Сконцентрируйтесь на одной. Работа двух девелоперов на одной ветке это нормально! Вы используете относительно тяжеловесный процесс (git flow) на небольшом проект (вас всего трое). Возможно, вам стоит посмотреть в сторону GitHub Flow. Пуллреквест на github сильно облегчат вам жизнь - тем, что в них есть явный индикатор немержабельност веток. И кроме того, TeamCity умеет собирать чек-билды на merge-ветках - результата автомержа - так что вы будете видеть реальную картину. Дополнение из комментариев: GitHub, и как и многие остальные системы с поддержкой PR, не просто проверяют возможност автомержа. Они реально проводят мерж, и создают новый head с именем вида merge/номер_pr TeamСity подхватывает его и запускает билд. Т.е. проверяется возможен ли мерж вообще пройдут ли тесты если вы смержите (до того, как вы действительно смержили) Это позволяет вовремя и автоматически(!) ловить изменения, которые не вызвали конфликты но поломали тесты. Сейчас же вы ради этого мержите (редко, вручную) и ждете билда (которы по сути тоже запускаете вручную, кнопкой push). Основная идея непрерывной интеграции - это действительно непрерывная автоматическа интеграция. Если у вас TeamCity используется только ради проверки ручного мержа - т он вам не нужен. Он просто экономит вам одно нажатие кнопки раз в пару дней. Билды надо собирать на каждый коммит (коммитать и пушить часто и по чуть-чуть - в же все равно в отдельный бранчах работаете) и на каждый потенциальный мерж - т.е. действительн непрерывно.

Ответ 4



В похожей ситуации гугление подсказало: она возникает из-за того, что технически средства — а именно git — не заменяют организации совместной работы. В частности, проблемные слияния возникают из-за того, что два и более независимы разработчика вносят существенные изменения в одни и те же файлы. Косвенно это може свидетельствовать о проблемах с архитектурой проекта. Обычно о том, что принцип едино ответственности нарушен в одном или нескольких классах, и эти классы приходится правит разным людям по разным поводам. Это может также свидетельствовать, что проект в самом начале, и идёт шлифовка то части, которая называется ядром. Соответственно, вариантами решений будут: Обсуждение и утверждение регламента совместной разработки (кто и что, когда и ка может менять). Рефакторинг ядра — разбиение его не более мелкие независимые классы. Аккуратное распределение работ между участниками команды. Сервер непрерывной интеграции не решает проблему слияний. Слияния это специфика Mercurial/Git распределённых систем версионирования. Сервер непрерывной интеграции позволяет контролироват появление проблем интеграции, которые могут возникнуть и в CVS, и в SVN, и даже пр обмене файлами на дискетах.

Ответ 5



Постараюсь ответить на ваш вопрос Хочу услышать как в ваших проектах организована работа с сервером непрерывной интеграции Как вы бы организовали нашу работу исходя из текущих условий? Вот список используемого софта (за исключением студий для разработок) Выбор SVN ил GIT не критичен, это дело вкуса. Данный пример реализован у нас на предприятии. TortoiseSVN — это бесплатный Windows-клиент с открытыми исходным кодом для систем управления версиями Apache™ Subversion®. Статус каждого версированного файла и папки отображается при помощи маленькой пометк поверх основного значка. Таким образом, вы сразу можете видеть состояние вашей рабоче копии. CVS отслеживает только историю отдельных файлов, тогда как Subversion реализуе «виртуальную» версионную файловую систему, которая отслеживает изменения в целых деревья папок во времени. Redmine — открытое серверное веб-приложение для управления проектами и задачами ( том числе для отслеживания ошибок). Redmine написан на Ruby и представляет собой приложени на основе широко известного веб-фреймворка Ruby on Rails. Распространяется согласн GNU General Public License. Данный продукт предоставляет следующие возможности: ведение нескольких проектов; гибкая система доступа, основанная на ролях; система отслеживания ошибок; диаграммы Ганта и календарь; ведение новостей проекта, документов и управление файлами; оповещение об изменениях с помощью RSS-потоков и электронной почты; вики для каждого проекта; форумы для каждого проекта; учёт временных затрат; настраиваемые произвольные поля для инцидентов, временных затрат, проектов и пользователей; лёгкая интеграция с системами управления версиями (SVN, CVS, Git, Mercurial, Bazaa и Darcs); создание записей об ошибках на основе полученных писем; поддержка множественной аутентификации LDAP; возможность самостоятельной регистрации новых пользователей; многоязычный интерфейс (в том числе русский); поддержка СУБД MySQL, PostgreSQL, SQLite, Oracle. Jenkins. Как прежде отмечалось необходимо контролировать работоспособ-ность написанных программны модулей при внесении изменений в дей-ствующий проект, тестировать их на разных платформах сигнализировать об ошибках при построении, для этого используется Jenkins. Инструмент непрерывной интеграции. Запускается в контейнере сервлетов (расширяе функциональные возможности сервера), таких как Apache Tomcat или GlassFish. Поддерживае инструментарий для работы с разными системами контроля версий, в нашем случае Subversion может собирать проекты, а также исполнять shell-скрипты и команды Windows. Автономна сборка проектов на сервере Jenkins может быть назначена на разные события, например производиться по расписанию, либо стартовать, когда другая сборка уже собрана, либ при запросе определённого URL, выкачивая перед этим все обновления из svn, и собира их на всех операционных системах автономно. Плюсы использования Jenkins: Когда кто-то ломает проект, вы узнаете об этом сразу, что позволяет быстро устранить проблему; Вы можете автоматизировать прогон тестов, развертывать приложения на тестовых серверах, выполнять проверку code style и тому подобные вещи; Также в Jenkins можно хранить собранные deb-пакеты, отчеты о прогоне тестов или Javadoc/Doxygen/EDoc-документацию; Данное решение, которое я вам предложу настроено приблизительно на 15-20 программистов Все программисты соблюдают одно простое правило. "Перед коммитом скачай Update, провер совместимость с твоими изменениями и вливай." Так как проект большой. Сделано всег две ветки. 1) Первая. В нее вливаются все изменения разработчиков. И каждый божий день Jenkin непрерывно ее интегрирует. В случае если-что, то пошло не так, то он отправляет уведомлени тому, кто поломал сборку. Сборка к стати производиться на множество ОС. 2) Тестовая. Как правило каждую неделю она мержится с первой. А в течении недел производит сборки под разные ОС. Тестировщики ее пытаются нагнуть. 3) За редким исключением выделяется отдельная ветка для разработчика. Это делаетс в случае, если он начинает вносить серьезные изменения в ядро или библиотеку общег пользования. После того, как ему удастся смержить две ветки, он получает разрешени на коммит.

Ответ 6



Википедия считает так: Непрерывная интеграция (CI, англ. Continuous Integration) — это практика разработк программного обеспечения, которая заключается в выполнении частых автоматизированны сборок проекта для скорейшего выявления и решения интеграционных проблем. В обычно проекте, где над разными частями системы разработчики трудятся независимо, стадия интеграци является заключительной. Она может непредсказуемо задержать окончание работ. Перехо к непрерывной интеграции позволяет снизить трудоёмкость интеграции и сделать её боле предсказуемой за счет наиболее раннего обнаружения и устранения ошибок и противоречий. Короче говоря, это выход обновлений по расписанию. Причём достаточно часто и автоматизированн (например, через Makefile)

Комментариев нет:

Отправить комментарий