Przejdź do treści

Kiedy stosować?

Trunk Based Development pozwala zaadresować problemy, jakie pojawiają się w coraz większych zespołach, które pracują nad tym samym projektem. Ta technika jest dla zespołów, które zaczynają odczuwać negatywne skutki działań na wielu aktywnych branch'ach.

Podstawowym celem jest zwiększenie częstotliwości wydawania zmian i minimalizacja Lead Time.

Lead Time

W kontekście wytwarzania oprogramowania jest to czas jaki upłynął od momentu zdefiniowania wymagania biznesowego do wdrożenia rozwiązania i udostępnienia go klientowi.

Różne zespoły różnie definiują początek tego odcinka czasu. Dla jednych będzie to moment wpłynięcia zgłoszenia od klienta. Dla innych moment rozpoczęcia pracy nad zgłoszeniem. W obu przypadkach odcinek ten obejmuje projektowanie, implementację, testy i wdrożenie.

Jeśli biznes i klienci są zadowoleni z częstotliwości wydawania nowych wersji oprogramowania oraz z szybkości poprawiania błędów, a członkowie zespołu (liczba mnoga!) nie mają problemu z łączeniem efektów swojej pracy, to być może ta technika nie jest dla Ciebie. Jednocześnie chciałbym, abyś się ze mna skontaktował i opowiedział mi... jak?

Uwaga

Jeśli pracujesz nad projektem, w modelu waterfall, w którym wdrożenie następuje po zbudowaniu całego systemu, to nie ma powodu, aby stosować Trunk Based Development. Taki projekt z definicji ma prawo nie działać, aż do zakończenia prac.

O tym, czy jesteśmy gotowi stosować Trunk Based Development, decyduje wiele czynników. Przede wszystkim zespół musi być do tego odpowiednio przygotowany i posiadać odpowiednie zaplecze.

System kontroli wersji

Aby móc integrować swój lokalny kod ze współdzielonym repozytorium kilka razy dziennie, konieczne jest zastosowanie wydajnego systemu kontroli wersji. Jeśli aktualizacja/synchronizacja/pobranie zmian trwa kilka minut, osoba czekająca na taką operację może się rozproszyć i w efekcie stracić dużo więcej czasu.

Continuous Integration

Kluczowe w stosowaniu Trunk Based Development jest ciągłe zapewnienie, że nasza gałąź główna trunk jest stabilna.

Wymagane jest zatem zastosowanie narzędzia, które będzie automatycznie budować, uruchamiać i testować naszą aplikację za każdym razem, kiedy wprowadzona zostanie zmiana, lub kiedy taką zmianę chcemy wprowadzić wraz z pull request'em z krótko żyjącego branch'a.

Zespół powinien dążyć do tego, aby zmiany wprowadzanie przez developerów były testowane lokalnie, zanim wogóle trafią do repozytorium.

Jak tylko okaże się, że wprowadzone zmiany spowodowały błąd, zespół powinien skupić się na ponownym ustabilizowaniu gałęzi głównej trunk, tak by inni członkowie zespołu mogli dalej pracować, i żeby możliwe było wydanie nowej wersji oprogramowania.

Niektóre zespoły podejmują się szybkich napraw bezpośrednio w gałęzi głównej. Inne decydują się na odwrócenie wprowadzonych zmian, by ustabilizować gałąź główną, kupując sobie w ten sposób czas na analizę problemu.

Zazwyczaj takie sytuacje są spowodowane zbyt małym pokryciem testami automatycznymi lub wprowadzeniem do gałęzi głównej zmian bez czekania na wynik testów automatycznych.

Czas trwania testów automatycznych / czas trwania build'a

Im krótszy czas testów, które dają realny feedback, tym więcej zmian jesteśmy w stanie wykonać w ciągu dnia.

Jeśli developer będzie musiał czekać na wynik pół godziny, może dojść do tego, że zajmie się innym zadaniem, które pochłonie go na tyle, że zapomni o poprzednim. Taka sytuacja niesie ryzyko zwiększenia ilości rozpoczętych i nieskończonych zadań.

Zamiast sprawdzić stan po 30 minutach, developer może sobie przypomnieć o tym po 4 godzinach i dopiero wtedy dowiedzieć się, że jego rozwiązanie jest błędne.

Nikt nie lubi pracować nad kilkoma zadaniami jednocześnie i przełączać się co chwile między kontekstami.

Krótszy czas do osiągnięcia feedback'u jest kluczowy dla utrzymania poziomu produktywności i doprowadzenia zadania do końca.

Czas oczekiwania na code-review

Jeśli proces code-review przebiega asynchronicznie, ciężko mówić o szybkim skończeniu zadania.

Sytuacja jest bardzo podobna do czasu trwania testów automatycznych. Im dłuższe oczekiwanie na feedback, tym gorzej.

Jeśli kod powstawał w towarzystwie drugiego developera (tzw. pair programming), to oczekiwanie na code review nie ma sensu.

Jeśli chcemy osiągnąć dużą wydajność, powinniśmy mieć w zespole tyle inżynierów, by code-review mogło zostać zrealizowane synchronicznie, w momencie zakończenia prac nad zadaniem. Idealnie by było, gdyby zostało zrealizowane równolegle do trwających w tle testów automatycznych.

Jeśli w momencie ukończenia zadania nie można wygospodarować czasu na krótkie code-review (pamiętajmy, że zadanie trwało maksymalnie kilka godzin), to powinna zapalić się mrugająca lampka, informująca, że zespół nie jest samodzielny lub jest za mały.

Niesamodzielny zespół nie będzie pracował wydajnie.

Częstotliwość wprowadzania zmian na produkcję

W zależności od projektu i organizacji możemy mieć do czynienia z różnymi wymaganiami biznesowymi co do długości cyklu wydawniczego. W każdej organizacji prędzej czy później pojawia się jednak nagła potrzeba wprowadzenia zmian. Czy to ze względu na błędy lub awarie, czy też ze względu na kwestie bezpieczeństwa, czy też w reakcji na działania konkurencji.

Na długość cyklu wydawniczego w organizacji wpływa wiele czynników. W rozważaniach o tym, jak ten cykl przyspieszyć należy brać pod uwagę wszystkie te czynniki.

Przed zastosowaniem Trunk Based Development należy sprawdzić, czy można zoptymalizować któryś z nich.

Długość sprintu

Różne "zwinne" zespoły w organizacji mogą pracować w cyklach pracy zwanych sprintami lub iteracjami o różnych długościach. Niektóre zespoły będą pracowały w cyklach tygodniowych, inne w dwu-tygodniowych, itd.

Istnieją też zespoły, które pracują w ramach sprintów jednodniowych, przybliżając się tym samym do stosowania Continuous Delivery. Takie zespoły są w stanie codziennie realizować inne zadania, bez obciążenia psychicznego faktem, że jakieś zadanie jeszcze nie zostało dokończone.

Jeśli zespół pracuje w cyklach wielotygodniowych, a koniec sprintu nie zbiega się z terminem wdrożenia zmian na produkcję, to będzie bardzo ciężko zmniejszyć współczynnik lead time, a tym samym w pełni wykorzystać zalety stosowania Trunk Based Development.

Taki stan uniemożliwia również osiągnięcie poziomu organizacji, w którym będzie można zastosować Continuous Deployment.

Wielkość zadania do realizacji

Nie da się stosować Trunk Based Development, jeśli w projekcie, w którym pracujesz, zadania nie są małe.

Zadania muszą być podzielne tak, by ich realizacja nie przekraczała jednego dnia.

Mniejsze zadania oznaczają też mniej kodu, więc i szybszy, i przyjemniejszy proces code-review.

Jeśli zadanie będzie wymagało utrzymania branch'a przez wiele dni, może dojść do sytuacji, w której ktoś inny, chcąc wykonać swoje zadanie, będzie zmuszony stworzyć swojego branch'a od innego branch'a... Taka strategia prowadzi do zamieszania przy późniejszym merge'owaniu i powoduje opóźnienia.

Zadania, które mają zostać zrealizowane, powinny być na tyle dobrze opisane, by nie tracić czasu na dodatkowe konsultacje.

Tu odsyłam już do definicji akronimu INVEST. Jestem też przekonany, że w Internecie jest niejedna strona opisująca perfekcyjny ticket na Jirze. Chciałbym się tu skupić na części praktycznej: jeśli programista nie ma pojęcia co ma zrobić, to najpierw musi znaleźć kogoś, kto wie. A to nie zawsze jest proste lub ta osoba nie zawsze jest dostępna.

Jeśli wiedza o projekcie w zespole nie jest wyrównana i chcemy uniknąć dodatkowych pytań na etapie implementacji, warto przeprowadzić warsztat Big Picture EventStorming, który pozwoli zamodelować cały system i rozwiać wszelkie wątpliwości co do jego funkcjonowania.

Kompetencje zespołu

Stosowanie Trunk Based Development wymaga wysokich umiejętności programistycznych oraz odpowiedniej kultury pracy.

  1. Wszyscy w zespole powinni umieć pisać i utrzymywać testy automatyczne.
  2. Programiści powinni znać i stosować techniki (takie jak Branch By Abstraction), pozwalające im na realizacje skomplikowanych, wielodniowych zadań, jednocześnie merge'ując i wydając niekompletny kod.
  3. Cały zespół powinien na co dzień pracować z Feature Flagami, by kontrolować w ten sposób moment udostępnienia funkcji klientom i zapewnić stabilność gałęzi głównej.

Bariera psychiczna

Nikt nie lubi zmian.

Praca w swoim długożyjącym branch'u, bez pisania testów automatycznych może wydawać się niezwykle fajnym sposobem na realizowanie zadań.

Kodzisz sobie spokojnie, nikt nie pogania, nikt nie komentuje. Masz pełną swobodę. W pewnym momencie stwierdzasz, że to nad czym pracowałeś przez ostatni kwartał, jest dobre. Pora otworzyć pull request, w Jirze kliknąć "fixed" i przejść do kolejnego zadania.

Ale moment.

Co się ma stać z tym, nad czym pracowałeś? Ktoś (pewnie Twój kolega) teraz musi przejrzeć w ramach code-review te 10k linii kodu.

Jeśli masz w zespole testera, to właśnie zrzuciłeś na niego odpowiedzialność ogarnięcia kwartału roboty i przetestowania całości.

Powodów, dla których coś w tym procesie może pójść nie tak, jest wiele i każdy ze swojego doświadczenia prawdopodobnie będzie w stanie przytoczyć choćby jeden scenariusz zakończenia tej historii.

Powyższa sytuacja (przynajmniej z perspektywy programisty, który pracuje nad kodem) jest niezwykle wygodna.

Ta wygoda sprawia, że wdrożenie Trunk Based Development może spotkać się ze sporym oporem.

Programista w naszej opowieści nie ma żadnej odpowiedzialności. Zakodował. Nawet nie wie, czy to działa. Ktoś inny sprawdzi i doda uwagi albo nawet sam zaproponuje zmiany w kodzie, w ramach code-review. Ktoś inny przetestuje, czy to rozwiązanie działa i spełnia założenia biznesowe. Nasz programista ewentualnie wdroży poprawki sugerowane przez kogoś bardziej odpowiedzialnego.

Zastosowanie Trunk Based Development wymaga jednak pracy zespołowej.

Wspólnej odpowiedzialności za stabilność oprogramowania, większych umiejętności programistycznych, pisania testów automatycznych, odpowiedzialności za swój kod. Odpowiedzialności za to, że do repozytorium wysyła się zmiany przetestowane, które nie destabilizują gałęzi głównej.

Takie podejście sprawi też, że testerzy będą mogli skupić się na testach eksploracyjnych aplikacji, zamiast setny raz sprawdzać, czy w aplikacji nie ma regresji.

Komunikacja w zespole

Twój zespół musi sprawnie i otwarcie się komunikować, w sytuacji, kiedy coś pójdzie nie tak. Każdy zespół doskonale sobie radzi w opowiadaniu dowcipów. Tylko niektóre zespoły świetnie współpracują w sytuacjach awaryjnych.

Błędy się zdarzają i zdarzać się będą zmiany, które - mimo testów automatycznych - zdestabilizują gałąź główną.

Jeśli w tym czasie część Twojego zespołu boi się przyznać do błędu, programiści twierdzą, że "nikt nic nie ruszał", a jedna osoba stara się po historii commit'ów znaleźć kto, kiedy i co zrobił, tracąc przy tym czas, bo nikt nie chce podnieść ręki mówiać "to chyba ja, zaraz dam szczegóły" - Twoja organizacja nie jest gotowa na Trunk Based Development. Powinieneś poświęcić czas na zbudowanie wzajemnego zaufania w zespole.