Jak dobrze użyć metod zwinnych?

Jak dobrze użyć metod zwinnych?

Wytwarzanie oprogramowania jest zagadnieniem złożonym, bo zmienność i nieprzewidywalność dotyka wszystkich istotnych jego aspektów: od technologii, poprzez zaangażowanych w ten proces ludzi, po trendy na rynku doprowadzające do zmiany potrzeb, jakie produkt ma spełniać. Najmniej stabilnym elementem stają się wymagania, w których przypadku jednego można być pewnym: na pewno ulegną zmianie, nieznany jest tylko zakres tej zmiany i moment, w którym ona nastąpi.

Udajemy, że słonia nie ma w pokoju

Największą słabością metod tradycyjnych (tak zwanych predyktywnych) jest dążenie do wytworzenia planu, który po zrealizowaniu da wartościowy produkt. Poza ekstremalnie prostymi rozwiązaniami, które da się zbudować w kilka dni, rzadko kiedy udaje się przewidzieć wszystko i wytworzyć plan, którego nie trzeba będzie zmieniać już w trakcie realizacji. Oczywiście metody te nie mają sensownych mechanizmów radzenia sobie ze zmiennością. Dlaczego? Bo tradycyjne metody takie jak Waterfall próbują zaprzeczać, iż wytwarzanie oprogramowania to zjawisko zbyt złożone, by dało się wytworzyć racjonalny plan zdolny przetrwać zderzenie ze zmienną rzeczywistością. Opierają się one na przewidywaniu, dokładnych analizach, planowaniu, założeniach (obłożonych niezbędnymi marginesami bezpieczeństwa)… Negowanie wpływu złożoności na przebieg projektów powoduje, że nie mogą one wspierać radzenia sobie z jej skutkami, bo po co zajmować się czymś, co nie jest istotne?

Realia są takie, że niewiele projektów udaje się zrealizować korzystając z planów poczynionych na początku, chyba że zaplanowano też radzenie sobie ze zmiennością. Brzmi to bez sensu, ale często się zdarza: z jednej strony zaprzeczamy, że zmagamy się ze złożonością, z drugiej strony dodajemy niezbędne (często ogromne) bufory na radzenie sobie ze zmianami, planujemy obsługę wielu wariantów postępowania na wypadek, gdyby jakieś założenie się nie potwierdziło… Za pierwszym razem jak to obserwujemy, wydaje się zabawne. Potem dociera do nas, jak dużym i irracjonalnym marnotrawstwem jest takie postępowanie.

Jedzmy słonia po kawałku

Agile nie próbuje walczyć z rzeczywistością, ale stanowi jedną z możliwych odpowiedzi na to, jaki charakter ma wytwarzanie oprogramowania. Skoro jest to domena złożona i wiemy o tym, nie próbujmy działać tak, jakby wszystko dało się przewidzieć. Opierajmy się na tym, co wiemy, poruszajmy się małymi kroczkami, gromadząc wiedzę i doświadczenia przed zrobieniem każdego z nich.

Zamiast predyktywnego podejścia opartego na przewidywaniu, analizach i założeniach, metody zwinne proponują empiryzm. Określamy cel, do którego chcemy podążać, po czym w oparciu o to, co już wiemy, określamy pierwszy krok. Nadal musimy go planować, nadal robimy jakieś przewidywania, analizy i założenia – ale dekomponujemy duży złożony problem na małe elementy. To zwiększa prawdopodobieństwo, że podjęte decyzje będą trafne. Co więcej, po zrealizowaniu każdego takiego elementu – w ramach krótkiej iteracji – możemy zobaczyć, co udało się zrobić i w oparciu o to zdecydować, co dalej. Im dłużej działamy, tym wiemy więcej, a jeśli przez pomyłkę pójdziemy w złą stronę, narażamy się na koszt niepotrzebnej pracy tylko przez jedną, z reguły krótką iterację.

Agile radzi sobie zatem ze złożonością w ten sposób, że dzieli ją na dużo mniejsze (choć najczęściej wciąż złożone) problemy do rozwiązania po kolei. Przy okazji daje to dużą elastyczność, ponieważ nie ma rygorystycznego, powiązanego zależnościami planu postępowania – a zatem zmiany nie stanowią problemu. Nie ma też potrzeby zostawiania „marginesów” bezpieczeństwa, bo sam proces wytwarzania oprogramowania jest nieustannie otwarty na zmiany, które nie dość, że go nie spowalniają, to stanowią jego istotną część.

Czy można zrobić sobie krzywdę na własne życzenie?

Już wiemy, że Agile działa dzięki redukcji złożoności (na to pozwala empiryczna kontrola procesu wspomniana wcześniej). Natomiast często zdarza się niestety, iż organizacje i zespoły developerskie na powrót dokładają złożoności do procesów wytwarzania oprogramowania, marnując potencjał metod zwinnych. To, co uda się ułatwić poprzez zastosowanie metod takich jak Scrum czy Kanban marnowane jest na poziomie praktyk stosowanych w zespołach.

Raz a dobrze!

Pierwszym gwoździem do trumny jest „raz-a-dobrzyzm”, czyli próba takiego definiowania wymagań, by zrealizować opisaną nimi funkcjonalność ciągiem, bez konieczności dokonywania w nim szeregu zmian. Zamiast zrobić najprostszą działającą wersję szybko, po czym empirycznie ją udoskonalać, dotąd polerujemy wymagania w backlogu produktu, aż każde z nich będzie opisywać finalną wersję jakiegoś rozwiązania. Zachowując mechanikę metody zwinnej (bo wciąż pracujemy iteracyjnie, wciąż niby rozwijamy produkt inkrementalnie), tak naprawdę rugujemy empiryzm z procesu.

Koszt: czas poświęcony na analizy i dyskusje oparte na projektach i założeniach, nie na czymś, co już działa. Do tego pojawia się ryzyko, że jak już ukończona zostanie ta pozornie finalna wersja, wtedy i tak trzeba będzie ją poprawiać – bo zupełnie inaczej ocenia się projekty niż działający, dający się użyć kawałek programu.

Problemy: można zapomnieć o krótkich iteracjach, bo wymagania są zbyt opasłe. To powoduje, że rośnie złożoność, ponieważ o wiele rzeczy trzeba zadbać, skoordynować je i zrealizować w tym samym czasie. Sama funkcjonalność w wersji wykonanej „raz-a-dobrze” też zapewne nie jest prosta (bo musimy od razu wziąć pod uwagę wszystkie aspekty użycia i potrzeby, na jakie odpowiada), przez co jej wytworzenie i testowanie wcale nie jest łatwe ani przewidywalne.

Rozwiązaniem jest oczywiście takie dekomponowanie dużych wymagań, by najpierw zrobić najprostsze działające rozwiązanie, które potwierdzi, że w ogóle da się to zrobić i warto kontynuować. Potem dodawać do niego coraz to nowe cechy i funkcjonalności, tak by wartość biznesowa rosła, a produkt cały czas działał. A gdy już będzie dość dobry, należy go wydać i zweryfikować jak zostanie przyjęty na rynku (lub przez klientów, użytkowników, odbiorców).

Tyraliera

Innym pomysłem na zabicie zwinności jest realizacja wymagań nie sekwencyjnie w kolejności, w jakiej umieszczone były w backlogu produktu, ale równolegle, tyle na raz, ile się zdoła. Daje to pozory uzyskania szybszego postępu prac, ponieważ – w początkowych etapach iteracji – rzeczywiście dużo się dzieje, praca wre. Taki na przykład Kanban wymaga, by świadomie kształtować limity pracy wykonywanej równocześnie, natomiast Scrum nie wspomina o tym – co daje asumpt do twierdzenia, że „tak można”. Warto wszakże zadać sobie trud zrozumienia tej metody, nie zaś jedynie jej mechaniki – ponieważ limitowanie to wpisane jest w jej DNA: jedną z wartości Scruma jest skupienie (ang. focus), poza tym backlog produktu jest uporządkowaną listą określającą kolejność realizacji umieszczonych na niej elementów również nie bez przyczyny…

Wracając do rozwinięcia się zespołu developerskiego w tyralierę: w końcu zaczynają się kłopoty, bo nie sztuka zacząć realizację wielu wymagań, ale wiele z nich ukończyć. Im więcej z nich realizowanych jest na raz, tym większa jest szansa na pojawienie się zależności lub interferencji między wykonywanymi przez różnych developerów czynnościami. Wszak pracują oni nad jednym produktem, więc nieuniknionym jest, że niektóre zmiany w kodzie lub konfiguracji będą powodować konflikty wymagające rozwiązania. Konieczne też będzie konkurowanie o zasoby takie jak środowiska testowe, dostęp do narzędzi, mocy obliczeniowej maszyn i tak dalej.

Koszt: pojawi się niepotrzebny element rozwiązywania zależności i koordynowania równolegle prowadzonych działań. Do tego wspólnota pracy, tak istotna zwłaszcza w metodzie Scrum, może zupełnie nie być potrzebna – bo każdy robi co innego. Spada przejrzystość, bo robimy zbyt wiele rzeczy na raz, niekoniecznie rozumiemy „nie swoje” wymagania. Rośnie złożoność, której chcieliśmy się pozbyć.

Problemy: ukaskadowiony zostaje proces, ponieważ całość testowania zostanie zepchnięta na ostatnie dni iteracji. To powoduje, że niemal do samego końca nie wiadomo, czy produkt uda się poskładać w działające rozwiązanie – jedno, przetestowane, spełniające jakieś kryteria biznesowe i techniczne (w Scrumie to Definition of Done).

Rozwiązaniem jest sekwencyjne realizowanie wymagań; model idealny to skupienie się całego zespołu nad jednym wymaganiem na raz. Dobrą zasadą może być zadawanie sobie prostego pytania: czy jeśli nie rozpocznę pracy nad kolejnym wymaganiem, będę siedział bezczynnie? Prawie zawsze okaże się, że jest jeszcze sporo do zrobienia w tym, które już jest realizowane, nie ma więc powodu, by dokładać złożoności zaczynając kolejne.

Wszystkie łapki na klawiaturę!

Pewnym wariantem pracy tyralierą jest presja organizacji na to, by wszyscy byli nieustannie zajęci. Czasami wynika to z przyzwyczajeń samych developerów, którzy nauczeni (aż kusi mnie napisać „wytresowani”) w różnych firmach, nieswojo czują się, gdy przez moment – kilka godzin – nie mają nic do zrobienia.

Jeśli każdy musi być nieustannie zajęty, pojawia się ochota, by pracować tyralierą. Jeśli wszakże zespół jest na tyle dojrzały, żeby tego nie robić, wciąż w dążeniu do pełnej zajętości zacznie kopać grób na swoją zwinność. Aby zapewnić sobie tą zajętość, będzie na przykład brał do iteracji więcej wymagań, niż realnie jest w stanie ukończyć – bez wątpienia to spowoduje, że pracy będzie aż nadto, niekoniecznie powstanie w jej wyniku działający produkt.

Innym pomysłem jest przełączanie się między różnymi zadaniami tak, żeby „maksymalnie wykorzystać umiejętności i czas”. Pomijając już potencjalną szkodliwość dla zespołu – który w tym modelu zamiast rozbijać silosy kompetencyjne będzie starał się z nich jak najefektywniej korzystać – to jeszcze pojawi się marnotrawstwo wynikające z przełączania między kontekstami. Rosła też będzie, a jakże, złożoność: nieukończone rozwiązanie jest przekazywane do dalszych prac między ludźmi o różnych kompetencjach na zasadzie kaskady – to utrudnia planowanie działań w iteracji. Im bliżej końca iteracji, tym trudniej tak poukładać pracę, żeby z jednej strony wszyscy mieli co robić, z drugiej optymalnie dobrać wykonawców do charakteru zadania, z trzeciej strony zdążyć na czas i poskładać całość w jeden, funkcjonalny produkt.

Koszty: dławienie się nadmiarem pracy (wciągniętej do iteracji) prowokuje do zdążenia za wszelką cenę kosztem jakości. Przełączanie między kontekstami poza marnowaniem czasu prowadzi do błędów, nieporozumień, przeoczeń. Nierzadko developerzy na siłę robią coś niepotrzebnego, jeśli tylko w ten sposób będą mieli co robić.

Problemy: chaotyczne końcówki iteracji, gdzie tak zwanym rzutem na taśmę udaje się jakoś poskładać produkt. Poza tym dążenie do pełnej zajętości (w domyśle: zajętości pracą nad wymaganiami biznesowymi) skutkuje często zawieszeniem na kołku wszystkich usprawnień, jakie udało się wymyślić. Bo, paradoksalnie, nie ma na nie czasu.

Rozwiązaniem znów jest ograniczenie ilości rzeczy wykonywanych jednocześnie, ale też takie definiowanie zadań w iteracji, aby nie były one tworzone „dla Miecia”, tylko dla całego zespołu. Wykorzystywania tych pozornych przestojów (ang. slack time) na realizację usprawnień. Rozwiązaniem jest też wykorzystanie takich praktyk jak Pair Programming, Code Review, wszelkie formy Test-Driven Developmentu.

Jak uniknąć błędów?

Próbując uniknąć błędów za wszelką cenę możemy zostać sparaliżowani przed dokonywaniem zmian, eksperymentowaniem z różnymi rozwiązaniami. Przede wszystkim należy zadbać o przejrzystość, żeby dokonywać oglądu spraw takimi, jakie one są. Scrum, ale też i inne metody zwinne, mają duży potencjał uderzania nas prosto w twarz problemami spowodowanymi deficytami umiejętności, dysfunkcjami organizacji, złą komunikacją… – o ile zapewnimy przejrzystość.

Drugim kluczowym elementem jest przyjęcie jako pewnik, że software development jest domeną złożoną. Stosujmy metody radzące sobie ze złożonością i mające odpowiednie mechanizmy, by to czynić. Szukajmy i eliminujmy z procesu to, co może wpychać nas na powrót w podejście oparte na przewidywaniu, założeniach, ciężkich analizach i detalicznym planowaniu z góry. Nie dokładajmy sobie złożoności sposobem działania, a jeśli tak się stanie, doskonalmy proces, by to eliminować.

Trzecim elementem jest wykorzystanie empiryzmu do poszukiwania najlepszych rozwiązań również jeśli chodzi o proces. Jeśli dziś niekoniecznie robimy coś dobrze, spróbujmy innego podejścia, oceńmy skutki tej zmiany, dokonajmy kolejnej, i jeszcze kolejnej… iteracja po iteracji. Kto powiedział, że tylko produkt można rozwijać iteracyjnie i inkrementalnie?

A jeśli potrzebujecie wsparcia, chętnie pomożemy, tym bardziej, że wiedza jest czwartym, zupełnie podstawowym elementem. Bez wiedzy i zrozumienia czym jest Agile ciężko wykorzystać go do radzenia sobie ze złożonością.


SZKOLENIA ZWIĄZANE Z TEMATYKĄ ARTYKUŁU


O autorze: Rafał Markowicz
Scrum Master z wieloletnim doświadczeniem, w branży IT od 2001. Praktyk Agile, ekspert w zakresie inżynierii testów i zapewnienia jakości. Pracował jako analityk systemowy i biznesowy, jest doświadczonym developerem, managerem i konsultantem.

Inne artykuły tego autora