
Обсудим почему CI-инструменты и CI – это совсем про разное.
Какую боль CI призвано решить, откуда возникла идея, какие последние подтверждения что оно работает, как понять что у вас есть именно практика, а не просто установленный Jenkins.
Мысль сделать доклад про Continuous Integration появилась еще год назад, когда я ходил по собеседованиям искал работу. Пообщался с 10-15 компаниями, из них только одна смогла вразумительно ответить что такое CI и объяснить как они поняли, что у них этого нет. Остальные же несли невразумительную чушь про Jenkins 🙂 Ну вот у нас есть Jenkins, он делает сборки, CI! За доклад постараюсь объяснить что же такое Continuous Integration на самом деле и почему Jenkins и подобные инструменты имеют очень слабое к этому отношению.

И так, что обычно приходит в голову при слове CI? Большинству людей придет в голову Jenkins, Gitlab CI, Travis и т.п.

Даже если мы загуглим, то нам выдаст эти инструменты.

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

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

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

А решали они боль совместной работы в команде!

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

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

Один закончил фичу быстрее и смержил в мастер.

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

Чем сложнее объединить свою фичу с общим мастером, Тем больше времени мы на это тратим. И это я еще достаточно простой пример показал. Это пример, где разработчиков всего 2. А представьте, если 10 или 15, или 100 человек в компании пишут в один репозиторий. Вы с ума сойдете все эти конфликты разрешать.

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

Они создали по веточке.

Один смержился, все хорошо, сдал задачу.

Второй разработчик тем временем сдал свою задачу. Допустим, он отдал ее на ревью. Во многих компаниях есть практика – ревью. С одной стороны, это практика – хорошая и полезная, с другой стороны, это нас во многом где-то тормозит. Не будем в это погружаться, но вот отличный пример, к чему может привести кривая история с ревью. Вы отдали pull request на ревью. Разработчику больше нечего делать. Что он начинает делать? Он начинает брать другие задачи.

За это время второй разработчик еще что-то поделал.

Первый выполнил третью задачу.

И спустя какое-то продолжительное время, его ревью опробовали, и он пытается смержиться. И что происходит? Он ловит огромное количество конфликтов. Почему? Потому что пока его pull request висел на ревью, в коде уже много чего поменялось.
Помимо истории с конфликтами, есть история с коммуникациями. Пока у вас веточка висит на ревью, пока она чего-то ждет, пока вы долго пилите фичу, вы перестаете отслеживать, что еще в кодовой базе вашего сервиса меняется. Возможно, то, что сейчас вы пытаетесь решить, это уже решили вчера и можно взять и какой-то метод переиспользовать. Но вы этого не увидите, потому что вы работаете всегда с устаревшей веткой. И эта устаревшая ветка всегда приводит к тому, что вам придется разрешать мерж-конфликт.
Получается, что если мы работаем командой, т. е. не один человек в репозитории ковыряется, а человек 5-10, то чем дольше мы не добавляем свой код в мастер, тем больше мы страдаем оттого, что на в конечном итоге нужно что-то смержить. И чем больше у нас конфликтов, и чем с более старой версией мы работаем, тем больше у нас проблем.

Совместно что-то делать – это больно! Мы друг дружке всегда мешаем.

На този проблем беше обърнато внимание преди повече от 20 години. Първото споменаване на практиката Continuous Integration намерих в екстремалното програмиране.
Екстремалното програмиране е първата agile рамка. Страницата се появи през 96-та година. Идеята беше да се използват определени практики в програмирането, планирането и други, за да бъде разработката колкото се може по-гъвкава, така че да можем да реагираме по-бързо на промени и изисквания от нашите клиенти. И те преди 24 години започнаха да се сблъскват с факта, че ако правите нещо много дълго и настрана, то губите много повече време поради конфликтите.

Сега ще разгледаме словосъчетанието „Continuous Integration“ по отделни думи. Ако го превеждаме буквално, получава се непрекъсната интеграция. Но доколко е непрекъсната не е много ясно, всъщност тя е доста прекъсната. А колко е integration също не е много очевидно.
И затова ви дам в момента цитати от екстремалното програмиране. И двете думи ще разгледаме поотделно.
Integration — Както вече споменах, ние се стремим всеки инженер да работи с най-актуалната версия на кода, за да добавя своя код възможно най-често в общата клонка, за да бъдат това малки клонки. Защото ако са големи, можем да се забием с мерж-конфликти за седмици. Особено, ако имаме дълъг цикъл на разработка като waterfall, където разработчикът се е отправил за месец да работи върху някаква огромна функция. И на етапа на интеграция ще се забие за дълго.
Integration – това е, когато взимаме нашата клонка и я интегрираме с мастера, т.е. мержим я. Има ултимативен вариант, когато сме transbase developer, където се стремим веднага в master да пишем без излишни клонки.
Всъщност, integration – е да вземеш своя код и да го дойдеш до master.

Какво се разбира под термина „континуален“ и какво означава непрекъснатост? Практиката предполагава, че разработчикът се стреми да интегрира своя код възможно най-бързо. Това е неговата цел при изпълнението на всяка задача – да направи така, че кодът му да се появи в главния клон възможно най-скоро. В идеалния свят разработчиците ще го правят на всеки няколко часа. Т.е. взимате малка задача, сливате я в главния клон. Всичко е страхотно. Вие се стремите към това. И трябва да го правите непрекъснато. Каквото и да направите, веднага го слагате в главния клон.
И разработчикът, който нещо прави, е отговорен за това, което е направил, за да работи и да не счупи нищо. Тук обикновено излиза въпросът за тестовете. Искаме да изпълним някакви тестове на нашето комитиране, на нашето сливане, за да се уверим, че работи. И тук може да ни помогне Jenkins.
Но с идеята: да направим промените малки, задачите малки, и веднага да опитаме да ги слеем в главния клон – тук никакви Jenkins няма да помогнат. Защото Jenkins ще ви помогне единствено да стартирате тестовете.
Можете да се справите и без тях. Това не ви пречи. Защото целта на практиката е да се сливате колкото се може по-често, за да не губите много време за конфликти в бъдеще.
Представете си, че имаме 2020 година, по някаква причина без интернет. И работим локално. Нямаме Jenkins. И това е нормално. Все още можете да вземете и да направите локален клон. Написали сте някакъв код. Направили сте задача за 3-4 часа. Превключвате на главния клон, правите git pull, сливате вашия клон. Готово. Ако правите това често – поздравления, имате Continuous Integration!

Какви са доказателствата в съвременния свят, че си струва да влагате усилия в това? Защото всъщност е сложно. Ако опитате да работите по този начин, ще разберете, че ви се налага да планирате, и ще трябва да отделите повече време за декомпозиране на задачите. Защото ако правите man…, няма да можете да се слеете бързо и съответно ще попаднете в капан. Практиката ви вече няма да е налична.
И това ще е скъпо. Няма да можете веднага да работите по Continuous Integration от утре. Всички ще се нуждаете от много време, за да свикнете, много време, за да научите как да декомпозиране задачите, много време, за да се адаптирате в практиката на ревюто, ако изобщо я имате. Защото нашата цел е да внедрим промените днес. А ако провеждате ревю в продължение на три дни, то имате проблеми и Continuous Integration не ви се получава.
Но имаме ли в момента действителни доказателства, които показват, че инвестирането в тази практика има смисъл?

Първото, което ми хрумна – е State of DevOps. Това е изследване, което колегите провеждат вече 7 години. Сега те го правят като независима организация, но под Google.
И тяхното изследване от 2018-та година показа корелация между компаниите, които се стремят да използват краткоживеещи клонове, които се интегрират бързо и често, и имат по-добри показатели за производителност в IT.
Какви са тези показатели? Това са 4 метрики, които те събират от всички компании в своите问ника: честота на внедряване, време за изменения, време за възстановяване на услугата, процент на неуспешни изменения.
Първо, има тази корелация, знаем, че компаниите, които често внедряват, имат значително по-добри резултати. Съществува разделение на компаниите на няколко категории: бавни компании, които произвеждат нещо бавно, средни производители, високи производители и елита. Елита – това са Netflix, Amazon, които са супер бързи, правят всичко бързо, красиво и качествено.

Втората история, която се случи преди месец. В Technology Radar се появи страхотна бележка за Gitflow. Gitflow се различава от всички останали, тъй като клоновете му живеят дълго. Има релизни клонове, които дълго време съществуват, и клонове за функции, които също продължават дълго. Тази практика в Technology Radar премина в HOLD. Защо? Защото хората срещат проблеми с интеграцията.
Ако клонът ти живее много дълго, той започва да загнива и ние започваме да прекарваме повече време, за да внесем каквото и да е изменение в него.
И наскоро авторът на Gitflow каза, че ако имате за цел Continuous Integration, ако искате да внедрявате колкото се може по-често, Gitflow не е добра идея. Той допълни в статията, че ако имате бекенд, където можете да се стремите към това, Gitflow е излишен, защото ще ви забави и ще създаде проблеми с интеграцията.
Но това не означава, че Gitflow е лош и не трябва да се използва. Той е подходящ за други случаи. Например, когато трябва да поддържате няколко версии на услугата или приложението, т.е. когато трябва да предоставяте поддръжка в течение на продължителен период от време.
Но ако говорите с хора, които поддържат такива услуги, ще чуете много оплаквания относно това, че версия 3.2, излязла преди 4 месеца, не включва определен фикс и сега, за да го внедрят, трябва да направят множество промени. Така отново се забавят и цяла седмица се мъчат да съчетаят нова функция.
Както правилно отбеляза Александър Ковалев в чата, корелацията не означава причинно-следствена връзка. Това е вярно. Т.е. няма пряка връзка между Continuous Integration и отличните метрики. Но има положителна корелация, че ако едното е наред, то вероятно и другото също е. Не е факт, но вероятно. Това е само корелация.

Изглежда, че вече правим нещо, изглежда, че вече се сливане, но как да разберем, че наистина имаме Continuous Integration и че се сливането е достатъчно често?
Джез Хъмбъл е автор на Handbook, Accelerate, сайта Continuous Delivery и книгата „Continuous Delivery“. Той предлага следния тест:
- Кодът на инженера попада в основния клон ежедневно.
- При всеки комит стартирате unit-тестове.
- Билдът в основния клон е паднал, но е поправен за около 10 минути.
Той предлага да използвате този тест, за да се уверите, че практиката наистина съществува.
Нами се наложи малко оспорвано. Т. е. ако можете да поправите за 10 минути, значи имате Continuous Integration, звучи малко странно, според мен, но в това има смисъл. Защо? Защото, ако често правите мерж, това значи, че промените ви са малки. Ако малка промяна е причината за проблема с основната версия, ще можете бързо да намерите примера, защото промяната е малка. Имахте малък мерж, в който се промениха 20-30 реда. И, съответно, можете бързо да разберете каква е причината, защото промените са малки, имате много малък обхват за търсене на проблема.
И дори ако след релиза продукцията се развали, ако имаме практика на Continuous Integration, ще ни е много по-лесно да действаме, защото промените са малки. Да, това ще повлияе на планирането. Това ще боли. И, вероятно, най-трудната част от тази практика е да свикнете да разпределяте задачите, т. е. как да направите нещо за няколко часа и все пак да преминете през рецензия, ако имате такава. Рецензията е отделна болка.
Unit тестовете са просто помощник, който ви помага да разберете дали интеграцията ви е преминала успешно и дали нищо не е счупено. Според мен, това също не е съвсем задължителен пункт, защото смисълът на практиката не е в това.
Това е накратко за Continuous Integration. Това е всичко, което има в тази практика. Аз съм готов за въпроси.
Накратко само отново ще подведа итогите:
- Continuous Integration не е Jenkins, не е Gitlab.
- Не е инструмент, а практика, при която колкото се може по-често мержим кода си в основната версия.
- Правим това, за да избегнем огромната болка, която възниква с мержовете в бъдеще, т. е. изпитваме малка болка сега, за да не изпитваме голяма в бъдеще. В това е целият смисъл.
- Отстрани комуникацията преминава през кода, но рядко го виждам, но именно за това е замислено.
Въпроси
Какво да правим с недекомпозируемите задачи?
Декомпозирайте. Какъв е проблемът? Можете ли да приведете пример, когато задача не може да бъде декомпозирана?
Има такива задачи, които не могат да бъдат декомпозирани от думата "совсем", например тези, които изискват много дълбока експертиза и които наистина могат да се решават в продължение на месец до някакъв приемлив резултат.
Ако правилно те разбирам, означава, че имаш някаква голяма и сложна задача, чийто резултат ще бъде видим само след месец?
Да, точно така. Да, оценката на резултата ще може да се извърши не по-рано от един месец.
Добре. В общи линии, това не е проблем. Защо? Защото в случая, когато говорим за клонове, не става дума за клон с функция. Функциите могат да бъдат големи и сложни. Те могат да засягат много компоненти. И, възможно, не можем да ги завършим напълно в един клон. Това е наред. Просто трябва да разделим историята. Ако функцията не е готова до края, това не означава, че някои части от нейния код не могат да се обединят. Например, добавяш миграция и в рамките на функцията има някои етапи. Имаш, да кажем, етап – да направиш миграция, да добавиш нов метод. И тези неща вече можеш да обединяваш ежедневно.
Добре. Какъв е смисълът тогава?
Какъв е смисълът да се обединяват малки неща ежедневно?
Да.
Ако те нещо е счупило, ти го виждаш веднага. Имаш малък фрагмент, който е счупил нещо, така че ти е по-лесно да го поправиш. Смисълът е, че да обединиш малък фрагмент сега е много по-лесно, отколкото да обединиш нещо голямо след няколко седмици. И третият смисъл е, че другите инженери ще работят с вече актуализираната версия на кода. Те ще виждат, че тук са добавени някои миграции, а тук се е появил някакъв метод, който също биха искали да използват. Всички ще виждат какво се случва с твоя код. Именно заради тези три неща се прави практиката.
Благодаря, въпросът е затворен!
(Олег Сорока) Може ли да добавя нещо? Всичко, което каза, е вярно, само искам да добавя една фраза.
Да.
При Continuous Integration кодът се обединява в общ клон не когато функцията е напълно готова, а когато билдът вече спира да се счупва. И вие смело може да комитвате в мастер колкото искате пъти на ден. Вторият аспект е - ако не можете по някаква причина да разделите месечната задача на задачи по поне три дни, говоря за три часа, тогава имате огромен проблем. И фактът, че нямате Continuous Integration – това е по-малкия от проблемите. Това означава, че имате проблеми с архитектурата и инженерните практики са на нулево ниво. Защото дори ако е изследване, все пак трябва да бъде формулирано под формата на хипотези или цикли.
Говорихме за 4 метрики, които отличават успешните компании от изоставащите. Трябва да се достигне до тези 4 метрики. Ако средната задача отнема един месец, първо бих се фокусирал върху тази метрика. Първо бих я намалил до 3 дни. След това бих започнал да мисля за Continuous.
Правилно ли те разбирам, че смяташ, че в цялост няма смисъл да инвестираме в инженерни практики, ако всяка задача отнема месец?
Имаш Continuous Integration. И там има такава идея, че за 10 минути или решаваш проблема, или го отменяш. Представи си, че си го пуснал. Даже имаш continuous deployment, пуснал си го на prod и едва след това забелязваш, че нещо не е наред. И трябва да го отмениш, а вече е минала миграция на базата данни. Разширена е схемата на базата данни, освен това е имало и бекъп, има и данни записани.
И каква алтернатива имаш? Ако отмениш кода, той вече не може да работи с актуализираната база данни.
Базата се движи само напред, да.
При хората с лоши инженерни практики, вероятно, те също не са чели дебела книга за … какво да правят с бекъпа? Ако се възстановяваш от бекъп, означава, че губиш данни, които са се натрупали през този период. Например, работил си три часа с новата версия на базата данни и потребители са се регистрирали. Отказваш се на стария бекъп, защото схемата с новата версия не работи, съответно, тези потребители ги губиш. А те са недоволни, те се оплакват.
За да усвоите целия спектър от практики, подкрепящи Continuous Integration и Continuous Delivery, не е достатъчно просто да научите как да пишете…. Първо, те могат да станат много, което ще е непрактично. Освен това има и куп други практики, като Scientific. Има една практика, която GitHub популяризира в определен момент. Това е, когато имате едновременно стар и нов код. Това е, когато правите недовършена функция, но тя може да връща някаква стойност: или като функция, или като Rest API. Вие изпълнявате и новия код, и стария код и сравнявате разликата между тях. И ако има разлика, логвате това събитие. По този начин знаете, че новата функция е готова да бъде внедрена над старата, ако през определен период от време няма разлики между тези две.
Такива практики са стотици. Бих предложил да започнете с transbase development. Тя не е 100% върху Continuous Integration, но практиките са същите, едно без друго не живее добре.
Ти посочи transbase development като пример, където може да се видят практиките или предлагаш на хората да започнат да използват transbase development?
Да се види, тъй като те няма да могат да я използват. За да я използват, трябва да прочетат много. И когато на човека му възниква въпрос: „Какво да правя с функция, която отнема месец“, това означава, че той не е чел за transbase development. Не бих и съветвал за сега. Бих посъветвал да се концентрират изцяло върху темата как правилно да се архитектурно разбиват големите задачи на по-малки. В това е същината на декомпозицията.
Декомпозицията е един от инструментите на архитекта. Първо правим анализ, след това декомпозиция, след това синтез, след това интеграция. И по този начин всичко се подрежда. И до Continuous Integration все още трябва да се стигне чрез декомпозиция. Въпросите на първия етап се пораждат, а ние вече говорим за четвъртия етап, т.е. колкото по-често се прави интеграция, толкова по-добре. Още е рано да се прави, не би било лошо първо да се нареже монолита.
Необходими са повече стрелки и квадратчета на някаква схема. Не можеш да кажеш, че сега ще покажа архитектурната схема на новото приложение и ще покажа само едно квадратче, в което има зелена бутона за приложението. Във всеки случай ще има повече квадратчета и стрелки. На всяка схема, която съм виждал, те са повече от едно. Декомпозицията дори на ниво графично представяне вече се извършва. Затова квадратчетата могат да бъдат независими. Ако не, то имам големи въпроси към архитекта.
Има въпрос от чата: «Ако ревюто е задължително и отнема дълго време, поне ден или повече?».
Имате проблеми с практиката. Ревютата не трябва да отнемат ден или повече. Това е свързано с предишния въпрос, само малко по-меко. Ако ревюто отнема ден, това означава, че вероятно става дума за някаква много голяма промяна. Значи трябва да се правят по-малки. В transbase development, който Олег препоръча, има такава практика, наречена continuous review. Идеята е, че правим толкова малки pull request по желание, защото искаме постоянно и малко да мърджим. И затова pull request променя една абстракция или 10 реда. Благодарение на това ревюто отнема няколко минути.
Ако ревюто отнема ден или повече, означава, че нещо не е наред. Първо, възможно е да имате проблеми с архитектурата. Или това е голям участък код, например 1000 реда. Или архитектурата е толкова сложна, че човек не може да я разбере. Това е проблем отстрани, но и той трябва да бъде решен. Може би изобщо не е нужно ревю. Трябва да се помисли и за това. Ревюто е нещото, което ви забавя. То носи своите предимства, но трябва да разберете защо го правите. Това е начин за бързо предаване на информация, начин за установяване на вътрешни стандарти, или какво? Защо ви е нужно? Защото ревюто трябва да бъде или много бързо, или изцяло отменено. Това е като transbase development – много красива история, но само за зрели момчета.
По отношение на 4 метрики, аз бих препоръчал да ги вземете наистина, за да разберете какво води до тях. Да погледнете числа, да видите картинката, колко зле е всичко.
(Дмитрий) Готов съм да дискутирам с теб по този въпрос. Цифрите и метриките са хубави, практиките също са полезни. Но е нужно да разберем – необходимо ли е това за бизнеса. Има бизнеси, на които не е нужна толкова бърза промяна. Зная компании, в които не могат да се правят промени на всеки 15 минути. И не е, защото са лоши. Това е жизнен цикъл. За да правиш функции на branches и toggle, са нужни дълбоки познания.
Това е сложно. Ако искате да прочетете повече за историята на функцията toggle, силно препоръчвам. . И има чудесна статия на Мартин Фаулър за функциите toggle: за типовете, жизнените цикли и т.н. Функцията toggle е сложна.
И все пак не отговори на въпроса: "Нужен ли е Jenkins или не?"
Jenkins не е нужен в никакъв случай. Ако говорим сериозно, инструментите: Jenkins, Gitlab ще ви донесат удобство. Ще виждате дали билдовете са се събрали или не. Те могат да ви помогнат, но не заменят практиките. Те само ви дават знак – Ок, не Ок. И то, ако все още пишете тестове, защото без тестове, това е почти безсмислено. Затова е нужен, защото е по-удобно, но генерално можете и без него, няма да загубите много.
Т.е. ако имате практики, това означава, че не ви е необходим?
Вярно. Препоръчвам теста на Jez Humble. Имах двусмислени чувства по последния му пункт. Но като цяло, ако имате три неща – постоянно сливате, стартирате тестове на комити в мастера и бързо фиксирате билд в мастера, то може би не ви трябва нищо повече.
Докато чакаме въпроси от участниците, имам един. Току-що говорихме за продуктов код. А използвал ли си го за инфраструктурен код? Това код ли е, с такива ли са принципите и жизненият му цикъл, или там са различни? Обикновено, когато всички говорят за Continuous Integration и Development, забравят, че има и инфраструктурен код. И в последно време той става все по-важен. Трябва ли и там да приложим всички тези правила?
Не е само, че трябва, а ще бъде страхотно, защото така ще улесни живота. Веднага щом работим с код, а не със скриптове на bash, а имаме качество на кода.
Стоп-стоп, скрипт на bash е също код. Не пипай старата ми любов.
Добре, няма да нарушавам спомените ти. Имам лична антипатия към bash. Често се счупва по страшен и неприятен начин. И става неочаквано, затова не го харесвам. Но добре, да предположим, че имаш код на bash. Може би наистина не разбирам и там има нормални рамки за тестване. Просто не съм в темата. И получаваме същите предимства.
В момента, в който работим с инфраструктура като с код, получаваме същите проблеми като разработчиците. Преди няколко месеца се сблъсках с ситуация, в която колега ми изпрати pull request за 1 000 реда на bash. И ти прекараш 4 часа в рецензия. Проблемите са същите. Това все още е код. И все още е работа в екип. Задържаме се на pull request и същевременно решаваме същите конфликти при сливане в bash, например.
Сега активно наблюдавам всичко това с максимално красивото програмиране на инфраструктура. В момента интегрирах Pulumi в инфраструктурата. Това е чисто програмиране. Там е още по-привлекателно, защото имам всички възможности на програмния език, т.е. с обикновени if изработих красиви превключватели и всичко е наред. Тоест, моето изменение е вече в главния клон. Всички вече го виждат. Други инженери знаят за него. То вече е оказало влияние на нещо. Но в същото време не е включено за всички инфраструктури. Включено е за моите тестови среди, например. Затова отговаряйки на въпроса ти отново, необходимо е. Това ни улеснява живота като инженери, работещи с код.
Има ли още въпроси?
Имам въпрос. Искам да продължа дискусията с Олег. Като цяло мисля, че си прав, че ако задачата ти отнема месец, имаш проблем с архитектурата, имаш проблем с анализа, декомпозицията, планирането и т.н. Но имам усещането, че ако започнеш да се опитваш да живееш по принципите на непрекъсната интеграция, ще започнеш да коригираш болките с планирането, защото няма как да избягаш от това.
(Олег) Да, точно. По трудоемкости эта практика сопоставима с любыми другими серьезными изменениями в культуре. Самое сложное - это преодолеть привычки, особенно плохие. И если для внедрения этой практики необходимо значительное изменение привычек окружающих: разработчиков, руководства, продакшн-менеджера, то вас могут ожидать сюрпризы.
Какие могут быть сюрпризы? Допустим, вы решили чаще проводить интеграции. На интеграциях могут возникнуть дополнительные задачи, например, работа с артефактами. А в вашей компании, скажем, есть политика, что каждый артефакт должен быть зафиксирован в какой-то системе учета. Это занимает определенное время. Человеку нужно отметить, что он как релиз-менеджер проверил этот артефакт на готовность к выкладке в продакшн. Если это занимает 5-10-15 минут, но вы делаете выкладку раз в неделю, то раз в неделю потратить полчаса – это небольшой налог.
Если вы проводите Continuous Integration 10 раз в день, то 10 раз нужно умножить на 30 минут. И это превышает рабочее время релиз-менеджера, он просто устает от этого. Существуют постоянные затраты на какие-то практики. И все.
И вам нужно либо отменять это правило, чтобы не заниматься такими вопросами, т. е. больше не проверять вручную степень готовности чего-либо. Вы полностью полагаетесь на автоматизированный набор тестов готовности.
Если вам нужно удостовериться, что главный подписал, и вы не входите в продакшн без его разрешения, то эти препятствия мешают внедрению новых практик. Поскольку если есть связанные с этим затраты, то все значительно усложняется. Поэтому многие не воспринимают изменения радостно, так как привычки людей очень трудно изменить.
Когда человек выполняет привычную работу, он делает это почти без раздумий. Когнитивная нагрузка близка к нулю. Он просто выполняет задачи по навыку, у него в голове уже есть чек-лист, он тысячу раз это делал. Как только вы говорите ему: «Давай отменим эту практику и с понедельника внедрим новую», для него это становится значительной когнитивной нагрузкой. И она возникает для всех сразу.
Затова най-просто е, наистина, тази лукс не всеки може да си позволи, но аз винаги действам именно така, и това е следното. Когато стартира нов проект, обикновено в него се вграждат всички непроверени практики. Докато проектът е още младежки, реално не поемаме големи рискове. Prod все още не съществува, няма какво да се разруши. Затова може да се използва като тренировка. Такъв подход работи. Но не всички компании имат възможност да стартират такива проекти често. Въпреки това, това е малко странно, защото сега всичко е в процес на цифрова трансформация, всички трябва да започват експерименти, за да наваксат конкуренцията.
Тук стигаш до това, че първо трябва да имаш разбиране за това, което трябва да направиш. Светът не е идеален, prod също не е идеален.
Да, тези неща са взаимосвързани.
Бизнесът също не винаги има разбиране за това, че трябва да върви натам.
Има ситуации, при които никакви промени не са възможни. Това е ситуация, когато на екипа се оказва голямо натоварване. Екипът е доста изтощен. Няма никакво време за експерименти. Те от сутрин до вечер разработват функции. А ръководството иска все повече и повече функции. В такава ситуация никакви промени не са възможни. На екипа могат само да кажат, че утре ще работим както вчера, просто трябва да направим още малко функции. Никакви преходи към каквито и да било практики в този смисъл не са възможни. Това е класическа ситуация, в която няма време да се точи брадва, нужно е да се рубят дървета, затова се реже с тъпа брадва. Тук няма прости съвети.
(Дмитрий) Ще прочета уточнение от чата: «Но е необходимо да има голямо покритие с тестове на различни нива. Колко време се отделя за тестове? Някак е скъпо, отнема много време».
(Олег) Това е класическо заблуждение. Тестовете трябва да са достатъчни, за да имате увереност в себе си. Continuous Integration не е нещо, при което първо правите 100 % тестове и чак после започвате да прилагате тази практика. Continuous Integration намалява когнитивното натоварване върху вас, понеже всяка от промените, които виждате, е толкова очевидна, че разбирате - дали ще счупи нещо или не, дори и без тестове. Можете бързо да тествате в главата си, защото промените са малки. Дори и да имате само ръчни тестери, за тях също е по-лесно. Вие пускате и казвате: „Погледни, нищо не се е счупило?” Те проверяват и казват: „Не, нищо не се е счупило”. Защото тестерът знае къде да гледа. Имате едно комит, свързано с един фрагмент код. И това се експлоатира с конкретно поведение.
Тук ти, разбира се, преувеличи.
(Дмитрий) Тук не мога да се съглася. Има практика – разработка чрез тестове, която точно спасява от това.
(Олег) Ето, до тук не бях стигнал. Първото заблуждение е, че трябва да напишете точно 100 % тестове или изобщо да не се занимавате с Continuous Integration. Това не е вярно. Това са две паралелни практики. И те не зависят директно една от друга. Вашето покритие с тестове трябва да е оптимално. Оптимално означава, че вие самите сте уверени в качеството на майстора, в който остава след комита, което ви позволява с увереност да натиснете бутона „Deploy” в петък вечер в пияно състояние. Как постигате това? Чрез ревю, чрез покритие, чрез добро мониторинг.
Добро мониторинг – не е различимо от тестовете. Ако стартирате тестовете един път на pre prod, те проверяват всичките ви потребителски сценарии само веднъж. А ако ги стартирате в безкраен цикъл, то това е вашата разширена система за мониторинг, която безкрайно тества всичко – падна ли или не. В този случай разликата е само в еднократността или многократността. Много добър набор тестове ..., стартирани безкрайно, това е мониторинг. И правилното мониторинг трябва да бъде такова.
И затова как точно ще постигнете това състояние, когато в петък вечер ще направите деплой и ще отидете вкъщи, е различен въпрос. Може би просто сте смел хладнокръвен човек.
Нека да се върнем малко назад към Continuous Integration. Избягахме малко в друга сложна практика.
Втората илюзия е, че MVP трябва да се прави бързо и следователно тестове не са необходими. Всъщност не е точно така. Когато пишете user story за MVP, можете или да го направите на аванта, т.е. да чуете за някаква user story и веднага да започнете да я кодите, или да работите по TDD. И, както показва практиката, това не отнема повече време, т.е. тестовете всъщност са страничен ефект. Практиката на TDD не е само за тестове. Въпреки че се нарича Test Driven Development, всъщност става въпрос за архитектурен подход. Това е методология за писане на точно това, което е необходимо, и избягване на ненужното. Тази практика се фокусира върху следващата итерация на вашето мислене в контекста на създаването на архитектурата на приложението.
Затова не е лесно да се освободите от тези илюзии. MVP и тестове не се противоречат взаимно. По-скоро, ако правите MVP с TDD практика, вие ще го завършите по-добре и по-бързо, отколкото ако действате случайно, без практика.
Това е много неочевидна и сложна идея. Когато чуете, че сега ще пишете тестове и все пак ще направите нещо по-бързо, звучи абсолютно неадекватно.
(Дмитрий) Много хора, когато споменават MVP, просто не им се пише нещо качествено. Това са различни неща. Не трябва да превръщате MVP в нещо лошо, което не работи.
Да-да, прав си.
А след това изведнъж MVP в продукция.
Завинаги.
TDD звучи много непривично, когато чуеш, че пишеш тестове и сякаш вършиш повече работа. Това звучи много странно, но всъщност така се получава по-бързо и по-симпатично. Когато пишеш тест, вече много мислиш за това какъв код ще пишеш и как ще бъде извикан, а също така какво поведение очакваме от него. Не просто казваш, че си написал някаква функция и тя нещо прави. Първо си помислил какви условия има и как ще бъде извикана. Покриваш го с тестове и от това разбираш как ще изглеждат интерфейсите в твоя код. Това оказва голямо влияние върху архитектурата. Кодът автоматично става по-модулен, защото първо се опитваш да разбереш как ще го тестваме, а после го пишеш.
При мен с TDD стана така, че в един момент наех ментор по Ruby, когато все още бях програмист на Ruby. И той казва: «Нека направиш всичко по TDD». Аз си мисля: «Уф, сега ще трябва да пиша нещо допълнително». Споразумяхме се, че в течение на две седмици ще пиша целия работен код на Python по TDD. След две седмици осъзнах, че вече не искам да се връщам обратно. През тези две седмици, като опитвах да прилагам метода, разбрах колко много ми стана по-лесно дори просто да мисля. Но това не е очевидно, затова препоръчвам на всеки, ако имате усещането, че TDD е сложно, дълго и излишно, да пробвате да се придържате към него за две седмици. На мен ми стигнаха две.
(Дмитрий) Можем да разгърнем тази идея от гледна точка на експлоатацията на инфраструктурата. Преди да стартираме нещо ново, правим мониторинг, а след това го стартираме. В този случай мониторингът става нормално тестване. И има разработка чрез мониторинг. Но почти всички казват, че е бавно, мързи ме, направих временно чернови. Ако сме направили мониторинга нормално, разбираме състоянието на CI системата. А в CI системата има много мониторинг. Разбираме състоянието на системата, знаем какво се случва вътре. И по време на разработката всъщност създаваме система, за да достигне желаното състояние.
Тези практики са известни отдавна. Обсъждахме ги преди около 4 години. Но за 4 години почти нищо не се е променило.
На тази нотка предлагам официалната дискусия да приключи.
Видео (вградден като медиа елемент, но нещо не работи):
Източник: habr.com
