161 90 4MB
Polish Pages 295 Year 2014
Spis treści Wprowadzenie Podziękowania O autorze 23
11 22
CZĘŚĆ I
1
Kluczowe korzyści
Zaczynamy! 27
Sprawniejsze wprowadzanie zmian .............................................................................................. 30 Wyższa jakość produktu ............................................................................................................... 32 Mniej przeróbek ............................................................................................................................ 36 Lepsze dostosowanie aktywności ................................................................................................. 39 Pamiętaj ........................................................................................................................................ 41
2
Wzorce kluczowych procesów
43
Zdefiniowanie zakresu prac w oparciu o cele biznesowe ............................................................. 45 Wspólne specyfikowanie .............................................................................................................. 45 Opisywanie z wykorzystaniem przykładów ilustrujących .............................................................. 46 Udoskonalanie specyfikacji .......................................................................................................... 47 Automatyzacja walidacji bez zmiany specyfikacji ........................................................................ 47 Częsta walidacja ........................................................................................................................... 49 Tworzenie systemu dokumentacji ................................................................................................. 49 Praktyczny przykład ...................................................................................................................... 50 Cel biznesowy ......................................................................................................................... 50 Przykład poprawnego celu biznesowego .............................................................................................51
Zakres ..................................................................................................................................... 51 Historyjki użytkowników podstawowego elementu systemu lojalnościowego .......................................51
Kluczowe przykłady ................................................................................................................ 51 Kluczowe przykłady: Darmowa dostawa ..............................................................................................52
Specyfikacja z przykładami .................................................................................................... 52 Darmowa dostawa ..............................................................................................................................52 Przykłady ............................................................................................................................................53
Wykonywalna specyfikacja .................................................................................................... 53 Żyjąca dokumentacja ............................................................................................................. 53 Pamiętaj ........................................................................................................................................ 54
3
Żyjąca dokumentacja
55
Dlaczego potrzebujemy pewnej dokumentacji? ............................................................................ 56 Testy mogą być dobrą dokumentacją ........................................................................................... 57 Tworzenie dokumentacji na podstawie wykonywalnej specyfikacji ............................................. 58 Zalety modelu zorientowanego na dokumentację ......................................................................... 60 Pamiętaj ........................................................................................................................................ 61
4
Spis treści
4
Inicjowanie zmian
63
Jak rozpocząć zmianę procesu? ................................................................................................... 64 Wdrażaj specyfikację przez przykłady jako część rozległego procesu zmian Kiedy: W projektach typu greenfield .............................................................................................65 Skup się na poprawie jakości ..............................................................................................................65 Zacznij od automatyzacji testów funkcjonalnych Kiedy: Zmiany dotyczą istniejącego projektu .................................................................................66 Wprowadź narzędzie do wykonywalnych specyfikacji Kiedy: Zależnie od potrzeb własnych testerów ..............................................................................68 Wykorzystaj TDD jako odskocznię Kiedy: Deweloperzy mają dużą wiedzę na temat TDD ...................................................................70
Jak zacząć zmieniać kulturę zespołu? .......................................................................................... 70 Unikaj używania terminów sugerujących zwinność lub bycie „agile” Kiedy: Pracujesz w środowisku opornym na zmiany .....................................................................70 Zadbaj o uzyskanie wsparcia kierownictwa ..........................................................................................72 Sprzedaj specyfikację przez przykłady jako lepszą metodę wykonywania testów akceptacyjnych .........73 Niech automatyzacja testów nie będzie celem końcowym ...................................................................74 Nie koncentruj się wyłącznie na narzędziu ...........................................................................................75 W czasie migracji niech jedna osoba ciągle pracuje nad starszymi skryptami Kiedy: Wprowadzasz automatyzację funkcjonalną do istniejących systemów ...............................75 Sprawdzaj, kto wykonuje testy automatyczne Kiedy: Deweloperzy niechętnie podchodzą do uczestnictwa w procesie ........................................76
Jak zespoły wdrażają zasady współpracy w procesach iteracyjnych i przepływu? ..................... 77 Zespół Global Talent Management z Ultimate Software ........................................................ 77 Zespół Sierra w BNP Paribas ................................................................................................. 80 Sky Network Services ............................................................................................................. 81 Radzenie sobie z potrzebą formalnego zatwierdzenia i identyfikowalnością ............................... 82 Zachowaj wykonywalne specyfikacje w systemie kontroli wersji ..........................................................83 Uzyskaj zatwierdzenie na eksportowanej żyjącej dokumentacji Kiedy: Zatwierdzasz iterację po iteracji ..........................................................................................84 Uzyskaj zatwierdzenie zakresu, a nie specyfikacji Kiedy: Zatwierdzasz odleglejsze kamienie milowe .........................................................................84 Uzyskaj zatwierdzenie „odchudzonych” przypadków użycia Kiedy: Formalne zatwierdzenia wymagają uzupełnienia o szczegóły ..............................................85 Wprowadź realizacje przypadków użycia Kiedy: Formalne zatwierdzenia wymagają uwzględniania wszystkich szczegółów .........................86
Znaki ostrzegawcze ....................................................................................................................... 87 Uważaj na testy, które często dają różne wyniki .................................................................... 87 Uważaj na bumerangi ............................................................................................................. 88 Uważaj na niedopasowanie organizacyjne ............................................................................. 88 Uważaj na kod „na wszelki wypadek” .................................................................................... 89 Uważaj na „chirurgię śrutówką” ............................................................................................ 90 Pamiętaj ........................................................................................................................................ 90
Spis treśc
CZĘŚĆ II
5
5
Wzorce kluczowych procesów
Definiowanie zakresu na podstawie celów
93
Określanie odpowiedniego zakresu .............................................................................................. 95 Znajdź odpowiedzi na pytania „Dlaczego?” i „Kto?” .............................................................................96 Zrozum, skąd bierze się wartość .........................................................................................................98 Dowiedz się, jakich wyników oczekują użytkownicy biznesowi ............................................................99 Niech deweloperzy zapewnią część „chcę” historyjek użytkownika Kiedy: Użytkownicy biznesowi ufają zespołowi zajmującemu się wytwarzaniem oprogramowania .....100
Współpraca w celu zdefiniowania zakresu bez kontroli wysokiego poziomu ............................. 101 Zapytaj o to, jak coś może być przydatne ..........................................................................................102 Zapytaj o rozwiązanie alternatywne ....................................................................................................103 Nie patrz na projekt wyłącznie z perspektywy najniższego poziomu ...................................................103 Zadbaj, aby zespoły dostarczały kompletne funkcje Kiedy: Pracujesz nad dużymi projektami z częściami zespołów w różnych lokalizacjach .............104
Więcej informacji ........................................................................................................................ 105 Pamiętaj ...................................................................................................................................... 106
6
Wspólne specyfikowanie
107
Dlaczego podczas definiowania specyfikacji musimy ze sobą współpracować? ....................... 108 Najpopularniejsze modele współpracy ....................................................................................... 109 Spróbuj zorganizować duże warsztaty dla wszystkich członków zespołu Kiedy: Zaczynasz wdrażać zasady specyfikacji przez przykłady ...................................................109 Wypróbuj spotkania w mniejszym gronie („trzej amigos”) Kiedy: Domena wymaga składania częstych wyjaśnień ..............................................................111 Programujcie w parach Kiedy: Pracujecie nad dojrzałymi produktami ..............................................................................113 Spraw, aby testerzy przed iteracją regularnie sprawdzali testy Kiedy: Analitycy tworzą testy ......................................................................................................115 Spróbuj nieformalnych rozmów Kiedy: Interesariusze biznesowi są łatwo dostępni ......................................................................115
Przygotowanie współpracy ......................................................................................................... 116 Organizuj spotkania przygotowawcze Kiedy: W projekcie uczestniczy wielu interesariuszy ...................................................................117 Zdobądź zaangażowanie interesariuszy ..............................................................................................118 Dobrze przygotuj się do wstępnych spotkań z interesariuszami Kiedy: Interesariusze nie są dostępni na miejscu ........................................................................119 Niech członkowie zespołu przejrzą historyjki na wczesnym etapie Kiedy: Analitycy/eksperci ds. domeny są wąskim gardłem procesu ............................................121 Przygotuj tylko wstępne przykłady Kiedy: Interesariusze są łatwo dostępni ......................................................................................122 Nie utrudniaj dyskusji przez przesadne przygotowania .......................................................................123
Wybór modelu współpracy ......................................................................................................... 124 Pamiętaj ...................................................................................................................................... 125
6
Spis treści
7
Wykorzystanie przykładów ilustrujących
127
Uzupełnienie specyfikacji z wykorzystaniem przykładów ilustrujących: przykład ...................... 130 Przykłady powinny być precyzyjne ............................................................................................. 131 Nie używaj w swoich przykładach systemu zamkniętych odpowiedzi (tak/nie) Kiedy: Bazowe koncepcje nie są definiowane osobno .................................................................131 Unikaj używania abstrakcyjnych klas równoważności Kiedy: Możesz zdefiniować konkretny przykład ...........................................................................132
Przykłady powinny być kompletne .............................................................................................. 133 Eksperymentuj z danymi ...................................................................................................................133 Pytaj, czy istnieje alternatywna metoda sprawdzenia funkcjonalności Kiedy: Pracujesz ze złożoną/starą infrastrukturą .........................................................................133
Przykłady powinny być realistyczne ........................................................................................... 134 Unikaj generowania zmyślonych danych Kiedy: Podczas prac nad projektem opartym na danych .............................................................134 Pozyskaj podstawowe przykłady bezpośrednio od klientów Kiedy: Pracujesz dla klientów korporacyjnych .............................................................................135
Przykłady powinny być zrozumiałe ............................................................................................. 137 Unikaj pokusy zbadania wszelkich możliwych kombinacji ..................................................................138 Szukaj ukrytych koncepcji .................................................................................................................138
Ilustrowanie wymagań niefunkcjonalnych .................................................................................. 140 Zdobądź precyzyjne wymagania wydajnościowe Kiedy: Wysoka wydajność jest funkcją kluczową ........................................................................140 Wykorzystaj uproszczone prototypy interfejsów użytkownika .............................................................141 Wypróbuj model QUPER Kiedy: Wymagania zmieniają się i są skalowalne ........................................................................142 Wykorzystaj listę kontrolną podczas dyskusji Kiedy: Pojawiają się obawy przekrojowe ....................................................................................143 Stwórz przykład referencyjny Kiedy: Wymagania są niemożliwe do oszacowania .....................................................................144
Pamiętaj ...................................................................................................................................... 145
8
Udoskonalanie specyfikacji
147
Przykład dobrej specyfikacji ....................................................................................................... 149 Darmowa dostawa ................................................................................................................ 149 Przykłady .............................................................................................................................. 149 Przykład złej specyfikacji ............................................................................................................ 150 Na co należy zwrócić uwagę podczas udoskonalania specyfikacji? ........................................... 152 Przykłady powinny być precyzyjne i testowalne ................................................................... 152 Skrypty to nie specyfikacje ................................................................................................... 152 Nie twórz opisów w formie przepływów .............................................................................................154
Specyfikacje powinny dotyczyć funkcjonalności biznesowej, a nie projektu oprogramowania ...... 154 Unikaj tworzenia specyfikacji, które są ściśle powiązane z kodem ......................................................155 Oprzyj się pokusie obejścia trudności technicznych w specyfikacjach Kiedy: Pracujesz na starym systemie .........................................................................................156 Nie pozwól uwięzić się przez szczegóły interfejsu użytkownika Kiedy: Pracujesz nad projektami internetowymi ..........................................................................157
Specyfikacje powinny być oczywiste .......................................................................................... 157 Użyj opisowego tytułu i wyjaśnij cel, stosując krótkie zdania .............................................................158 Pokaż i milcz Kiedy: Ktoś pracuje nad specyfikacją samodzielnie W celu: Sprawdzenia, czy specyfikacja jest oczywista i nie wymaga dodatkowych tłumaczeń ....158
Spis treśc
7
Nie upraszczaj nadmiernie przykładów ..............................................................................................159 Zacznij od podstawowych przykładów, a następnie rozszerz zakres przez eksplorowanie Kiedy: Opisujesz reguły za pomocą wielu kombinacji parametrów ..............................................161
Specyfikacje powinny być ostre ........................................................................................... 161 Zastosuj wzorzec „Zakładając/Jeżeli/Wtedy” W celu: Sprawienia, by testy były łatwiejsze do zrozumienia .......................................................162 Nie definiuj jawnie wszystkich zależności w specyfikacji Kiedy: Musisz poradzić sobie ze skomplikowanymi zależnościami/integralnością referencyjną ......163 Zastosuj ustawienia domyślne w warstwie automatyzacji ..................................................................164 Nie polegaj na domyślnych wartościach w każdym przypadku Kiedy: Pracujesz z obiektami o wielu atrybutach .........................................................................164
Specyfikacje powinny być napisane w języku domeny ............................................................... 165 Udoskonalanie specyfikacji w praktyce ...................................................................................... 165 Pamiętaj ...................................................................................................................................... 168
9
Automatyczna walidacja bez zmiany specyfikacji
169
Czy automatyzacja jest w ogóle potrzebna? ............................................................................... 170 Rozpoczęcie automatyzacji ......................................................................................................... 172 Aby poznać narzędzia, wypróbuj je najpierw w prostym projekcie Kiedy: Pracujesz z istniejącym systemem ..................................................................................172 Zaplanuj automatyzację z wyprzedzeniem ..........................................................................................173 Nie opóźniaj i nie odsuwaj od siebie prac związanych z automatyzacją ..............................................175 Unikaj automatyzacji istniejących skryptów testów ręcznych .............................................................175 Zdobądź zaufanie dzięki testom interfejsu użytkownika Kiedy: Członkowie zespołu są nastawieni sceptycznie do wykonywalnych specyfikacji ...............176
Zarządzanie warstwą automatyzacji ........................................................................................... 178 Nie traktuj kodu automatyzacji jak kodu drugiej kategorii ....................................................................178 Opisz procesy walidacji w warstwie automatyzacji ............................................................................179 Nie powielaj logiki biznesowej w warstwie automatyzacji testów ........................................................180 Automatyzuj wzdłuż granic systemu Kiedy: Integracje są skomplikowane ...........................................................................................181 Nie sprawdzaj logiki biznesowej za pomocą interfejsu użytkownika ....................................................182 Automatyzacja pod skórą aplikacji Kiedy: Sprawdzasz ograniczenia sesji i przepływu ......................................................................183
Automatyzacja interfejsów użytkownika ..................................................................................... 184 Określ funkcjonalność interfejsu użytkownika na wyższym poziomie abstrakcji ..................................186 Funkcjonalność interfejsu użytkownika sprawdzaj tylko ze specyfikacją interfejsu użytkownika Kiedy: Interfejs użytkownika zawiera złożoną logikę ....................................................................188 Unikaj zarejestrowanych testów interfejsu użytkownika ......................................................................188 Ustaw kontekst w bazie danych .........................................................................................................189
Zarządzanie danymi testowymi ................................................................................................... 191 Unikaj wykorzystywania danych wstępnie wypełnionych Kiedy: Definiujesz logikę, która nie bazuje na danych ..................................................................191 Spróbuj wykorzystać wstępnie przygotowane dane referencyjne Kiedy: W systemach bazujących na danych ...............................................................................192 Wyciągnij prototypy z bazy danych Kiedy: W starych, dojrzałych systemach bazujących na danych .................................................193
Pamiętaj ...................................................................................................................................... 194
8
Spis treści
10
Częsta walidacja
195
Zmniejszenie zawodności ........................................................................................................... 197 Znajdź najbardziej irytujący Cię element, napraw go, a następnie powtórz całą operację Kiedy: Pracujesz w systemie z kiepskim wsparciem dla testów automatycznych ........................198 Określ niestabilne testy, korzystając z historii testów ciągłej integracji Kiedy: Modernizujesz i dopasowujesz automatyczne testy do starego systemu ..........................199 Utwórz dedykowane środowisko ciągłej walidacji ..............................................................................199 Zastosuj w pełni zautomatyzowaną procedurę instalacji .....................................................................200 Utwórz uproszczonych „dublerów” systemów zewnętrznych Kiedy: Pracujesz z zewnętrznymi źródłami danych referencyjnych ..............................................201 Odizoluj wybrane systemy zewnętrzne Kiedy: Na Waszą pracę mają wpływ systemy zewnętrzne ...........................................................202 Wypróbuj walidację wielostopniową Kiedy: Pracujesz w dużych grupach lub z grupami w różnych lokalizacjach ................................202 Wykonaj testy w transakcjach Kiedy: Wykonywalne specyfikacje modyfikują dane referencyjne ................................................203 Wykonaj szybkie testy danych referencyjnych Kiedy: W systemach opartych na danych ...................................................................................204 Oczekuj zdarzeń, zamiast nastawiać się na określony czas trwania ....................................................204 Uczyń przetwarzanie asynchroniczne rozwiązaniem opcjonalnym Kiedy: Pracujesz nad projektami typu greenfield .........................................................................205 Nie wykorzystuj wykonywalnych specyfikacji w funkcji walidacji kompleksowej typu end-to-end Kiedy: W projektach typu brownfield ..........................................................................................206
Szybsze uzyskiwanie informacji zwrotnej ................................................................................... 207 Wprowadź operacyjny czas działania Kiedy: Musisz radzić sobie z ograniczeniami czasowymi ............................................................207 Podziel duże zestawy testów na mniejsze moduły .............................................................................208 Unikaj wykorzystywania do testów baz danych przechowywanych w pamięci Kiedy: W systemach bazujących na danych ...............................................................................209 Oddziel testy szybkie od wolnych Kiedy: Niewielka część testów zajmuje większość czasu przeznaczonego na ich wykonanie .......210 Utrzymaj stabilność uruchamianych na noc pakietów testów Kiedy: Niemrawe testy są rozpoczynane w nocy ........................................................................210 Stwórz pakiet aktualnej iteracji ...........................................................................................................211 Wykonuj testy równolegle Kiedy: Możesz stworzyć kilka środowisk testowych ...................................................................212 Spróbuj wyłączyć testy, z których wykonaniem wiąże się mniejsze ryzyko Kiedy: Feedback z testów jest bardzo niemrawy .........................................................................213
Zarządzanie testami, które kończą się niepowodzeniem ............................................................ 214 Stwórz pakiet znanych nieudanych testów regresji ............................................................................215 Sprawdzaj automatycznie, które testy są wyłączone Kiedy: Nieudane testy zostają zneutralizowane, a nie trafiają do oddzielnego pakietu ...................216
Pamiętaj ...................................................................................................................................... 217
11
Tworzenie systemu dokumentacji
219
Żyjąca dokumentacja powinna być łatwa do zrozumienia .......................................................... 219 Nie twórz długich specyfikacji ...........................................................................................................220 Nie używaj wielu specyfikacji do opisania jednej funkcji ....................................................................220 Szukaj koncepcji wyższego poziomu .................................................................................................221 Unikaj stosowania w testach technicznych pojęć automatyki Kiedy: Interesariusze nie mają wystarczającej wiedzy technicznej ...............................................221
Spis treśc
9
Żyjąca dokumentacja powinna być spójna ................................................................................. 222 Ewoluujący język ...............................................................................................................................223 Tworząc język specyfikacji, bazuj na personach Kiedy: W projektach internetowych ............................................................................................224 Promuj współpracę w celu zdefiniowania słownika języka Kiedy: Rezygnujesz z warsztatów specyfikacji ............................................................................225 Gromadź dokumentację swoich bloków konstrukcyjnych ..................................................................226
Żyjąca dokumentacja powinna być zorganizowana zgodnie z regułami ułatwiającymi dostęp ............................................................................ 227 Organizuj bieżącą pracę, segregując ją według historyjek ..................................................................228 Zorganizuj historyjki na podstawie obszarów funkcjonalnych .............................................................228 Pogrupuj specyfikacje według dróg nawigacji w interfejsie użytkownika Kiedy: Dokumentujesz interfejsy użytkownika .............................................................................229 Zorganizuj specyfikacje według procesów biznesowych Kiedy: Wymagana jest identyfikowalność przypadków użycia typu end-to-end ...........................230 Używaj znaczników zamiast adresów URL, odnosząc się do specyfikacji wykonywalnych Kiedy: Potrzebujesz identyfikowalności specyfikacji ...................................................................231
Słuchaj swojej żyjącej dokumentacji .......................................................................................... 232 Pamiętaj ...................................................................................................................................... 233
CZĘŚĆ III
12
uSwitch
Studia przypadków
237
Rozpoczęcie zmiany procesu ...................................................................................................... 238 Optymalizacja procesu ............................................................................................................... 240 Obecny kształt procesu ............................................................................................................... 244 Efekt końcowy ............................................................................................................................. 245 Najważniejsze lekcje ................................................................................................................... 245
13
RainStor
247
Zmiana procesu .......................................................................................................................... 247 Obecny kształt procesu ............................................................................................................... 250 Najważniejsze lekcje ................................................................................................................... 251
14
Iowa Student Loan
253
Zmiana procesu .......................................................................................................................... 253 Optymalizacja procesu ............................................................................................................... 255 Żyjąca dokumentacja jako przewaga konkurencyjna ................................................................. 258 Najważniejsze lekcje ................................................................................................................... 259
15
Sabre Airline Solutions
261
Zmiana procesu .......................................................................................................................... 261 Poprawa współpracy .................................................................................................................. 263 Efekt końcowy ............................................................................................................................. 265 Najważniejsze lekcje ................................................................................................................... 265
10
16
Spis treści
ePlan Services
267
Zmiana procesu .......................................................................................................................... 267 Żyjąca dokumentacja .................................................................................................................. 270 Obecny proces ............................................................................................................................ 271 Najważniejsze lekcje ................................................................................................................... 273
17
Songkick
275
Zmiana procesu .......................................................................................................................... 276 Obecny kształt procesu ............................................................................................................... 278 Najważniejsze lekcje ................................................................................................................... 280
18
Podsumowanie
283
Współpraca przy definiowaniu wymagań buduje wzajemne zaufanie interesariuszy i członków zespołu ................................................................................................................ 283 Współpraca wymaga przygotowania .......................................................................................... 284 Współpraca może przybierać wiele różnych form ...................................................................... 285 Przydaje się umiejętność spojrzenia na cel końcowy jak na dokumentowanie procesów biznesowych ......................................................................................................... 286 W dłuższej perspektywie prawdziwą wartością dla zespołu jest system żyjącej dokumentacji ..... 287
Dodatek A. Źródła Skorowidz 293
289
Wprowadzenie
K
siążka, którą trzymasz w dłoniach (lub którą widzisz na monitorze swojego komputera), jest efektem końcowym cyklu badań nad procesem, w czasie którego zajmujące się wytwarzaniem oprogramowania zespoły na całym świecie definiują, rozwijają i dostarczają właściwe produkty — wolne od błędów i opracowywane w krótkich cyklach projektowych. Ta książka zawiera wiedzę zgromadzoną dzięki analizie prawie pięćdziesięciu projektów inżynierii oprogramowania, podczas których zespoły pracowały nad dostarczeniem szerokiego zakresu produktów — począwszy od ogólnodostępnych stron internetowych aż po wewnętrzne systemy typu back-office. Zbierając materiały do tej książki, przeanalizowałem działania zespołów rozmaitych typów — były to zarówno małe grupy ludzi pracujących w tym samym biurze, jak i powiązane sieci programistów czasami rozlokowane nawet na różnych kontynentach, osoby posługujące się różnorakimi metodologiami procesów inżynierii: programowaniem ekstremalnym (ang. Extreme Programming), Scrumem, Kanbanem czy podobnymi metodami (często połączonymi ze sobą i przybierającymi formy metod zwinnych, tj. agile i lean). Wszystkie te zespoły łączyło jedno: ścisła współpraca w zakresie opracowywania poprawnych specyfikacji oraz testów, a także końcowy sukces i korzyści, jakie stały się ich udziałem dzięki tej współpracy.
Specyfikacja przez przykłady Różne zespoły stosują różne terminy dla nazwania tego, co robią ze specyfikacjami i testami, a przecież w każdym przypadku ludzie ci odwołują się do tych samych kluczowych zasad i koncepcji, które moim zdaniem w gruncie rzeczy są zawsze takie same. Wśród używanych przez zespoły terminów i skrótów znajdujemy takie jak: Zwinne testowanie akceptacyjne. ATDD (ang. Acceptance Test-Driven Development), czyli wytwarzanie oprogramowania w oparciu o testy akceptacyjne. EDT (ang. Example-Driven Development), tj. wytwarzanie oprogramowania w oparciu o przykłady. Testowanie przez historyjki użytkownika (ang. story testing). BDD (ang. Behavior-Driven Development), czyli wytwarzanie oprogramowania w oparciu o analizę zachowań użytkowników. Specyfikacja przez przykłady (ang. Specification by Example). Już sam fakt, że te same działania mają tak wiele różnych nazw, może nam wiele powiedzieć o ogromnej innowacyjności, z jaką mamy do czynienia w tej dziedzinie. Mnogość stosowanych terminów i definicji świadczy także o tym, że praktyki opisane w tej książce wpływają na zmianę podejścia zespołów do specyfikacji oraz do zagadnienia wytwarzania oprogramowania i jego testowania. Kierując się dążeniem do zachowania spójności przekazu, musiałem
12
Specyfikacja na przykładach
jednak wybrać jeden termin. Zdecydowałem się na specyfikację przez przykłady i będę używał tego określenia w całej książce. Wyjaśnię mój wybór w części tego wprowadzenia zatytułowanej „Kilka słów na temat terminologii”, gdzie znajdzie się także kilka szczegółów dotyczących reszty terminów zastosowanych dla nazwania elementów opisywanego procesu.
W świecie rzeczywistym… Szczegóły proponowanej przeze mnie metodyki przedstawiam, odwołując się do licznych studiów przypadków i zarejestrowanych rozmów z członkami grup programistów. Wybrałem to podejście świadomie, z myślą o tym, żeby czytelnicy mieli szansę dowiedzieć się, jak radziły sobie prawdziwe zespoły, pracujące zgodnie z regułami tej metody i czerpiące z niej spore korzyści. Specyfikacja przez przykłady w żadnym razie nie jest ciemniejszą stroną sztuki, mimo że niektóre popularne media przekonują, że jest inaczej. Prawie wszystko, o czym mówimy w tej książce, pochodzi z rzeczywistego świata inżynierii oprogramowania, dotyczy działających w tym świecie zespołów oraz ich — jak najbardziej realnych — doświadczeń. Tylko nieliczne praktyki zostały przedstawione w formie sugestii niepopartych studium przypadku. Są to zwykle pomysły, które — moim zdaniem — będą w przyszłości stanowić ważny przyczynek do dyskusji. I właśnie jako takie są przeze mnie przedstawiane. Jestem przekonany, że moje wnioski, a także badania, jakie przeprowadziłem na potrzeby tej książki, nie zostaną uznane za poważne studia naukowe przez sceptyków, którzy twierdzą, iż zwinne praktyki się nie sprawdzają, a branża powinna wrócić do „prawdziwej inżynierii oprogramowania”1. Akceptuję to. Zasoby, do jakich miałem dostęp podczas zbierania materiałów na potrzeby tego projektu, można uznać za niewystarczające w porównaniu z tym, czego wymaga się od poważnych badań naukowych. I nawet gdybym dysponował zasobami spełniającymi kryteria uznanych metodologii, to przecież ani nie jestem naukowcem, ani nie zamierzam przedstawiać siebie jako naukowca. Jestem praktykiem.
Kto powinien zapoznać się z tą książką? Jeśli tak jak ja jesteś praktykiem i zarabiasz na chleb, pracując przy wytwarzaniu oprogramowania lub wspierając pracę nad oprogramowaniem, ta książka ma Ci wiele do zaoferowania. Powstała wszak przede wszystkim z myślą o zespołach, które starały się wdrożyć w swoich środowiskach zwinne praktyki, ale napotkały problemy wpływające niekorzystnie na jakość produktu końcowego, zwiększające nakład pracy i prowadzące do tego, że dzieło rąk programistów nie spełniało oczekiwań klientów. (Tak… wówczas mamy do czynienia
1
Jeśli chcesz poznać argumenty tych, którzy łudzą się, iż rygorystyczne podejście do inżynierii oprogramowania przynosi korzyści, tak jak gdyby była to jakaś drugorzędna gałąź fizyki, zajrzyj na stronę http://www.semat.org. Dobre kontrargumenty zawiera prezentacja Glenna Vanderburga zatytułowana Software Engineering Doesn’t Work!, z którą można zapoznać się na stronie http://confreaks.net/videos/282lsrc2010-real-software-engineering.
Wprowadzenie
13
z prawdziwymi kłopotami i w takiej sytuacji zwykła iteracja nie na wiele się zda, ponieważ staje się „objazdem”, a nie rozwiązaniem problemu). Specyfikacja przez przykłady, zwinne testowanie akceptacyjne, BDD i wszystkie alternatywne nazwy określają ten sam proces, zorientowany na rozwiązywanie tych problemów. Ta książka pomoże Ci poznać podstawy wspomnianych dobrych praktyk inżynierii oprogramowania. Dowiesz się z niej, jak możesz mieć większy pozytywny wpływ na zespół, niezależnie od tego, czy jesteś testerem, deweloperem, analitykiem, czy właścicielem produktu. Jeszcze kilka lat temu większość ludzi, których spotykałem na konferencjach, nigdy wcześniej nie słyszała o opisanych w tej książce praktykach. Gros tych, z którymi rozmawiam dziś, ma świadomość istnienia wspomnianych praktyk, ale wielu z nich nie udało się wdrożyć ich prawidłowo. Istnieje niewielka baza literatury fachowej traktującej o problemach, jakie napotykają zespoły podczas szeroko pojętego wdrażania zwinnych praktyk, dlatego każdy zniechęcony zespół stwierdza, że jego przypadek musi być wyjątkowy, a sformalizowane koncepcje po prostu nie sprawdzają się w „jego świecie”. Ludzie z takich zniechęconych zespołów dziwią się, jak po zaledwie pięciu minutach rozmowy udaje mi się trafnie zidentyfikować ich trzy lub cztery największe problemy. Często są bardzo zdziwieni, słysząc, że wiele innych zespołów napotyka na swojej drodze te same przeszkody. Jeśli pracujesz w takim zespole, książka, którą właśnie trzymasz w dłoniach, uświadomi Ci przede wszystkim, że nie jesteś sam. Zespoły, z którymi rozmawiałem podczas zbierania materiałów do tej pozycji, wcale nie były zespołami idealnymi. Także one napotkały na swojej drodze mnóstwo problemów! Jednak zamiast rezygnować po zderzeniu z murem przeciwności, ludzie Ci postanowili go „objechać” lub zburzyć. Taka świadomość wspólnoty często pozwala zobaczyć swoje problemy w innym świetle. Mam nadzieję, że po przeczytaniu tej książki będziesz właśnie jedną z tych wyjątkowych osób, które potrafią spojrzeć na sytuację z innej perspektywy. Jeśli akurat znajdujesz się w trakcie wdrażania specyfikacji przez przykłady, ta książka dostarczy Ci przydatnych wskazówek, dzięki którym dowiesz się, jak poradzić sobie z bieżącymi problemami i czego możesz spodziewać się w przyszłości. Mam nadzieję, że będziesz uczyć się na błędach innych ludzi i niektórych z nich uda Ci się uniknąć. Ta książka została napisana także z myślą o doświadczonych praktykach, osobach, którym udało się wdrożenie zasad specyfikacji przez przykłady. Gdy zaczynałem rejestrowanie wywiadów z zespołami, spodziewałem się, że nie dowiem się niczego nowego. Myślałem, że „wiem, co jest grane”, i szukałem tylko potwierdzenia. Tymczasem ostatecznie musiałem przyznać, że zaskoczyło mnie to, jak wiele różnych pomysłów można zastosować zależnie od kontekstu. Dowiadywałem się o rozwiązaniach, które wcześniej trudno mi było sobie wyobrazić! Wiele się przy tym nauczyłem. Dlatego mam nadzieję, że i Ty, drogi Czytelniku, wiele nauczysz się dzięki lekturze tej książki. Przedstawione w niej praktyki i pomysły powinny zainspirować Cię do wypróbowania alternatywnych rozwiązań problemów i dać Ci kilka podpowiedzi, jak usprawnić pracę zespołu, gdy tylko natkniesz się na historię przypominającą jakiś opisany tu przykład.
14
Specyfikacja na przykładach
Co znajdziesz w środku? W pierwszej części książki przedstawię podstawy koncepcji specyfikacji przez przykłady. Zamiast przekonywać Cię do tego, byś przestrzegał zasad opisanych w tej książce, pokażę Ci — w sposób charakterystyczny dla metodyki specyfikacji przez przykłady — konkretne korzyści, jakie zespoły pracujące nad wytwarzaniem oprogramowania mogą uzyskać dzięki zastosowaniu prezentowanych tu reguł. Jeśli zastanawiasz się nad zakupem tej książki, najpierw przejrzyj rozdział 1. i odpowiedz sobie na pytanie, czy którejś z opisanych tam korzyści można spodziewać się także podczas realizacji Twojego projektu. W rozdziale 2. przedstawię najważniejsze modele procesów i kluczowe artefakty specyfikacji przez przykłady. W rozdziale 3. omówię szczegółowo koncepcję żyjącej dokumentacji. W rozdziale 4. przedstawię typowe punkty wyjścia dla zainicjowania zmian procesu i kultury pracy zespołu oraz wskażę, na co należy zwrócić uwagę podczas implementacji metodyki. Jednym z moich celów jako autora tej książki jest stworzenie spójnego słownika dla wzorców, idei i artefaktów, który będzie mógł być stosowany podczas wdrażania zasad specyfikacji przez przykłady. W branży inżynierii oprogramowania używa się tuzina różnych terminów dla nazwania samej praktyki i dwa razy więcej dla nazwania poszczególnych elementów kluczowych metodyki. Ludzie nazywają ten sam element: plikami właściwości, przypadkami testowymi, plikami BDD, testami akceptacyjnymi itp. Z tego powodu w rozdziale 2. przedstawię najlepsze (moim zdaniem) terminy stosowane dla określenia wszystkich kluczowych elementów omawianej metodyki. Nawet jeśli jesteś doświadczonym praktykiem, proponuję, żebyś zapoznał się z tym rozdziałem i odpowiedział sobie na pytanie, czy tak samo rozumiemy kluczowe terminy, wyrażenia i wzorce, o których mówimy w tej książce. W drugiej części przedstawię najistotniejsze praktyki, z których zespoły opisane w studiach przypadków korzystały, by wdrożyć zasady specyfikacji przez przykłady. Zespoły działające w różnych środowiskach podejmowały różnorakie decyzje — czasem diametralnie różne, a czasami wręcz sprzeczne — aby jednak ostatecznie uzyskać takie same efekty. Opis tych praktyk uzupełnię dodatkowo charakterystyką kontekstów, w których działały zespoły podczas wdrażania reguł specyfikacji przez przykłady. Siedem rozdziałów drugiej części podzieliłem mniej więcej zgodnie z podziałem na obszary procesów. W branży takiej jak inżynieria oprogramowania nie istnieją uniwersalne, idealne rozwiązania, ale na pewno można mówić o dobrych pomysłach, które da się zastosować ze świetnym skutkiem w różnych kontekstach. W drugiej części tej książki znajdziesz ikonki przedstawiające kciuk uniesiony w górę lub skierowany w dół. Takie grafiki będą pojawiać się przy nagłówkach z opisem działań, które badane zespoły uznały za użyteczne, lub problemów, z którymi często musiały się mierzyć. Potraktuj te wskazania jak propozycje wypróbowania przedstawionego przeze mnie rozwiązania lub ostrzeżenie przed sytuacją, jakiej warto unikać. Nie są to w żadnym razie gotowe recepty, które należy koniecznie zastosować. Ikony przedstawiające strzałki podkreślają najistotniejsze koncepcje związane z każdym z prezentowanych działań. Wytwarzanie oprogramowania nie jest sztuką statyczną, ponieważ stale zmieniają się zarówno zespoły, jak i środowiska, w których pracują ludzie. Procesy rozwoju produktu muszą nadążać za tymi zmianami. W części trzeciej tej książki przedstawię studia przypad-
Wprowadzenie
15
ków opisujące „podróże” kilku wybranych zespołów. Omówię procesy, ograniczenia i konteksty, analizując ewolucję projektów. Przedstawione w tej części historie pozwolą Ci lepiej przygotować się do czekających Cię zmian lub zachęcą do wykonania następnego kroku, pomogą w poszukiwaniach inspiracji, a także zainspirują do odkrywania nowych metod działań i rozwiązań. W ostatnim rozdziale podsumuję najważniejsze wnioski, do których doszedłem dzięki analizie licznych studiów przypadków zebranych na potrzeby tej książki.
Coś więcej niż podstawy Gdyby odwołać się do tradycyjnego modelu doskonalenia Shu-ha-ri2, ta książka znajduje się na poziomie ha. Na tym etapie uczeń łamie obowiązujące zasady i dowiaduje się, że istnieje wiele różnych sprawdzających się modeli. Mój model i moje doświadczenie przedstawiłem w Bridging the Communication Gap. Natomiast w książce, którą właśnie trzymasz w dłoniach, bardzo staram się zachować obiektywne spojrzenie i uniknąć ulegania wpływom moich dotychczasowych osobistych doświadczeń. O projektach, nad którymi pracowałem osobiście, mówię tylko wtedy, gdy naprawdę zależy mi na przekazaniu ważnych informacji, a żaden z ankietowanych zespołów nigdy nie zetknął się z podobną sytuacją. W tym sensie specyfikacja przez przykłady zaczyna się tam, gdzie skończyłem Bridging the Communication Gap. Podstawowe zasady opisuję krótko w rozdziale 2. Nawet jeśli nigdy wcześniej nie słyszałeś o żadnej z przedstawionych tam koncepcji, lektura tego rozdziału powinna zapewnić Ci dość danych, żebyś mógł zrozumieć resztę książki. Staram się przy tym nie zagłębiać za bardzo w podstawy. Szczegółową analizę fundamentów teorii specyfikacji przez przykłady znajdziesz w Bridging the Communication Gap i nie jest moim celem kopiowanie tych informacji. Jeśli chcesz poszerzyć swoją wiedzę w zakresie podstaw, zajrzyj na stronę http:// specificationbyexample.com, zarejestruj posiadany egzemplarz tej książki, a otrzymasz za darmo plik PDF z Bridging the Communication Gap. Nie sądzę, że kiedykolwiek powstanie kontynuacja tej pozycji — to znaczy książka mojego autorstwa na poziomie ri — ponieważ moim zdaniem poziom ten jest w ogóle nieosiągalny dla książek. Z drugiej strony wierzę, że ta książka pomoże Ci przejść na wyższy poziom. Gdy zaczniesz rozumieć, że wybór konkretnego narzędzia nie ma znaczenia, będzie to znaczyło, że znalazłeś się na poziomie ri.
2
Shu-ha-ri to model doskonalenia związany z nauką aikido. Shu-ha-ri znaczy mniej więcej tyle co: podporządkuj się – zerwij – odejdź. Na pierwszym poziomie (shu — podporządkuj się) uczeń zdobywa wiedzę, pilnie naśladując przedstawiony mu model. Na drugim poziomie (ha — zerwij) uczeń dowiaduje się, że istnieją inne modele i rozwiązania. Na trzecim poziomie (ri — odejdź) uczeń przekracza granicę, wychodząc poza działania polegające na bezrefleksyjnym powtarzaniu znanych rozwiązań.
16
Specyfikacja na przykładach
Ta książka nie zawiera kodu źródłowego i nie wyjaśnia działania żadnych narzędzi Nie znajdziesz w tej książce kodu źródłowego ani instrukcji opisujących, jak użyć konkretnego narzędzia. Czuję się zobligowany do uprzedzenia o tym już teraz, ponieważ nawet w trakcie trwania procesu wydawniczego byłem zmuszony do składania wyjaśnień w tej kwestii (zwykle chodziło o odpowiedź na pytanie: „Co właściwie masz na myśli? Książka o programowaniu bez kodu źródłowego? Jak to możliwe?”). Zasady i praktyki specyfikacji przez przykłady wpływają przede wszystkim na sposób komunikacji międzyludzkiej w zespołach pracujących nad dostarczaniem oprogramowania, a także na współpracę zespołów z użytkownikami biznesowymi i interesariuszami (ang. stakeholders). Jestem pewien, że wielu sprzedawców narzędzi informatycznych będzie próbować sprzedać Ci gotowe rozwiązania. Z kolei wielu menedżerów chętnie nawet zapłaciłoby za to, aby ktoś sprawił, żeby ich problem po prostu zniknął. Niestety mamy do czynienia przede wszystkim z problemem ludzkim, a nie technicznym. Bill Gates mawiał: „Pierwszą zasadą dotyczącą wszelkich technologii wykorzystywanych w działalności gospodarczej jest to, że zautomatyzowanie skutecznego działania potęguje efektywność. Druga zasada mówi, że automatyzacja zastosowana do nieefektywnego działania zwiększa poziom nieskuteczności”. Wiele zespołów, którym nie udało się poprawne wdrożenie specyfikacji przez przykłady, powiększyło swoją nieefektywność poprzez automatyzację dotychczasowych (niepoprawnych) praktyk. Zamiast więc skupiać się na konkretnym narzędziu, chcę zaproponować rozwiązanie problemów, które są prawdziwą przyczyną niepowodzeń. Jeśli tylko uda Ci się zapanować nad komunikacją i ustalić zasady współpracy, przyjdzie czas na wybranie odpowiednio dopasowanego narzędzia. Jeśli po przeczytaniu tej książki będziesz chciał poszerzyć swoją wiedzę na temat narzędzi, które wspierają wdrożenie specyfikacji przez przykłady, odwiedź stronę http://specificationbyexample.com i przejrzyj znajdujące się tam zasoby.
Kilka słów na temat terminologii Jeśli jest to Twój pierwszy kontakt ze specyfikacją przez przykłady, ATDD, ze zwinnymi testami akceptacyjnymi, BDD czy z którymkolwiek z terminów, których ludzie używają na określenie zbioru praktyk będącego podstawowym tematem tej książki, oznacza to, że udało Ci się uniknąć wielu lat zamieszania spowodowanego powielaniem i kreowaniem mylących nazw. Powinieneś się z tego ucieszyć i możesz pominąć tę część wprowadzenia. Jeśli jednak zetknąłeś się kiedyś z którymkolwiek z wymienionych terminów, określenia używane przeze mnie w tej książce mogą Cię zaskoczyć. Za chwilę wyjaśnię, dlaczego wybrałem te, a nie inne terminy, i dlaczego uważam, że Ty także powinieneś zacząć z nich korzystać.
Wprowadzenie
17
Podczas prac nad tą książką borykałem się z problemami, które nie są obce wszystkim praktykom piszącym na temat zautomatyzowanych specyfikacji. Jeśli terminologia ma mieć sens, musi być spójna. Często rozumiemy to dopiero wtedy, gdy sami zabieramy się do opisania jakiegoś zagadnienia. Ponieważ moja książka jest produktem bazującym na cyklu wywiadów, a wiele osób, z którymi rozmawiałem, używało różnych terminów do nazwania tej samej rzeczy, uzyskanie spójności terminologicznej okazało się zadaniem niezwykle trudnym. Zdałem sobie sprawę, że specjaliści realizujący reguły specyfikacji przez przykłady w praktyce — na czele ze mną — sami są sobie winni, bo to przecież oni używają zdradliwych terminów technicznych, wprowadzających w błąd nie tylko ich samych, ale i wszystkich tych, którzy próbowali wdrożyć owe praktyki. Wtedy zdecydowałem, że jednym z celów tej książki będzie opracowanie spójnej terminologii, którą będą mogli posługiwać się wszyscy członkowie społeczności wytwórców oprogramowania. Jeśli zależy nam na większym zaangażowaniu w prace projektowe użytkowników biznesowych — co jest przecież jednym z naszych głównych celów — musimy zacząć używać właściwych terminów do nazwania właściwych rzeczy. Czas przestać wprowadzać zamieszanie! Doskonale rozumiemy potrzebę zachowania spójności, gdy tworzymy specyfikacje. Wiemy, że musimy zachować powtarzalność terminów i unikać wprowadzania pojęć niejednoznacznych. Tyle że jakoś zapominamy o tym, gdy zaczynamy mówić o procesach. Na przykład gdy mówimy o ciągłej integracji w kontekście specyfikacji przez przykłady, tak naprawdę wcale nie chodzi nam o wykonywanie testów integracyjnych. Dlaczego więc mielibyśmy używać tego terminu, a następnie wyjaśniać, czym różnią się testy akceptacyjne od testów integracyjnych? Zanim sam nie zacząłem używać terminu warsztat specyfikacji do nazwania spotkania, w którym uczestniczą osoby odpowiedzialne za wspólne opracowanie testów akceptacyjnych, miałem spore trudności, aby przekonać użytkowników biznesowych do udziału w takich zgromadzeniach. Zwykła zmiana nazwy sprawiła, że problem przestał istnieć. Dzięki użyciu lepszego glosariusza terminologicznego można uniknąć zupełnie bezsensownych dysput, sprawiając, że wszyscy dobrze się rozumieją.
Dlaczego specyfikacja przez przykłady? W pierwszej kolejności chciałbym wyjaśnić, dlaczego wybrałem termin „specyfikacja przez przykłady” dla nazwania zbioru praktyk. Dlaczego nie zwinne testowanie akceptacyjne, BDD czy ATDD? Podczas konferencji „Domain Driven Design eXchange”, która odbyła się w 2010 roku w Londynie3, Eric Evans stwierdził, że termin zwinny (ang. agile) stracił już wszelkie znaczenie, bo obecnie wszystko można nazwać zwinnym. Niestety Eric ma rację. Widziałem o wiele za dużo zespołów, próbujących wdrożyć proces, który nie miał szans zakończenia się powodzeniem, choć wszystkim wydawało się, że etykietka agile w jakiś magiczny sposób sprawi, że okaże się skuteczniejszy, niż był w rzeczywistości. Przecież mamy do swojej dyspozycji ogromną bibliotekę dostępnego piśmiennictwa omawiającego prawidłowe wdrażanie zasad programowania ekstremalnego, Scruma czy innych mniej popularnych procesów z bogatego wachlarza praktyk zwinnych. 3
http://skillsmatter.com/event/design-architecture/ddd-exchange-2010.
18
Specyfikacja na przykładach
Aby odejść od tych wprowadzających zamieszanie niejasności oraz dyskusji na temat tego, czy zwinne praktyki się sprawdzają, czy nie (i wyjaśnić, co to właściwie znaczy być agile), w tej książce staram się ze wszystkich sił unikać terminu zwinny. Używam go tylko wtedy, gdy nawiązuję do zespołów, które rozpoczęły realizację dobrze zdefiniowanych procesów zbudowanych na zasadach określonych w Manifeście Agile. Tak więc w sytuacji, gdy nie mogę umieścić wtrętu ze słowem „agile” w co drugim moim zdaniu, użycie terminu „zwinne testowanie akceptacyjne” jest po prostu nie do przyjęcia. Opisane w tej książce praktyki nie stanowią kompletnej metodyki tworzenia oprogramowania. Są za to uzupełnieniem innych metod — zarówno tych bazujących na iteracji, jak i na przepływach — zapewniając dyscyplinę specyfikacji i testów, poprawiając komunikację między interesariuszami i członkami zespołów deweloperskich, ograniczając liczbę zbędnych przeróbek i ułatwiając wprowadzanie zmian. Nie chcę zatem używać żadnego terminu zawierającego element „Driven Development” (a zwłaszcza Behavior-Driven Development — BDD). Nie chodzi o to, że mam coś przeciwko BDD. Wręcz przeciwnie! Kocham BDD i uważam, że większość z tego, co znajdziesz w tej książce, w rzeczywistości stanowi kluczowy element BDD. Ale BDD również jest ofiarą problemu z nazewnictwem. Znaczenie terminu BDD podlega ciągłym zmianom. Dan North, największy autorytet w kwestii metodyki BDD oraz człowiek, który jako jeden z niewielu ma prawo decydować, czym jest i czym nie jest BDD, stwierdził podczas konferencji „Agile Specifications, BDD and Testing Exchange” w 2009 roku, że BDD jest metodyką4. (A dokładniej powiedział, że BDD jest: „zwinną metodyką drugiej generacji, typu outside-in, pull-based, multiplestakeholder, multiple-scale, high-automation”). Aby uniknąć nieporozumień i niejasności w kwestii różnicy pomiędzy definicją BDD zaproponowaną przez Dana Northa a tym, co ja sam uważam za BDD, rezygnuję ze stosowania także tego terminu. Ta książka mówi o precyzyjnie zdefiniowanym zestawie praktyk, które można stosować w ramach różnych metod, w tym również metodyki takiej jak BDD (jeśli przyjąć, że BDD naprawdę jest metodyką). Chciałbym również uniknąć nadużywania terminu test. Wielu menedżerów i użytkowników biznesowych niestety uważa testy za aktywność uzupełniającą o czysto technicznej naturze, a nie coś, w czym chcieliby brać udział. Przecież mają od tego wyspecjalizowanych testerów! Specyfikacja przez przykłady wymaga aktywnego uczestnictwa interesariuszy i członków zespołu dostarczającego oprogramowanie, włącznie z deweloperami, testerami i analitykami. Jeśli nie możemy nadużywać terminu test, trudno mówić o testowaniu historyjek, zwinnym testowaniu akceptacyjnym i posługiwać się innymi, podobnymi określeniami. W ten oto sposób doszliśmy do terminu specyfikacja przez przykłady, który staje się najsensowniejszym wyborem, ponieważ niesie najmniejszy bagaż negatywnych konotacji.
Wzorce procesów Na model specyfikacji przez przykłady składa się kilka wzorców procesów, tj. etapów cyklu życiowego procesu wytwarzania oprogramowania, definiowanych w nieco szerszej perspektywie. Terminy, których używam w tej książce w kontekście specyfikacji przez przykłady, 4
http://skillsmatter.com/podcast/java-jee/how-to-sell-bdd-to-the-business.
Wprowadzenie
19
są efektem wymiany opinii na spotkaniach grupy użytkowników „UK Agile Testing”, dyskusji poruszanych w korespondencji grupy „Agile Alliance Functional Testing Tools” oraz na licznych warsztatach, w jakich miałem okazję uczestniczyć. Niektóre nazwy procesów pojawiają się w materiałach fachowych już od jakiegoś czasu. Inne będą zupełnie nowe dla większości czytelników. Bardzo często zdarza się, że członkowie społeczności używają nazwy praktyki lub narzędzia do opisania części procesu. Dobrym przykładem może być tu termin feature injection nazywający jedną z metod określania zakresu projektu na podstawie zdefiniowanych celów biznesowych. Trzeba zdawać sobie sprawę z tego, że feature injection to tylko jedna z dróg prowadzących do celu. Istnieją inne, alternatywne sposoby jego osiągnięcia. Aby mówić o rozwiązaniach, na jakie decydują się różne zespoły w różnych kontekstach, potrzebujemy koncepcji wyższego poziomu, która obejmie swoją definicją wszystkie te działania. Dobra nazwa opisuje oczekiwany wynik i jednoznacznie wskazuje kluczowy element wyróżniający cały zestaw praktyk. W przypadku feature injection i temu podobnych praktyk celem działań jest uzyskanie jasnej wizji zakresu projektu lub kamienia milowego. Kluczowym wyróżnikiem tej metody jest fakt, że skupiamy się przede wszystkim na celach biznesowych. I właśnie dlatego proponuję, abyśmy zamiast mówić o jakimś wstrzykiwaniu funkcjonalności, mówili o definiowaniu zakresu na podstawie celów. Jednym z największych problemów, z którymi muszą poradzić sobie zespoły wdrażające specyfikację przez przykłady, jest jasne i jednoznaczne określenie, kto i kiedy powinien wykonać ustaloną część pracy. Potrzebujemy zatem właściwego terminu, który nie pozostawi cienia wątpliwości co do tego, że zależy nam na zaangażowaniu wszystkich (jeszcze zanim zespół zajmie się programowaniem lub testowaniem), ponieważ chcemy, aby testy akceptacyjne stały się celem procesu wytwarzania oprogramowania. Termin test first (czyli najpierw test) jest dobrym pojęciem technicznym, ale użytkownicy biznesowi go nie zrozumieją, a w użytej formie nie ma niczego, co nawiązywałoby do konieczności ścisłej współpracy wszystkich zainteresowanych stron projektu. Proponuję mówić o wspólnym specyfikowaniu i nie posługiwać się terminami „najpierw test” lub „tworzenie testów akceptacyjnych”. Dążenie do uwzględnienia w ramach zautomatyzowanych testów funkcjonalnych wszystkich możliwych wartości wydaje się działaniem całkiem naturalnym. Dlaczego mielibyśmy tego nie robić, jeśli test jest automatyczny? Tymczasem takie skomplikowane, złożone testy są bezużyteczne w funkcji narzędzia komunikacji, a w ramach specyfikacji przez przykłady musimy używać testów w celu optymalizacji komunikacji. A zatem zamiast pisać testy funkcjonalne, zajmijmy się raczej opisywaniem z pomocą przykładów ilustrujących i oczekujmy, że wynikiem tego procesu będą kluczowe przykłady, które mają nam służyć tylko do właściwego przedstawienia kontekstu5. Kluczowe przykłady są w zasadzie surowym materiałem, ale jeśli mówimy o testowaniu akceptacyjnym, to dlaczego nie mielibyśmy po prostu wrzucić do testu akceptacyjnego bez żadnego wyjaśnienia skomplikowanych tabel składających się z pięćdziesięciu kolumn i stu wierszy z przykładami? Przecież i tak testy wykonywać będzie komputer. W metodyce 5
Za tę sugestię dziękuję Davidowi Evansowi.
20
Specyfikacja na przykładach
specyfikacji przez przykłady zakłada się, że testy są tworzone nie tylko dla automatów, ale i dla ludzi. Musimy zatem wyjaśnić, że po przedstawieniu wykorzystania przykładów należy wykonać kolejny krok, w którym wybieramy minimalny zestaw atrybutów i przykładów przydatnych do określenia reguł biznesowych, uzupełniając opis i nadając specyfikacji jakiś tytuł i tak dalej. Proponuję nazwać ten etap udoskonalaniem specyfikacji6. Wynikiem tego procesu jest: specyfikacja, cel dla zespołu wytwarzającego oprogramowanie, obiektywna metoda uzyskania akceptacji oraz funkcjonalny test regresji, który będzie można wykonać później. Nie chcę nazywać tego komponentu procesu testem akceptacyjnym, ponieważ wówczas trudno byłoby uzasadnić, dlaczego dokument uzyskany na tym etapie musi pozostać w języku domeny, być czytelny i łatwo dostępny. Proponuję nazwać wynik udoskonalania specyfikacji specyfikacją z przykładami. Ten termin natychmiast przywołuje na myśl fakt, że dokument wynikowy musi bazować na przykładach, ale także zawierać coś więcej niż surowe dane. Nazwanie tego artefaktu specyfikacją sprawia, że staje się oczywiste, iż każdy powinien o niego dbać. Tym samym specyfikacja z przykładami zachowa formę dokumentu prostego i łatwego do zrozumienia. Poza tym zupełnie inną kwestią jest w takim przypadku ustalenie, czy takie testy mają automatycznie akceptować oprogramowanie, czy raczej automatycznie odrzucać kod, który nie spełnia naszych wymagań7. Nie chcę już więcej spędzać czasu na sprzeczkach, udowadniając ludziom, którzy zapłacili za licencję na QTP, że oprogramowanie to jest zupełnie bezużyteczne jako narzędzie do wykonywania testów akceptacyjnych. Jeśli chodzi o automatyzację testów, zawsze będziemy mieli do czynienia z ogromną presją dotyczącą wykorzystywania wszelkich dostępnych narzędzi używanych przez testerów do automatyzacji pracy, ponieważ menadżerom wydaje się logiczne zastosowanie przez wszystkie zespoły jednego i tego samego narzędzia do automatyzacji testów. AAT i narzędzia BDD nie stanowią konkurencji dla QTP lub innych, podobnych aplikacji. Stworzono je z myślą o rozwiązaniu zupełnie innego problemu. Specyfikacja nie powinna być konwertowana na dokument o czysto technicznym charakterze wyłącznie z myślą o automatyzacji. Zamiast mówić o automatyzacji testów, nazwijmy automatyzacją test przeprowadzony bez zniekształcania danych — automatyzację walidacji bez zmiany specyfikacji. Zwrócenie uwagi na fakt, że musimy zautomatyzować walidację bez zmiany źródłowej specyfikacji, powinno pomóc nam w uniknięciu problemów wynikających z zastosowania skryptów i odwoływania się do bibliotek bezpośrednio w specyfikacjach testowych. Wykonywalna specyfikacja powinna pozostać niezmieniona — identyczna z tą, która powstała jeszcze na tablicy w pokoju projektowym. Nie powinna być tłumaczona na język poleceń Selenium. Po automatyzacji walidacji specyfikacji możemy użyć jej do przetestowania całego systemu. W ten sposób otrzymujemy wykonywalne specyfikacje. Powinno nam zależeć na regularnym sprawdzaniu wszystkich specyfikacji w celu zagwarantowania, że system nadal robi to, czego od niego oczekujemy, oraz — co równie ważne — sprawdzenia, czy specyfikacje wciąż jeszcze opisują to, co robi system. Gdybyśmy nazwali 6
Chciałbym w tym miejscu podziękować Elisabeth Hendrickson, która zasugerowała zastosowanie tego terminu. 7 http://www.developsense.com/blog/2010/08/acceptance-tests-lets-change-the-title-too.
Wprowadzenie
21
to działanie testem regresyjnym, wówczas bardzo trudno byłoby wyjaśnić testerom, dlaczego nie powinni dodać pięciu milionów innych przypadków testowych do gotowej, zgrabnej, małej i precyzyjnej specyfikacji. Jeśli użyjemy w tym kontekście terminu „ciągła integracja”, wtedy trudno nam będzie wyjaśnić, dlaczego testy nie zawsze powinny pokrywać całą specyfikację i sprawdzać działanie całego systemu. W przypadku niektórych gotowych i działających systemów musimy przeprowadzać testy akceptacyjne na żywym, realnym środowisku pracy. Testy integracji technicznej są przeprowadzane przed wdrożeniem. Nie mówmy zatem o testach regresyjnych lub o ciągłej integracji. Mówmy o częstej walidacji. Korzyści z zastosowania metodyki specyfikacji przez przykłady w perspektywie długoterminowej wynikają z uzyskania danych referencyjnych dotyczących tego, co robi system, równie istotnych jak sam kod, ale znacznie łatwiejszych do zrozumienia. To sprawia, że w tej samej perspektywie długoterminowej praca nad oprogramowaniem staje się bardziej wydajna, a współpraca z użytkownikami biznesowymi łatwiejsza. Co więcej, efektem końcowym wdrożenia metody jest lepsze dopasowanie projektowania oprogramowania i modeli biznesowych i po prostu znaczne ułatwienie pracy każdego człowieka zaangażowanego w realizację projektu. Jednak aby można było osiągnąć ten cel, nasze dane referencyjne naprawdę muszą zawierać relewantne informacje, muszą ułatwiać utrzymanie i konserwację oraz zachowywać pełną zgodność z kodem wewnętrznym. Nie powinniśmy gromadzić ogromnych archiwów testów, w których są wykorzystywane terminy modne trzy lata temu czy rok wstecz. Obciążone zespoły trudno przekonać do zrobienia kilku kroków do tyłu i aktualizacji testów. Jednak powrót do dokumentacji i jej modyfikacja po wprowadzeniu sporych zmian jest czymś naturalnym. Nie mówmy więc o folderach wypełnionych setkami testów, a porozmawiajmy raczej o tworzeniu systemu żyjącej dokumentacji. Dzięki temu znacznie łatwiej wyjaśnimy, dlaczego pewne elementy powinny być oczywiste i nie mogą wymagać dodatkowych objaśnień, dlaczego użytkownicy biznesowi potrzebują dostępu do tych danych i dlaczego — jeśli dane mają być łatwiejsze do odnalezienia — konieczne jest zachowanie odpowiedniego porządku i dobra organizacja. Tu dochodzimy do konkluzji: nie wybrałem tych terminów, bazując na ich dotychczasowej popularności, ale dlatego, że uważam tę terminologię za racjonalną. Nazwy wzorców procesów powinny tworzyć mentalny model, który naprawdę podkreśla najistotniejsze elementy poszczególnych etapów i rzeczywiście zmniejsza problemy z komunikacją. Mam nadzieję, że i Ty, drogi Czytelniku, zrozumiesz, co chcę przez to osiągnąć, i sam przekonasz się do nowej terminologii.
Podziękowania
T
a książka nie mogłaby powstać, gdyby nie wsparcie i wkład wielu ludzi. Przede wszystkim chciałbym podziękować tym, którzy pozwolili mi zaczerpnąć ze źródeł ich wiedzy i intelektu i którzy podzielili się ze mną swoimi doświadczeniami. Na moje ogromne podziękowania zasłużyli: Adam Knight, André Brissette, Andrew Jackman, Aslak Hellesøy, Børge Lotre, Channing Walton, Christian Hassa, Cindy Bartz, Clare McLennan, Damon Morgan, Francesco Rizzi, Gaspar Nagy, Geoff Bache, Hemal Kuntawala, Ian Cooper, Ismo Aro, Jodie Parker, Johannes Link, Jon Neale, Jonas Bandi, Justin Davis, Kumaran Sivapathasuntharam, Lance Walton, Lisa Crispin, Marco Milone, Marta Gonzalez Ferrero, Martin Jackson, Matthew Steer, Mikael Vik, Mike Vogel, Maykel Suarez, Pascal Mestdach, Peter Janssens, Phil Cowans, Pierre Veragen, Rakesh Patel, Rob Park, Scott Berger, Stuart Ervine, Stuart Taylor, Stephen Lloyd, Suzanne Kidwell, Tim Andersen, Tony To, Wes Williams oraz Xu Yi. To Wy stworzyliście tę książkę. Ja tylko zapisałem to, co mieliście mi do powiedzenia. Elisabeth Hendrickson, David Evans, Matt Wynne, Pekka Klärck i Ran Nyman wspaniałomyślnie pomogli mi w nawiązaniu kontaktów z ich kolegami, klientami i współpracownikami, wspierając mnie w badaniach prowadzonych na potrzeby tej książki. Adam Geras, Joseph Wilk, Markus Gärtner, Mike Stockdale, Rick Mugridge, Robert Martin, Dan North, Tom Vercauteren i Tom Roden pomogli mi w dopracowaniu wszystkich pomysłów i lepszym wyjaśnieniu przedstawianych przeze mnie koncepcji. Pierwszy rękopis powstającej książki otrzymali: Bas Vodde, Craig Smith, Alex Bepple, John Stevenson, Joseph Wilk, Michele Mauro, Oleksandr Alesinskyy, Robert Martin, Robert Wenner i Saicharan Manga. Chciałbym podziękować im za wszystkie uwagi oraz spostrzeżenia, którymi się ze mną podzielili. Na specjalne podziękowania za ostateczną korektę rękopisu w fazie produkcji zasłużył Rick Mugridge. Pracownicy wydawnictwa Manning — Jeff Bleiel, June Eding, Linda Recktenwald, Barbara Mirecki, Leslie Haimes, Martin Murtonen i Mary Piergies — odegrali kluczową rolę w procesie transformacji zbioru historyjek mojego autorstwa w prawdziwą książkę. Wielkie podziękowania należą się także Craigowi Larmanowi, Jimowi Shore’owi i Harveyowi Wheatonowi za to, że poświęcili swój czas, aby odpowiadać na moje e-maile.
O autorze
G
ojko Adžić złapał wirusa specyfikacji przez przykłady pięć lat temu. Od tego czasu pomógł już wielu zespołom we wdrożeniu tej metody, napisał dwie książki i przyczynił się do stworzenia kilku projektów typu open source promujących koncepcję specyfikacji przez przykłady. Gojko jest częstym prelegentem najważniejszych konferencji poświęconych inżynierii oprogramowania i metodologii wykonywania testów. Zarządza także grupą użytkowników zwinnej metodyki z siedzibą w Wielkiej Brytanii. Przez ostatnie 12 lat autor pracował jako programista, architekt, dyrektor techniczny i konsultant w projektach informatycznych, których celem było tworzenie aplikacji służących do zarządzania obrotem papierami wartościowymi, oprogramowania dla dostawców energii, firm zajmujących się pozycjonowaniem urządzeń mobilnych, portalami typu e-commerce, grami online, a także zaawansowanego oprogramowania do zarządzania konfiguracją systemów. Gojko kieruje Neuri Ltd., firmą z siedzibą w Wielkiej Brytanii, specjalizującą się w doradzaniu ambitnym zespołom — od start-upów internetowych aż po duże instytucje finansowe — podczas wdrażania specyfikacji przez przykłady i praktyk zwinnego testowania. Jeśli chciałbyś nawiązać kontakt z autorem, napisz na adres: [email protected] lub zajrzyj na stronę internetową http://gojko.net.
Forum Author Online Z autorem można się również skontaktować za pośrednictwem forum internetowego Autor Online, prowadzonego przez wydawnictwo Manning Publications. Wystarczy odwiedzić stronę: www.manning.com/SpecificationbyExample. Wydawnictwo Manning stawia sobie za cel stworzenie miejsca, w którym czytelnicy mogliby prowadzić konstruktywny dialog (między sobą oraz z autorami). Zaangażowanie wydawnictwa nie oznacza zobowiązania autora do poświęcenia określonego czasu na kontakt z czytelnikami, ponieważ udział w dyskusjach każdego z nich pozostaje dobrowolny (i nieodpłatny). Forum Author Online oraz archiwa dotychczasowych dyskusji będą dostępne na stronie internetowej wydawcy tak długo, jak długo książka pozostanie w ofercie wydawnictwa.
24
Specyfikacja na przykładach
CZĘŚĆ I
Zaczynamy!
1
Kluczowe korzyści
W
dobie internetu motywem przewodnim w świecie wytwórców oprogramowania jest czas dostawy produktu. W poprzedniej dekadzie projekty trwały kilka lat, a fazy projektu mierzono w miesiącach. Dziś czas trwania większości projektów liczy się w miesiącach, a czas realizacji faz skrócono do kilku tygodni lub nawet do kilku dni. Wszystko, co wymaga długoterminowego planowania, jest odrzucane. To oznacza rezygnację z dużych projektów, w których potrzebna jest obszerna specyfikacja oraz przygotowywane wcześniej szczegółowe analizy wymagań. Nie są już opłacalne zadania, na które trzeba poświęcić więcej czasu, niż trwa średnio faza projektu. Żegnajcie chwile zamrożenia kodu i tygodnie ręcznych testów regresji! Przy tak wysokiej częstotliwości zmian dokumentacja projektowa szybko staje się nieaktualna. Zachowanie aktualności szczegółowych, kompleksowych specyfikacji i planów testów wymaga zbyt wielkiego wysiłku i jest uważane za marnotrawstwo zasobów. Ludzie, którzy dawniej podczas swojej codziennej pracy bazowali na dokumentacji wymagań — analitycy biznesowi lub testerzy — często czują się zagubieni w nowej rzeczywistości, ponieważ nie wiedzą, jak mają się zachowywać w tym nowym świecie tygodniowych iteracji. Programiści, którym wydawało się, że nie będą cierpieć z powodu braku papierowej dokumentacji, tracą czas na przeróbki i utrzymanie niewymaganych funkcji. Zamiast przeznaczać czas na tworzenie wielkich planów, marnują tygodnie pracy, doprowadzając do perfekcji niepotrzebny produkt. W ostatnim dziesięcioleciu społeczność programistów dążyła do opracowania systemu tworzenia oprogramowania „we właściwy” sposób, koncentrując się na działaniach czysto technicznych i pomysłach, które miały zapewnić odbiorcy produkt wysokiej jakości. Jednak tworzenie właściwego produktu i właściwe tworzenie produktu to dwie różne rzeczy. Jeśli myślimy o sukcesie, musimy zadbać o jedno i drugie.
28
Specyfikacja na przykładach
Rysunek 1.1. Specyfikacja przez przykłady pomaga zespołom tworzyć właściwy produkt, uzupełnia dobre praktyki inżynieryjne, które gwarantują, że produkt jest tworzony właściwie
Efektywne tworzenie właściwego produktu jest możliwe wówczas, gdy praktyki inżynierii oprogramowania gwarantują, że: Wszyscy interesariusze i członkowie zespołu pracującego nad dostarczeniem produktu są zgodni w kwestii tego, co powinno zostać wytworzone. Specyfikacje są na tyle precyzyjne, że zespoły mogą uniknąć niepotrzebnych przeróbek spowodowanych niejasnościami i lukami funkcjonalnymi. Istnieje obiektywny sposób oceny produktu pozwalający stwierdzić, że dzieło jest kompletne. Istniejąca dokumentacja ułatwia wprowadzanie zmian, zarówno pod względem funkcji oprogramowania, jak i struktury zespołu. W tradycyjnym modelu wytwarzania oprogramowania tworzenie odpowiedniego produktu wymagało zebrania obszernych wymagań funkcjonalnych, opracowania kompletnej dokumentacji oraz przejścia produktu przez długą fazę testowania. Dziś, w świecie kolejnych wersji oprogramowania wydawanych co tydzień, takie praktyki po prostu się nie sprawdzają. Potrzebujemy rozwiązania, które pozwala nam na: Uniknięcie tworzenia złożonej dokumentacji pełnej niepotrzebnych szczegółów i marnotrawienia czasu na doprecyzowanie detali, które zmienią się, zanim dany etap prac zostanie zakończony. Dysponowanie wiarygodną dokumentacją, która wyjaśnia, co robi system, dzięki czemu z łatwością można wprowadzić wszelkie zmiany. Dysponowanie skutecznym narzędziem sprawdzania, czy system robi to, co mówi specyfikacja.
Rozdział 1. Kluczowe korzyści
29
Zachowanie relewantności i wiarygodności dokumentacji przy minimalnych kosztach utrzymania. Dopasowanie wszystkich wcześniej wymienionych elementów do krótkich iteracji i procesów bazujących na przepływach tak, aby informacja na temat prognozowanego zakresu najbliższych prac zawsze pojawiała się na czas.
Rysunek 1.2. Kluczowe czynniki decydujące o powstaniu właściwej dokumentacji na potrzeby zwinnych procesów
Mimo że wymienione cele na pierwszy rzut oka mogą wydawać się sprzeczne, wielu zespołom udało się osiągnąć je wszystkie. Zbierając materiały na potrzeby tej książki, rozmawiałem z członkami trzydziestu zespołów, które realizowały około pięćdziesięciu projektów. Szukałem schematów działań i podobnych do siebie praktyk oraz zidentyfikowanych podstawowych reguł stojących za tymi praktykami. Powtarzające się koncepcje wykorzystywane w tych projektach składają się na dobrą metodę tworzenia właściwego oprogramowania: specyfikację przez przykłady. Specyfikacja przez przykłady jest zestawem wzorów procesów, które pomagają zespołom tworzyć właściwe oprogramowanie. W tej metodzie zespoły piszą tylko taką dokumentację, która ułatwia im wprowadzanie zmian w krótkich iteracjach lub w procesach wytwórczych bazujących na przepływach. Najważniejsze schematy procesów specyfikacji przez przykłady zostaną wprowadzone w następnym rozdziale. W tym zajmę się przedstawieniem korzyści wynikających z wdrożenia specyfikacji przez przykłady. Zadanie to wykonam w stylu charakterystycznym dla całej metody — zamiast wymyślać przykłady czysto teoretyczne, przedstawię osiemnaście rzeczywistych historii zespołów, które bardzo skorzystały na wdrożeniu reguł specyfikacji przez przykłady. Pozwól jednak, że zanim przejdę do konkretów, podkreślę, jak trudne jest wyizolowanie wpływu lub efektu jednego, konkretnego elementu projektu. Praktyki opisane w tej książce wpływają na skuteczność innych, lepiej znanych komponentów zwinnego tworzenia oprogramowania (tj. takich uznanych praktyk jak TDD, ciągła integracja i planowanie
30
Specyfikacja na przykładach
z wykorzystaniem historyjek użytkowników) i poprawiają ją. Jednak analizując szereg projektów w różnych kontekstach, można zidentyfikować powtarzające się w nich wzorce i schematy. Niektóre z zespołów, których pracę analizowałem, korzystały ze zwinnych procesów jeszcze przed wdrożeniem zasad specyfikacji przez przykłady, a inne wdrożyły te reguły podczas przechodzenia na metodykę zwinną inżynierii oprogramowania. Większość zespołów wykorzystywała procesy oparte na iteracjach, takie jak Scrum i programowanie ekstremalne (ang. Extreme Programming — XP), lub bazujące na przepływach (Kanban), ale zdarzały się także zespoły stosujące wymienione praktyki w środowiskach, które zupełnie, według żadnego standardu, nie mogły uchodzić za zwinne. A przecież większość tych zespołów donosiła, że udaje im się osiągnąć podobne korzyści, takie jak: Sprawniejsze wprowadzanie zmian — zespoły dysponowały żyjącą dokumentacją, wiarygodnym źródłem informacji na temat funkcjonalności systemu, dzięki któremu można było łatwo przeanalizować konsekwencje potencjalnych zmian i sprawnie dzielić się wiedzą. Wyższa jakość produktu — zespołom udawało się jasno określać stawiane przed nimi zadania i definiować oczekiwania, co poprawiało wydajność procesu weryfikacji. Mniej przeróbek — członkowie zespołu lepiej ze sobą współpracowali, korzystając z tej samej specyfikacji, co sprawiało, że wszyscy mieli takie samo wyobrażenie na temat oczekiwań. Lepsze dostosowanie aktywności do różnych ról w ramach projektu — poprawa jakości współpracy prowadziła do zwiększenia regularności wydawania gotowych wersji produktów. W najbliższych czterech częściach tego rozdziału przyjrzymy się bliżej każdemu ze wspomnianych dobrodziejstw specyfikacji przez przykłady. Przedstawię korzyści na przykładach z rzeczywistego świata inżynierii oprogramowania.
Sprawniejsze wprowadzanie zmian Jedna z najważniejszych rzeczy, jakich nauczyłem się podczas zbierania materiałów do tej książki, dotyczyła długoterminowych korzyści wynikających z posiadania żyjącej dokumentacji. Tak naprawdę uważam też, że jest to jedno z najważniejszych przesłań całej książki, i mam zamiar omówić to zagadnienie bardziej szczegółowo w osobnym rozdziale. Żyjąca dokumentacja to źródło informacji na temat funkcjonalności systemu. Jest równie wiarygodna co kod oprogramowania, ale wyróżnia się znacznie większą dostępnością i zrozumiałością. Żyjąca dokumentacja umożliwia zespołom wspólne analizowanie wpływu proponowanych zmian i omawianie potencjalnych rozwiązań. Pozwala również skorzystać z istniejącej dokumentacji, rozszerzając ją o nowe wymagania. To sprawia, że określanie i wdrażanie zmian staje się z czasem bardziej efektywne. Zespoły odnoszące największe sukcesy odkryły długoterminowe korzyści z posiadania żyjącej dokumentacji w wyniku wdrożenia specyfikacji przez przykłady.
Rozdział 1. Kluczowe korzyści
31
W 2009 roku Iowa Student Loan Liquidity Corporation z siedzibą w West Des Moines w stanie Iowa przeszła dość istotną zmianę modelu biznesowego. Ostatnie zawirowania na rynkach finansowych sprawiły, że znalezienie źródeł finansowania prywatnych pożyczek studenckich stało się niemal niemożliwe. Z tego powodu wielu kredytodawców zostało zmuszonych do opuszczenia rynku kredytów studenckich lub zmiany swoich modeli biznesowych. Iowa Student Loan Liquidity Corporation udało się jednak dostosować do nowych warunków biznesowych. Zamiast korzystać z wpływów z obligacji, pozyskiwano teraz środki z banków i innych instytucji finansowych. Jeśli adaptacja do nowych warunków rynkowych miała się udać, konieczna była — według analityka oprogramowania i programisty Tima Andersena — „całkowita modyfikacja rdzenia systemu”. Podstawowym mechanizmem dokumentowania wymagań biznesowych podczas tworzenia oprogramowania była żyjąca dokumentacja. To dzięki niej można było ustalić, jakie będą konsekwencje dostosowania się do nowych wymogów, określić zakres koniecznych zmian, upewnić się, że reszta systemu działa — jak wcześniej — bez zarzutu. Deweloperom udało się wprowadzić zasadnicze zmiany w systemie i przekazać go do produkcji w czasie zaledwie jednego miesiąca. Kluczowym elementem umożliwiającym sprawne wprowadzenie zmian okazało się istnienie żyjącej dokumentacji. Tim Andersen przyznaje: Każdy system, w którym nie byłoby testów [żyjącej dokumentacji], doprowadziłby do wstrzymania prac projektowych i trzeba byłoby tworzyć wszystko od zera. Podobne doświadczenia zebrał zespół projektu Talia, pracujący dla Pyxis Technologies z Montrealu (w prowincji Quebec). Talia to wirtualny asystent stworzony na potrzeby systemów korporacyjnych, robot chatu, komunikujący się z pracownikami według skomplikowanych zasad. Od pierwszego dnia prac nad projektem zespół korzystał ze specyfikacji przez przykłady, budując system żyjącej dokumentacji. Rok później pojawiła się konieczność stworzenia rdzenia silnika wirtualnego agenta od podstaw — i właśnie wtedy okazało się, że inwestycja w żyjącą dokumentację naprawdę przyniosła wymierne korzyści. André Brissette, dyrektor produktu w projekcie Talia, skomentował: Bez niej wszelkie prace refaktoryzacyjne byłyby samobójstwem. Żyjąca dokumentacja dała zespołowi pewność, że kiedy uda się wprowadzić wszystkie zmiany, nowy system będzie działać tak samo jak stary. Dzięki niej André Brissette mógł także śledzić postępy projektu i właściwie nim zarządzać. Zespół Songkick z siedzibą w Londynie, pracujący nad witryną udostępniającą muzykę na żywo, wykorzystywał system żyjącej dokumentacji do ułatwienia wprowadzania zmian w trakcie przebudowy kanałów aktywności na stronie, gdy stało się jasne, że ich wcześniejsza konstrukcja nie zapewnia wymaganej skalowalności w zakresie wydajności. Żyjąca dokumentacja przydała się, kiedy trzeba było odtworzyć kanały. Phil Cowans, CTO Songkick, szacuje, że dzięki żyjącej dokumentacji zespół oszczędził co najmniej 50% czasu potrzebnego na wprowadzenie zmian. Według Cowansa:
32
Specyfikacja na przykładach
Ponieważ dysponowaliśmy tak dobrym pokryciem i naprawdę mogliśmy wierzyć w wyniki naszych testów [w systemie żyjącej dokumentacji], pracując nad poważnymi szybkimi zmianami w infrastrukturze, czuliśmy się bardzo pewnie. Wiedzieliśmy, że funkcjonalność systemu nie zmieni się, a nawet gdyby miała się zmienić, będziemy o tym wiedzieć dzięki testom. Zespół programistów ePlan Services, firmy z siedzibą w Denver w stanie Kolorado, oferującej udziały w funduszach i narzędzia polityki emerytalnej, wykorzystywał specyfikację przez przykłady od 2003 roku. Informatycy stworzyli i utrzymywali aplikację zarządzającą usługami finansowymi, która była kompromisem oczekiwań wielu zainteresowanych stron, działała według skomplikowanych reguł biznesowych i złożonych wymogów zgodności. Trzy lata po rozpoczęciu projektu menedżer dysponujący unikalną wiedzą na temat części działającego systemu przeniósł się do Indii. Według Lisy Crispin, testera pracującego dla ePlan Services i autorki Agile Testing: A Practical Guide for Testers and Teams (Addison Wesley, 2009), zespół ciężko pracował, aby odtworzyć bazę wiedzy menedżera, gromadząc ją w żyjącej dokumentacji. Nowy system żyjącej dokumentacji pozwolił członkom zespołu odzyskać to, co stracono wraz z odejściem specjalisty, i sprawił, że ta wiedza stała się dostępna dla wszystkich członków zespołu. W ten sposób wyeliminowano wąskie gardło w zakresie transferu wiedzy, umożliwiając tym samym skuteczne wsparcie i rozbudowę aplikacji. Zespół projektowy Central Patient Administration IHC Group w belgijskim Oostkamp wdrożył system żyjącej dokumentacji z podobnymi wynikami. Projekt, który pierwotnie zakładał modyfikację istniejącego głównego systemu, rozpoczął się w 2000 roku. Pascal Mestdach, architekt ds. rozwiązań, powiedział, że zespół osiągnął ogromne korzyści: Tylko nieliczni deweloperzy wiedzieli, jakie funkcje pełniły niektóre elementy naszego starego systemu. Dzisiaj wiemy na ten temat o wiele więcej, ponieważ zespół może korzystać ze stale powiększającego się zestawu testów [żyjącej dokumentacji] powiązanych tematycznie z poszczególnymi funkcjami i opisujących działanie systemu. Ponadto uzyskujemy także odpowiedzi na trudne pytania nawet wtedy, gdy specjalista jest na urlopie. Dzięki tej bazie wiedzy inni deweloperzy mogą łatwo i szybko sprawdzić, za co odpowiada konkretna część kodu oprogramowania. I ten system pomyślnie przeszedł wszystkie testy. Opisane przykłady pokazują, że system żyjącej dokumentacji pomaga zespołom roboczym sprawnie dzielić się wiedzą i radzić sobie ze zmianami w składzie grupy pracowników. Pozwala również efektywniej reagować na zmiany rynkowe. Tym zagadnieniem zajmę się szerzej w rozdziale 3.
Wyższa jakość produktu Specyfikacja przez przykłady poprawia współpracę między członkami zespołu pracującego na rzecz dostarczenia produktu, ułatwia komunikację z użytkownikami biznesowymi i pozwala zdefiniować jasne, obiektywne cele zespołu pracowników — prowadząc przy tym do dużej poprawy jakości produktu.
Rozdział 1. Kluczowe korzyści
33
Chciałbym przedstawić dwa wyróżniające się studia przypadków. Wes Williams, zwinny trener z Sabre Holdings, oraz Andrew Jackman, programista konsultant, który pracował nad projektem dla BNP Paribas, opowiadają, jak projekty, których długo nie udało się zakończyć z powodzeniem, ostatecznie powiodły się dzięki zastosowaniu reguł specyfikacji przez przykłady. Metodyka opisana w tej książce pomogła zespołom poradzić sobie ze złożonością domen biznesowych, których wcześniej nie dało się opanować, a także zapewnić wysoką jakość produktu dostarczanego klientom. W Sabre Holdings Wes Williams pracował nad ciągnącym się przez dwa lata projektem systemu rezerwacji biletów lotniczych wyróżniającym się skomplikowaną siecią globalnej dystrybucji i procesów opartych na wymianie danych. Do projektu zaangażowano trzydziestu programistów pracujących w trzech zespołach na dwóch kontynentach. Według Wesa Williamsa dwie pierwsze próby stworzenia systemu zakończyły się kompletnym fiaskiem, dopiero trzecia — gdy sięgnięto po specyfikację przez przykłady — wreszcie się powiodła. Oddajmy mu głos: Sprawdzaliśmy system na żywo z dużym klientem [dużą linią lotniczą] i nie było większych kłopotów. Wśród nielicznych problemów odkrytych podczas testów biznesowych [akceptacyjnych] tylko jeden, związany z przejściem na serwer awaryjny, został uznany za poważny (miał status: 1). Williams szacuje, że jednym z kluczy do sukcesu projektu okazało się wdrożenie zasad specyfikacji przez przykłady. Poza zapewnieniem wyższej jakości produktu metoda pozwoliła zbudować wzajemne zaufanie deweloperów i testerów. Projekt Sierra realizowany na potrzeby BNP Paribas jest kolejnym świetnym przykładem potwierdzającym to, że specyfikacja przez przykłady pomaga w tworzeniu produktów wysokiej jakości. Sierra to repozytorium danych dotyczących obligacji, w którym informacje z kilku systemów wewnętrznych, agencji ratingowych i innych źródeł zewnętrznych są konsolidowane, łączone, a następnie przesyłane do różnych systemów wewnątrz banku. Wcześniej różne systemy i organizacje stosowały te same terminy, nadając im różne znaczenia, co prowadziło do wielu nieporozumień. Według Channinga Waltona, jednego z deweloperów zespołu, który wymiernie przyczynił się do sukcesu projektu, dwie pierwsze próby stworzenia produktu skończyły się totalnymi klapami. Trzecia próba, tym razem udana, zakończyła się powodzeniem między innymi dlatego, że zastosowanie reguł specyfikacji przez przykłady pozwoliło zespołowi sprawnie poradzić sobie ze złożonością projektu i znaleźć odpowiedni sposób na zapewnienie pełnego zrozumienia systemu. Jakość produktu końcowego oceniono bardzo wysoko. Jak twierdzi Andrew Jackman, deweloper i konsultant projektu Sierra, gotowy system działający obecnie bez przestojów już od 2005 roku nie uległ od tego czasu żadnej poważniejszej awarii. Większość obecnych członków obsługi projektu Sierra nie uczestniczyło w rozpoczęciu projektu, a jakość utrzymywanego systemu wciąż zachwyca. Podobne wyniki uzyskała firma Bekk Consulting, opracowująca specjalistyczny system leasingu samochodów dla oddziału jednego z największych francuskich banków. Według Aslaka Hellesøya, członka pierwszego zespołu projektowego i autora Cucumbera, popularnego
34
Specyfikacja na przykładach
narzędzia automatyzacji działającego zgodnie z zasadami specyfikacji przez przykłady, w produkcie, który ujrzał światło dzienne dwa lata wcześniej, zgłoszono zaledwie pięć błędów, mimo że aplikacja wspierana jest obecnie przez zupełnie nowy zespół. Z kolei Lance Walton pracował jako konsultant procesu dla londyńskiego oddziału dużego banku szwajcarskiego w ramach projektu, którego celem było opracowanie systemu zarządzania zamówieniami. Wcześniejsze próby kilka razy kończyły się niepowodzeniem. Walton wyjaśnił, że projekt realizowano w unikalnym środowisku i zakładano, że zespół wsparcia systemu będzie co najmniej tak duży jak zespół deweloperów. Dzięki wdrożeniu specyfikacji przez przykłady udało się zakończyć projekt i przejść do fazy produkcji w czasie dziewięciu miesięcy od jego rozpoczęcia. Biznesowe testy akceptacyjne przeprowadzono z powodzeniem w trakcie jednego dnia, a w ciągu sześciu miesięcy po uruchomieniu systemu nie zgłoszono żadnych błędów. Według Waltona nowy system nie wymagał żadnego dodatkowego personelu pomocniczego, kosztował mniej, niż przewidywano, i umożliwił zespołowi wcześniejsze dostarczenie gotowego produktu. Dla porównania — poprzedni zespół pracujący nad realizacją wizji klienta zakładał, że zespół wsparcia będzie dziesięciokrotnie liczniejszy niż zespół rozwoju oprogramowania. Według Waltona: Obecnie zespół ciągle, regularnie co tydzień, przekazuje nową wersję oprogramowania, a użytkownicy są zawsze zadowoleni ze zmian. Pod kątem jakości produktu to wręcz wymarzona sytuacja. Techniki specyfikacji przez przykłady sprawdzają się zarówno w przypadku projektów typu brownfield, jak i greenfield1. To prawda, że na stworzenie wiarygodnej dokumentacji oraz oczyszczenie starych systemów potrzeba trochę czasu, ale zespoły szybko zaczynają dostrzegać wiele korzyści, nabierając przy tym pewności siebie i wierząc w dostarczane wersje produktów. Dobrym przykładem może być system zarządzania wymianą walut stworzony dla JP Morgan Chase w Londynie. Martin Jackson, pracujący przy tym projekcie konsultant ds. automatyzacji testów, stwierdził, że analitycy firmy oczekiwali opóźnienia projektu, a gotowy produkt został im dostarczony dwa tygodnie przed czasem. Wysoka jakość oprogramowania pozwoliła z powodzeniem zakończyć fazę biznesowych testów akceptacyjnych w czasie jednego tygodnia, a nie czterech, jak pierwotnie planowano. Jackson powiedział:
1
Projektem typu greenfield zwykło się nazywać działania w „obszarze dziewiczym”, czyli rozpoczynane właściwie zupełnie od zera, bez „infrastruktury” lub z co najwyżej podstawową infrastrukturą. Termin ten jest stosowany nie tylko w inżynierii oprogramowania, ale także w inwestycjach, budownictwie itd. Natomiast projekty typu brownfield — na zasadzie analogii — to inwestycje na bazie istniejących już, choć często nienadających się do wykorzystania komponentów — przyp. tłum.
Rozdział 1. Kluczowe korzyści
35
Uruchomiliśmy system i wszystko działało jak trzeba. Uczestniczący w testach stwierdzili w swoich raportach dla zarządu, że to było najlepsze doświadczenie UAT2, jakie kiedykolwiek stało się ich udziałem. Specyfikacja przez przykłady pozwoliła również zespołowi Jacksona na późniejszym etapie rozwoju projektu szybko wprowadzić „dość znaczącą modyfikację techniczną”, która poprawiała precyzję wykonywanych obliczeń. Jackson mówił: Cały zakres funkcjonalności pakietu FitNesse [żyjącej dokumentacji] przeszedł pozytywnie wszystkie testy systemowe, testy UAT, po czym bez jednego błędu został uruchomiony w środowisku produkcyjnym. Owszem, pojawiło się kilka błędów w komponentach nieznajdujących się w rdzeniu kodu; błędy te wychwycono podczas testowania systemu. Zebranie dobrych recenzji podczas testów UAT okazało się możliwe dzięki temu, że gdy pojawiły się błędy obliczeniowe, byliśmy przekonani, że wynikają one z danych niezależnych od podstawowego kodu obliczeniowego. Dzięki pakietowi FitNesse łatwiejsze okazało się także diagnozowanie źródeł defektów, co pozwoliło na bezproblemowe, szybsze przekazanie naszego dzieła do produkcji. Zespół ds. rozwoju oprogramowania w Weyerhaeuser w Denver (w stanie Kolorado) stworzył (a obecnie wspiera ich utrzymanie) kilka różnych aplikacji, których używa dział inżynierii, oraz silnik obliczeniowy wykorzystywany do analiz wymiarowania drewnianych ram. Przed zastosowaniem specyfikacji przez przykłady zatrudnieni w firmie inżynierowie zwykle nie byli angażowani w rozwój oprogramowania, chociaż zespół wykorzystywał w swoich programach złożone formuły obliczeniowe. W konsekwencji firma cierpiała z powodu wielu problemów z jakością produktu, a system wdrażano z opóźnieniami. Dodatkowe komplikacje wynikały z faktu, że z silnika obliczeniowego korzystało kilka aplikacji. Według Pierre’a Veragena, głównego SQA projektu, faza poprzedzająca udostępnienie produktu często ciągnęła się w nieskończoność, a sam produkt końcowy rzadko był wolny od błędów. Obecnie, po wdrożeniu reguł specyfikacji przez przykłady, zespół współpracuje przy tworzeniu specyfikacji z kilkoma konstruktorami oraz automatyzuje walidację. Gdy pojawia się wniosek o zmiany, testerzy pracują wspólnie z inżynierami strukturalnymi, aby zdefiniować oczekiwane rezultaty i wprowadzić je do specyfikacji w funkcji przykładów jeszcze przed rozpoczęciem prac programistycznych. Inżynier, który zatwierdza zmiany, później tworzy specyfikacje i testy. Veragen stwierdza, że podstawową zaletą nowego podejścia jest to, że wszelkie zmiany można obecnie wprowadzać z pełnym zaufaniem do wyniku końcowego. Na początku 2010
2
UAT (ang. User Acceptance Testing), czyli testy akceptacyjne z udziałem użytkownika, podczas których sprawdza się nie tyle działanie systemu (z perspektywy poprawności rozwiązań technicznych), ile proces jego wykorzystania przez użytkownika. W polskiej nomenklaturze mówi się czasami o „testach beta” — przyp. tłum.
36
Specyfikacja na przykładach
roku, gdy system żyjącej dokumentacji zawierał już ponad 30 000 testów, stwierdzono, że od lat nie pojawił się żaden poważny błąd, i zdecydowano o zaprzestaniu śledzenia błędów. Według Veragena: Nie potrzebujemy licznika [błędów], ponieważ wiemy, że nic nie pokaże… inżynierowie pokochali podejście »najpierw test« i fakt, że mają bezpośredni dostęp do zautomatyzowanych testów. Lance Walton pracował nad aplikacją do zarządzania ryzykiem kredytowym dla oddziału dużego francuskiego banku w Londynie. Na początku projektu zewnętrzni konsultanci pomagali zespołowi deweloperskiemu we wdrażaniu praktyk programowania ekstremalnego (XP), ale nie uwzględnili wprowadzenia w życie żadnej z reguł specyfikacji przez przykłady (chociaż w XP przewiduje się istnienie testów klienckich, które są niemal równoznaczne z wykonywalnymi specyfikacjami). Walton dołączył do zespołu po sześciu miesiącach i stwierdził, że kod ma niską jakość. Chociaż zespół dostarczał nowy produkt co dwa tygodnie, jakość powstającego kodu utrudniała właściwe wykonywanie walidacji. Deweloperzy testowali tylko ostatnio wprowadzone funkcje i w miarę rozrastania się systemu takie podejście przestawało wystarczać. „Gdy nadchodził etap przekazania produktu, ludzie rozglądali się nerwowo po sobie, sprawdzając, czy aby na pewno wszystko nadal działa, i spodziewając się poważnych błędów, które dadzą o sobie znać w ciągu kilku najbliższych godzin” — przyznał Walton. Po wdrożeniu praktyk specyfikacji przez przykłady jakość produktu oraz zaufanie do produktu znacznie się poprawiły. Walton dodaje: Byliśmy przekonani, że przekazanie gotowego produktu odbędzie się bez żadnych problemów. Po pewnym czasie zwykle po prostu uruchamialiśmy nową wersję systemu, a potem, zadowoleni, udawaliśmy się na lunch, nie siedząc przy komputerach i nie obserwując, czy aby wszystko działa. Za to projekt zakładający stworzenie nowej wersji strony internetowej Trader Media Group z Wielkiej Brytanii, gdy zespół zdecydował się zrezygnować ze stosowania reguł specyfikacji przez przykłady z powodu problemów z jakością produktu, zaczął się rozpadać. Początkowo członkowie zespołu ściśle ze sobą współdziałali, tworząc specyfikacje i pracując nad automatyzacją walidacji. Sytuacja zmieniła się ze względu na presję kierownictwa firmy, które chciało uzyskać większą funkcjonalność strony możliwie najwcześniej i najszybciej. „Zauważyliśmy, że jakość dramatycznie spadała” — powiedział Stuart Taylor, lider zespołu testowego. „Tak jak wcześniej testerom trudno przychodziło znalezienie jakiegokolwiek błędu w produkcie, tak później w jednej tylko historyjce znajdowaliśmy ich cztery czy pięć”.
Mniej przeróbek Częste dostarczanie kolejnych wersji produktu zwykle oznacza szybkie uzyskiwanie informacji zwrotnej, umożliwia zespołom deweloperów łatwiejsze znajdowanie błędów i szybsze ich usuwanie. Jednak krótkie iteracje nie wykluczają całkowicie istnienia błędów. Często
Rozdział 1. Kluczowe korzyści
37
Nie tylko dla zwinnych zespołów Wspólna praca nad dokumentacją może przynieść korzyści nie tylko zwinnym zespołom. W Bridging the Communication Gap† zasugerowałem, że podobny zestaw praktyk może znaleźć swoje zastosowanie także w procesach o bardziej tradycyjnym charakterze. Już po tym, gdy moja pierwsza książka ukazała się na rynku, a w trakcie zbierania materiałów do tej, którą trzymasz w ręku, natknąłem się na przykład pewnej firmy. Jej historia może być uznana za dowód, że miałem rację. Matthew Steer, starszy konsultant w brytyjskiej Sopra Group, wspomagał dużą firmę telekomunikacyjną w czasie, gdy zagraniczny podwykonawca rozpoczął wdrażanie praktyk specyfikacji przez przykłady. Podstawowym powodem wprowadzenia zmian był fakt stwierdzenia niedociągnięć w zakresie definiowania wymagań systemowych. Steer porównał ubiegłoroczne i aktualne koszty dostarczania oprogramowania. Nie zdziwił się, że przy zastosowaniu metody kaskadowej produkty nigdy nie miały zerowej liczby błędów, a zmiany wpłynęły na „poprawienie efektywności wykrywania wad na wczesnym etapie i zmniejszenie zakresu przeróbek oraz redukcję kosztów”. Słowami samego Steera: Mogliśmy wykazać skuteczność tej metody, ponieważ coraz więcej błędów udawało nam się wyłapywać we wczesnej fazie cyklu projektowania, a nie na ostatnich etapach, tak jak miało to miejsce wcześniej. Liczba defektów na końcu cyklu życia produktu wyraźnie spadła, a stos problemów zdefiniowanych już na początku zaczął rosnąć. W efekcie tylko w 2007 roku na kosztach dostarczenia produktów udało się oszczędzić 1,7 mln funtów szterlingów. †
Gojko Adžić, Bridging the Communication Gap: Specification by Example and Agile Acceptance Testing, Neuri Limited, 2009.
zdarza się, że zespoły próbują trzy lub cztery razy wprowadzić do systemu pewną funkcję. Deweloperzy twierdzą przy tym, że nieudane próby wynikają z tego, że klienci nie wiedzą, czego tak naprawdę chcą, dopóki nie dostaną w swoje ręce czegoś namacalnego, czym można się „pobawić”. Nie zgadzam się z taką argumentacją. Korzystającym ze specyfikacji przez przykłady zespołom udaje się trafić w dziesiątkę zwykle już przy pierwszej próbie. W ten sposób można zaoszczędzić mnóstwo czasu i sprawić, że proces dostarczania produktu staje się bardziej przewidywalny i pewniejszy. Grupa Sky Network Services (SNS) działająca w ramach British Sky Broadcasting Corporation z siedzibą w Londynie jest odpowiedzialna za pracę oprogramowania do zarządzania łączami szerokopasmowymi i usługą telefonii, wyróżniającego się dużą złożonością środowisk biznesowych i integracyjnych. Grupa składa się z sześciu zespołów, które od lat stosowały praktyki specyfikacji przez przykłady. Według Rakesha Patela, starszego zwinnego programisty Java: „Zwykle udaje się dotrzymać obietnicy”, a grupa ma świetną reputację w British Sky Broadcasting Corporation. Przez jakiś czas Patel współpracował z przedstawicielami innej firmy. Oto jak porównuje zespoły, w których przyszło mu pracować:
38
Specyfikacja na przykładach
Gdy oni [deweloperzy w innej organizacji] przekazywali pod koniec sprintu oprogramowanie testerom, ci za każdym razem znajdowali jakiś błąd i temat zawsze wracał do deweloperów. A tutaj [w British Sky Broadcasting Corporation] nie ma miejsca na takie zamieszanie. Jeśli pojawia się jakiś problem, tj. nie udaje się zakończyć testu powodzeniem na etapie rozwoju produktu, to wszystko sprowadza się tylko do tego, czy trzeba naprawić błąd, czy nie. Zajmujemy się problemem tu i teraz. Kilka innych zespołów zauważyło znaczne zmniejszenie liczby koniecznych przeróbek. Jednym z takich zespołów był LeanDog, grupa deweloperów pracująca nad stworzeniem aplikacji dla dużego ubezpieczyciela ze Stanów Zjednoczonych. Ich oprogramowanie odpowiada za wyświetlanie jednolitego interfejsu dla użytkowników pracujących w różnych systemach i korzystających z różnych usług internetowych. Sprawę dodatkowo komplikowała znaczna liczba uczestniczących w projekcie partnerów z całego kraju. Rob Park, zwinny trener LeanDog, który pomagał zespołowi podczas przejścia na nową metodę, stwierdził, że początkowo projekt cierpiał z powodu wielu luk funkcjonalnych: Gdy zaczęliśmy dochodzić do źródeł problemów, potrzebowaliśmy nieco jaśniejszego przekazu. I wtedy okazywało się, że tak naprawdę powinniśmy byli zrobić coś innego. Zespół zaczął wdrażać procesy specyfikacji przez przykłady, w wyniku czego znacznej poprawie uległa jakość specyfikacji, a liczba koniecznych przeróbek spadła. Mimo że gdy deweloperzy zaczynają pracę nad kartą historyjki, nadal zadają pytania analitykom biznesowym, „liczba pytań wyraźnie spadła, podobnie jak intensywność wymiany informacji, a pytania dotyczą obecnie zupełnie innych rzeczy” — powiedział Park. Dla niego najbardziej przekonującym aspektem specyfikacji przez przykłady jest fakt, że twórcy kodu „od razu łapią sens historyjki i znają jej zakres, gdy tylko rozpoczynają prace”. Wiele zespołów stwierdza również, że dzięki zastosowaniu praktyk specyfikacji przez przykłady na początku cyklu produkcyjnego do uszczegółowienia wymagań projektowych łatwiejsze staje się także zarządzanie rejestrem produktu. Na przykład możliwość wczesnego wykrycia historyjek, które są zbyt ogólnikowe lub które mają za dużo luk w zakresie wymaganej funkcjonalności, zapobiega ujawnianiu się problemów na późniejszych etapach cyklu rozwoju produktu. Bez specyfikacji przez przykłady zespoły często odkrywają istnienie problemów dopiero w trakcie iteracji, co wpływa negatywnie na płynność prac i wymaga czasochłonnych renegocjacji — a przecież w dużych przedsiębiorstwach osoby, które decydują o zakresie funkcjonalności, często nie są jakoś specjalnie łatwo dostępne. Specyfikacja przez przykłady pomaga zespołom w stworzeniu warunków do wspólnego definiowania specyfikacji, co zmniejsza prawdopodobieństwo pojawienia się problemów w trakcie iteracji. Ponadto specyfikacja przez przykłady doskonale pasuje do krótkich sprintów i nie wymaga miesięcy pisania długich dokumentów.
Rozdział 1. Kluczowe korzyści
39
Dla zespołu Global Talent Management w Ultimate Software w Weston na Florydzie mniejsza liczba przeróbek stanowi podstawową korzyść płynącą z zastosowania procesów specyfikacji przez przykłady. Współpraca na etapie tworzenia specyfikacji ma istotny wpływ na koncentrowanie wysiłków na rzecz rozwoju oprogramowania. Według Scotta Bergera, starszego inżyniera ds. rozwoju testów w Ultimate Software: Spotkanie z właścicielami produktu, którego celem jest dokonanie przeglądu scenariuszy testowych, zanim zespół zaakceptuje historyjkę, pozwala łatwo rozwiać wszelkie wątpliwości całej grupy roboczej (składającej się z właściciela produktu, dewelopera i testera) dzięki usunięciu niejednoznaczności lub doprecyzowaniu brakujących wymagań. Czasami zdarzało się też, że konsekwencją takiego spotkania było anulowanie całych historyjek, gdy na przykład scenariusze testowe ujawniły ukryte dotąd skomplikowane elementy składowe lub wskazały na istnienie sprzecznych wymagań w obrębie systemu. Po jednej z takich dyskusji zapadła decyzja, która wymagała niemal całkowitego przeprojektowania całej funkcji! Właściciele produktu uzyskali możliwość przepisania i ponownego podzielenia specyfikacji. Nie wymuszano rozpoczęcia prac programistycznych, które później trzeba byłoby zatrzymywać lub które zmuszałyby nas do zrezygnowania z określonej historyjki w połowie prac. Dzięki tym spotkaniom staliśmy się bardziej wydajni i skuteczni, ponieważ ograniczyliśmy niepotrzebne prace, a do sytuacji, w których musimy korzystać z niejasnych danych lub zaakceptować braki, dochodzi bardzo rzadko. Dzięki temu cały zespół lepiej rozumie, czego się od niego oczekuje. Większości zespołów udało się znacznie zmniejszyć lub całkowicie wyeliminować konieczność przeróbek, które wynikały z niezrozumienia wymogów lub zaniedbań w kontekście spełnienia oczekiwań klientów. Praktyki opisane w tej książce pomogły zespołom w nawiązywaniu udanej współpracy z użytkownikami biznesowymi i zapewnieniu lepszego zrozumienia wyników, którymi dysponowały wszystkie strony.
Lepsze dostosowanie aktywności Inną ważną zaletą specyfikacji przez przykłady jest możliwość dostosowania różnych aktywności procesu wytwarzania oprogramowania do krótkich cykli iteracyjnych. Z mojego doświadczenia oraz z analiz przypadków przygotowanych na potrzeby tej książki wynika, że jednym z najczęściej powtarzających się problemów, z którymi nie radzą sobie zespoły przechodzące na Scruma, jest niemożność wykonania zadania w czasie zdefiniowanego sprintu. Wiele zespołów trzyma się koncepcji „starego świata”: najpierw trzeba zakończyć programowanie, potem wykonać testy, a wreszcie udoskonalić produkt na tyle, żeby można go było przekazać klientowi. Takie podejście sprzyja podtrzymywaniu złudzenia, że rozwój oprogramowania składa się z etapów, podczas gdy w rzeczywistości potrzebne są następujące po sobie cykle testowania i poprawiania. Jednak kolumna „ukończono” na tablicy iteracji Scruma oznacza, że deweloperowi wydaje się, że naprawdę coś skończył. Dwie sąsiadujące ze sobą kolumny i znaki akceptacji „ukończone – ukończone” oznaczają, że tester
40
Specyfikacja na przykładach
zgadza się z opinią programisty i tak dalej (znam także przypadki tworzenia trzech kolumn „ukończone – ukończone – ukończone”). Praca nierzadko przebiega właśnie według tego wzoru, a wyniki testów często wpływają na kolejny cykl, przynosząc dużą zmienność i czyniąc proces dostarczania oprogramowania dużo mniej przewidywalnym. Specyfikacja przez przykłady rozwiązuje ten problem. Praktyki opisane w tej książce umożliwiają zespołom jasne określenie celu, rozumianego przez wszystkich uczestniczących w projekcie tak samo, a ponadto dającego się zmierzyć w sposób obiektywny. W rezultacie wiele zespołów stwierdza, że ich analizy, faza rozwoju i etap testowania są lepiej do siebie dopasowane. Dobrym przykładem takiego polepszenia dopasowania jest przypadek uSwitch, jednej z najbardziej obleganych stron internetowych w Wielkiej Brytanii. Firma uSwitch wdrożyła procesy specyfikacji przez przykłady w 2008 roku, a przyczyną takiego kroku były trudności związane z wątpliwościami w zakresie oceny „ukończenia” poszczególnych funkcji. „Kończyliśmy prace, przekazywaliśmy produkt do działu kontroli jakości, a oni od razu informowali nas, że zapomnieliśmy przetestować produkt w pewnym konkretnym scenariuszu. To sprawiało nam wiele problemów” — powiedział Stephen Lloyd, deweloper pracujący nad stworzeniem strony internetowej. Problem udało się rozwiązać dzięki wdrożeniu praktyk specyfikacji przez przykłady. Lloyd stwierdził, że od momentu ich wdrożenia osoby pracujące nad projektem są lepiej zintegrowane jako zespół i lepiej rozumieją potrzeby klienta. Zmiany procesu przyniosły również poprawę jakości oprogramowania. Hemal Kuntawala, inny deweloper zatrudniony przy wspomnianym projekcie, tak oto skomentował zmiany, jakie zaszły w zespole: Znacznie spadła liczba odnajdowanych na stronie błędów. Znacznemu skróceniu uległ również czas reakcji i proces usuwania błędów. Jeśli problem pojawia się na stronie online, zazwyczaj udaje nam się wprowadzić poprawki w ciągu kilku godzin, podczas gdy wcześniej zajmowało nam to kilka dni lub nawet tygodni. Zmiany na lepsze nie uszły także uwadze zespołu Beazley pracującego na zlecenie pewnej specjalistycznej firmy ubezpieczeniowej. Ich analitycy biznesowi ze Stanów Zjednoczonych współpracują z programistami i testerami z Wielkiej Brytanii. Zespół wdrożył praktyki specyfikacji przez przykłady przede wszystkim po to, aby zadbać, by oprogramowanie naprawdę było gotowe wraz z końcem iteracji. Ian Cooper, kierownik zespołu ds. rozwoju, przyznaje: Zawsze robiliśmy testy jednostkowe, ale problem polegał na tym, że testy mówiły nam, czy program działa, a nie czy wykonuje to, czego oczekuje od niego nasz klient. Zwykle testerzy nie zajmowali się wszyscy tym samym cyklem. Koncentrowali się na przekazaniu informacji z poprzedniej iteracji do bieżącej. Nic takiego nie ma już miejsca. Obecnie zupełnie inaczej podchodzimy do kwestii akceptacji produktu. Podobne doświadczenia miał pewien nowozelandzki zespół programistów pracujący nad AdScale.de, portalem oferującym usługi kojarzenia reklamodawców i reklamobiorców
Rozdział 1. Kluczowe korzyści
41
internetowych. Dwa lata po rozpoczęciu projektu interfejs użytkownika był już mocno skomplikowany, a integracja systemów sprawiła, że baza kodu urosła do takich rozmiarów, że trudno było kontrolować ją tylko na podstawie testów jednostkowych. Deweloperom wydawało się, że zakończyli prace nad jakimś elementem, zajmowali się kolejnym zagadnieniem, a potem, gdy produktowi przyjrzeli się testerzy, często zmuszani byli do powtórzenia swojej pracy. Ze względu na brak bliskiej współpracy pomiędzy testerami i programistami odnajdowanie i usuwanie problemów zajmowało dużo czasu. Problemy mające swoje źródła w poprzednich iteracjach wpływały na kolejne, zaburzając przepływy w ramach cyklu wytwarzania produktu. Po wdrożeniu procesów specyfikacji przez przykłady faza rozwoju i testowania zostały lepiej dopasowane. Clare McLennan, programista/tester pracująca nad projektem, przyznaje: Udało się nam wpłynąć na wyraźne zmniejszenie stresu związanego z procesem prowadzącym do przekazania gotowego produktu, ponieważ obecnie informacje zwrotne uzyskujemy natychmiast. Wcześniej deweloperzy wściekali się na nas ze względu na to, że nie mogli pochwalić się zakończeniem prac nad poszczególnymi funkcjami, a my z kolei wściekaliśmy się na nich, bo niczego nie poprawili i nie mogliśmy testować kolejnych funkcjonalności. My czekaliśmy na nich, a oni czekali na nas. Teraz nic takiego nie ma miejsca, ponieważ wykonanie wszystkich testów trwa godzinę. Funkcje nie wracają do następnej iteracji. Specyfikacja przez przykłady pozwala zespołom definiować oczekiwaną funkcjonalność w sposób jasny i mierzalny. Przyspiesza również feedback, poprawiając przepływ informacji w trakcie tworzenia oprogramowania, oraz zapobiega pojawianiu się przerw w zaplanowanej pracy.
Pamiętaj Właściwe tworzenie produktu oraz tworzenie właściwego produktu to dwie różne rzeczy. Aby osiągnąć sukces, musisz spełnić oba warunki. Specyfikacja przez przykłady pozwoli Ci zgromadzić bogatą dokumentację dokładnie wtedy, gdy jest ona potrzebna, promując tworzenie właściwego produktu w czasie krótkich iteracji lub podczas procesów rozwoju oprogramowania bazujących na przepływach. Specyfikacja przez przykłady przyczynia się do poprawy jakości oprogramowania, znacznie zmniejsza liczbę koniecznych przeróbek i umożliwia zespołom lepsze dopasowanie analizy, rozwoju i testowania produktu. W dłuższej perspektywie specyfikacja przez przykłady pomaga zespołom w tworzeniu systemu żyjącej dokumentacji, godnego zaufania i niezawodnego opisu funkcjonalności, który jest automatycznie aktualizowany wraz ze zmianą kodu języka programowania. Procesy specyfikacji przez przykłady najlepiej sprawdzają się z krótkimi iteracjami (Scrum, XP) lub w metodach bazujących na przepływach (Kanban). Niektóre koncepcje
42
Specyfikacja na przykładach
można zastosować również w systemach strukturalnych (takich jak Rational Unified Process czy w systemie kaskadowego wytwarzania oprogramowania). Zdarzało się, że specyfikacja przez przykłady pozwalała firmom oszczędzić naprawdę wielkie pieniądze.
2
Wzorce kluczowych procesów
S
pecyfikacja przez przykłady to zbiór wzorców procesów, które ułatwiają wprowadzanie zmian do oprogramowania w celu zagwarantowania dostarczenia klientowi właściwego produktu. Na rysunku 2.1 pokazano wzorce kluczowych procesów stosowane powszechnie przez najskuteczniejsze zespoły, badane przeze mnie podczas zbierania materiałów do tej książki, oraz ich wzajemne relacje. Większość zespołów wdrożyła nowe koncepcje procesów metodą prób i błędów w trakcie poszukiwania sposobów na zwiększenie efektywności działań mających na celu wytwarzanie i utrzymanie opracowanego przez siebie oprogramowania. Opisując te procesy, mam nadzieję pomóc innym zespołom w przemyślanym i świadomym wdrożeniu gotowych koncepcji. Dlaczego mowa o „wzorcach”? Proponowane w tej książce koncepcje procesów można nazwać wzorcami, ponieważ są to regularnie powtarzające się elementy modelu, występujące w zastosowaniach wprowadzonych w życie przez różne zespoły. Nie mam tu na myśli definicji wzorca Christophera Aleksandra. Koncepcje procesów, o których mówię, pojawiają się w różnych kontekstach i prowadzą do osiągnięcia podobnych rezultatów. Nie zgromadziłem przy tej okazji dokumentacji opisującej znaczenie różnych sił i zmian w formie, jakiej można spodziewać się po bardziej tradycyjnych książkach. Po zapoznaniu się z kilkoma studiami przypadków opisanymi w tej książce grupa The Agile Alliance Functional Testing Tools przygotowała kilka warsztatów poświęconych tworzeniu wzorców, które po archiwizacji mogłyby stworzyć katalog (w tradycyjnym znaczeniu tego słowa) schematów działań. Jednak wykonanie tego zadania zajmie trochę czasu. Zdecydowałem się zatem zostawić rozszerzenie listy wzorców do nieco bardziej tradycyjnej formy na przyszłość — być może pojawi się ona w kolejnych wydaniach tej książki.
W Bridging the Communication Gap skoncentrowałem się przede wszystkim na konkretnych elementach metody, takich jak specyfikacje i testy akceptacyjne. Nie zwróciłem uwagi na fakt, że zespoły pracujące w różnych środowiskach mogą wymagać radykalnie odmiennych
44
Specyfikacja na przykładach
Właściwy timing Zespoły, którym udaje się osiągnąć sukces, nie wdrażają całej sekwencji w tym samym czasie i dla wszystkich specyfikacji (jak pokazano na rysunku 2.1). Co więcej, na pewno nie rozpoczynają procesu zmiany przed rozpoczęciem procesu wytwarzania oprogramowania. Definiowanie zakresu w oparciu o cele biznesowe rozpoczyna się wtedy, gdy zespół jest gotowy do pracy, czyli na przykład na początku konkretnej fazy projektu lub w momencie dotarcia do określonego kamienia milowego. Do specyfikacji przechodzi się wówczas, gdy zespół jest gotowy do wdrożenia elementu, na przykład na początku właściwej iteracji. Nie traktuj zatem sekwencji zdarzeń przedstawionej na rysunku 2.1 jak jednej wielkiej specyfikacji w systemie kaskadowym.
rozwiązań, które prowadziłyby do uzyskania identycznych artefaktów. W tej książce skupiam się na wzorcach procesów, na tworzeniu artefaktów oraz na tym, jak wpływają one na kolejne artefakty, pojawiające się na dalszych etapach.
Rysunek 2.1. Wzorce kluczowych procesów specyfikacji przez przykłady
Rozdział 2. Wzorce kluczowych procesów
45
W tym rozdziale dokonuję krótkiego przeglądu wzorców kluczowych procesów. Później przejdziemy do omówienia najważniejszych wyzwań utrudniających implementację tych procesów, przedstawię także kilka pomysłów na to, jak wdrożyć poszczególne wzorce w różnych kontekstach (w części II).
Zdefiniowanie zakresu prac w oparciu o cele biznesowe Zakres implementacji mówi o rozwiązaniu jakiegoś problemu lub jest środkiem do osiągnięcia celu biznesowego. Wiele zespołów oczekuje, że klient, właściciel produktu lub użytkownicy biznesowi zdecydują o zakresie prac przed rozpoczęciem implementacji (wszystko, co dzieje się wcześniej, często bywa ignorowane przez zespół zajmujący się tworzeniem oprogramowania). Gdy użytkownicy biznesowi dokładnie określą, czego chcą, zespoły mogą zająć się przetworzeniem tych potrzeb w produkt. Taki stan rzeczy miałby sprawiać, że klienci będą zadowoleni. Tymczasem już na tym etapie pojawiają się pierwsze problemy, od których rozwiązania zależy to, czy zespół dostarczy właściwy produkt. Poleganie na klientach jako źródle listy historyjek użytkowników, przypadków użycia lub innych istotnych informacji jest równoznaczne z tym, że zespoły zajmujące się tworzeniem oprogramowania proszą swoich klientów o zaprojektowanie rozwiązania. A przecież użytkownicy biznesowi nie są projektantami oprogramowania. Jeśli klienci określają zakres prac, w projekcie nie zostanie wykorzystana unikalna wiedza ludzi tworzących zespół odpowiedzialny za dostarczenie produktu końcowego. W efekcie powstaje oprogramowanie, które działa tak, jak prosił klient, ale nie jest tym, czego on tak naprawdę chciał. Zamiast ślepo akceptować wymagania programowe w funkcji rozwiązań nieznanego problemu, zespoły powinny definiować zakres prac na podstawie celów. Wszystko przecież zaczyna się od celów biznesowych klienta. Potem potrzebna jest współpraca na rzecz określenia zakresu komponentów, które pomogą osiągnąć wspomniane cele. Zespół współpracuje z użytkownikami biznesowymi, dążąc do zdefiniowania oczekiwanego rozwiązania. Użytkownicy koncentrują się na przekazywaniu informacji o intencji stojącej za żądaną funkcją i objaśnieniu, jakiej wartości od niej oczekują. Dzięki temu wszyscy lepiej rozumieją podstawy związane z wytworzeniem tego, co jest naprawdę potrzebne. Wówczas zespół może zaproponować rozwiązanie, które — w porównaniu z rozwiązaniem, jakie mógłby zaproponować klient — jest tańsze, szybsze i łatwiejsze do wykonania lub utrzymania1.
Wspólne specyfikowanie Jeśli programiści i testerzy nie są zaangażowani w projektowanie specyfikacji, trzeba ją przekazać każdej części zespołu oddzielnie. W praktyce oznacza to wzrost ryzyka nieporozumień. Przy okazji można przegapić wiele istotnych szczegółów. W rezultacie użytkownicy biznesowi muszą sprawdzić oprogramowanie po jego dostarczeniu, a gdy taki sprawdzian zakończy się negatywnie, zespoły nie mają innego wyjścia, jak tylko wrócić na swoje stanowiska i wprowadzić zmiany. To wszystko oznacza zupełnie niepotrzebne przeróbki. 1
Dobre przykłady znajdziesz na stronie: http://gojko.net/2009/12/10/challenging-reguirements.
46
Specyfikacja na przykładach
Zamiast liczyć na to, że jedna osoba sama poradzi sobie z przygotowaniem kompletnej i drobiazgowej specyfikacji, zespoły odnoszące sukcesy ściśle współpracują z użytkownikami biznesowymi w celu zdefiniowania najlepszego rozwiązania. Ludzie z różnych środowisk mają różne pomysły i podczas rozwiązywania problemów odwołują się do własnych technik, bazując na swoim doświadczeniu. Eksperci techniczni wiedzą, jak najlepiej wykorzystać podstawową infrastrukturę lub jak zastosować nowe technologie. Testerzy wiedzą, gdzie należałoby szukać potencjalnych kłopotów, a cały zespół powinien robić wszystko, aby zapobiec pojawianiu się defektów. Ta wspólna wiedza jest istotna już na etapie opracowywania specyfikacji. Wspólne specyfikowanie pozwala nam wykorzystać wiedzę i doświadczenie całego zespołu. Tworzy również świadomość zbiorowej własności specyfikacji, sprawiając, że wszyscy członkowie zespołu są bardziej zaangażowani w proces dostarczania produktu.
Opisywanie z wykorzystaniem przykładów ilustrujących Język naturalny jest niejednoznaczny, a sens przekazu w dużym stopniu zależy od kontekstu. Wymagania napisane w takim języku mogą nie zapewnić pełnego i jednoznacznego kontekstu, niezbędnego do stworzenia właściwego produktu i jego przetestowania. Programiści i testerzy muszą interpretować wymagania na bieżąco, podczas tworzenia oprogramowania oraz testowania skryptów, a różni ludzie mogą odmiennie interpretować co bardziej niejasne koncepcje. Problem z zastosowanym językiem staje się szczególnie dokuczliwy, gdy coś, co wydaje się oczywiste, w rzeczywistości wymaga specjalistycznej wiedzy lub znajomości jakiegoś żargonu. Małe różnice znaczeniowe utrudniają zrozumienie sensu i mogą się kumulować, co często prowadzi do problemów, których rozwiązanie wymaga przeróbek już po przekazaniu gotowego produktu. A to z kolei prosta droga do niepotrzebnych opóźnień. Zamiast oczekiwać, że specyfikacje zostaną wyrażone właściwie od razu w języku programowania, w trakcie implementacji, zespoły osiągające sukcesy ilustrują dane za pomocą przykładów. Pracują z użytkownikami biznesowymi, aby zidentyfikować kluczowe przykłady, które opisują oczekiwaną funkcjonalność. W tym czasie programiści i testerzy często przedstawiają dodatkowe przykłady ilustrujące przypadki brzegowe lub odnoszące się do tych funkcji systemu, które są wyjątkowo problematyczne. Dzięki temu udaje się zapełnić luki funkcjonalne, przeciwdziałać niespójnościom i zagwarantować, że wszyscy zaangażowani będą mieli takie samo wyobrażenie tego, co powinno być dostarczone, i uda się uniknąć przeróbek, które wynikają z błędnej interpretacji i konieczności tłumaczenia lub doprecyzowywania założeń. Jeśli system działa poprawnie w zakresie wszystkich najważniejszych kluczowych przykładów, to spełnia wymogi zaakceptowanej przez wszystkich specyfikacji. Kluczowe przykłady skutecznie definiują to, co oprogramowanie powinno wykonywać. Taka sytuacja jest oczekiwana zarówno jako cel rozwoju oprogramowania, jak i kryterium oceny ukończenia prac projektowych. Jeśli kluczowe przykłady łatwo zrozumieć i komunikować, mogą być skutecznie wykorzystywane jako niedwuznaczne wymagania o wystarczającym poziomie szczegółowości.
Rozdział 2. Wzorce kluczowych procesów
47
Udoskonalanie specyfikacji Otwarta dyskusja w trakcie współpracy przy specyfikacji prowadzi do tego, że wszyscy tak samo rozumieją określony zakres pojęć z domeny, ale stworzone przykłady często zawierają więcej szczegółów, niż to konieczne. Na przykład użytkownicy biznesowi patrzą na pewne zagadnienia z perspektywy interfejsu użytkownika, więc mówią o przykładach tego, jak coś powinno działać po kliknięciu łącza i wypełnieniu pól. Takie opisowe przykłady zachowań prowadzą do powstania ograniczeń systemu — szczegółowy opis tego, jak coś powinno być zrobione, a nie tego, czego się wymaga od systemu, jest marnotrawieniem zasobów. Zbyt duża liczba szczegółów sprawia, że przykłady trudniej komunikować i zrozumieć. Jeśli kluczowe przykłady mają być użyteczne, powinny być zwięzłe. W procesie nazwanym udoskonalaniem specyfikacji skuteczne zespoły usuwają nadmiarowe partie informacji i tworzą konkretny, ostry kontekst na potrzeby rozwoju oprogramowania i jego testowania. Definiują cel zawierający tyle szczegółów, ile jest niezbędnych do wykonania oprogramowania i jego przetestowania. Określają, co ma robić oprogramowanie, a nie zastanawiają się, jak ma to robić. Poprawione przykłady mogą być zastosowane jako kryteria akceptacji na potrzeby dostawy. Proces tworzenia oprogramowania nie będzie zakończony, dopóki system nie będzie pracować poprawnie na wszystkich przykładach. Po zapewnieniu dodatkowych informacji, które mają sprawić, że kluczowe przykłady będą łatwiejsze do zrozumienia, zespoły tworzą specyfikację z przykładami, to znaczy specyfikację roboczą, test akceptacyjny i przyszły funkcjonalny test regresyjny.
Automatyzacja walidacji bez zmiany specyfikacji Gdy zespół osiągnie kompromis w kwestii składu specyfikacji z przykładami i poprawia je, w kolejnym kroku może wykorzystać specyfikacje jako cel dla implementacji i sposób walidacji produktu. Podczas całego cyklu rozwoju oprogramowania system będzie podlegał wielokrotnej walidacji z wykorzystaniem tych testów, co ma zagwarantować osiągnięcie wspomnianego celu. Nieautomatyczne testy wprowadziłyby niepotrzebne opóźnienia oraz spowolniłyby gromadzenie informacji i opinii ze sprzężenia zwrotnego. Szybkie sprzężenie zwrotne jest istotnym elementem cyklu rozwoju oprogramowania — zarówno tego realizowanego w krótkich iteracjach, jak i w trybie przepływów, dlatego proces walidacji systemu musi być tani i wydajny. I tu z pomocą przychodzi oczywiście automatyzacja procesu testowania. Warto jednak pamiętać, że w tym przypadku automatyzacja różni się zasadniczo od zwykłej automatyzacji pracy dewelopera lub testera. Jeśli automatyzujemy walidację kluczowych przykładów przy użyciu automatycznych narzędzi tradycyjnego programowania (jednostkowych) lub tradycyjnych narzędzi automatyzacji testów funkcjonalnych, w czasie przejścia od specyfikacji biznesowej do automatyzacji technicznej ryzykujemy zgubienie pewnych szczegółów. A to oznacza problemy. Technicznie zautomatyzowane specyfikacje staną się niedostępne dla użytkowników biznesowych. Gdy dojdzie do zmiany wymagań (a możemy tylko zastanawiać się nad tym, kiedy to się stanie, a nie czy się stanie) lub gdy deweloperzy albo testerzy będą wymagać jakiegoś
48
Specyfikacja na przykładach
doprecyzowania, nie będziemy w stanie wykorzystać poprzednio zautomatyzowanej specyfikacji. Możemy wprawdzie zachować kluczowe przykłady zarówno pod postacią testów, jak i w bardziej czytelnej formie (choćby jako dokumenty Worda lub strony internetowe), ale gdy tylko okaże się, że mamy więcej niż jedną „wersję prawdy”, staniemy przed problemem zapewnienia odpowiedniej synchronizacji dokumentów. I właśnie dlatego papierowa dokumentacja nigdy nie jest rozwiązaniem idealnym. Aby jak najlepiej wykorzystać kluczowe przykłady, skuteczne zespoły automatyzują proces walidacji bez zmiany specyfikacji. Podczas automatyzacji zachowują wszystkie dane znajdujące się w specyfikacji bez zmian, tj. dosłownie, żeby nie ryzykować pojawienia się błędów wynikających z translacji. Gdy dochodzi do automatyzacji walidacji bez zmiany specyfikacji, kluczowe przykłady wyglądają niemal tak samo jak wtedy, kiedy trafiały na tablicę zespołu projektowego: są zrozumiałe i dostępne dla wszystkich członków zespołu. Zautomatyzowana specyfikacja przez przykłady, zrozumiała i dostępna dla wszystkich członków zespołu, staje się specyfikacją wykonywalną. Możemy użyć jej w funkcji celu dla procesu rozwoju oprogramowania i łatwo sprawdzić, czy system działa zgodnie z tym, co zostało uzgodnione. Można także wykorzystać ten sam dokument, aby uzyskać wyjaśnienia użytkowników biznesowych. Jeśli pojawia się konieczność zmiany specyfikacji, wystarczy dokonać modyfikacji tylko w jednym miejscu. Jeśli nigdy wcześniej nie miałeś kontaktu z automatyzacją wykonywalnych specyfikacji, być może trudno będzie Ci w to uwierzyć. Spójrz jednak na rysunki 2.2 i 2.3, które przedstawiają w pełni zautomatyzowane wykonywalne specyfikacje przygotowane za pomocą dwóch popularnych narzędzi: Concordion i FitNesse.
Rysunek 2.2. Wykonywalna specyfikacja zautomatyzowana z wykorzystaniem Concordion
Rozdział 2. Wzorce kluczowych procesów
49
Rysunek 2.3. Wykonywalna specyfikacja zautomatyzowana z wykorzystaniem FitNesse
Wiele innych systemów automatyzacji nie wymaga żadnego tłumaczenia kluczowych przykładów. W tej książce skupiamy się na praktykach stosowanych przez zespoły, którym udało się skuteczne zaimplementowanie specyfikacji przez przykłady, a nie tych opisujących poprawne wykorzystanie istniejących narzędzi. Jeśli chcesz zdobyć nieco wiedzy na temat narzędzi, zajrzyj na stronę http://specificationbyexample.com, skąd można pobrać artykuły omawiające najpopularniejsze aplikacje. Listę proponowanych narzędzi znajdziesz także w części dodatku, zatytułowanej „Narzędzia”.
Częsta walidacja Jeśli mamy efektywnie wspierać system, musimy wiedzieć, co robi i dlaczego. W wielu przypadkach jedynym sposobem zdobycia tej wiedzy jest dokładna analiza kodu lub znalezienie kogoś, kto zrobi to za nas. Kod jest często jedynym elementem tej układanki, któremu naprawdę możemy zaufać. Większa część gotowej dokumentacji staje się nieaktualna, zanim projekt zostanie zakończony. Programiści są wyroczniami wiedzy i wąskim gardłem strumienia informacji. Wykonywalne specyfikacje mogą być łatwo sprawdzone poprzez konfrontację z systemem. Jeśli taka walidacja jest wystarczająco regularna, możemy mieć tyle samo zaufania do wykonywalnych specyfikacji, ile do samego kodu. Zespoły, z którymi rozmawiałem, szybko odkrywały różnice między systemem i specyfikacjami dzięki regularnemu sprawdzaniu wszystkich wykonywalnych specyfikacji. Ponieważ wykonywalne specyfikacje są jasne i zrozumiałe, członkowie zespołów mogą omówić zmiany z użytkownikami biznesowymi i zdecydować, jak należy rozwiązać pojawiające się problemy. Stale synchronizują przy tym swoje systemy i wykonywalne specyfikacje.
Tworzenie systemu dokumentacji Zespoły odnoszące największe sukcesy nie zadowalają się zestawami często sprawdzanych wykonywalnych specyfikacji. Dbają o to, aby specyfikacje były dobrze zorganizowane, spójne oraz łatwe do odszukania i udostępnienia. Wraz ze zmianą ewoluującego projektu zmienia się też to, co zespoły wiedzą na temat sfery biznesowej. Zmiany w modelach domen
50
Specyfikacja na przykładach
Testy są specyfikacjami, specyfikacje to testy Gdy w specyfikacji znajdują się bardzo konkretne przykłady, można wykorzystać ją do testowania systemu. Po automatyzacji specyfikacja staje się wykonywalnym testem akceptacyjnym. Ponieważ w tej książce mówię wyłącznie o tego rodzaju specyfikacjach i testach, będę stosował określenia specyfikacje i testy wymiennie. To nie znaczy, że nie ma innych rodzajów testów — jednak na przykład testy eksploracyjne lub testy użyteczności nie są specyfikacjami. Społeczność testerów specjalizujących się w testach opartych na kontekście stara się stworzyć definicje pozwalające odróżnić wspomniane klasy testów, odwołując się do zmiany terminologii i wprowadzając podział na sprawdziany — dla określenia deterministycznych walidacji, które mogą być zautomatyzowane, i testy — dla nazwania niedeterministycznych walidacji, które wymagają interakcji człowieka (jego opinii i oceny)†. W tym kontekście podziału terminologicznego w tej książce mówimy zatem wyłącznie o sprawdzianach projektowania i automatyzacji. Koncepcja specyfikacji przez przykłady zakłada, że testerzy korzystają z opinii, wiedzy i wsparcia innych członków zespołu z myślą o zaprojektowaniu odpowiednich sprawdzianów. Nie są one wykonywane ręcznie, co oznacza, że testerzy mają więcej czasu, który mogą przeznaczyć na wykonywanie innych rodzajów testów. _______________ †
Zajrzyj na stronę: http://www.developsense.com/blog/2009/08/testing-vs-checking.
biznesowych są wywoływane także przez zmieniającą się sytuację rynkową. Zespoły, które korzystają z dobrodziejstw specyfikacji przez przykłady, aktualizują swoje specyfikacje tak, aby właściwie odzwierciedlały wspomniane zmiany, tworząc system żyjącej dokumentacji. Żyjąca dokumentacja jest wiarygodnym, pewnym i ogólnodostępnym źródłem informacji na temat funkcjonalności systemu. Jest równie wiarygodna jak kod, ale znacznie łatwiejsza do odczytania i zrozumienia. Personel zespołu wsparcia może odwołać się do niej, by dowiedzieć się, co i dlaczego robi system. Deweloperzy mogą używać jej w funkcji celu rozwoju. Testerzy podczas testowania. Analitycy biznesowi mogą wykorzystać ją jako punkt wyjścia przy analizie konsekwencji zmiany funkcjonalności. Co więcej, żyjąca dokumentacja może umożliwić także darmowe testowanie regresyjne.
Praktyczny przykład W pozostałej części tej książki skupię się raczej na wzorcach procesów niż na artefaktach procesu. Z myślą o zapewnieniu odpowiedniego kontekstu i aby mieć pewność, że rozumiesz, o czym mówię, uwzględniłem przykłady artefaktów wytworzonych w trakcie całego procesu, od etapu określenia celów biznesowych, aż po osiągnięcie systemu żyjącej dokumentacji. W omówieniu poniższego przykładu wskazuję rozdziały, w których zajmę się szczegółowym opracowaniem każdej kolejnej części procesu. Cel biznesowy Cel biznesowy jest motywacją rozpoczęcia projektu lub dążenia do osiągnięcia kamienia milowego w cyklu rozwoju projektu. To właśnie wizją celu kierują się interesariusze z wewnątrz lub z zewnątrz organizacji, gdy decydują o zainwestowaniu swoich pieniędzy w rozwój
Rozdział 2. Wzorce kluczowych procesów
51
oprogramowania. Organizacje nastawione na zysk powinny umieć jasno stwierdzić, w jaki sposób zdefiniowany przez nich cel biznesowy pozwoli im zarobić, zaoszczędzić lub ochronić pieniądze. Dobrym punktem wyjścia dla określenia celu biznesowego może być zadanie zdefiniowane jako: „Wzrost sprzedaży powtarzalnej wśród obecnych klientów”. W idealnych warunkach cel dałoby się zmierzyć, co pomogłoby wszystkim w podejmowaniu decyzji dotyczących implementacji. Zakres prac nad oprogramowaniem, które ma pomóc w osiągnięciu celu biznesowego, zdefiniowanego jako: „Dziesięcioprocentowy wzrost sprzedaży powtarzalnej wśród obecnych klientów w ciągu najbliższych 12 miesięcy” i „Wzrost sprzedaży powtarzalnej wśród dotychczasowych klientów o 500% w ciągu najbliższych 3 miesięcy” najczęściej wygląda zupełnie inaczej. Mierzalny cel pozwala stwierdzić, czy projekt skończył się sukcesem, śledzić postępy bądź wykonać lepszą priorytetyzację. Przykład poprawnego celu biznesowego
Zwiększenie sprzedaży powtarzalnej wśród obecnych klientów o 50% w ciągu najbliższych 12 miesięcy. Zakres Poprzez zastosowanie praktyk, które opiszę w rozdziale 5., zdefiniujemy zakres implementacji na podstawie celów biznesowych. Zespół wdrożeniowy i sponsorzy przedstawią pomysły, które mogą zostać rozdysponowane według klucza zdefiniowanych elementów dostarczanego oprogramowania. Powiedzmy, że zidentyfikowaliśmy system lojalnościowy klientów, który może mieć pewne podstawowe i bardziej zaawansowane funkcje systemów premiowych. Podejmujemy decyzję, która zakłada skupienie się w pierwszej kolejności na zbudowaniu podstawowego elementu systemu: klienci mogą zarejestrować się w celu uzyskania statusu VIP, dzięki czemu, pod pewnymi warunkami, będą mogli skorzystać z darmowej dostawy. Dyskusję na temat zaawansowanych elementów systemów premiowych na tym etapie odkładamy na później. Oto poprawny zakres dla naszego przykładu. Historyjki użytkowników podstawowego elementu systemu lojalnościowego
Jako szef marketingu chcę, aby klienci, przystępując do programu VIP, przekazali swoje dane osobowe, żeby umożliwić marketing bezpośredni produktów przeznaczonych dla obecnych klientów. Aby zachęcić dotychczasowych klientów do rejestracji w programie VIP, jako szef marketingu chcę dysponować systemem pozwalającym mi zaoferować klientom zarejestrowanym w programie VIP darmową dostawę niektórych pozycji. Jako aktualny klient chcę oszczędzić pieniądze i otrzymywać informacje na temat dostępnych ofert specjalnych. Kluczowe przykłady Poprzez zastosowanie praktyk opisanych w rozdziałach 6. i 7., gdy nasz zespół rozpoczyna proces implementacji konkretnej funkcji, tworzymy szczegółową specyfikację dotyczącą odpowiedniego zakresu. I tak na przykład kiedy zaczynamy prace nad drugim elementem
52
Specyfikacja na przykładach
zakresu — darmową dostawą — musimy najpierw określić, co właściwie oznacza owa „darmowa dostawa”. Dzięki współpracy wszystkich zainteresowanych produktem stron stwierdzamy, że system powinien zaproponować darmową dostawę tylko w przypadku zakupu książek, przez co unikniemy problemów logistycznych związanych z wysyłką elektroniki i przedmiotów o większych gabarytach. Ponieważ celem biznesowym firmy jest promowanie sprzedaży powtarzalnych, staramy się skłonić klientów do zakupu kilku przedmiotów. Tym samym „darmowa dostawa” oznacza właściwie dostawę „minimum pięciu zakupionych książek”. Następnie identyfikujemy najważniejsze przykłady, takie jak „klient VIP kupuje pięć książek”, „klient VIP kupuje mniej niż pięć książek” albo „klient nienależący do programu VIP kupuje książki”. Takie zdefiniowanie „darmowej dostawy” prowadzi nas do postawienia pytania o to, co powinno się stać, gdy klient kupuje zarówno książki, jak i elektronikę. Wśród ewentualnych propozycji działań pojawiają się sugestie rozszerzenia zakresu: na przykład podzielenie zamówienia na dwie części i zaproponowanie darmowej wysyłki tylko przesyłki zawierającej książki. Dyskusję na temat tej alternatywy decydujemy się odłożyć na później, by najpierw skupić się na wdrożeniu najprostszej wersji systemu. Nie oferujemy bezpłatnej dostawy, gdy w zamówieniu znajdują się elementy niebędące książkami. Tym samym dodajemy do zdefiniowanego już zestawu kolejny kluczowy przykład do późniejszego potwierdzenia. Kluczowe przykłady: Darmowa dostawa
Klient VIP z pięcioma książkami w koszyku otrzymuje propozycję darmowej dostawy. Klient VIP z czterema książkami w koszyku nie otrzymuje propozycji darmowej dostawy. Zwykły klient z pięcioma książkami w koszyku nie otrzymuje propozycji darmowej dostawy. Klient VIP z pięcioma pralkami w koszyku nie otrzymuje propozycji darmowej dostawy. Klient VIP z pięcioma książkami i jedną pralką w koszyku nie otrzymuje propozycji darmowej dostawy. Specyfikacja z przykładami Możemy dopracować specyfikację poprzez zastosowanie praktyk z rozdziału 8. i na podstawie kluczowych przykładów, tworząc dokument, który jest wystarczająco oczywisty (nie wymaga dodatkowego opisu i wyjaśnień), a ponadto sformatowany tak, aby możliwe było później łatwe zautomatyzowanie walidacji (jak przedstawiono poniżej). Darmowa dostawa
Darmowa dostawa jest proponowana klientom VIP po zakupie pewnej liczby książek. Darmowa dostawa nie jest oferowana zwykłym klientom lub klientom VIP, którzy kupują inne produkty.
Rozdział 2. Wzorce kluczowych procesów
53
Zakładając, że minimalna liczba książek uprawniająca do darmowej dostawy jest równa „pięć”, spodziewamy się, że: Przykłady Rodzaj klienta
Zawartość koszyka z zakupami
Dostawa
VIP
5 książek
Darmowa, standardowa
VIP
4 książki
Standardowa
Zwykły
10 książek
Standardowa
VIP
5 pralek
Standardowa
VIP
5 książek, 1 pralka
Standardowa
Ta specyfikacja — na tyle oczywista, że nie wymaga dodatkowych wyjaśnień — może być wykorzystana jako cel implementacji oraz przewodnik do stworzenia testu automatycznego, który pozwoli sprawdzić, czy implementacja została przeprowadzona właściwie. Specyfikacja jest przechowywana w repozytorium, aby stać się częścią żyjącej dokumentacji. Przykładem takiego repozytorium może być system wiki FitNesse lub struktura katalogów z plikami właściwości narzędzia takiego jak Cucumber. Wykonywalna specyfikacja Kiedy nasi programiści rozpoczną prace nad funkcją opisaną w specyfikacji, test bazujący na tej specyfikacji będzie początkowo kończyć się niepowodzeniem, ponieważ nie będzie zautomatyzowany, a funkcja nie będzie jeszcze zaimplementowana. Deweloperzy dokonają implementacji odpowiedniej funkcji i powiążą ją z systemem automatyzacji. Będą korzystać z systemu, który pobiera komponenty ze specyfikacji i sprawdza oczekiwane wyniki bez konieczności zmiany zawartości dokumentu, tj. specyfikacji. Koncepcje i praktyki opisane w rozdziale 9. pozwolą skutecznie zautomatyzować specyfikację. Po automatyzacji walidacji specyfikacja staje się wykonywalna. Żyjąca dokumentacja Specyfikacje dotyczące wszystkich realizowanych funkcji będą często sprawdzane, najprawdopodobniej przez zautomatyzowany proces kompilacji. Dzięki temu uda się uniknąć problemów z regresją funkcjonalną przy jednoczesnym zapewnieniu aktualności specyfikacji. W celu zapewnienia płynności częstej walidacji zespół będzie korzystał z praktyk opisanych w rozdziale 10. Gdy uda się zaimplementować całą historyjkę użytkownika, ktoś najpierw potwierdzi fakt ukończenia, a następnie dokona restrukturyzacji specyfikacji tak, aby dopasować je do specyfikacji dla funkcji, które zostały już wcześniej zaimplementowane. W tym zadaniu wykorzystane zostaną praktyki z rozdziału 11., opisujące ewolucję systemu dokumentacji od specyfikacji w przyrostach. Na przykład na tym etapie może dojść do przeniesienia specyfikacji dotyczącej darmowej dostawy do hierarchii funkcji związanych z dostawą i dołączenia jej do ewentualnych gotowych już innych przykładów darmowej dostawy, będących
54
Specyfikacja na przykładach
konsekwencją pojawienia się innych warunków. Aby dokumentacja była łatwiej dostępna, możliwe, że zostaną ustanowione odnośniki pomiędzy specyfikacją darmowej dostawy oraz specyfikacjami opisującymi inne formy i warunki dostaw. W kolejnym kroku cały cykl rozpoczyna się od nowa. Gdy pojawi się konieczność zrewidowania zasad darmowej dostawy — na przykład podczas pracy nad implementacją zaawansowanych systemów premiowych lub w celu rozszerzenia funkcjonalności wydzielenia zamówień książek i zamówień na inne produkty —będziemy mogli odwołać się do żyjącej dokumentacji, by zrozumieć, jak działają istniejące funkcje, i opracować ewentualne zmiany. Możemy też skorzystać z istniejących przykładów, aby współpraca i ilustrowanie specyfikacji przykładami stały się efektywniejsze. Następnie zdefiniujemy kolejny zestaw kluczowych przykładów, prowadzących nas do przyrostowej zmiany w specyfikacji dotyczącej darmowej dostawy, która ostatecznie zostanie połączona z resztą specyfikacji. Następnie cykl zostanie powtórzony. Teraz gdy dokonaliśmy szybkiego przeglądu wzorców kluczowych procesów, w rozdziale 3. przyjrzymy się bliżej żyjącej dokumentacji. W rozdziale 4. przedstawię pomysły dotyczące zastosowania specyfikacji przez przykłady, a następnie — w części II — opowiem o kilku propozycjach wdrożenia poszczególnych wzorców procesów.
Pamiętaj Wzorce procesu specyfikacji przez przykłady to: zdefiniowanie zakresu w oparciu o cele, wspólne specyfikowanie, opisywanie specyfikacji z wykorzystaniem przykładów ilustrujących, udoskonalenie specyfikacji, automatyzacja walidacji bez zmiany specyfikacji, częste walidacje systemu i opracowanie żyjącej dokumentacji. W przypadku specyfikacji przez przykłady terminy takie jak wymagania funkcjonalne, specyfikacje i testy akceptacyjne są równoznaczne. Efektem naszych działań jest żyjąca dokumentacja, która wyjaśnia, jak działa system, i jest równie wiarygodna jak kod języka programowania, a jednocześnie o wiele łatwiejsza do zrozumienia. Zespoły pracujące w różnych kontekstach korzystają z różnych praktyk w celu implementacji procesów modelu.
3
Żyjąca dokumentacja
I
stnieją dwa popularne modele, w których nieco inaczej podchodzi się do procesu i artefaktów specyfikacji przez przykłady. To model koncentrujący się na testach akceptacyjnych i model, w którym skupiamy się na specyfikacji zachowania systemu. W tym pierwszym, często nazywanym w skrócie ATDD lub A-TDD (ang. Acceptance Test-Driven Development), szczególną wagę przykłada się do testów zautomatyzowanych, które stanowią ważną część specyfikacji przez przykłady. Największymi zaletami tego modelu są jasno zdefiniowane cele rozwoju oprogramowania i zapobieganie regresji funkcjonalnej. Z kolei drugi ze wspomnianych modeli, często określany skrótem BDD (ang. Behavior-Driven Development), zakłada skupienie się na procesie tworzenia scenariuszy na bazie informacji o zachowaniu systemu. W tym przypadku koncentrujemy się na budowaniu uniwersalnego rozumienia funkcjonalności przez interesariuszy i zespoły pracujące nad dostarczeniem produktu dzięki bliskiej współpracy i jednoznaczności specyfikacji. W tym modelu zapobieganie regresji funkcjonalnej jest równie ważne. Nie mogę powiedzieć, aby jeden z tych modeli był lepszy od drugiego. Zależnie od celu, zastosowanie jednego lub drugiego przynosi lepsze rezultaty. Model ATDD jest bardziej przydatny w początkowej fazie projektu, jeśli zespół musi radzić sobie z wieloma problemami dotyczącymi jakości funkcjonalnej. Jeśli wszystko idzie jak po maśle, model BDD lepiej sprawdza się podczas precyzowania działań w ramach wersji przekazywanych w perspektywie krótko- i średnioterminowej. W obu modelach kluczem do osiągnięcia długoterminowych korzyści ze specyfikacji przez przykłady jest zapobieganie regresji funkcjonalnej dzięki automatyzacji testów. Chociaż testowanie regresyjne jest oczywiście ważne, nie sądzę, żeby to właśnie ono gwarantowało uzyskanie korzyści w dłuższej perspektywie. Po pierwsze, zastosowanie specyfikacji przez przykłady nie jest jedynym sposobem zapobiegania regresji funkcjonalnej. Na przykład zespół uSwitch rezygnuje z wielu testów po pierwszym zaimplementowaniu powiązanej funkcjonalności (więcej na ten temat w rozdziale 12.), a mimo to nadal udaje mu się utrzymać wysoki poziom jakości kodu. Po drugie, Capers Jones w Estimating Software Costs zwraca uwagę na fakt, że średnia skuteczność usuwania defektów w testach regresyjnych wynosi
56
Specyfikacja na przykładach
zaledwie 23%1. Taka wartość nie uzasadnia długoterminowych inwestycji poczynionych przez odnoszące sukcesy zespoły stosujące model specyfikacji przez przykłady. Zbierając materiały do tej książki, miałem przywilej rozmawiania z członkami zespołów, którzy używali specyfikacji przez przykłady już od minimum pięciu lat. Ich doświadczenia, zwłaszcza te zebrane w ostatnich latach, pomogły mi spojrzeć na przedstawianą tematykę z nieco innej perspektywy — takiej, którą gotów jestem nazwać „dokumentacyjnocentryczną”. Wiele ankietowanych przeze mnie zespołów przyznało, że w miarę upływu czasu artefakty specyfikacji przez przykłady zaczęły stanowić dla nich ważne źródło dokumentacji. Większość zespołów odkryła to po latach eksperymentowania z różnymi metodami definiowania specyfikacji i testów. Jednym z moich głównych celów jako autora tej książki jest przedstawienie żyjącej dokumentacji jako pierwszorzędnego artefaktu specyfikacji przez przykłady. To powinno pomóc czytelnikom w implementacji systemu żyjącej dokumentacji szybko i z pełną świadomością, bez lat prób i błędów. W tym rozdziale omówię model żyjącej dokumentacji i korzyści z jego wdrożenia. Ten model koncentruje się na zagadnieniu dokumentowania procesów biznesowych i zapewnia efektywne, długoterminowe wsparcie dla procesów biznesowych. Jest szczególnie przydatny dla zapewnienia długoterminowych korzyści z wdrożenia specyfikacji przez przykłady. Zapobiega także wielu typowym problemom związanym z zastosowaniem rozwiązań pomagających utrzymywać i serwisować testy systemowe (więcej na ten temat w dalszej części rozdziału).
Dlaczego potrzebujemy pewnej dokumentacji? Straciłem już rachubę, licząc, ile razy ktoś dawał mi grubą książkę opisującą system i ostrzegał jednocześnie, że „to nie do końca jest to”. Podobnie jak tanie wino, obszerna, papierowa dokumentacja szybko się starzeje. Jeśli próbujesz skorzystać z niej rok po przygotowaniu… ból głowy gwarantowany. Z drugiej strony utrzymanie systemu bez jakiejkolwiek dokumentacji również prowadzi do bólów głowy… Musimy wiedzieć, co robi system, aby móc przeanalizować wpływ proponowanych zmian, zapewnić wsparcie programistyczne i znajdować rozwiązania pojawiających się problemów. Często okazuje się niestety, że jedynym sposobem, by przekonać się, „co robi system”, jest przeanalizowanie kodu źródłowego języka programowania i dokonanie inżynierii wstecznej funkcjonalności biznesowej. Gdy przygotowując materiały do tej książki, rozmawiałem z Christianem Hassą, właścicielem TechTalk, mój rozmówca nazwał proces odzyskiwania informacji na temat funkcjonalności systemu „archeologią systemową”. Opowiedział mi przy okazji pewną historię, która bez wątpienia nie będzie obca większości czytelników:
1
Patrz Capers Jones, Estimating Software Costs: Bringing Realism to Estimating, McGraw-Hill Companies, 2007, s. 509. Zajrzyj także na stronę http://gojko.net/2011/03/03/simulating-your-way-out-ofregression-testing.
Rozdział 3. Żyjąca dokumentacja
57
Pracowaliśmy nad projektem systemu, który miał zastąpić starą wersję. Ani jeden przedstawiciel interesariuszy nie miał zielonego pojęcia, jak uzyskiwano pewne obliczenia/raporty. Użytkownicy po prostu wykorzystywali dane wynikowe i ślepo ufali staremu systemowi. Wsteczna inżynieria w celu zdobycia wymagań starego systemu okazała się prawdziwym koszmarem. No i ostatecznie oczywiście przekonaliśmy się, że niektóre operacje przeprowadzane przez stary system prowadziły do uzyskania niewłaściwych wyników. Nawet jeśli udokumentowany kod jest prawidłowy, wsteczna inżynieria staje się dla użytkowników biznesowych, testerów, inżynierów zespołu wsparcia (a w przypadku większości projektów nawet dla przeciętnego dewelopera) misją wręcz niemożliwą do wykonania. Najwyraźniej takie podejście się nie sprawdza. Potrzebujemy czegoś lepszego. Poprawna i pewna dokumentacja przydaje się nie tylko podczas procesu wytwarzania oprogramowania. Wiele firm może bardzo skorzystać na posiadaniu właściwej dokumentacji dotyczącej procesów biznesowych, zwłaszcza że coraz więcej organizacji w większym i większym stopniu zaczyna bazować na nowoczesnych technologiach. Dokumentacja opisująca procesy biznesowe nie różni się specjalnie od typowej dokumentacji systemowej pod kątem stopnia trudności czy kosztów. Idealnym rozwiązaniem byłby system dokumentacji, który jest na tyle łatwy i tani w utrzymaniu, żeby można było zapewnić jego spójność z funkcjonalnością systemu nawet w przypadku, gdyby dochodziło do częstych zmian kodu programowania. Problem z każdą kompleksową dokumentacją jest zwykle ten sam: wysokie koszty utrzymania. Z mojego doświadczenia wynika, że zmiana części przestarzałej dokumentacji nie wpływa znacząco na zwiększenie kosztów. Często okazuje się, że koszt wzrasta w konsekwencji konieczności poświęcenia czasu na poszukiwanie tego, co należy zmodyfikować.
Testy mogą być dobrą dokumentacją Problem ze zautomatyzowanymi testami wynika z czegoś zupełnie innego. Łatwo znaleźć miejsca, które muszą być zaktualizowane. Testy automatyczne można uruchamiać dość często i jest oczywiste, że wszystkie testy, które kończą się niepowodzeniem, straciły synchronizację z kodem bazowym. Jednak jeśli testów nie stworzono z myślą o łatwej modyfikacji, ich aktualizacja po wprowadzeniu zmian do systemu może zająć dużo czasu. Jedną z pułapek modelu ATDD jest właśnie nieuwzględnienie problemu modyfikacji. Zespoły, które koncentrują się na testach i testowaniu, często zapominają o potrzebie tworzenia testów łatwych w utrzymaniu. Z biegiem czasu kolejne pojawiające się problemy sprawiają, że zespoły szukają sposobów definiowania i automatyzowania testów tak, aby łatwiej je aktualizować. Jeśli to zadanie zakończy się sukcesem, zespoły zaczynają dostrzegać wiele innych długoterminowych korzyści wynikających z zastosowania modelu specyfikacji przez przykłady. Zespół Adama Knighta w RainStor, brytyjskiej firmie dostarczającej rozwiązania przechowywania danych online, uświadomił sobie, że jeśli testy udowadniają słuszność podstawowych założeń, jakimi kierują się twórcy, stają się łatwiejsze w utrzymaniu. Oto co usłyszałem od swojego rozmówcy:
58
Specyfikacja na przykładach
Gdy opracujesz zestaw zautomatyzowanych testów, jeśli tylko przygotujesz je tak, aby odkryć ich prawdziwe zadanie, wówczas mogą one stać się twoją dokumentacją. Przygotowaliśmy listę raportów w formacie HTML, które zawierały dane na temat uruchomionych testów i ich przeznaczenia. Wykrywanie błędów regresji stało się o wiele łatwiejsze. Sprawniej rozwiązywaliśmy konflikty, bo od razu znaliśmy cel, bez potrzeby odwoływania się do innej dokumentacji. Dla mnie najważniejszym przekazem mojego rozmówcy jest to, co czytamy w ostatnim zdaniu: jeśli testy są jasne i jednoznaczne, nie trzeba odwoływać się do dokumentacji innego rodzaju. Lisa Crispin z ePlan Services przyznała, że chwila, w której zrozumiała, jak cenne są testy w roli dokumentacji, była dla niej jednym z ważniejszych momentów olśnienia, gdy czujesz, jak wszystko układa się w spójną całość: Mamy płatność kredytu z nieprawidłową kwotą odsetek. Wydaje nam się, że gdzieś tam musi tkwić błąd. Mogę spojrzeć na test FitNesse i wprowadzić odpowiednie wartości. Może wymagania były niewłaściwe, ale widzę to, co robi kod. Oszczędzam mnóstwo czasu! Andrew Jackman mówi, że zespół Sierra wykorzystuje wyniki testów jako bazę wiedzy dla grupy wsparcia: Analitycy biznesowi stale korzystają z zalet tego rozwiązania. Gdy ktoś pyta, skąd biorą się jakieś dane zespołu, często po prostu wysyłają pytającemu link do wyniku testu — i to jest rozsądne źródło dokumentacji. Nie mamy specyfikacji przybierających formę plików programu Word. Wspomniałem już wcześniej, że zespół Iowa Student Loan Liquidity Corporation stosował własne testy w celu oszacowania konsekwencji zmiany modelu biznesowego i wspomożenia procesu implementacji. Zespół w Songkick wykorzystał swoje testy do sterowania procesem implementacji zmiany systemu, dzięki czemu zaoszczędził szacunkowo 50% swojego czasu. Podobne historie słyszałem z ust wielu przedstawicieli innych zespołów. Gdy zespół wykorzystuje jakąś część danych w celu wsparcia rozwoju oprogramowania, systemu lub oszacowania efektów zmian, nazywanie tych danych „testem” jest mylące. Testy nie są wykorzystywane do wspierania i rozwijania naszych systemów. To nie testy. To dokumentacja.
Tworzenie dokumentacji na podstawie wykonywalnej specyfikacji Gdy oprogramowanie jest stale sprawdzane z zestawem wykonywalnych specyfikacji, zespół może mieć pewność, iż będzie ono działać tak, jak mówi specyfikacja, lub — innymi słowy — że specyfikacja będzie przez cały czas właściwie opisywać to, co robi system. Te specyfikacje żyją z systemem i zawsze są spójne. Ponieważ od razu wiemy, kiedy pojawiają się
Rozdział 3. Żyjąca dokumentacja
59
jakiekolwiek różnice między specyfikacjami oraz podstawową funkcjonalnością systemu, wspomnianą spójność otrzymujemy niskim kosztem. Tim Andersen z Iowa Student Loan twierdzi, że ufa tylko tego rodzaju dokumentacji: Jeśli nie mogę uzyskać dokumentacji w sposób zautomatyzowany, nie ufam jej. Nie wyobrażam sobie innej sytuacji. Wykonywalne specyfikacje tworzą główną część dokumentacji, autorytatywnego źródła informacji na temat funkcjonalności systemu, które nie cierpi na chorobę „nie do końca poprawnego” zbioru informacji, a na dodatek jest stosunkowo tanie w utrzymaniu. Jeśli specyfikacje z przykładami są stronami, to żyjąca dokumentacja będzie książką. Żyjąca dokumentacja zastępuje wszystkie artefakty, których potrzebują zespoły, by dostarczyć właściwy produkt. Może nawet ułatwiać tworzenie zewnętrznych instrukcji obsługi (chociaż prawdopodobnie nie może ich zastąpić). Spełnia te zadania w sposób, który dobrze pasuje do krótkich procesów iteracyjnych lub przepływu. Ponieważ specyfikacje są tworzone na bieżąco podczas rozwijania bazowego systemu software’owego, powstająca dokumentacja będzie miała charakter przyrostowy, a jej przygotowywanie będzie tanie. Możemy budować dokumentację procesów biznesowych w tym samym czasie, gdy powstają systemy wspomagające, i wykorzystać ją do opracowania oprogramowania oraz jako pomoc w prowadzeniu przedsięwzięcia biznesowego. Świat wcale nie musi się zatrzymać na sześć miesięcy, podczas gdy ktoś zajmuje się kompilacją pięciuset stron materiału. André Brissette z Pyxis twierdzi, że jest to jeden z najbardziej niezrozumianych aspektów wytwarzania oprogramowania w metodyce zwinnej: Początkujący praktycy agile uważają, że w metodyce zwinnej w ogóle nie istnieje żadna dokumentacja. To nieprawda. Chodzi raczej o wybranie typu dokumentacji, która będzie przydatna. Dla ludzi, którzy obawiają się konsekwencji rzekomego braku dokumentacji, tego rodzaju test jest dobrą okazją, aby samemu przekonać się, iż w metodyce zwinnej tak czy owak dokumentacja jest przygotowywana, choć nie ma formy wysokiego na dwie stopy stosu papierów. Zgromadzone materiały nie mają takiego ciężaru, ale dotyczą realnego kodu. Gdy pytasz: »Czy twój system ma tę funkcję?«, nie odwołujesz się do dokumentu Worda, z którego dowiadujesz się, że coś jest zrobione. Masz do swojej dyspozycji coś naprawdę działającego, co stanowi gwarancję, że system rzeczywiście robi to, czego od niego chcesz. To jest prawdziwa dokumentacja. Większość narzędzi do automatyzacji stosowanych w ramach specyfikacji przez przykłady wspiera zarządzanie specyfikacjami przez strony internetowe lub eksport wyników testów do formatu HTML lub PDF. To dobry punkt wyjścia do stworzenia systemu dokumentacji. Spodziewam się, że na przestrzeni kilku kolejnych lat będziemy mieli do czynienia z wieloma zmianami w zakresie innowacyjności narzędzi, które będą miały na celu coraz łatwiejsze tworzenie dokumentacji na podstawie specyfikacji z przykładami. Jednym z ciekawszych
60
Specyfikacja na przykładach
projektów jest Relish2, który importuje specyfikacje z przykładami z wielu narzędzi do automatyzacji, a także formatuje je, tworząc system dokumentacji wyjątkowo łatwy w użyciu. Patrz rysunek 3.1.
Rysunek 3.1. Relish tworzy strony internetowe zawierające dokumentację, wykorzystując wykonywalne specyfikacje
Zalety modelu zorientowanego na dokumentację Model zorientowany na dokumentację specyfikacji przez przykłady powinien pomóc zespołom w unikaniu najczęstszych problemów związanych z długoterminowym utrzymaniem wykonywalnych specyfikacji. Powinien także pomóc zespołom w przygotowywaniu przydatnej dokumentacji, która z czasem usprawni ewoluowanie oprogramowania i pozwoli uniknąć problemów z utrzymaniem systemu spowodowanych brakiem współdzielonej wiedzy. Wiele zespołów, z którymi rozmawiałem, na jakimś etapie prac wymieniło główne komponenty systemu lub stworzyło od nowa niemałe jego części, zachowując specyfikacje z przykładami i używając ich do sterowania całym procesem zmiany. Właśnie podczas tego rodzaju działań naprawdę zwraca się inwestycja w stworzenie żyjącej dokumentacji. Zamiast 2
Odwiedź stronę www.relishapp.com.
Rozdział 3. Żyjąca dokumentacja
61
marnować miesiące na archeologię systemową i weryfikacje systemu, dzięki systemowi żyjącej dokumentacji łatwo dokonasz analizy wymagań do aktualizacji technicznych i zmian. Myślę, że zespoły powinny potraktować żyjącą dokumentację jak niezależny artefakt, który jest tak samo ważny jak dostarczany system. Koncepcja, zgodnie z którą dokumentacja jest kluczowym elementem dostarczanego produktu, jest podstawą modelu „dokumentacyjnocentrycznego”. Spodziewam się, że taki model umożliwi rozwiązywanie większości typowych problemów, które z czasem mogą przyczyniać się do porażek zespołów stosujących metodykę specyfikacji przez przykłady. Mimo że żaden z opisanych w niniejszej książce przypadków nie dostarcza dowodów na poparcie postawionej przeze mnie tezy, uważam, iż moja przesłanka stanowi istotny argument do przyszłych dyskusji. Mam nadzieję, że dzięki umiejętności spojrzenia na proces z innej perspektywy, czytelnicy będą mogli osiągnąć świetne wyniki łatwiej i szybciej. Na przykład uświadomienie sobie, że żyjąca dokumentacja jest ważnym artefaktem, natychmiast przekłada się na odpowiedź na pytanie o to, czy testy akceptacyjne powinny znaleźć swoje miejsce w systemie kontroli wersji. Skoncentrowanie się na dokumentacji procesów biznesowych pozwala uniknąć tworzenia nadmiernie sformalizowanych specyfikacji technicznych i ograniczyć się do informacji na temat tego, co (z perspektywy biznesowej) ma robić system, a nie marnować czas na tworzenie skryptów. Oczyszczanie kodu testu nie wymaga już dodatkowych wyjaśnień. Poprawa struktury lub przejrzystości testów nie jest czymś, co trafia na listę długu technicznego. Jest raczej częścią standardowej listy zadań definiowanej przed dostarczeniem produktu. Natychmiast zdajemy sobie wówczas sprawę z wad rozwiązania, w którym prace nad testami akceptacyjnymi powierzane są młodszym programistom i testerom. Świadomość przydatności dobrze zorganizowanej dokumentacji powinna zapobiec gromadzeniu tysięcy niezrozumiałych testów w jednym katalogu. Dzięki uznaniu żyjącej dokumentacji za osobny artefakt procesu dostarczania produktu zespoły mogą również uchronić się przed przeinwestowaniem. Mogą z góry ustalić, ile czasu poświęcą na stworzenie systemu żyjącej dokumentacji, unikając przy tym pułapki zbytniego upiększania testów kosztem podstawowego produktu. Podejrzewam, że utrzymywanie zbyt wysokiego poziomu abstrakcji specyfikacji może stać się potencjalną pułapką modelu dokumentacji. Spodziewam się, że model sprawdzi się lepiej w systemach, które zostały stworzone w celu automatyzacji złożonych procesów biznesowych. W projektach, w których największe znaczenie ma interfejs użytkownika i w których nie ma mowy o wyjątkowej złożoności podstawowych procesów, korzyści wcale nie muszą być aż tak wielkie.
Pamiętaj Istnieje kilka modeli zastosowania specyfikacji przez przykłady, które sprawdzają się w różnych okolicznościach. Specyfikacja przez przykłady pozwala tworzyć odpowiedni system dokumentacji, który jest uzupełniany przyrostowo.
62
Specyfikacja na przykładach
Żyjąca dokumentacja jest ważnym artefaktem procesu dostarczania produktu — równie ważnym jak sam kod. Skoncentrowanie się na stworzeniu systemu dokumentacji procesów biznesowych w dłuższej perspektywie powinno pomóc Ci uniknąć typowych problemów z utrzymaniem i konserwacją specyfikacji i testów.
4
Inicjowanie zmian
W
iele pomysłów, które mają absolutnie kluczowe znaczenie dla metody specyfikacji przez przykłady, znanych było już od dziesięcioleci. W późnych latach 80. Gerald Weinberg i Donald Gause pisali o problemach komunikacyjnych z wymaganiami dotyczącymi oprogramowania w Exploring Requirements: Quality Before Design1. Sugerowali, że najlepszym sposobem sprawdzenia kompletności i spójności wymagań jest zaprojektowanie tzw. testów czarnej skrzynki (ang. black-box tests), przedstawiając tym samym podstawy definicji obecnego dualizmu specyfikacji i testów w specyfikacji przez przykłady. W 1986 roku armia niemiecka zaczęła stosować system nazwany później modelem V, żeby opisać sposoby tworzenia testów akceptacyjnych przed implementacją dla walidacji. Dzisiaj używamy tej samej metody, ale o testach akceptacyjnych mówimy jako o specyfikacjach z przykładami. Ward Cunningham zastosował opisywanie wymagań przy użyciu przykładów ilustrujących oraz automatyczną walidację bez zmiany specyfikacji w projekcie WyCASH+ już w 1989 roku2. Niestety w tamtych czasach zaproponowane rozwiązania nie przyjęły się. Długie fazy rozwoju oprogramowania sprawiły, że pomysły te w praktyce były po prostu nierealne. W tamtych czasach ludzie miesiącami usiłowali kompletować abstrakcyjne wymagania dla projektów, które miały być realizowane przez lata. Konieczność uszczegółowienia wszystkiego zawczasu i uzupełnienia specyfikacji o przykłady dodatkowo opóźniała rozpoczęcie prac. Metodyka zwinna w zarządzaniu projektami zmieniła spojrzenie ludzi z branży na kwestię etapów dostarczania oprogramowania i znacznie skróciła te etapy. To sprawiło, że specyfikacja przez przykłady stała się metodą wykonalną. Projekty bazujące na iteracjach i przepływach mogą wiele skorzystać na wdrożeniu specyfikacji przez przykłady. W sytuacji, gdy na zakończenie każdej fazy pozostaje tak niewiele czasu, musimy wyeliminować jak najwięcej niepotrzebnej pracy. Typowe problemy, które przychodzą wówczas do głowy, to: ponowne 1
Gerald M. Weinberg, Donald C. Gause, Exploring Requirements: Quality Before Design, Dorset House Publishing Company, 1989. 2 http://fit.c2.com/wiki.cgi?FrameworkHistory.
64
Specyfikacja na przykładach
przeróbki, zadania zduplikowane będące konsekwencją nieporozumień, strata czasu wynikająca z potrzeby inżynierii wstecznej i analizy kodu, aby zrozumieć działanie systemu, a także czas zmarnowany na wielokrotne ręczne wykonywanie tych samych testów. Skuteczność w kontekście krótkich iteracji lub stałego przepływu wymaga usuwania jak największej liczby oczekiwanych przeszkód, tak aby można było skupić swoje siły na rozwiązywaniu problemów. Adam Geras przywołuje bardzo trafne porównanie: „Jakość oznacza przygotowanie na typowe, tak żeby mieć czas, aby zmierzyć się z niezwykłym”. Żyjąca dokumentacja sprawia, że typowe problemy po prostu znikają. Specyfikacja przez przykłady jest rozwiązaniem: środkiem umożliwiającym radzenie sobie ze zwykłymi problemami, aby uzyskać więcej czasu na zajmowanie się tymi niezwykłymi w czasie kilku dni lub tygodni cyklu produkcji oprogramowania. Żyjąca dokumentacja stała się obecnie warunkiem sukcesu. W tym rozdziale zastanowimy się nad pierwszymi krokami procesu zmiany kultury pracy zespołu, która umożliwia wdrożenie specyfikacji przez przykłady. Przeanalizujemy trzy przypadki zespołów, które mogą stanowić dla nas przykłady odmiennych sposobów integracji współpracy przy działaniach zmierzających do zdefiniowania specyfikacji w programowaniu iteracyjnym i bazującym na przepływach. Na końcu tego rozdziału przedstawię kilka użytecznych pomysłów, dzięki którym ów proces można zastosować w środowiskach programistycznych wymagających formalnego podpisu pod wymaganiami i ich identyfikowalnością (ang. traceability on requirements).
Jak rozpocząć zmianę procesu? Rozpoczęcie zmiany procesu nigdy nie jest łatwe, zwłaszcza jeśli próbujesz wpłynąć na fundamentalne zasady współpracy pomiędzy członkami zespołu. Aby poradzić sobie z początkowymi oporami i stworzyć dobre warunki do dalszych zmian, większość zespołów zaczyna od wdrożenia praktyki, która szybko wymiernie wpływa na poprawę jakości produktów i oszczędność czasu. Najczęściej pojawiają się następujące propozycje: Jeśli proces zmiany już rozpoczęto, wykorzystaj go do wdrożenia kluczowych koncepcji specyfikacji przez przykłady. Wykorzystaj koncepcje specyfikacji przez przykłady jako inspirację do poprawy jakości produktów. Zastosuj automatyzację testów funkcjonalnych w przypadku zespołów, które nie korzystają z tego systemu. Wprowadź zautomatyzowane wykonawcze specyfikacje w zespołach, w których automatyzacja testów jest niezależna od prac rozwojowych. Wykorzystaj TDD jako odskocznię — dla zespołów, które praktykują TDD. Wszystkie wymienione działania przyniosą korzyści krótkoterminowe i skierują zespół na drogę prowadzącą do dalszej poprawy.
Rozdział 4. Inicjowanie zmian
65
Wdrażaj specyfikację przez przykłady jako część rozległego procesu zmian Kiedy: W projektach typu greenfield
Cztery zespoły uczestniczące w moich badaniach zastosowały kluczowe koncepcje specyfikacji przez przykłady (SBE, ang. Specification by Example) podczas przejścia na zwinną metodykę. W tych przypadkach nie było konieczności podjęcia aktywnych działań na rzecz zmniejszenia oporów lub uzyskania specjalnego wsparcia kierownictwa.
Wdrożenie Scruma, XP lub innej metodyki zwinnej tak czy owak przypomina terapię szokową, dlatego jeśli pojawia się taka okazja, równie dobrze możesz w tym samym czasie podjąć próbę implementacji specyfikacji przez przykłady.
Zespoły, w których implementacja zakończyła się sukcesem, informowały o mniejszej liczbie napotkanych problemów i wdrożeniu przebiegającym szybciej niż w zespołach z dysfunkcjonalnym środowiskiem scrumowym. Najbardziej prawdopodobną przyczyną osiągnięcia tych korzyści jest fakt, że wszystkie cztery zespoły cieszyły się silnym wsparciem udzielonym w czasie przejścia na zwinną metodykę (w trzech przypadkach firma zatrudniła konsultantów, a w czwartym przypadku zespół mógł liczyć na wsparcie kogoś, kto poznał wcześniej metodykę specyfikacji przez przykłady).
Skup się na poprawie jakości Zamiast skupiać się na konkretnym procesie docelowym, zespół uSwitch (patrz rozdział 12.) postanowił skoncentrować się na poprawie jakości produktów. Wszyscy członkowie zespołu mogli przedstawić swoje pomysły. Wiele z tych sugestii zainspirowało kierownictwo do wprowadzenia prawdziwych modyfikacji. Ostatecznie zespołowi udało się — przy lekkim tylko oporze — wdrożyć większość elementów procesu specyfikacji przez przykłady. Z punktu widzenia kierownictwa, jeśli opór ze strony pracowników przeciwnych zmianie jest spodziewany, podejście zakładające skoncentrowanie wysiłków na poprawie jakości jest wyjątkowo dobrym rozwiązaniem. Ludzie mogą narzekać na Scruma, metodykę zwinną, specyfikację przez przykłady, Kanbana czy każdą inną metodę, która jest powiązana z samym procesem. Otwarta inicjatywa na rzecz poprawy jakości to mniejsze prawdopodobieństwo utyskiwań i skarg. David Anderson w swoim przepisie na sukces podczas wdrażania Kanbana3 zaleca przede wszystkim skupienie się na korzyściach wynikających z poprawy jakości.
Zacznij od zidentyfikowania największej przeszkody, która uniemożliwia dostarczanie oprogramowania wysokiej jakości. A potem usuń ją ze swojej drogi. 3
David Anderson, Kanban: Successful Evolutionary Change for Your Technology Business, Blue Hole Press, 2010.
66
Specyfikacja na przykładach
Jeśli programiści i testerzy nie współpracują ze sobą wystarczająco blisko i mają odmienne zdania na temat tego, czy coś jest „odpowiedniej jakości”, być może przyda się wizualizacja działań związanych z dostarczeniem produktu. Jodie Parker z LMAX, firmy działającej na rynku narzędzi elektronicznych systemów zarządzania systemami giełdowymi, uczyniła wszystkie działania transparentnymi, tworząc tablicę „uwolnienia kandydata”, która przedstawiała wysokopoziomowy opis postępów trzech zespołów. Znalazło się w niej miejsce na informację o statusie wszystkich produktów, nad którymi pracowano, głównym celu wydania, zestawie zadań, które muszą być wykonane przed wydaniem, i najważniejszych kwestiach, które muszą zostać rozstrzygnięte, zanim będzie można przekazać produkt. Członkowie wszystkich zespołów powinni przeanalizować znajdujące się na tablicy informacje, a następnie przedstawić propozycje poprawy przepływu rozwoju i dostarczania produktu.
Zacznij od automatyzacji testów funkcjonalnych Kiedy: Zmiany dotyczą istniejącego projektu
Większość zespołów, z którymi rozmawiałem, przyjęła specyfikację przez przykłady, zaczynając od automatyzacji testów funkcjonalnych, a następnie stopniowo przechodząc od badań po etapie rozwoju do użycia wykonywalnych specyfikacji, które odtąd miały decydować o kierunku rozwoju. Wydaje się, że takie rozwiązanie jest pójściem po linii najmniejszego oporu dla projektów, które i tak już charakteryzują się wielką ilością kodu i wymagają od testerów ręcznej weryfikacji. Kilka zespołów starało się rozwiązać problem wąskich gardeł w fazie testów, który był konsekwencją tego, że inaczej niż pracownicy działu rozwoju, testerzy stale musieli nadrabiać zaległości. Gdy cykle dostaw są krótkie (mowa o tygodniach lub nawet dniach), obszerne testowanie ręczne jest po prostu niemożliwe. W konsekwencji liczba testów, które trzeba wykonać pod koniec jednej iteracji, rośnie i zajmuje czas następnej, zakłócając przepływy pracy. Automatyzacja testów funkcjonalnych pozwala usunąć wąskie gardło i zmusza testerów do ściślejszej współpracy z programistami, motywując ich do udziału w zmianie procesu. Markus Gärtner mówi: Dla testera, który zna tylko koncepcję »testowania jako wąskiego gardła«, stale sprzeciwiającego się każdej zmianie w oprogramowaniu, praca według nowej metodyki — w której staje się on źródłem niezwykle istotnych informacji zwrotnych, jeszcze zanim bug zostanie usunięty dzięki zautomatyzowanym testom — stała się bardzo, ale to bardzo przyjemnym przeżyciem. Taka wizja stanowi sporą motywację decydującą o kierunku pracy.
Jeśli nie stosujesz jeszcze automatyzacji testów funkcjonalnych, wiedz, że masz do czynienia z „nisko wiszącym owocem” — łatwo dostępnym sposobem pozwalającym Ci miło rozpocząć podróż ze specyfikacją przez przykłady, a także przynoszącym natychmiastowe korzyści.
Rozdział 4. Inicjowanie zmian
67
Automatyzacja testów funkcjonalnych dobrze sprawdza się w pierwszej fazie implementacji specyfikacji przez przykłady. Dlaczego? Oto przyczyny: Korzyści są natychmiastowe. Ze zautomatyzowanymi testami faza testowania staje się wyraźnie krótsza, podobnie jak krótsza staje się lista problemów, które dają o sobie znać dopiero na etapie produkcji. Efektywna automatyzacja testów wymaga współpracy programistów i testerów, co oznacza, że prowadzi do zniesienia podziałów między tymi grupami. Starsze produkty rzadko charakteryzują się konstrukcją, która ułatwia testowanie. Wyjście od automatyzacji testów funkcjonalnych zmusza zespół do podjęcia konkretnych działań, które pozwolą poradzić sobie z tym utrudnieniem i dostosować architekturę oraz rozwiązać wszelkie problemy dotyczące rzetelności badań i środowisk testowych. To przygotowuje grunt pod późniejszą automatyzację wykonywalnych specyfikacji. Jeśli większość testów przeprowadza się ręcznie, a zespół pracuje w krótkich cyklach, testerzy często stają się hamulcowymi procesu. To sprawia, że praktycznie niemożliwe jest ich zaangażowanie do żadnych innych zadań. Automatyzacja testów sprawia, że testerzy mają więcej czasu na działania związane z tworzeniem specyfikacji i mogą brać udział w innych pracach, na przykład wykonując testy eksploracyjne. Już pierwsze zautomatyzowanie umożliwia zespołowi wykonywanie większej liczby testów oraz wykonywanie ich częściej, niż byłoby to możliwe w przypadku testów ręcznych. To często prowadzi do odkrycia większej liczby błędów i niespójności, a nagły wzrost jawności działań pomaga interesariuszom biznesowym dostrzec korzyści płynące z automatyzacji. Tworzenie i początkowa automatyzacja testów funkcjonalnych często wymaga zaangażowania użytkowników biznesowych, którzy muszą odpowiedzieć na pytanie, czy dostrzeżona niespójność jest błędem, czy może takiego właśnie działania oczekuje się od systemu. To prowadzi do nawiązania współpracy między testerami, deweloperami i użytkownikami biznesowymi. Co więcej, wymusza na zespole takie automatyzowanie testów, aby użytkownicy biznesowi mogli je zrozumieć, przygotowując dobre warunki do tworzenia wykonywalnych specyfikacji. Szybszy feedback pomaga programistom dostrzec i zrozumieć wartość automatyzacji testów. Automatyzacja testów funkcjonalnych pomaga członkom zespołu zrozumieć, jak działają narzędzia potrzebne do automatyzacji wykonywalnych specyfikacji. Wdrażanie automatyzacji testów funkcjonalnych sprawi, że zespół zacznie ze sobą bliżej współpracować, i przygotuje system do zastosowania wykonywalnych specyfikacji w późniejszym terminie. Aby osiągnąć jak najlepsze efekty, dokonaj automatyzacji testów funkcjonalnych przy użyciu narzędzia do przygotowywania wykonywalnych specyfikacji. Zaplanuj dobrze cały proces, korzystając z pomysłów przedstawionych w rozdziałach 9. i 11. Automatyzacja testów przy użyciu tradycyjnych narzędzi nie da Ci korzyści, których potrzebujesz.
68
Specyfikacja na przykładach
Czy tu nie chodzi tylko o przerzucanie się zadaniami? Typowa obiekcja przed uwolnieniem testerów poprzez przerzucenie części wspólnej pracy nad automatyzacją testów na barki programistów wiąże się z założeniem, że to oznacza dodatkowe obciążenie programistów, a to z kolei spowoduje opóźnienie w dostarczeniu jakiejś funkcji. Tymczasem mamy obecnie do czynienia z trendem, w którym w tworzonych zespołach znajduje się więcej programistów niż testerów, dlatego przekazanie dodatkowej pracy tym pierwszym wcale nie musi być złe. Co więcej, może pozwolić Ci na odblokowanie wąskich gardeł systemu.
Zacznij od automatyzacji elementów systemu, z którymi wiąże się większe ryzyko Podjęcie wysiłku pokrycia zautomatyzowanymi testami całego starego systemu jest nieuzasadnione. Jeśli korzystasz z automatyzacji testów funkcjonalnych z myślą o wdrożeniu specyfikacji przez przykłady, opracuj tyle testów, ile trzeba, aby uzmysłowić innym wartość automatyzacji i przyzwyczaić ich do korzystania z narzędzi. Później dokonuj implementacji wykonywalnych specyfikacji i pracuj nad pokryciem testami stopniowo, w miarę wprowadzania kolejnych zmian. Aby osiągnąć jak najlepsze efekty zastosowania automatyzacji testów, skoncentruj się na automatyzacji dotyczącej tych części systemu, z którymi wiąże się duże ryzyko — w obszarach, w których ewentualne problemy mogą powodować znaczne straty finansowe. Zapobieganie problemom będzie wyraźnym dowodem wartości Twoich działań. Dobre pokrycie testami funkcjonalnymi może poprawić poziom zaufania członków Twojego zespołu. Korzyści wynikające ze zautomatyzowania testów w obszarach cechujących się mniejszym ryzykiem prawdopodobnie nie są aż tak wielkie†. _______________ †
Patrz http://gojko.net/2011/02/08/test-automation-strategy-for-legacy-systems.
Wprowadź narzędzie do wykonywalnych specyfikacji Kiedy: Zależnie od potrzeb własnych testerów
W przypadku projektów, w których automatyzacja testów funkcjonalnych w pełni zależy od testerów, kluczowym wyzwaniem jest rozbicie wyimaginowanego muru oddzielającego testerów od deweloperów. Nie ma potrzeby udowadniania wartości automatyzacji testów lub wywoływania konfliktów na tle środowisk testowych, ale konieczna jest zmiana sposobu myślenia członków zespołu, którzy muszą zacząć lepiej ze sobą współpracować. Ten problem ma głównie wymiar kulturowy (odniosę się jeszcze do niego w dalszej części), ale czasami wynika z trudności natury finansowej. W przypadku drogich systemów automatyzacji, takich jak QTP, w których płaci się za licencję stanowiskową, programistów i analityków biznesowych celowo trzyma się z dala od testowania. Gdy jednak zmienia się stosunek do współpracy, zespół może wspólnie pracować nad specyfikacją i zautomatyzować proces walidacji bez zmian specyfikacji.
Rozdział 4. Inicjowanie zmian
69
Kilka znanych mi zespołów nie miało innego wyjścia, jak tylko pójść w tym kierunku, gdy pojawił się problem, a jego rozwiązania nie dało się należycie przetestować posiadanymi w firmie narzędziami automatyzacji. Ludzie wykorzystali wówczas sytuację, uznając ją za dobrą okazję, by zacząć używać narzędzi do automatyzacji wykonywalnych specyfikacji. (Przykłady znajdziesz w części dodatku zatytułowanej „Narzędzia”, a kilka artykułów na temat narzędzi zebrałem na stronie internetowej pod adresem http://specificationbyexample.com).
Zespoły odkryły, że wykorzystanie narzędzi automatyzacji wykonywalnych specyfikacji sprawia, iż deweloperzy bardziej angażują się w automatyzację testów, przekazując użytkownikom biznesowym więcej informacji, pozwalających im zrozumieć testy.
Wkrótce deweloperzy bardziej angażują się w proces automatyzacji testów i zaczynają uruchamiać je na swoich komputerach, uświadamiając sobie wartość szybkości pozyskania informacji zwrotnej dzięki testom funkcjonalnym. Użytkownicy biznesowi mogą zrozumieć działanie zautomatyzowanych testów dzięki narzędziom służącym do tworzenia wykonywalnych specyfikacji oraz uczestniczeniu w określaniu powiązanych kryteriów akceptacji. Jeśli do tego dojdzie, zmiana procesu projektowania wykonywalnych specyfikacji i zaakceptowanie pierwszorzędnego znaczenia testów stają się już stosunkowo proste. Pracując dla dużego dostawcy produktów ubezpieczeniowych, zespół Roba Parka wykorzystał funkcję generowania dowodu ubezpieczenia w formacie PDF jako pretekst do wprowadzenia narzędzia automatyzacji wykonywalnych specyfikacji i przeniesienia testów funkcjonalnych na wcześniejszy etap cyklu rozwoju. Rob Park mówi: Nie było możliwości przetestowania generowania pliku w QTP. Można było sprawdzić, czy pojawia się okno bez komunikatu o błędzie… i to wszystko. Chciałem, żeby deweloperzy mieli możliwość uruchamiania testów na swoich maszynach, co było jednym z ograniczeń QTP [ze względu na koszt licencji stanowiskowej]. Spróbowaliśmy JBehave. Właściwie to sami skoczyliśmy na głęboką wodę, ale wszystko zaczęło śmigać już po tygodniu. Teraz możemy sprawić, że testy akceptacyjne umożliwiają projektowanie bazowego kontrolera”. Pierre Veragen pracujący dla Weyerhaeuser projektował niestandardowe narzędzia automatyzacji testów, które umożliwiały zapisywanie danych poprzez interfejs użytkownika. Zespół musiał ponosić znaczne koszty utrzymania. Po ostatnich zmianach, gdy wiele testów przestało działać, Pierre miał pretekst, aby uzasadnić przejście na FitNesse, szacując, że przepisanie istniejących testów do nowego narzędzia zajmie zespołowi mniej czasu niż ponowne nagranie wszystkich niefunkcjonujących testów. Przejście na FitNesse pozwoliło zespołowi na nawiązanie ściślejszej współpracy z inżynierami w kwestii wykonywalnych specyfikacji i stało się iskrą, która zainicjowała implementację specyfikacji przez przykłady.
70
Specyfikacja na przykładach
Wykorzystaj TDD jako odskocznię Kiedy: Deweloperzy mają dużą wiedzę na temat TDD
Inną typową strategią prowadzącą do efektywnego wdrożenia specyfikacji przez przykłady jest wyjście od (jednostkowego) TDD, zwłaszcza jeśli mamy do czynienia z projektami typu greenfield.
Praktyki związane z TDD są znacznie lepiej udokumentowane i lepiej rozumiane przez społeczność niż specyfikacja przez przykłady. Jeśli zespół wdrożył już dobre praktyki TDD, prawdopodobnie nie trzeba nikomu udowadniać wartości zautomatyzowanych testów lub zmieniać projektu, aby uczynić oprogramowanie bardziej sprawdzalnym. Wykonywalne specyfikacje mogą być postrzegane jako rozszerzenie TDD przystosowane do reguł biznesowych. (Termin Acceptance-Test-Driven Development jest popularnym synonimem specyfikacji przez przykłady). Lisa Crispin z ePlan Services zastosowała to podejście podczas pierwszej fazy wdrażania metodyki specyfikacji przez przykłady: Nie mogłam poradzić sobie z przekonaniem ludzi do zainteresowania się testami akceptacyjnymi. Sugerując się podpowiedziami Mike’a Cohna, wybrałam historyjkę, z którą udałam się do pracującego nad nią dewelopera. Zapytałam go: »Czy przy tej historyjce możemy popracować w parze?«. Deweloperzy łatwo zrozumieją, jakie to proste. W kolejnym sprincie wybrałam inną historyjkę i innego programistę. Od razu znaleźliśmy błąd, który wynikał z niezrozumienia założeń. I tak to programiści szybko zrozumieli zalety metody. Gdy zespół dobrze rozumie reguły TDD, przekonanie go do wykonywalnych specyfikacji jest łatwe: Przedstaw je jako testy funkcjonalności biznesowej.
Jak zacząć zmieniać kulturę zespołu? W przeważającej liczbie przypadków wdrożenie specyfikacji przez przykłady wiąże się z koniecznością zmiany kulturowej — przekonania ludzi do współpracy w kwestii wymagań i zmodyfikowania sposobu, w jaki przedstawiciele biznesu, programiści i testerzy przyczyniają się do tworzenia specyfikacji. Oto kilka pomysłów na zmianę kultury pracy zespołu.
Unikaj używania terminów sugerujących zwinność lub bycie „agile” Kiedy: Pracujesz w środowisku opornym na zmiany
Zwinne metody wytwarzania oprogramowania uginają się pod modnymi terminami i różnymi słowami wytrychami. Scrum, codzienne spotkania scrumowe, historyjki użytkowników, mistrzowie, programowanie parami i podobne terminy łatwo prowadzą do nieporozumień i mogą wywołać dezorientację. Taka nowomodna terminologia może nawet wydawać się przytłaczająca i przerażająca. Niepokój wywołany przez żargon jest jednym z najważniejszych
Rozdział 4. Inicjowanie zmian
71
powodów tego, że ludzie unikają zmiany procesów i opierają się jej — albo biernie czekają na to, co ma się stać, licząc, że ostatecznie nic się nie zmieni. Z mojego doświadczenia wynika, że wielu użytkownikom biznesowym trudno zrozumieć terminy techniczne stosowane przez deweloperów, co sprawia, że równie trudno im zrozumieć koncepcje dotyczące procesu doskonalenia i współpracy z zespołem.
Bez wątpienia wdrożenie specyfikacji przez przykłady jest możliwe bez odwoływania się do specjalistycznych terminów. Jeśli pracujesz w środowisku, które jest niechętnie nastawione do zmian, podejmując wysiłek zmiany, unikaj żargonu.
Nie mów o historyjkach użytkowników, testach akceptacyjnych lub wykonywalnych specyfikacjach — spróbuj przedstawić zasady specyfikacji przez przykłady, nie zamykając jej w ramach sztywnych definicji. W ten sposób ograniczysz zapasy swojej „amunicji”, którą Twoi przeciwnicy mogliby wykorzystać przeciwko Tobie. Opisz specyfikację przez przykłady jako proces gromadzenia przykładów, które służą do objaśnienia szczegółów wymagań, tworzenia testów i ich automatyzacji. Wszystko inne pozostaw do odkrycia. Adam Knight wdrożył większość kluczowych elementów specyfikacji przez przykłady w RainStor bez wielkiego szumu. Proces został przeprowadzony bez wcześniejszego planowania, a Knight mówi, że nikt w firmie poza nim nie wie, że istnieje coś takiego jak specyfikacja przez przykłady. „Ludzie tak naprawdę nie są świadomi istnienia jakiejś sformalizowanej metody” — stwierdził podczas naszej rozmowy. Dla jego zespołu jest to tylko proces, który ludzie z firmy wypracowali sobie sami. Pierre Veragen zastosował podobne podejście, celując w usprawnienie procesu tworzenia oprogramowania w jednym z zespołów pracujących dla firmy Weyerhaeuser. Zadaniem zespołu było serwisowanie pewnej starszej aplikacji, na którą składało się ponad milion linii kodu. Członkowie zespołu z niechęcią odnosili się do wszystkiego, co zawierało słowo klucz „agile”. Bez używania wielkich słów Veragen zasugerował automatyzację testów na poziomie niższym od interfejsu użytkownika, co miało sprawić, że testowanie stanie się bardziej efektywne. Gdy zespół przekonał się do tej sugestii, zaproponował, aby deweloperzy uruchamiali testy na swoich komputerach, dzięki czemu szybciej mogliby uzyskiwać informacje zwrotne, lepiej dopasowując do siebie testowanie i rozwój oprogramowania. Przy odpowiedniej dawce uwagi i monitorowania pracy Veragen ostatecznie sprawił, że członkowie zespołu przestali traktować testowanie jak coś, co ma miejsce po ukończeniu pracy nad kodem. Osiągnięcie tego stanu zajęło mu około sześciu miesięcy, głównie dlatego, że zautomatyzowany zestaw testów musiał urosnąć na tyle, aby programiści sami byli w stanie zaobserwować, jak testy kończące się negatywnym wynikiem wskazują im błędy podczas wprowadzania nowych linijek kodu dotyczących projektowanych funkcji. Veragen komentuje: Ludzie pracujący nad aplikacją zdali sobie sprawę, że zakończone niepowodzeniem testy wykonywane na ich komputerach rzeczywiście wskazywały istnienie
72
Specyfikacja na przykładach
problemów w ich kodzie. A kiedy już do tego doszło, deweloperzy zrozumieli wartość tej wiedzy i przestali kwestionować pomysł uruchamiania testów na ich sprzęcie. Aby doprowadzić do zmiany procesu bez odwoływania się do specjalistycznej terminologii, spraw, by problemy stały się lepiej widoczne, i delikatnie popchnij ludzi we właściwym kierunku, aby sami mogli je rozwiązywać. Gdy zespół wychodzi z propozycją rozwiązania problemu, nawet jeśli ktoś mu w tym pomaga, ludzie będą mieć poczucie odpowiedzialności i bardziej zaangażują się w zmiany procesu.
Zadbaj o uzyskanie wsparcia kierownictwa Większość zespołów podczas wdrażania reguł specyfikacji przez przykłady znacząco zmieniła sposób pracy. Dla wielu członków zespołów oznaczało to zmianę podejścia do specyfikacji, rozwoju i testowania oprogramowania — a także konieczność nauczenia się, jak lepiej współpracować w grupie oraz z przedstawicielami zainteresowanych stron spoza firmy. Zmiana charakteru ról często prowadziła do irytacji. Testerzy musieli bardziej zaangażować się w analizy. Programiści musieli bardziej przyłożyć się do testowania. Z kolei analitycy musieli zmienić sposób zbierania i przekazywania wymagań. Użytkownicy biznesowi musieli zaakceptować aktywniejszą rolę w zakresie przygotowania specyfikacji. Tak duże zmiany wymagają uzyskania wsparcia kierownictwa firmy. W przypadku braku tego wsparcia są skazane na niepowodzenie. Oto jak podsumowuje tę kwestię Clare McLennan: Musisz uzyskać wsparcie kierownictwa dla projektu, zwłaszcza wtedy, gdy ludzie wypracowali już sobie wcześniej jakiś system pracy, ponieważ zanim uda się wam stworzyć dobry, stabilny system testów, minie trochę czasu. Musisz przejść przez wszystkie iteracje i sprawdzić wiele możliwości, identyfikując miejsca, w których system jest niestabilny lub zwraca ci dziwne dane. Musisz to naprawić i powtórzyć cały proces. Jeśli poświęcisz na to rok lub więcej, stworzysz naprawdę nieoceniony system. W przeciwnym razie lub jeśli uważasz, że chodzi o szybkie rozwiązanie i możesz otrzymać gotowe testy UI po kilku kliknięciach, stworzysz system trudny do wspierania, charakteryzujący się niewielką wartością. Na początku automatyzacja wykonywalnych specyfikacji była sporym wyzwaniem dla wielu zespołów, ponieważ ta koncepcja różniła się od tego, do czego przyzwyczaili się zarówno testerzy, jak i programiści pracujący nad automatyzacją testów (więcej na ten temat w rozdziale 9.). Ludzie musieli nauczyć się korzystać z nowego narzędzia, znaleźć dobry sposób projektowania wykonywalnych specyfikacji i tworzenia struktury żyjącej dokumentacji. Przez pierwsze kilka miesięcy wydajność zespołu spada, zanim będzie mogła wzrosnąć. I to wymaga zrozumienia, wsparcia i akceptacji szefów.
Bez przekonania i uzyskania wsparcia kierownictwa zmiana procesu ma nikłe szanse zakończyć się sukcesem.
Rozdział 4. Inicjowanie zmian
73
Jeśli reakcja kierownictwa firmy sprowadza się do wywierania presji, a nie udzielania wsparcia, ludzie wracają do starych, znanych im z przeszłości sposobów działania i zaczynają chronić swoją pozycję w organizacji, nie myśląc o współpracy. Podzielenie się z szefami opisem przypadków udanych zmian i przedstawienie korzyści (zgodnie z sugestiami z rozdziału 1.) powinno pomóc w uzyskaniu wsparcia. Jednak gdyby to się nie powiodło, lepiej poszukać mniej ambitnych sposobów poprawy procesu lub zdecydować się na mniejsze kroczki prowadzące do celu.
Sprzedaj specyfikację przez przykłady jako lepszą metodę wykonywania testów akceptacyjnych Kilka zespołów, w tym także te działające w warunkach ściśle kontrolowanych, dotarło do punktu, w którym testy akceptacyjne użytkownika — jako pewien etap w procesie wytwarzania oprogramowania — przestały już być im potrzebne. (Niektóre firmy nazywają ten etap fazą testów akceptacji klienta lub testowaniem akceptacji biznesowej). To nie znaczy, że całkowicie zrezygnowano w nich z testowania dla uzyskania akceptacji użytkownika. Identyfikowanie i sprawdzanie kryteriów akceptacji różni się od testów akceptacyjnych użytkownika, które są etapem wytwarzania oprogramowania. Jest to zagadnienie tak ważne, że nie powinniśmy zostawiać tego elementu na sam koniec. Wykonywalne specyfikacje i częsta walidacja poprawności sprawiają, że zespoły programistów stale potrzebują akceptacji użytkownika. Produkt nie zostanie dostarczony do użytkowników, chyba że wszystkie testy akceptacyjne kończą się sukcesem. Gdy wykonywalne specyfikacje są wystarczająco wyczerpujące i regularnie sprawdzane, wzajemne zaufanie pomiędzy deweloperami i ich klientami wzrasta do poziomu, na którym ręczna weryfikacja oprogramowania po wydaniu staje się zbędna. (Nie oznacza to, że testerzy nie powinni wykonywać testów eksploracyjnych przed dostarczeniem produktu).
Spodziewam się, że większość zespołów będzie w stanie uzasadnić koszty wprowadzenia specyfikacji przez przykłady uniknięciem spóźnionych testów akceptacyjnych. Taka zmiana procesu, dzięki której zespół będzie mógł szybciej znaleźć się na etapie akceptacji, powinna wiązać się z wymiernymi korzyściami finansowymi, uzasadniającymi inwestowanie w tę zmianę.
Krótkie iteracje lub tworzenie oprogramowania bazujące na przepływach (ang. flowbased development) znacząco zwiększają częstotliwość potencjalnych wydań. Powiedzmy, że chcesz w ciągu najbliższych 12 miesięcy wydać 12 wersji oprogramowania (większość badanych zespołów celuje nawet w dwukrotnie większą liczbę wersji), a testy akceptacyjne użytkownika trwają średnio 3 dni. Oznacza to, że w przyszłym roku spędzisz 36 dni, wykonując testy akceptacyjne użytkownika, przy założeniu, że nie napotkasz żadnych problemów — czyli że nigdy nie pojawią się żadne kłopoty, a oprogramowanie zawsze będzie akceptowane
74
Specyfikacja na przykładach
(dlaczego wówczas testowanie miałoby w ogóle trwać aż 3 dni?). Lepiej realistycznie założyć, że na końcowe testy akceptacyjne, przeróbki i ponowne testy będziesz potrzebować co najmniej 2 z 12 miesięcy, jakie masz do dyspozycji. Jeśli zaczynasz od promowania współpracy w celu określenia kryteriów akceptacji i automatyzacji walidacji, nie będziesz musiał tracić czasu na ręczne testowanie i poprawki. Automatyzacja wiąże się z poniesieniem pewnych kosztów, ale specyfikacja przez przykłady może znacznie skrócić czas wprowadzania produktu na rynek. Wdrożenie specyfikacji przez przykłady wiąże się z wieloma innymi korzyściami, ale ta (oznaczająca skrócenie czasu wprowadzania produktu na rynek) jest najprostszym przekazem, jakim można podzielić się z interesariuszami biznesowymi. Równocześnie te informacje łatwo sprawdzić i zmierzyć. Jeśli chcesz „sprzedać” zmianę procesów biznesowych swoim interesariuszom, spróbuj przedstawić ją jako sposób na wprowadzenie produktu na rynek dwa miesiące wcześniej.
Niech automatyzacja testów nie będzie celem końcowym Jednym z najbardziej powszechnych początkowych błędów popełnianych przez badane przeze mnie zespoły było traktowanie automatyzacji testów funkcjonalnych jako ostatecznego celu zmiany procesu. Użytkownicy biznesowi na ogół myślą o automatyzacji testów funkcjonalnych jak o czymś, co ma związek z… nomen omen, testowaniem, a tym samym wydaje im się, że jest to coś, w co nie muszą się angażować. Jeśli deweloperzy nie zrozumieją, że jeżeli ma dojść do poprawy komunikacji, zautomatyzowane testy muszą być czytelne dla człowieka, będą tworzyć je przede wszystkim z myślą o minimalizacji wysiłku rozwoju.
Gdy zespoły skupiły się wyłącznie na automatyzacji testów, nie udało się poprawić współpracy.
Takie podejście często prowadzi do tworzenia testów zbyt technicznych, przypominających raczej skrypty, a nie specyfikacje, a to z kolei jest symptomem przyszłej porażki (patrz „Skrypty to nie specyfikacje” w rozdziale 8.). W dłuższej perspektywie zautomatyzowane w ten sposób testy stają się przeszkodą utrudniającą wprowadzenie zmian, a nie elementem, który je ułatwia. Jeśli automatyzacja testów funkcjonalnych jest krokiem w kierunku specyfikacji przez przykłady, upewnij się, że każdy członek zespołu jest świadomy celu końcowego. Gdy system automatyzacji testów funkcjonalnych przyjmie się, oznacza to, że nadszedł czas, aby ruszyć dalej.
Rozdział 4. Inicjowanie zmian
75
Nie koncentruj się wyłącznie na narzędziu Trzech moich rozmówców rozpoczynało swoją przygodę ze specyfikacją przez przykłady od wybrania narzędzia. Deweloperzy słyszeli co nieco o FitNesse lub Cucumberze i postanowili je wypróbować podczas realizacji projektu. I ja kiedyś dałem się zwieść… dlatego dziś mogę powiedzieć, że takie podejście ma małe szanse powodzenia.
Specyfikacja przez przykłady nie jest metodą koncentrującą się na aspekcie programowania, a programiści korzystający z narzędzi indywidualnie daleko Cię nie zaprowadzą.
Takie podejście często kończy się tym, że programiści korzystają z nietechnicznych narzędzi, przeznaczonych do tworzenia wykonywalnych specyfikacji, używając ich do zarządzania testami technicznymi, zorientowanymi na deweloperów. To najzwyklejsza strata czasu. Spośród trzech znanych mi przypadków, w których deweloperzy koncentrują się na użyciu jakiegoś szczególnego narzędzia, tylko zespołowi Iana Coopera z Beazley udało się opracować właściwy proces. Wszyscy bardzo starali się uzyskać zaangażowanie testerów i analityków biznesowych, a następnie dostosowali skład i organizację testów, aby jak najlepiej je wykorzystać. Co więcej, krytycznie podchodzili do zalet stosowania tych narzędzi i stale szukali łatwiejszych sposobów, by uzyskać takie same korzyści. W dwóch pozostałych przypadkach zespoły skoncentrowały się na narzędziu, a nie na współpracy na wysokim poziomie oraz zmianie procesu. Efekt był taki, że stracono wiele czasu i zmarnowano wysiłki zmierzające do stworzenia zestawu testów technicznych, z których nie mogli korzystać użytkownicy biznesowi i testerzy. Zapłacono zatem wysoką cenę — w kategoriach czasu i wysiłku utrzymania testów — bez osiągnięcia żadnych korzyści ze specyfikacji przez przykłady.
W czasie migracji niech jedna osoba ciągle pracuje nad starszymi skryptami Kiedy: Wprowadzasz automatyzację funkcjonalną do istniejących systemów
Przepisanie testów funkcjonalnych i ich automatyzacja przy użyciu nowego narzędzia wymaga czasu. Dopóki nowy system walidacji nie nabierze mocy, być może trzeba będzie na bieżąco utrzymywać i uaktualniać istniejące testy. Dobrym sposobem rozwiązania takiego problemu jest powierzenie tej pracy jednej osobie, uwzględniając czas tej osoby przy planowaniu dotyczącym najbliższej przyszłości. James Shore i Shane Warden opisują wzorzec zmian procesu w kontekście projektów dotyczących starszego oprogramowania (kryjący się pod kodem „Batman”) w książce zatytułowanej The Art of Agile Development4. Batman to także osoba oddelegowana do pracy nad 4
James Shore, ShaneWarden, The Art of Agile Development, O’Reilly Media, 2007. W Polsce książka została wydana pod tytułem: Agile Development. Filozofia programowania zwinnego nakładem wydawnictwa Helion, 2008 — przyp. tłum.
76
Specyfikacja na przykładach
starym systemem, której zadaniem jest rozwiązywanie pojawiających się problemów i eliminowanie istotnych błędów, podczas gdy reszta zespołu pracuje nad nową funkcją. Markus Gärtner zastosował to podejście, aby stopniowo przenieść szereg testów do narzędzia automatyzacji dla wykonywalnych specyfikacji. Oto jak podsumowuje swoje doświadczenia: Kiedy przenieśliśmy nasze testy ze skryptów powłoki do zestawu testów FitNesse, zaczęliśmy od dwójki pracującej nad nowym materiałem i trzech osób zajmujących się utrzymaniem starszych skryptów. Z biegiem czasu proporcje zmieniały się i coraz więcej testerów angażowaliśmy do pracy nad częścią nowej koncepcji. Najpierw trzech, potem jeszcze jeden, aż wreszcie udało nam się całkowicie pozbyć się starych skryptów. Podstawowa koncepcja zakładała wykorzystanie »Batmana«, który pojawiał się na miejscu, gdy trzeba było poradzić sobie z jakimś problemem. Pamiętam, że któryś z moich kolegów kupił nawet taki zabawkowy samochodzik Hot Wheels — batmobil — i sprezentował go naszemu Batmanowi. Początkowo chciałem zastosować rotację roli Batmana, ale nigdy ostatecznie się na to nie zdecydowałem, bo moi koledzy byli wówczas prawdziwymi skarbcami wiedzy. Zmieniliśmy tę zasadę wraz z nowym podejściem i teraz staram się zmieniać obsadę roli Batmana, żeby w czasie transformacji każdy członek zespołu miał do czynienia nie tylko z nowymi, ale i ze starymi skryptami. Uzyskanie zaangażowania wszystkich członków zespołu ma kluczowe znaczenie.
Dzięki zleceniu aktualizacji istniejących elementów starego systemu jednej osobie reszta zespołu może nabrać rozpędu, zmierzając w kierunku migracji do nowego procesu.
Przedstawiona koncepcja Batmana przypomina strategię Alistaira Cockburna „Poświęć jedną osobę”5, w której jeden człowiek z zespołu zostaje przypisany do obsługi zadań rozpraszających, a reszta pędzi do przodu z pełną prędkością.
Sprawdzaj, kto wykonuje testy automatyczne Kiedy: Deweloperzy niechętnie podchodzą do uczestnictwa w procesie
Gdy deweloperzy mają za sobą głównie doświadczenia pracy w środowisku z bardziej uporządkowanym procesem tła, gdzie programiści piszą kod testowany przez testerów, zespoły mają wiele problemów z przekonaniem programistów do wzięcia udziału w procesie zmiany. Jeśli implementacja specyfikacji przez przykłady ma się udać, to musi się zmienić. Pierre Veragen zaproponował unikalne rozwiązanie ułatwiające zaangażowanie programistów w proces zmiany. Stworzył prosty scentralizowany system raportowania, dzięki któremu wiedział, gdzie i kiedy zostały sprawdzone wykonywalne specyfikacje:
5
http://alistair.cockburn.us/Sacrifice+one+person+strategy.
Rozdział 4. Inicjowanie zmian
77
Wprowadziłem do kodu mechanizm, dzięki któremu wiedziałem, kiedy ludzie uruchamiali testy na swoich maszynach. Ta grupa ze sporą niepewnością podchodziła do zmiany. Korzystałem z mojego mechanizmu, aby dowiedzieć się, kiedy ludzie nie uruchamiali testów, a potem z nimi rozmawiałem. Mogłem dowiedzieć się, o co im chodzi, albo spytać, czy mieli jakieś problemy. Celem było uzyskanie bardziej obiektywnego feedbacku niż »Tak. Wszystko w porządku«. Dzięki wiedzy na temat tego, kto nie wykonuje testów, Pierre mógł skupić swoje wysiłki na przekonaniu członków zespołu, którzy mieli wątpliwości lub potrzebowali pomocy. Nasz bohater mówi, że wszyscy programiści od początku wiedzieli wszystko na temat tego procesu, tak więc zamiast monitorować rzeczywiste wyniki testów, zbierał tylko dane na temat tego, kiedy ktoś wykonywał testy.
Zbieraj dane o tym, kiedy są uruchamiane testy, a programiści będą uruchamiali mechanizmy automatyczne.
To ciekawe podejście, które może sprawdzić się w przypadku większych zespołów, gdzie trener nie jest w stanie cały czas pracować ze wszystkimi członkami grupy. Spodziewam się, że efekt zastosowania takich narzędzi monitorujących będzie podobny do umieszczenia fotoradarów na drogach — programiści po prostu będą wiedzieć, że ktoś patrzy, dlatego zaczną bardziej dbać o to, by naprawdę uruchomić testy.
Jak zespoły wdrażają zasady współpracy w procesach iteracyjnych i przepływu? Umiejętne wpasowanie zagadnienia współpracy do cyklu dostaw jest jednym z największych wyzwań, przed jakimi stoją zespoły decydujące się na wdrożenie specyfikacji przez przykłady. Nie ma uniwersalnego rozwiązania, które zagwarantuje skuteczny proces zmiany, a każdy zespół będzie musiał sam zdecydować, jak najlepiej poprawić proces wytwarzania oprogramowania. Na kolejnych stronach znajdziesz kilka ciekawych reprezentatywnych przykładów, które pomogą Ci zacząć ten proces. Wybrałem trzy dobre studia przypadków, po jednym dla każdej z popularnych metod. Zespół Global Talent Management pracuje według przepływowej metodyki Kanban. Zespół Sierra dostarcza oprogramowanie przy użyciu iteracyjnego procesu XP. Sky Network Services pracuje w iteracjach w oparciu o Scruma. Zespół Global Talent Management z Ultimate Software Global Talent Management z Ultimate Software jest jednym z szesnastu zespołów pracujących nad własnym systemem zarządzania zasobami ludzkimi. Zespół składa się z właściciela produktu, eksperta ds. doświadczenia użytkowników, czterech testerów i dziesięciu deweloperów. Gdy rozmawiałem ze Scottem Bergerem i Maykelem Suarezem, będącymi częścią zespołu, ich projekt był realizowany już od ośmiu miesięcy. Zespół pracuje, wykorzystując metodę procesu przepływu Kanban.
78
Specyfikacja na przykładach
Różnice pomiędzy specyfikacją przez przykłady i analizą kaskadową Wielu ludzi, których spotykałem na konferencjach, myli się, sądząc, że inkrementacyjne budowanie systemu dokumentacji oznacza powrót do koncepcji kaskadowych, obszernych analiz wykonywanych przed faktycznym rozpoczęciem projektu. W listopadzie 2009 roku podczas prezentacji zatytułowanej How to Sell BDD to the Business† Dan North stwierdził, że BDD to tak naprawdę V-Model skompresowany na tyle, by zmieścił się w dwóch tygodniach. Nie jest to całkiem trafna definicja, ale może stanowić dobry punkt wyjścia. Istnieje kilka kluczowych różnic pomiędzy analizą kaskadową a celem, do którego dąży się, wdrażając specyfikację przez przykłady. Uświadomienie sobie tych różnic ma wielkie znaczenie, ponieważ dzięki tej wiedzy łatwiej dopasujesz praktyki metody do swojego procesu, niezależnie od tego, o jakim procesie mówimy. Oto kluczowe elementy odróżniające specyfikację przez przykłady od starszych, uznanych systemów: Zapewnij szybki feedback i jak najszybszą wymianę informacji; skup się na opracowaniu małych elementów działającego oprogramowania, nie starając się od razu przetworzyć większych komponentów. Skoncentruj się na efektywnej, wydajnej komunikacji, a nie na długich, nudnych dokumentach. Zapewnij wspólną własność, tak aby specyfikacji nikt nikomu nie podrzucał lub nie przerzucał jej nad wysokim, wirtualnym murem oddzielającym kod od testu. Pracuj nad integracją multidyscyplinarnych zespołów, w których testerzy, analitycy i deweloperzy pracują razem nad stworzeniem odpowiednich specyfikacji opisujących system, a nie zajmują się każdy swoją częścią zadań w samotności. _______________ †
http://skillsmatter.com/podcast/agile-testing/how-to-sell-bdd-to-the-business.
Ponieważ analityk produktu (połączenie analityka i właściciela produktu) jest człowiekiem bardzo zajętym, zespół stara się efektywnie wykorzystać czas podczas wspólnej pracy przy definiowaniu specyfikacji. Analityk produktu wyjaśnia historyjkę na wysokim poziomie, mówiąc o „punktach historyjki” (w tym przypadku punkty historyjki nie są symbolem szacunkowej złożoności, ale wypunktowaną listą uwag wyjaśniających). Członkowie zespołu starają się unikać stosowania żargonu technicznego podczas tworzenia wyliczenia. W kolejnym kroku historyjka jest dodawana do tablicy Kanban jako część rejestru. Podczas codziennego spotkania ograniczonego do 30 minut główni inżynierowie spotykają się z analitykiem produktu i wszystkimi osobami zainteresowanymi rejestrem. W tym czasie szybko przeglądają historyjki w rejestrze, sprawdzając, czy każda z nich jest odpowiednio podzielona, czy ma sens i czy można dokonać jej implementacji w czasie maksymalnie czterech dni (zespół sam przyjął takie ograniczenie dla każdej historyjki). W trakcie spotkania wszyscy mogą zadawać pytania otwarte, aby wyjaśnić wszelkie niejasności dotyczące wzajemnych zależności historyjek. Następnie historyjka trafia do kolejki specyfikacji z przykładami, które są wykorzystane w funkcji testów akceptacyjnych. Członek zespołu, który będzie pracować nad implementacją historyjki, paruje się z kimś, kto koncentruje się na aspekcie testowania, tworząc zarysy
Rozdział 4. Inicjowanie zmian
79
tych specyfikacji. (W zespole nikt nie gra typowych ról testerów lub deweloperów, ale będę używał tych terminów, aby odnieść się do zadań każdej osoby z pary, dzięki czemu moje wyjaśnienia będą bardziej przejrzyste). Berger wyjaśnia: Dzięki odpowiedniemu dobraniu pary jesteśmy w stanie zmniejszyć liczbę testów wymaganych dla każdej historyjki, ponieważ deweloper ma większą wiedzę na temat kodu. Taki system sprawdził się całkiem nieźle, ponieważ parom zazwyczaj udaje się usunąć niezgodności i wady projektowe, które nie zostały wcześniej zidentyfikowane podczas przeglądu historyjek. Po zdefiniowaniu zarysu specyfikacji tester zwykle kończy scenariusze w formacie „Zakładając/Jeżeli/Wtedy”. Dwóch członków zespołu tworzących parę oraz analityk produktu spotykają się w celu dokonania przeglądu scenariuszy w trakcie sesji nazywanej SKIT (ang. Story Knowledge & Information Transfer). W ten sposób eliminuje się ryzyko tego, że programista w parze z testerem nie będą w stanie opracować odpowiedniej specyfikacji bez analityka. Od momentu, gdy analityk produktu zatwierdzi scenariusze, zespół traktuje je jak wymagania. Dopóki historyjka nie zostanie dostarczona, żadne inne zmiany — poza mniej istotnymi modyfikacjami tekstu — nie są już dozwolone. Później deweloper dokonuje zautomatyzowania scenariuszy — co zwykle ma miejsce przed implementacją kodu produkcyjnego. To pozwala testerowi spędzić więcej czasu z testami eksploracyjnymi. Tester może również pracować nad automatyzacją, ale nie jest to już jego podstawowym celem. Berger twierdzi, że taki podział zadań umożliwia bardziej wydajną pracę: Deweloperzy, którzy znają kod od podszewki, znacznie szybciej radzą sobie z automatyzacją, a właściwie piszą kod pozwalający im przekazywać zapytania bezpośrednio do obiektów (inaczej niż w przypadku automatyzacji za pośrednictwem interfejsu użytkownika). Przynosi im to większe korzyści podczas rozwoju, jako że dzięki temu systemowi zostaje opisanych o wiele więcej warunków błędów i kombinacji warunków. Ponieważ na tym etapie testujemy pod kontrolą GUI, testy wykonywane są znacznie szybciej i są bardziej stabilne. Testerzy mogą poświęcić więcej czasu na wykonywanie kodu i przekazywanie informacji zwrotnej. Wszystkie wykonywalne specyfikacje muszą przejść przez etap rozwoju, aby można było uznać je za zakończone. Wszystkie testy wykonywane są po raz drugi w fazie testów zintegrowanych, tym razem z innymi zespołami. Czekając na etap przyjęcia, zespół przygotowuje krótkie demo produktu dla analityka produktu, po czym otrzymuje jego akceptację. Według Bergera ten proces przynosi wyjątkowo dobre wyniki: Dzięki ścisłej współpracy z naszymi analitykami produktów i wykorzystaniu testów w roli podstawy dla wymagań projektowych jesteśmy w stanie osiągnąć wyjątkowo wysoki poziom jakości. Firma zebrała wiele danych, lecz jest taki wskaźnik, który moim zdaniem świetnie odzwierciedla nasze wysiłki zaangażowania
80
Specyfikacja na przykładach
w prace na rzecz jakości — mówię o DDE6. Po analizie pracy zespołu Global Team Management wskaźnik DDE wynosi 99% [za kwartały od 1. do 3. w 2010 roku]! Zespół Sierra w BNP Paribas Zespół Sierra pracujący dla BNP Paribas buduje wewnętrzny system referencyjny zarządzania danymi i dystrybucji. Zespół składa się z ośmiu deweloperów, dwóch analityków biznesowych oraz kierownika projektu. Ponieważ nie ma dedykowanych testerów, każdy członek zespołu jest odpowiedzialny za wykonywanie testów. Interesariuszami zespołu są użytkownicy biznesowi korzystający z systemu z lokalizacji znajdujących się poza siedzibą firmy. Propozycje zmiany w systemie zazwyczaj wymagają dokładnej analizy i pracy ze wszystkimi zainteresowanymi stronami. Projekt realizowany przez zespół Sierra trwa już około pięciu lat, więc można powiedzieć, że jest dość dojrzały i analitycy biznesowi mają do swojej dyspozycji wiele gotowych wykonywalnych specyfikacji, które można wykorzystać jako przykłady. Andrew Jackman, który był swego czasu członkiem tego zespołu, podzielił się ze mną opinią, że opisany przypadek stanowi jeden z nielicznych przykładów z branży usług finansowych, gdy zastosowano niemal książkowe reguły metody programowania ekstremalnego. Proces rozwoju rozpoczyna kierownik projektu, który zawczasu wybiera historyjki do wykonania w danej iteracji. Analitycy firmy pracują z interesariuszami przebywającymi poza firmą nad szczegółowymi kryteriami akceptacji przed rozpoczęciem iteracji. Przy tworzeniu struktur nowych specyfikacji korzystają z istniejących przykładów. Jeśli nowe przykłady znacząco różnią się od istniejących, para deweloperów weryfikuje testy w celu zapewnienia szybkiego feedbacku i sprawdzenia, czy testy można zautomatyzować. Iteracje rozpoczynają się w co drugą środę. Cały zespół zbiera się na spotkanie planowania i opiniuje historyjki, które przyjdzie mu realizować w kolejności wyznaczonej przez priorytety. Celem spotkania jest zadbanie o to, aby wszyscy deweloperzy rozumieli sens historyjek, potrafili je oszacować oraz mogli zidentyfikować istnienie zależności technicznych, które umożliwiałyby wybór innej, lepszej kolejności dostarczania funkcji. Podczas spotkania dokonuje się także rozbicia historyjek na konkretne zadania przekazywane deweloperom. Zanim historyjka zostaje poddana takiej analizie na spotkaniu planowania, jej kryteria akceptacji na ogół są już dobrze zdefiniowane. Od czasu do czasu zdarza się, że zespół odkrywa, iż historyjka nie została dobrze zrozumiana. Gdyby iteracje trwały tydzień, taka historyjka mogłaby zakłócić prace, jednak iteracje dwutygodniowe pozwalają zespołowi poradzić sobie w takich sytuacjach bez wymuszania dłuższych przerw całego procesu. Następnie historyjki są wdrażane przez pary deweloperów. Gdy para deweloperów realizuje implementację historyjki, a wszystkie powiązane testy kończą się pozytywnie, analityk biznesowy spędza trochę czasu na testach eksploracyjnych. Jeśli odkrywa niespodziewane 6
Defect Detection Efficiency, procentowy wskaźnik wykrytych błędów, DDE = (liczba defektów wprowadzonych do kodu i wykrytych w bieżącej fazie cyklu wytwarzania/całkowita liczba defektów wprowadzonych w tej samej fazie) × 100% — przyp. tłum.
Rozdział 4. Inicjowanie zmian
81
zachowanie systemu lub stwierdza, że zespół nie do końca zrozumiał, jakie powinny być konsekwencje historyjki w istniejącym systemie, rozszerza specyfikację, uzupełniając ją odpowiednimi przykładami, po czym odsyła historyjkę z powrotem do deweloperów. Sky Network Services Grupa Sky Network Services (SNS) pracująca dla British Sky Broadcasting Company zapewnia wsparcie systemu obsługi dostępu szerokopasmowego. Grupa składa się z sześciu zespołów, a w każdym z nich zatrudnionych jest sześciu deweloperów i jeden lub dwóch testerów. Cała grupa współpracuje z sześcioma analitykami biznesowymi obsługującymi wszystkie zespoły. Ponieważ zespoły zajmują się utrzymaniem sprawności różnych komponentów funkcjonalnych, różniących się pod względem dojrzałości, każdy z nich działa według nieco odmiennych schematów procesu. Cała grupa działa w metodyce scrumowej w dwutygodniowych sprintach. Na tydzień przed oficjalnym startem sprintu organizowane jest spotkanie koordynacyjne, w którym uczestniczą dwie lub trzy osoby z każdego zespołu. Celem tego spotkania jest ustalenie priorytetów dla historyjek. Zanim dochodzi do tego spotkania, analitycy w firmie zbierają i definiują dla każdej historyjki pewne kryteria przyjęcia wysokiego poziomu. Po spotkaniu testerzy rozpoczynają tworzenie specyfikacji z przykładami, zazwyczaj współpracując przy tym z analitykiem biznesowym. Zanim sprint zostaje oficjalnie rozpoczęty, każdy zespół dysponuje co najmniej jedną lub dwiema historyjkami uzupełnionymi szczegółowymi specyfikacjami z przykładami gotowymi do automatyzacji. Iteracje rozpoczynają się w co drugą środę spotkaniem planowania w obecności członków wszystkich zespołów, podczas którego ludzie informowani są o ogólnych postępach projektu i celach biznesowych nadchodzącej iteracji. Następnie poszczególne zespoły przechodzą do bardziej szczegółowych analiz planistycznych. Niektóre poświęcają na to 15 minut, przeglądając tylko pokrótce swoje historyjki, inne spędzają kilka godzin, pracując nad szczegółami. Rakesh Patel, jeden z deweloperów, który pracuje nad projektem, twierdzi, że czas trwania spotkania zależy przede wszystkim od statusu komponentu bazowego systemu:
W tej chwili pracujemy nad elementem systemu, który funkcjonuje poprawnie w systemie już od dłuższego czasu. Naszym zadaniem jest dodanie kilku komunikatów. Tak naprawdę zespół wcale nie musi być informowany o wszystkich szczegółach i konsekwencjach tej operacji. Możemy poczekać i zabrać się za pracę nad zadaniem po odebraniu karty z historyjką. Jednak inne zespoły budują nowy graficzny interfejs użytkownika, dodają do systemu zupełnie nowe funkcje, dlatego w takich przypadkach lepiej, gdy zbierze się cały zespół, aby usiąść i porozmawiać o szczegółach, zastanawiając się nad tym, co należy zrobić. W tym momencie możemy również omówić wymagania niefunkcjonalne, architekturę itp. Po zakończeniu spotkania planowania deweloperzy zaczynają prace nad historyjkami, które są już uzupełnione specyfikacjami z przykładami. Analitycy biznesowi i testerzy pracują nad ukończeniem kryteriów przyjęcia dla wszystkich planowanych w tej iteracji historyjek. Po przygotowaniu specyfikacji dla historyjki spotykają się z deweloperem wyznaczonym na
82
Specyfikacja na przykładach
„mistrza historyjki” (patrz ramka) i przechodzą do testów. Jeśli nikt nie ma wątpliwości, że zespół dysponuje danymi wystarczającymi do zakończenia historyjki, karta historyjki zostaje oznaczona niebieską naklejką, co oznacza, że nadszedł czas pracy dewelopera. Po zakończeniu etapu rozwoju kodu analitycy firmy ponownie przeglądają specyfikacje i umieszczają na karcie czerwoną naklejkę. Testerzy uruchamiają dodatkowe testy i dodają zieloną nalepkę, gdy testy kończą się powodzeniem. Niektóre historyjki będą wymagać uczestnictwa zespołu wsparcia, administratorów baz danych lub administratorów systemów, którzy sprawdzają historyjkę po testerach. Administratorzy baz danych umieszczają na karcie złotą gwiazdkę, a administratorzy systemów — gdy sprawdzą wyniki — dodają gwiazdkę srebrną. Naklejki są znakiem, że wszystkie osoby, które musiały zostać zaangażowane we współpracę nad daną historyjką, rzeczywiście zostały zaangażowane i są tego świadome. Zamiast organizować spotkania w dużym gronie w sprawie specyfikacji, zespoły SNS skupiły się raczej na stworzeniu procesu przepływu. Wciąż wykorzystują dwufazowy proces tworzenia specyfikacji z analitykami biznesowymi i testerami przygotowującymi przykłady zawczasu, a potem analizującymi je wspólnie z deweloperami, jednak taki system daje programistom więcej czasu na skupienie się na pracy na rzecz rozwoju. Zamiast gromadzić wszystkich deweloperów podczas przeglądu historyjki po to, by zadbać, aby wszyscy dobrze rozumieli założenia, zespoły wykorzystują unikalną rolę „mistrza historyjki”, który jest odpowiedzialny za przekazanie niezbędnych informacji podczas parowania z innymi deweloperami. Trzy przedstawione przykłady pokazują, w jaki sposób można dopasować do krótkich iteracji lub procesów opartych na przepływach współpracę członków kilku zespołów. Udowadniają, że nie istnieje uniwersalne i powszechnie stosowane podejście do tworzenia struktury procesu. Wszystkie zespoły z powodzeniem zintegrowały element współpracy w ramach krótkich cykli dostarczania oprogramowania, ale wybrały różne rozwiązania w zależności od struktury zespołu, dostępności użytkowników biznesowych i złożoności oczekiwanych zmian. Kilka ciekawych pomysłów zaprojektowania procesu tak, aby dopasować go do swojego zespołu, znajdziesz w części zatytułowanej „Wybór modelu współpracy” w rozdziale 6. Więcej przykładów można znaleźć w studium przypadku w części III książki.
Radzenie sobie z potrzebą formalnego zatwierdzenia i identyfikowalnością Dla niektórych zespołów duży problem z niewielką ilością lub zupełnym brakiem dokumentacji projektów zwinnych przekształca się w brak wymagań. To sprawia, że uzyskanie jakichkolwiek formalnych zatwierdzeń na dokumentach z wymaganiami lub efektami pracy staje się naprawdę trudne. Uogólniając, można powiedzieć, że obecnie cała branża inżynierii oprogramowania o wiele mniej troszczy się o te zatwierdzenia, niż miało to miejsce jeszcze 10 lat temu. W niektórych przypadkach są one nadal wymagane, ponieważ wymuszają je ograniczenia prawne lub porozumienia handlowe. Specyfikacja przez przykłady pozwala dostarczyć pewne artefakty — żyjącą dokumentację — które można wykorzystać na potrzeby identyfikowalności, tj. śledzenia przebiegu zatwierdzeń wymagań (ang. traceability on requirements). Dzięki temu zwinne procesy mogą
Rozdział 4. Inicjowanie zmian
83
Mistrz historyjki Zespoły SNS korzystają z ról tak zwanych mistrzów historyjki, aby zapewnić efektywny przepływ wiedzy deweloperów pracujących nad przygotowaniem historyjki. Kumaran Sivapathasuntharam, analityk biznesowy uczestniczący w projekcie SNS, wyjaśnia, kim są owi mistrzowie historyjki: Historyjka jest przydzielana konkretnemu deweloperowi, który odpowiada za nią aż do chwili, gdy zostanie ukończona. Dzięki temu przez cały czas tylko jeden człowiek jest osobą kontaktową — jeśli masz jakieś wątpliwości lub pytania, udajesz się z nimi do mistrza historyjki. Jedna osoba pracuje nad historyjką od początku do końca, dbając o to, aby pary nie utknęły w jakimś martwym punkcie. Pary mogą się zmieniać, a wciąż zapewniona jest ciągłość pracy. Zespół Global Talent Management z Ultimate Software również korzysta z podobnej roli, nazywając wchodzącego w nią człowieka mianem „sponsora”. Według Maykela Suareza sponsor jest odpowiedzialny za komunikację z innymi zespołami, śledzi postępy i zapisuje je na tablicy Kanban, sprawdza status podczas spotkań oraz usuwa wszelkie przeszkody stojące na drodze zespołu.
być zastosowane także w środowiskach regulowanych. Bas Vodde i Craig Larman pisali o pierwszym zwinnym projekcie rozwoju oprogramowania w amerykańskim przemyśle nuklearnym7 w Practices for Scaling Lean and Agile8. Zespół pracujący nad tym projektem wykorzystał wykonywalne specyfikacje do zapewniania pełnej identyfikowalności wymagań, kluczowej dla warunków w branży dostawców energii jądrowej i innych domenach, w których szczególną uwagę zwraca się na kwestie bezpieczeństwa. Z drugiej strony ze względu na bardzo dynamiczny, iteracyjny charakter procesu wymuszającego współpracę podczas tworzenia wspomnianych artefaktów system formalnych zatwierdzeń uzyskiwanych zawczasu jest praktycznie nierealny. Chciałbym jednak przedstawić Ci kilka pomysłów dotyczących tego, jak radzić sobie z ograniczeniami zatwierdzania i identyfikowalności.
Zachowaj wykonywalne specyfikacje w systemie kontroli wersji
Kilka osób z którymi rozmawiałem, utrzymywało, że zachowanie wykonywalnej specyfikacji w systemie kontroli wersji, w którym jest przechowywany kod źródłowy, jest jednym z najważniejszych rozwiązań decydujących o pomyślnej implementacji procesu.
Wiele narzędzi do automatyzacji współdziała z wykonalnymi specyfikacjami w formie plików tekstowych, dlatego też dobrze współpracuje z systemami kontroli wersji. Dzięki temu 7
Bardzo chętnie uwzględniłbym w tej książce studium przypadku opisujące taki projekt, ale niestety nie udało mi się znaleźć nikogo, kto chciałby podzielić się ze mną swoimi doświadczeniami w tym temacie. 8 Craig Larman, BasVodde, Practices for Scaling Lean and Agile Development: Large, Multi-site, and Offshore Product Development with Large-Scale Scrum, Pearson Education, 2010.
84
Specyfikacja na przykładach
możesz łatwo oznaczyć kolejne specyfikacje, podobnie jak kod źródłowy. W efekcie otrzymujesz aktualną i poprawną wersję testów, które mogą być używane do sprawdzania poprawności dowolnej wersji produktu. Systemy kontroli wersji idealnie nadają się do śledzenia zatwierdzeń, ponieważ zawierają informacje dotyczące tego, kto i kiedy zmienił każdy plik. Do tych danych można bardzo łatwo i szybko dotrzeć. Jeśli przechowujesz swoje wykonywalne specyfikacje w systemie kontroli wersji, nie musisz dodatkowo ustalać wymagań dotyczących identyfikowalności w specyfikacjach. W przypadku wdrożenia specyfikacji przez przykłady wykonywalne specyfikacje będą bezpośrednio powiązane z kodem języka programowania (poprzez warstwę automatyzacji), co oznacza, że stosunkowo proste będzie także zapewnienie identyfikowalności kodu. Prawdopodobieństwo, że wykonywalne specyfikacje znajdujące się w systemie kontroli wersji po prostu znikną, jest o wiele mniejsze niż to, że ulotnią się specyfikacje przechowywane w oddzielnych dokumentach z wymaganiami lub w narzędziach testowych.
Uzyskaj zatwierdzenie na eksportowanej żyjącej dokumentacji Kiedy: Zatwierdzasz iterację po iteracji
Specyfikacja przez przykłady powinna pomóc budować zaufanie między sponsorami projektu i zespołem dostarczającym oprogramowanie, a także usunąć potrzebę uzyskiwania formalnych zatwierdzeń. Jeśli z powodów handlowych lub politycznych potrzebujesz podpisu pod zatwierdzonymi wymaganiami, możesz wykorzystać do tego system żyjącej dokumentacji.
Jeśli potrzebujesz formalnego zatwierdzenia specyfikacji przed rozpoczęciem procesu implementacji funkcjonalności, a przygotowanie takiego etapu dla każdej iteracji jest możliwe, wówczas możesz stworzyć plik Worda lub dokument w formacie PDF na podstawie wykonywalnych specyfikacji planowanych dla przyszłej iteracji i uzyskać niezbędne podpisy zatwierdzające na takim papierowym dokumencie.
Niektóre narzędzia automatyzacji, takie jak Cucumber, umożliwiają bezpośrednie eksportowanie dokumentów do formatu PDF, a to może pomóc Ci w tym procesie.
Uzyskaj zatwierdzenie zakresu, a nie specyfikacji Kiedy: Zatwierdzasz odleglejsze kamienie milowe
Jeśli potrzebujesz formalnego zatwierdzenia partii oprogramowania większych niż te, które można dostarczyć podczas krótkich iteracji, postaraj się uzyskać akceptację zakresu, a nie szczegółowych specyfikacji. Możesz na przykład skupić się na uzyskaniu zatwierdzenia historyjek użytkownika lub przypadków zastosowania.
Rob Park skorzystał z tego rozwiązania w trakcie projektu realizowanego dla dużej amerykańskiej firmy ubezpieczeniowej. Jego zespół zatrzymał proces zatwierdzania znany z metodyki kaskadowej, ale znacznie zmniejszył zakres niezbędnych zatwierdzeń. Park wyjaśnia:
Rozdział 4. Inicjowanie zmian
85
Mamy do czynienia z pewnego rodzaju metaprocesem, który wykracza poza to, co mamy pod kontrolą. Analitycy biznesowi pracują na dokumentach Worda przy użyciu szablonu, ale z ośmiu stron ograniczyli go do dwóch. Korzystamy z systemu zatwierdzania kart historyjki, na których ludzie płacący za projekt naprawdę podpisują się, zanim ktokolwiek (inny niż analityk biznesowy) w ogóle rzuci na nie okiem. A zatem korzystamy z procesu kaskadowego na wysokim poziomie, ale gdy karta trafia do zespołu, sprawy wyglądają już nieco inaczej. Dokumenty Worda używane są w tym przypadku wyłącznie dlatego, że warunki umowy nakazują dopełnienie formalności na papierze, zanim historyjka trafi do zespołu zajmującego się projektowaniem. Z kolei po zatwierdzeniu zakresu zespół korzysta z wykonywalnych specyfikacji jako jedynego źródła wymagań.
Uzyskaj zatwierdzenie „odchudzonych” przypadków użycia Kiedy: Formalne zatwierdzenia wymagają uzupełnienia o szczegóły
Uzyskanie zatwierdzenia zakresu może nie sprawdzić się w środowisku silnie regulowanym. Mike Vogel z Knowledgent Group pracował nad projektem dla firmy z branży farmaceutycznej, korzystając z procesu bazującego na Scrumie i XP, poszerzonego o elementy pozwalające spełniać wymogi regulacyjne. Jego zespół stosował przypadki użycia (ang. use cases), ponieważ standard systemu regulacji nie przewidywał wyłącznie odniesień do historyjek użytkownika. Zespół wykorzystał „odchudzone przypadki użycia” (w gruncie rzeczy nazywano je „historyjkami ustrukturyzowanymi”), dzięki czemu wstępne i bieżące wychwytywanie ewolucji nie stanowiło większego problemu. We wspomnianych przypadkach użycia unikano gros szczegółów zawierających konkretne dane i decyzje (zostały one wyodrębnione w oddzielnych sekcjach danych). Vogel wyjaśnia: Potrzebowaliśmy jakiegoś terminu zamiennego dla części danych, który byłby zrozumiały dla klienta i stanowiłby część języka z jego domeny. Sekcji danych zawierającej w sobie omówienie struktury i zasad opisujących dane — nie przykładów. Przykłady znajdują się w testach [akceptacyjnych]/wymaganiach, gdy opisujemy przykłady użycia, definiując takie, które obejmują i wyjaśniają warianty wszystkich nazwanych fragmentów danych. Modyfikujesz swoje przykłady fragmentów danych, które zostały w nich uwzględnione.
Uzyskaj zatwierdzenie „odchudzonych” przypadków użycia — bez przykładów.
Zespół Vogla tworzył dokument zawierający wymagania przy uwzględnieniu „odchudzonych” przypadków użycia, ale bez żadnych przykładów. Jak mówi nasz bohater, w efekcie
86
Specyfikacja na przykładach
otrzymano dokument nie dłuższy niż sto stron dla dużego projektu „z całą wymaganą ustawowo paletą”. W trakcie realizacji projektu członkowie zespołu stale współpracowali z klientem w celu określenia przypadków użycia oraz przykładów: Siadaliśmy z klientem w pokoju, w którym pracował zespół, i staraliśmy się opracować dany przypadek użycia wraz z przykładami. Nasze rozmowy dotyczyły szczegółowych przykładów. Spotkanie kończyło się wprowadzeniem do dokumentacji niektórych szczegółów, które potem klient opiniował. Takie podejście pozwala zespołowi uzyskać formalne zatwierdzenie czegoś, co bardzo przypomina tradycyjne specyfikacje, bez niepotrzebnego rozwlekania dokumentacji. Szczegóły pojawiały się dopiero na etapie procesu iteracyjnego i współpracy; rejestr, z którym pracuje klient, bazuje na przypadkach użycia wysokiego poziomu, a szczegóły pojawiają się później.
Wprowadź realizacje przypadków użycia Kiedy: Formalne zatwierdzenia wymagają uwzględniania wszystkich szczegółów
Matthew Steer pracował nad kilkoma projektami w oparciu o RUP (ang. Rational Unified Process). Proces wymagał pełnego zestawu zatwierdzeń wszystkich szczegółów, a specyfikacje posłużyły do wychwycenia przypadków użycia. Oprócz wykorzystania przypadków użycia Steer i jego zespół wprowadzili także nowy element — realizacje przypadków użycia, które skutecznie ilustrowały przypadki użycia z przykładami. To pozwoliło im na wykorzystanie metodyki specyfikacji przez przykłady w ustrukturyzowanym procesie. Steer mówi: Wymagania zostały zdefiniowane jako przypadki użycia i dodatkowe specyfikacje dla niefunkcjonalnych wymagań. Takie podejście miało charakter typowy, wręcz książkowy. Na podstawie przypadków użycia tworzyliśmy realizacje przypadków użycia, przykłady i scenariusze, które były wypełniane przypadkami użycia. Opracowaliśmy tabele z mnóstwem parametrów i powiązanych danych pochodzących z różnych źródeł, opisane diagramami przepływów pokazujących, jak dany przypadek użycia będzie realizowany. Realizacja przypadków użycia było wersją roboczą tego, co określony element oznacza dla biznesu przy wykorzystaniu prawdziwych scenariuszy.
Dodawanie szczegółów takich jak realizacje przypadków użycia jest dobrym pomysłem na sformalizowanie procesu implementacji specyfikacji przez przykłady z wykorzystaniem systemu monitorowania metodologicznego. Takie działanie może także pomóc we wdrożeniu koncepcji specyfikacji przez przykłady, gdy umowy handlowe wymagają formalnych zatwierdzeń wymogów, ale pozwalają na późniejsze modyfikowanie szczegółów.
Zespół Steera, ale i grupy wymienione w poprzedniej sekcji, stosował przykłady — nawet jeśli były one przebrane za realizacje przypadków użycia — zamiast opierać się wyłącznie na przypadkach użycia i testach weryfikujących poprawność bardziej generycznych wymogów ogólnych. To dzięki nim zwiększono wydajność procesu wytwarzania oprogramowania.
Rozdział 4. Inicjowanie zmian
87
Z technicznego punktu widzenia system żyjącej dokumentacji automatycznie zapewnia identyfikowalność zmian wymagań, ponieważ zespoły korzystają z systemów kontroli wersji, aby przechowywać w nich specyfikacje wykonywalne. Proces iteracyjnego wytwarzania oprogramowania jest generalnie sprzeczny z koncepcją uzyskiwanych zawczasu zatwierdzeń i akceptacji, ale dzięki podpowiedziom z tej sekcji książki można poradzić sobie z tym problemem przy jednoczesnym wdrożeniu procesu zmiany i wzroście zaufania użytkowników biznesowych do zespołu. Transparentność gwarantowana przez system żyjącej dokumentacji, a także umiejętna współpraca podczas tworzenia specyfikacji powinny przyczynić się do wyeliminowania konieczności uzyskiwania formalnych zatwierdzeń.
Znaki ostrzegawcze Możesz śledzić swoje postępy, aby upewniać się, że proces wdrażania zasad specyfikacji przez przykłady przebiega prawidłowo. Tak jak w przypadku wszelkich danych śledzenia, pamiętaj jednak, aby wskaźniki same w sobie nie stały się Twoim celem. W przeciwnym razie uda Ci się wprawdzie zoptymalizować proces lokalnie i uzyskać właściwe wyniki, ale nie zagwarantujesz sobie w ten sposób długotrwałych rezultatów. Wykorzystaj zebrane dane do sprawdzenia, czy proces wymaga Twojej reakcji. Uważaj na testy, które często dają różne wyniki Podczas XPDay w 2009 roku Mark Striebeck mówił o tym, jakie techniki stosuje Google w celu optymalizacji praktyk testowania9. Jednym z pomysłów, który zrobił na mnie wielkie wrażenie, było to, w jaki sposób sprawdzić test (jednostkowy). Gdy test kończy się niepowodzeniem, zespoły Google szukają zmian w kodzie źródłowym dopóty, dopóki test znów nie zakończy się pozytywnie. Jeśli kod bazowy został zmieniony, uznają, że test jest dobry. Jeśli wynik testu się zmienił, a kod bazowy nie został zmieniony, uznają, że test jest niewłaściwy. Dzięki zebraniu tych danych liczą na udaną analizę wzorców testów jednostkowych, co pozwoli im odpowiedzieć na pytanie, czy test jest dobry, czy zły. Wierzę, że te same kryteria można zastosować do wykonywalnych specyfikacji. Jeśli walidacja się nie powiedzie i zmieniasz kod, oznacza to, że znalazłeś i wyeliminowałeś błąd. Jeśli walidacja się nie powiedzie, a Ty musisz zmienić specyfikację, to znaczy, że test nie został napisany poprawnie. Reguły biznesowe powinny być dużo bardziej stabilne niż technologia, która pozwala na ich implementację. Zwróć szczególną uwagę na wykonywalne specyfikacje, które zmieniają się zbyt często. Zastanów się, jak możesz je lepiej zdefiniować. Możesz też mierzyć czas, jaki zespół spędza na refaktoryzacji specyfikacji i tworzeniu powiązanego z nią kodu automatyzacji w celu utrzymania procesu pod kontrolą. Jeśli na wspomnianych zadaniach upływa znaczna część czasu iteracji, poszukaj lepszych sposobów automatyzacji testów (kilka dobrych rad znajdziesz w rozdziale 9.).
9
http://gojko.net/2009/12/07/improving-testing-practices-at-google.
88
Specyfikacja na przykładach
Uważaj na bumerangi Innym wskaźnikiem, dzięki któremu możesz sprawdzić, czy przypadkiem nie robisz nic, co może pchnąć proces w złym kierunku, jest obecność bumerangów. Bumerang to historyjka lub element z rejestru produktu, który ponownie pojawia się w procesie w ciągu niecałego miesiąca od wydania. Zespołowi wydaje się, że skończył pracę, a tu okazuje się, iż zaistniała konieczność dokonania przeróbek. Z bumerangiem nie ma nic wspólnego sytuacja, w której użytkownicy biznesowi po jakimś czasie rozszerzają wcześniej zdefiniowane wymagania w celu włączenia jakiejś innowacji, w miarę jak produkt ewoluuje. Po implementacji specyfikacji przez przykłady liczba bumerangów powinna zostać znacznie zredukowana, aż do osiągnięcia stanu, w którym takie zdarzenia staną się prawdziwą rzadkością. Współpraca przy tworzeniu specyfikacji i lepsze dostosowanie testów i fazy wytwarzania powinno prowadzić do wyeliminowania niepotrzebnych rewizji wynikających z nieporozumień. Przyglądaj się przez kilka miesięcy trendowi bumerangów, a będziesz mógł odpowiedzieć sobie na pytanie, jak bardzo poprawił się Twój proces. Jeśli liczba zidentyfikowanych powracających tematów nie spadnie, to znaczy, że coś jest nie tak ze sposobem implementacji procesu. Śledzenie bumerangów nie zajmuje dużo czasu. Zazwyczaj wystarczy kilka minut pomiędzy iteracjami. Jednak dzięki temu wiele zyskasz, gdy przyjdzie czas stawić czoła wyzwaniu i udowodnić, że specyfikacja przez przykłady działa. W większych firmach taka analiza może również dostarczyć przekonujących dowodów na poparcie tezy, że proces warto wdrożyć w innych zespołach. W przypadku potrzeby zebrania bardziej złożonych statystyk możesz śledzić czas spędzony na pracy nad bumerangami, bo ta wartość bezpośrednio przekłada się na straty finansowe oraz stratę czasu podczas rozwoju/testowania. Jeśli ludzie skarżą się, uznając, że marnują za dużo czasu na automatyzację wykonywalnych specyfikacji, porównaj te dane z rejestrem czasu zmarnowanego na bumerangi kilka miesięcy wcześniej. To powinno w zupełności wystarczyć, aby przekonać decydentów do biznesowego uzasadnienia wdrożenia specyfikacji przez przykłady. Gdy liczba bumerangów spada i zaczynają się one pojawiać stosunkowo rzadko, możesz zrezygnować z monitorowania tego wskaźnika. Jeśli zdarzy się, że do rejestru wróci jakiś temat, postaraj się odkryć, dlaczego tak się stało. Jeden z moich klientów zauważył, że wiele bumerangów wracało do niego z wydziału finansowego. Ta wiedza sprawiła, że dostrzegł istnienie jakiegoś problemu w zakresie wewnętrznej komunikacji firmy. Wszyscy zrozumieli, że istnieje potrzeba znalezienia lepszego sposobu zaangażowania w prace projektowe wspomnianego wydziału. Śledzenie bumerangów to również dobry sposób budowania uzasadnienia biznesowego dla wdrożenia specyfikacji przez przykłady. Może pomóc zespołowi w zidentyfikowaniu źródeł marnotrawstwa wynikającego z niejasnych wymagań i luk funkcjonalnych w specyfikacjach. Uważaj na niedopasowanie organizacyjne Wiele zespołów rozpoczęło wdrażanie specyfikacji przez przykłady z myślą o lepszym dopasowaniu działań firmy do systemu iteracji. Po zapoznaniu się z wykonywalnymi specyfikacjami, gdy kod automatyzacji staje się stabilny, powinieneś móc dokonać implementacji
Rozdział 4. Inicjowanie zmian
89
historyjki i ostatecznie zakończyć jej testowanie (oznacza to także wykonanie ręcznych testów eksploracyjnych) w ramach tej samej iteracji. Jeżeli jednak Twoi testerzy wloką się za deweloperami, wówczas możesz mieć pewność, że robisz coś źle. Podobnym znakiem ostrzegawczym jest niedopasowana analiza. Niektóre zespoły rozpoczynają analizę z wyprzedzeniem przed właściwą iteracją, a mimo to nadal udaje im się zachować regularność i przepływ. Zbyt złożona analiza wykonywana zawczasu, analizowanie elementów, które nie zostaną natychmiast zaimplementowane, albo też opóźnienia analizy, gdy potrzebujesz już szczegółowych danych — to wszystko znaki błędów procesu. Uważaj na kod „na wszelki wypadek” Mary i Tom Poppendieck w Lean Software Development10 piszą o tym, że źródłem największego marnotrawstwa zasobów w procesie wytwarzania oprogramowania jest kod tworzony na wszelki wypadek — coś, co powstało, mimo że wcale nie było potrzebne. Nie jestem przekonany do tezy, że jest to największe źródło strat, ale widziałem na własne oczy, jak wiele pieniędzy, czasu i wysiłku marnuje się na rzeczy, które nie są potrzebne lub o które nikt nie prosił. Specyfikacja przez przykłady znacznie redukuje częstotliwość pojawiania się tego problemu, ponieważ pomaga budować wspólne rozumienie tego, co trzeba dostarczyć. Jodie Parker stwierdza, że rozmowy i współpraca podczas definiowania specyfikacji pomogły jej zespołowi w ograniczeniu marnotrawienia zasobów:
Kiedy deweloperzy otrzymują kartę historyjki, bardzo chcą dostarczyć wszystko, co się na niej znajduje, celując w jak najlepsze z perspektywy ograniczeń technicznych efekty swojej pracy, nawet jeśli mówi się im dobitnie, aby »uzyskali daną wartość przy minimalnej aktywności«. Najważniejsza jest efektywność pracy, a każdą historyjkę można potem przywołać i ulepszyć. Wiele razy wspólnie zastanawialiśmy się nad pytaniem, czy jesteśmy w stanie stworzyć model biznesowy, który chcemy osiągnąć. Stale nad tym pracujemy. Przez modelowanie domeny można bardzo łatwo rozbić to na zadania. Wówczas Twoim zadaniem są… zadania i tylko zadania! Ponieważ zadania są niewielkie, bardzo łatwo można zboczyć przy tym na manowce, ale jeśli dzieje się coś takiego, szybko zostaje to dostrzeżone przez resztę zespołu, który podejmuje odpowiednie działania. Gdyby ktoś zajmował się jednym zadaniem przez kilka dni, wówczas taki przypadek zostałby przywołany na spotkaniu grupy. Uważaj na ludzi, którzy próbują stworzyć coś więcej niż to, co zostało uzgodnione i opisane przykładami. Innym dobrym sposobem uniknięcia sytuacji, w której kod powstaje „na wszelki wypadek”, jest omawianie nie tylko funkcji, jakie chcecie zaimplementować, ale także zwrócenie uwagi na to, co znajduje się poza zakresem prac.
10
Mary Poppendieck, Tom Poppendieck, Lean Software Development: An Agile Toolkit, Addison-Wesley Professional, 2003.
90
Specyfikacja na przykładach
Uważaj na „chirurgię śrutówką” Chirurgia śrutówką (ang. shotgun surgery)11 jest klasycznym antywzorem programowania (zwanym także „śmierdzącym kodem”), który pojawia się, gdy mała zmiana jednej klasy wymaga kaskadowej zmiany w kilku powiązanych klasach. Zdarza się, że taki wzorzec daje się zidentyfikować także w żyjącej dokumentacji; jeśli pojedyncza zmiana kodu produkcyjnego wymaga zmiany wielu wykonywalnych specyfikacji, to znaczy, że coś robisz źle. Zorganizuj swoją żyjącą dokumentację tak, by jedna mała zmiana w kodzie prowadziła do jednej małej zmiany w testach (patrz „Słuchaj swojej żyjącej dokumentacji” w rozdziale 11., gdzie znajdziesz kilka dobrych wskazówek, jak doprowadzić do takiej sytuacji). Jest to jeden z najważniejszych kroków do długofalowego zmniejszenia kosztów utrzymania automatyzacji.
Pamiętaj Specyfikacja przez przykłady jest dobrym sposobem zapewnienia zespołom programistycznym specyfikacji just-in-time, dlatego stanowi kluczowy czynnik sukcesu w krótkich iteracjach i w procesach wytwarzania oprogramowania w oparciu o system przepływów. Koncentruj się na pracy nad małymi częściami oprogramowania, skutecznie narzucając krótki czas realizacji i feedbacku. Podkreślaj znaczenie efektywnej i sprawnej komunikacji, która zastępuje obszerne, nudne dokumentacje. Integruj multidyscyplinarne zespoły, w których testerzy, analitycy i deweloperzy pracują razem, aby stworzyć właściwą specyfikację systemu. Zawczasu uwzględnij w swoich planach większe obciążenie automatyzacją.
11
Por. Joshua Kerievsky, Refaktoryzacja do wzorców projektowych, Helion, 2005 — przyp. tłum.
CZĘŚĆ II
Wzorce kluczowych procesów
5
Definiowanie zakresu na podstawie celów
F
-16 Fighting Falcon jest prawdopodobnie najbardziej udanym myśliwcem o napędzie odrzutowym, jaki kiedykolwiek zaprojektowano. Historia projektu jest tym ciekawsza, że ten samolot powstał na przekór wszystkim przeciwnościom. W latach 70., gdy rozpoczęły się prace nad projektem F-16, myśliwce musiały przede wszystkim osiągać jak największą prędkość. Zasięg, uzbrojenie i zwrotność maszyny — w kontekście wymagań projektowych — uważano za mniej istotne1. A jednak to właśnie zasięg i zwrotność F-16 zapewniły idealne dopasowanie maszyny do jej roli na polu walki oraz zdecydowały o sukcesie odrzutowca. W książce zatytułowanej 97 Things Every Architect Should Know2 Einar Landre cytuje Harry’ego Hillakera, głównego projektanta F-16, twierdzącego, że podstawowym wymogiem postawionym projektowanemu samolotowi, który miał trafić do produkcji, było osiągnięcie prędkości 2 – 2,5 Ma. Kiedy Hillaker zapytał przedstawicieli US Air Force, dlaczego wymóg prędkości maksymalnej jest tak istotny, usłyszał w odpowiedzi, że myśliwiec musi być zdolny do „uniknięcia walki”. Chociaż dzieło Hillakera nigdy nie osiągnęło prędkości maksymalnej wyraźnie przekraczającej 2 Ma, samolot jest tak zwrotny, że pozwala pilotowi decydować, kiedy podjąć walkę, a kiedy się z niej wycofać. W projekcie F-16 zastosowano wiele innowacyjnych rozwiązań, takich jak kroplowa osłona kabiny pilota, która zapewniała lepszą widoczność, fotel pilota o zmiennym położeniu oparcia dla zmniejszenia wpływu przeciążenia, wyświetlacz, który przekazuje wszystkie informacje z pola walki bezpośrednio przed oczami pilota, nie wpływając negatywnie na przegląd przestrzeni, oraz układ sterowania montowany z boku, który przyczynia się do poprawienia zdolności manewrowej podczas lotów z dużą prędkością. Dzięki tym cechom projekt F-16 okazał się lepszy niż wszystkie konstrukcje alternatywne, a przy tym tańszy w produkcji. Konstruktorom udało się wygrać konkurs na projekt. Ponad 30 lat później F-16 wciąż jest jeszcze produkowany.
1 2
Kev Darling, F-16 Fighting Falcon (Combat Legend), Crowood Press, 2005. Richard Monson-Haefel, 97 Things Every Software Architect Should Know, O’Reilly Media, 2009.
94
Specyfikacja na przykładach
Z liczbą ponad 4400 egzemplarzy samolotów sprzedanych do 25 państw3 konstrukcja okazała się również ogromnym sukcesem komercyjnym. F-16 jest jednym z najbardziej popularnych samolotów bojowych i często pojawia się w filmach akcji, jak X-Men 2 i Transformers: Zemsta upadłych. Konstrukcja F-16 była udana, ponieważ projektanci zastosowali rozwiązania lepsze i tańsze niż te zaproponowane przez klienta. Pierwotne wymagania projektowe, w tym założenie o prędkości maksymalnej na poziomie 2,5 Ma, prowadziły do jedynego możliwego rozwiązania pewnego problemu. Tymczasem okazało się, że nikt nie przekazał umiejętnie jego istoty! Zamiast implementować rozwiązania będące odpowiedzią na zdefiniowane wymagania, projektanci dążyli do lepszego zrozumienia problemu. A kiedy to się udało, mogli skoncentrować się na celach i bazować właśnie na nich, a nie na założonych z góry rozwiązaniach lub arbitralnych oczekiwaniach dotyczących funkcjonalności. To właśnie istota udanego projektu produktu — równie ważna podczas wytwarzania oprogramowania, jak i w czasie konstruowania samolotów. Większość użytkowników biznesowych i klientów, z którymi pracuję, ma skłonność do przedstawiania wymogów jako narzuconych rozwiązań. Rzadko zdarza się, że klienci godzą się na omówienie celów, które chcą osiągnąć, lub przeanalizowanie szczególnego charakteru problemów, które wymagają rozwiązania. Widziałem zbyt wiele zespołów cierpiących w konsekwencji przyjęcia niebezpiecznego dogmatu, że klient ma zawsze rację i że to, o co prosi, jest niezmienne, niczym wyryte w kamieniu. Takie nieporozumienie prowadzi do tego, że zespoły ślepo akceptują proponowane rozwiązania, a następnie borykają się z licznymi problemami, walcząc o implementację wymagań potraktowanych dosłownie. Zespoły osiągające sukcesy tego nie robią. Tak jak konstruktorzy F-16, odnoszące sukcesy zespoły zajmujące się wytwarzaniem oprogramowania naciskają klientów, aby uzyskać jak najwięcej informacji na temat prawdziwego problemu, a dopiero potem próbują wspólnie z klientami obmyślić jakieś potencjalne rozwiązania. Zbierają się nawet w celu wspólnego doprecyzowania zakresu prac. Zakres podpowiada rozwiązanie. Zamiast zrzucić odpowiedzialność za określenie zakresu na kogoś innego, skuteczne zespoły są aktywne i wolą współpracować z użytkownikami biznesowymi w celu zdefiniowania go wspólnie, tak aby zrealizować postawione przez użytkowników cele. To jest esencja działań zmierzających do wyznaczenia zakresu na podstawie celów. Współpraca prowadząca do zdefiniowania zakresu na podstawie celów jest bez wątpienia najbardziej kontrowersyjnym tematem poruszonym w tej książce. Wzrost popularności łańcuchów wartości w procesie wytwarzania oprogramowania, z jakim mamy do czynienia w ciągu ostatnich pięciu lat, doprowadził do wzrostu świadomości znaczenia koncepcji zakładającej współpracę z myślą o zdefiniowaniu zakresu na podstawie celów biznesowych. Z drugiej strony większość zespołów, z którymi pracuję, nadal uważa, że zakres projektu znajduje się zupełnie poza ich kontrolą, i oczekuje, że to klienci lub użytkownicy biznesowi będą odpowiedzialni za kompletną definicję. W trakcie zbierania materiałów do tej książki udało mi się zdefiniować wzorzec zespołów uzyskujących zakres projektu na 3
Patrz http://www.lockheedmartin.com/products/f16.
Rozdział 5. Definiowanie zakresu na podstawie celów
95
podstawie wspólnej analizy celów, jednak muszę przyznać, że praktyka ta jest znacznie mniej rozpowszechniona niż inne kluczowe wzorce. Początkowo myślałem o zrezygnowaniu z tego rozdziału. Ostatecznie jednak postanowiłem go uwzględnić. Uczyniłem to z trzech powodów: Definiowanie zakresu odgrywa ważną rolę w procesie wytwarzania odpowiedniego oprogramowania. Jeśli zakres jest niewłaściwy, to cała reszta jest w zasadzie tylko niczym zamalowywanie rdzy na starym gruchocie. W przyszłości będzie to jeden z najważniejszych tematów, na którym koncentrować się będzie uwaga specjalistów od inżynierii oprogramowania. Dlatego liczę na podniesienie poziomu świadomości istnienia tego tematu. Definiowanie zakresu świetnie pasuje do procesów projektowania z łańcucha wartości, które stają się coraz bardziej popularne, co wynika z tego, że odchudzone wytwarzanie oprogramowania (ang. lean software development) zyskuje sobie coraz większą rzeszę zwolenników. W dwóch następnych częściach tego rozdziału przedstawię techniki wpływania na zakres projektu, które mogą zostać zastosowane zarówno przez zespoły mające bezpośrednią kontrolę nad tym zakresem, jak i te, które tej kontroli nie mają. Zespoły, które mają kontrolę wysokiego poziomu nad zakresem prac, mogą być aktywne i natychmiast występować z własnymi propozycjami ustalenia odpowiedniego zakresu. Niestety wiele zespołów w kilku dużych organizacjach, z którymi miałem okazję pracować, nie dysponuje aż taką swobodą. To jednak nie znaczy, że nie mogą w żaden sposób wpływać na zakres.
Określanie odpowiedniego zakresu Przypadki użycia, historyjki użytkowników lub elementy z rejestru produktu pozwalają na dość szerokie zdefiniowanie zakresu projektu. Wiele zespołów uważa, że dostarczenie tych artefaktów należy do użytkowników biznesowych, właścicieli produktów lub klientów. Prośba dotycząca przedstawienia zakresu jest w rzeczywistości aktem zawierzenia tym osobom, które miałyby przedstawić nam rozwiązania wysokiego poziomu, choć nie mają żadnego doświadczenia w projektowaniu oprogramowania. Projektowanie rozwiązania jest jednym z najtrudniejszych i najważniejszych etapów pracy nad oprogramowaniem. W tym miejscu przytoczę obowiązkowy cytat z książki Freda Brooksa zatytułowanej The Mythical Man-Month4: „Bez wątpienia najtrudniejszą częścią procesu powstawania systemu software’owego jest podjęcie konkretnej decyzji o tym, co powinno powstać”. Sam Albert Einstein powiedział, że „sformułowanie problemu jest często ważniejsze niż jego rozwiązanie”. W stosowanych obecnie projektach w metodyce zwinnej i odchudzonej dla określenia zakresu projektów najczęściej korzysta się ze źródła, jakim są historyjki użytkowników. To one też sprawiły, że mamy do czynienia z fantastycznym wzrostem świadomości wartości biznesowej w projektach informatycznych. Nie musimy już prosić użytkowników biznesowych 4
Fred Brooks, The Mythical Man-Month: Essays on Software Engineering, Addison-Wesley, 1975.
96
Specyfikacja na przykładach
o wybór pomiędzy opracowaniem platformy integracyjnej a stworzeniem ekranów transakcji CRUD (ang. Create, Read, Update, Delete) — historyjki użytkowników pozwalają nam wreszcie zacząć rozmawiać o rzeczach, które użytkownicy biznesowi mogą zrozumieć i racjonalnie spriorytetyzować. Warto pamiętać, że każda historyjka powinna mieć niedwuznacznie skojarzoną z nią wartość biznesową. Użytkownicy biznesowi często wybierają te wartości arbitralnie (i zwykle jest to wierzchołek góry lodowej). Jednak gdy wiemy, co dana historyjka ma nam przynieść, możemy nie ustawać w wysiłkach zbadania jej prawdziwego znaczenia i zasugerować rozwiązanie alternatywne. Christian Hassa z TechTalk wyjaśnia: Ludzie mówią ci o własnym wyobrażeniu tego, czego potrzebują. Zadając pytanie »Dlaczego?«, można zidentyfikować nowe cele ukryte za tą fasadą. Wiele organizacji nie potrafi wystarczająco jasno określić swoich celów biznesowych. Jednak gdy wreszcie udaje się je zidentyfikować, należy zrobić krok wstecz i czerpiąc z nowej wiedzy, zdefiniować nowy zakres na podstawie nowo poznanych celów, potencjalnie odrzucając pierwotnie zakładany zakres. To jest istota praktyki, którą w Bridging the Communication Gap nazywam rzuceniem wyzwania wymaganiom. Nadal uważam, że ten proces jest niezwykle ważny, ale opisany przeze mnie sposób ma charakter reaktywny. Mimo że jest zdecydowanie lepszy niż wszystkie metody pasywne — a ta grupa najlepiej opisuje to, jak większość zespołów podchodzi obecnie do problemu zakresu — pojawiły się nowe techniki, które pozwalają zespołom na znacznie większą aktywność w zakresie identyfikacji celów biznesowych. Zamiast reagować na nieodpowiednie historyjki, możemy przede wszystkim pracować z naszymi użytkownikami biznesowymi nad wymyśleniem stuprocentowo właściwych historyjek! Kluczowym zadaniem jest w tym przypadku wyjście nie od historyjek, ale od celów biznesowych i wspólne wypracowanie zakresu.
Znajdź odpowiedzi na pytania „Dlaczego?” i „Kto?” Historyjki użytkowników mają zazwyczaj trzy części: „Jako ___ chcę ___ , aby ___”. Istnieją alternatywne formaty tego wzorca, ale wszystkie mają te trzy składniki.
Zrozumienie, dlaczego coś jest potrzebne i kto tego potrzebuje, ma kluczowe znaczenie dla oszacowania sugerowanego rozwiązania.
Te same problemy można zidentyfikować w zakresie projektu na znacznie wyższym poziomie. W rzeczywistości odpowiedzi na wspomniane pytania bazowe (na wyższym poziomie) mogą skierować projekt w zupełnie inną stronę. Peter Janssens z iLean w Belgii pracował nad projektem, w którym przyszło mu nagle zamienić się miejscami z inną osobą — teraz to on odpowiadał za zdefiniowanie wymagań w postaci rozwiązań. Powierzono mu przygotowanie aplikacji, która przechowywała dane dotyczące lokalnych znaków drogowych. Zaczęło się od zwykłej bazy danych Accessa dla całej Belgii, jednak baza szybko urosła, ponieważ wkrótce zaczęto gromadzić w niej dane
Rozdział 5. Definiowanie zakresu na podstawie celów
97
z większości krajów na świecie. Firma zatrudniała w każdym kraju jedną osobę, której zadaniem było zbieranie informacji, a wszyscy pracownicy korzystali z lokalnych baz, od czasu do czasu scalanych. Aby zwiększyć wydajność pracy i zapobiec problemom ze scalaniem tak ogromnych porcji danych, firma zdecydowała o umieszczeniu bazy danych online i opracowaniu obsługującej ją aplikacji internetowej. Zanim ostatecznie wybrano jedną ofertę, etap rozmów z dostawcami i porównywania warunków ciągnął się przez cztery miesiące. Szacowany koszt opracowania aplikacji wyniósł 100 000 euro. Jednak gdy naprawdę skrupulatnie przeanalizowano odpowiedzi na pytanie „Kto i dlaczego będzie korzystać z aplikacji?”, sprawy przybrały zupełnie nieoczekiwany obrót! Janssens wyjaśnia: Dzień przed ostateczną decyzją pewien facet od inżynierii poprosił o to, żebyśmy jeszcze raz wyjaśnili mu, na czym polega nasz problem, by mógł wszystko lepiej zrozumieć. Powiedziałem: »Potrzebujemy rozwiązania internetowego dla centralnej bazy danych«. A wtedy on stwierdził: »Nie, nie! Nie wyciągajmy pochopnych wniosków. Nie rozwijaj się w opowiadaniu o tym, jakie rozwiązanie powinniśmy według ciebie wybrać tu i teraz. Wyjaśnij mi, proszę, dlaczego i po co«. No to wyjaśniłem. Jeszcze raz. Po chwili usłyszałem: »A więc problem polega na tym, że potrzebujecie jednego źródła, na którym można by pracować, bo tracicie czas podczas scalania«. »Tak jest« — odpowiedziałem — »właśnie o to chodzi«. Zadał mi kolejne pytanie: »Kto pracuje obecnie na tej bazie?«. Odparłem, że zatrudniamy dziesięć osób, które odpowiadają za grupę krajów. Przyjrzeliśmy się zawartości baz danych i stwierdziliśmy, że tego typu dane o lokalnym ruchu drogowym nie zmieniają się zbyt często, może raz lub dwa razy w roku w zależności od kraju. I wtedy usłyszałem: »Posłuchaj, Peter… Do jutra rozwiążę twój problem«. I następnego dnia mój rozmówca dodał bazę danych do swojego serwera (zdalnego dostępu) typu Citrix. Aplikacja miała obsługiwać co najwyżej dziesięciu użytkowników, którzy dokonywali jedynie aktualizacji informacji o rzadko zmieniających się ciągach znaków drogowych. Access mógł poradzić sobie z ilością danych, a prawdziwym problemem było scalanie porcji danych. Gdy inżynier zrozumiał podstawowy problem, mógł zaproponować rozwiązanie znacznie tańsze niż pierwotnie sugerowane. Janssens wyjaśnia: Zrozumiałem, że mieliśmy właśnie do czynienia z klasyczną konfrontacją — zawsze ważne jest dotarcie do sedna problemu, który prowadzi do wniosku klienta. Dlatego odpowiedź na pytanie »Dlaczego?« jest niezwykle ważna. Ostatecznie gdy poruszyliśmy temat tego, »Kto?« będzie korzystał z bazy danych, inżynierowi zaświtało w głowie inne rozwiązanie. Przecież ta baza będzie miała średnio jednego użytkownika w miesiącu!
98
Specyfikacja na przykładach
Nawet na poziomie definiowania zakresu projektu klient może sugerować określone rozwiązanie. Nie wdając się w opis możliwych historyjek użytkownika lub przypadków użycia, już sam fakt, że ktoś zaproponował aplikację internetową podczas omawiania specyfikacji opisujących zadania, podsuwa jakieś rozwiązanie. Tymczasem zamiast spędzać pięć miesięcy na wyborze dostawcy (a jeszcze dłużej trwałoby dostarczenie gotowego produktu), można było rozwiązać problem jednym ruchem, który kosztował grosze. Opisany przypadek jest skrajny, ale pokazuje, że zrozumienie tego, „dlaczego” ktoś potrzebuje konkretnej aplikacji i jak ten „ktoś” będzie z niej korzystać, często prowadzi do lepszych rozwiązań.
Zrozum, skąd bierze się wartość Poza tym, że dzięki poznaniu źródeł wartości osiągamy korzyść, sięgając po lepsze rozwiązanie, okazuje się to również niezwykle istotne w czasie ustalania priorytetów. Zespół Roba Parka pracujący dla dużego ubezpieczyciela ze Stanów Zjednoczonych koncentruje się na priorytetyzacji tylko na wyższym poziomie funkcjonalnym, który pozwala mu unikać przechodzenia przez ten sam proces na niższym poziomie historyjek. W ten sposób członkowie zespołu oszczędzają mnóstwo czasu. Rob Park wyjaśnia: Trzymamy się wysokiego poziomu, opisując wartości biznesowe i to, co naprawdę stanowi rdzeń określonej funkcji. Rozkładamy ją na historyjki użytkownika, starając się, aby były jak najmniejsze. Przykładem takiej funkcji może być: »Dostarczenie dowodu ubezpieczenia w formacie PDF dla użytkowników z czternastu stanów«. Bardzo ważne pytanie — zwłaszcza z perspektywy biznesowej — na które próbowałem uzyskać odpowiedź, brzmiało: »Ile to jest warte? Postarajmy się określić cenę tej funkcji liczoną w dolarach«. W tym konkretnym przypadku udało nam się doczekać odpowiedzi jednego z menedżerów wyższego szczebla: »No cóż… 50% rozmów telefonicznych w naszym biurze dotyczy tego tematu, a ich połowa wiąże się z potrzebą uzyskania dowodu zawarcia ubezpieczenia, co oznacza, że 25% połączeń można by wyeliminować«. Menedżer miał wiedzę z pierwszej ręki dotyczącą tematów rozmów, co przekładało się na konkretną kwotę oszczędności dzięki automatycznemu generowaniu PDF-ów, co mogłoby zastąpić metodę kopiowania i wklejania danych, bo tak ludzie z tej firmy radzili sobie dotąd z wnioskami ubezpieczycieli. A zatem firma mogła rzeczywiście określić wartość biznesową funkcji. I to naprawdę była przydatna informacja.
Przeniesienie dyskusji na poziom celów, w odróżnieniu od pracy na poziomie historyjki, pozwala zespołom lepiej radzić sobie z określaniem zakresu i priorytetów.
Dobrym przykładem obszaru, na którym takie podejście okazuje się niezwykle pomocne, jest zadanie oszacowania wysiłku. Zespół Roba Parka stwierdził, że dyskusja na temat celów sprawiła, iż zespół nie tracił już czasu na szacowanie wysiłku dla poszczególnych historyjek:
Rozdział 5. Definiowanie zakresu na podstawie celów
99
My naprawdę nie chcemy męczyć się z szacowaniem historyjek. Jeśli zaczniesz szacowanie — na przykład posługując się wartościami z ciągu Fibonacciego — szybko zdasz sobie sprawę, że każda historyjka o wartości osiem i powyżej jest zbyt duża, aby zmieściła się w iteracji. I wtedy koncentrujesz się na historyjkach o wartości jeden, dwa, trzy i pięć. Następnie przechodzisz na kolejny poziom i stwierdzasz, że pięć to naprawdę dużo. A potem, gdy wszystkie historyjki mają wartość jeden, dwa czy trzy… w gruncie rzeczy wydają się takie same. Możemy po prostu rozbić je na historyjki o tej wielkości i zapomnieć o całym szacowaniu, a następnie mierzyć czas cyklu, kiedy historyjki są rzeczywiście realizowane. W książce zatytułowanej Software by Numbers5 Mark Denne i Jane Cleland-Huang opisują formalną metodę ustalania priorytetów, która bazuje na definicji wartości biznesowej na podstawie dopasowania zakresu do tak zwanych minimalnych zbywalnych właściwości (ang. minimum marketable features), czyli minimalnego zestawu funkcji kwalifikujących się do sprzedaży. Z mojego doświadczenia wynika, że przewidywania dotyczące tego, ile pieniędzy można zaoszczędzić po implementacji określonej funkcji, są równie trudne i tak samo podatne na błędy jak przewidywania dotyczące czasu niezbędnego do implementacji funkcji. Jednak jeśli w Twojej domenie można przypisać elementom konkretne wartości, to pomoże Ci to w uzyskaniu większego zaangażowania użytkowników biznesowych. Prośba o nadanie priorytetów funkcjom lub nawet celom biznesowym przynosi lepsze efekty niż prośba o priorytetyzację historyjek lub zadań niskiego poziomu.
Dowiedz się, jakich wyników oczekują użytkownicy biznesowi Gdy cele nie są łatwe do zdefiniowania, dobrym punktem wyjścia jest poznanie oczekiwanych przez klientów wyników działania systemu. Dowiedz się, dlaczego są potrzebne i jak można je osiągnąć dzięki oprogramowaniu. Gdy poznasz oczekiwane efekty, możesz skoncentrować się na spełnianiu wymogów, które im towarzyszą. Analiza przyczyn oczekiwanych wyników prowadzi do sformułowania celów projektu.
Zamiast podejmować próby włączenia użytkowników biznesowych w określanie sposobu implementacji funkcji w systemie, powinniśmy zacząć od zebrania przykładów oczekiwanych wyników. To pomoże zaangażować użytkowników biznesowych w dyskusję i pozwoli przedstawić jasny obraz tego, co otrzymają dzięki systemowi.
Wes Williams pracował nad pewnym projektem realizowanym przez firmę Sabre, w którym opóźnienie w budowie interfejsu użytkownika spowodowało konieczność dokonania wielu przeróbek: 5
Mark Denne, Jane Cleland-Huang, Software by Numbers: Low-Risk, High-Return Development, Prentice Hall, 2003.
100
Specyfikacja na przykładach
Testy akceptacyjne zostały napisane pod kątem domeny [warstwa aplikacji], zanim nasz klient mógł zobaczyć graficzny interfejs użytkownika. Opóźnienie z interfejsem użytkownika wzrosło do czterech miesięcy. Okazało się, że na podstawie interfejsu użytkownika klient zupełnie inaczej wyobrażał sobie całą aplikację. Gdy zaczęliśmy pisać testy UI, dotyczyły one o wiele większego obszaru niż te napisane dla domeny [warstwy]. Kod domeny trzeba było zmienić, ale klient zakładał, że ta część została wykonana. Oni mieli swoje testy, wykonywali je i na podstawie pozytywnych wyników zakładali, że etap został ukończony. Oczekiwane efekty działania systemu pomagają zdefiniować cele i dokładnie określić, co należy opracować, aby użytkownik mógł osiągnąć rezultaty, jakich się spodziewa. Adam Geras zastosował w praktyce reguły mówiące o konieczności skoncentrowania się na stworzeniu potrzebnego produktu jeszcze przed przejściem na metodykę zwinnego projektowania: W przypadku wielu naszych projektów stosowaliśmy system, który nazywaliśmy »najpierw raport«, chociaż trzeba powiedzieć, że sprawdza się on na poziomie epika, tj. rozbudowanej historyjki użytkownika, a nasze doświadczenia dotyczą głównie zastosowania metody w przestrzeni wdrożenia ERP. Nie mówię tu o zwinnych projektach. System służył nam bardzo dobrze. Liczba przeróbek wymaganych w reakcji na brak jednego, nieuwzględnionego w raporcie elementu danych mogła być naprawdę spora. My potrafiliśmy unikać tej niepotrzebnej pracy dzięki skoncentrowaniu się przede wszystkim na oczekiwanych wynikach. Wyjście od efektów pracy systemu i opracowanie na ich podstawie informacji o zakresie jest koncepcją znaną z BDD. Koncepcja ta cieszy się ostatnio coraz większym zainteresowaniem, ponieważ eliminuje pewien pospolity problem. Podczas realizacji wielu z moich pierwszych projektów skupialiśmy się na przebiegu procesu i wstępnej fazie wprowadzania danych do systemu. Elementy efektów końcowych procesów — choćby takie jak raporty — zostawialiśmy na później. Istnieje jednak obawa, że użytkownicy biznesowi niezbyt chętnie włączają się do prac zespołu, gdy nie widzą efektów na zrozumiałym dla nich etapie końcowym. W rezultacie często trzeba dokonywać przeróbek. Rozpoczęcie prac na poziomie efektów pracy systemu jest niemalże gwarancją feedbacku ze strony użytkowników biznesowych.
Niech deweloperzy zapewnią część „chcę” historyjek użytkownika Kiedy: Użytkownicy biznesowi ufają zespołowi zajmującemu się wytwarzaniem oprogramowania
Zespół uSwitch współpracuje ze swoimi użytkownikami biznesowymi przy definiowaniu historyjek użytkowników. Użytkownicy biznesowi odpowiadają za wypełnienie części historyjki, w której znajduje się miejsce do nazwania podmiotu działań oraz spodziewanych korzyści, a zespół określa część, w której sugeruje się rozwiązania. W standardowym formacie historyjki użytkownika oznacza to, że użytkownicy biznesowi wypełniają puste pola w czę-
Rozdział 5. Definiowanie zakresu na podstawie celów
101
ściach „Jako ____” i „W celu ____”, podczas gdy deweloperzy dostarczają treść części „Chcę _____” historyjki.
Świetnym sposobem, aby zdefiniować właściwy zakres dla określenia celu, jest powierzenie z pełnym przekonaniem zadania wyboru rozwiązania zespołowi deweloperskiemu.
Jeśli jesteś w tej szczęśliwej sytuacji, że sprawujesz kontrolę wysokiego poziomu nad zakresem projektu, zadbaj, aby programiści i testerzy uczestniczyli w rozmowach na temat zakresu, koncentrując się na tych sugerowanych rozwiązaniach, które pozwolą osiągnąć jasno określone cele biznesowe. W ten sposób unikniesz mnóstwa niepotrzebnej pracy w późniejszym czasie i przygotujesz warunki do lepszej współpracy nad zdefiniowaniem specyfikacji. Części historyjki użytkownika Historyjka użytkownika opisuje sposób, w jaki ktoś korzystający z systemu może uzyskać konkretną wartość. Historyjki użytkownika na ogół są wykorzystywane przez zespoły do zaplanowania i spriorytetyzowania pewnego zakresu zadań szacowanych w krótkiej perspektywie. Często składają się z trzech części: Jako interesariusz W celu uzyskania konkretnej wartości Chcę funkcji systemu. Przykład: „Jako menedżer ds. marketingu w celu uzyskania możliwości reklamowania produktów bezpośrednio naszym klientom chcę dysponować systemem, w którym będzie można zbierać i zapisywać dane adresowe w czasie rejestracji użytkownika w programie lojalnościowym”. Różni autorzy proponują różną formę lub różne terminy użyte do sformułowania trzech części historyjki użytkownika, ale wszyscy zgadzają się w kwestii liczby jej komponentów. Dla celów niniejszej książki rozbieżności w układzie lub terminologii zastosowanej do nazwania każdej z tych części nie mają znaczenia.
Współpraca w celu zdefiniowania zakresu bez kontroli wysokiego poziomu W przypadku większości zespołów, z którymi pracuję — zwłaszcza jeśli chodzi o zespoły z dużych firm — informacja o zakresie zostaje zwykle przekazana członkom zespołu przez kogoś z wyższego szczebla hierarchii służbowej. Wielu zespołom wydaje się, że nie mają możliwości dyskutowania o celach biznesowych, jeśli ich zadaniem jest zapewnienie obsługi części złożonego systemu. Nawet w takiej sytuacji zrozumienie tego, co użytkownicy biznesowi starają się osiągnąć, może pomóc w zogniskowaniu działań projektowych na rzeczach, które się naprawdę liczą.
102
Specyfikacja na przykładach
Oto kilka wskazówek mogących ułatwić współpracę, której celem ma być określenie zakresu projektu, gdy zespół nie dysponuje pełną kontrolą na wysokim poziomie.
Zapytaj o to, jak coś może być przydatne Stuart Ervine pracował nad aplikacją typu back-office dla dużego banku, pozwalającą użytkownikom biznesowym zarządzać relacjami z kontrahentami w układzie hierarchicznym drzewa — był to idealny przykład wspomnianego zarządzania „wycinkiem większego systemu”. Nawet wtedy zespołowi udało się jednak dotrzeć do ukrytych przesłanek stojących za zadaniami. Zespół otrzymał polecenie zoptymalizowania wydajności układu hierarchicznego, co brzmi jak jedno z konkretnych wymagań biznesowych z wyraźnymi korzyściami i konkretną wartością dla użytkowników. Jednak zespół nie potrafił odtworzyć błędów prowadzących do spadku wydajności, dlatego wyglądało na to, że wszelkie poważne ulepszenia będą wymagać zmian infrastrukturalnych. Zespół zwrócił się więc do użytkowników z prośbą o wyjaśnienie, jak oczekiwana poprawa wydajności miałaby przynieść im jakieś korzyści. Okazało się, że użytkownicy wykonywali ręcznie złożone obliczenia, przechodząc po kolei przez gałęzie hierarchii i sumując salda. Otwierali i zamykali wszystkie gałęzie w interfejsie użytkownika, przechodząc od kontrahenta do kontrahenta, i dodawali salda kont. Był to proces powolny i podatny na błędy obliczeń. Dlatego też zamiast zajmować się poprawą wydajności hierarchii, zespół przygotował dla użytkowników automatyczny system zliczający. Dzięki niemu dodawanie sald odbywało się prawie natychmiast i znacznie zmniejszyło się ryzyko popełnienia jakiegoś błędu w ręcznych obliczeniach. Takie rozwiązanie przyniosło lepsze efekty pracy zespołu i okazało się tańsze.
Zamiast o techniczny opis funkcji powinniśmy wnioskować o przykłady wysokiego poziomu dotyczące użyteczności określonej funkcji. Odpowiedź użytkowników naprowadzi nas na prawdziwy problem.
W mojej książce zatytułowanej Bridging the Communication Gap zalecam jak najczęstsze zadawanie pytania „Dlaczego?” i powtarzanie go dopóty, dopóki w odpowiedziach nie zaczną się pojawiać nawiązania do pieniędzy. Obecnie wydaje mi się, że pytanie o to, jak przykład funkcji stanie się użyteczny, jest znacznie lepszym sposobem, by uzyskać ten sam efekt. Pytanie „Dlaczego coś jest potrzebne?” może wydawać się rzuceniem wyzwania i zmusza do konfrontacji. Może sprawić, że Twój rozmówca zamknie się w sobie i przyjmie postawę obronną, szczególnie jeśli mówimy o przedstawicielach dużych organizacji. Pytanie o to, jak coś może okazać się przydatne, prowadzi do rozpoczęcia dyskusji bez naciskania na zajęte stanowisko.
Rozdział 5. Definiowanie zakresu na podstawie celów
103
Zapytaj o rozwiązanie alternatywne Oprócz zadawania pytania o to, jak rozwiązanie może okazać się przydatne, Christian Hassa radzi sprowokować rozmowę na temat rozwiązania alternatywnego, które może naprowadzić zespół na prawdziwe cele biznesowe. Hassa wyjaśnia: Czasami ludziom trudno przychodzi udzielenie odpowiedzi na pytanie o wartość danej funkcji (nawet gdy prosi się ich o podanie przykładu). Dlatego w kolejnym kroku zwykle proszę o posłużenie się przykładem i wyjaśnienie, co będą musieli zrobić inaczej (obejście problemu), jeśli system będzie działać tak jak do tej pory i nie będzie zapewniać funkcjonalności, o której stworzeniu rozmawiamy. Zazwyczaj takie postawienie sprawy pomaga im w przekazaniu informacji o wartości danej funkcji.
Dobrą strategią ułatwiającą odkrywanie innych opcji działania z biznesowej perspektywy jest poproszenie o przedstawienie alternatywnego rozwiązania.
Prośba o przedstawienie alternatywnego rozwiązania sprawi, że osoba, która prosi o implementację danej funkcji, dobrze zastanowi się, czy proponowane rozwiązanie naprawdę jest najlepsze. Twoje pytanie powinno także stać się dobrym punktem wyjścia do dyskusji o ewentualnych alternatywach, prowadzonej już w gronie zespołu, którego zadaniem jest dostarczenie funkcji.
Nie patrz na projekt wyłącznie z perspektywy najniższego poziomu Wiele zespołów, które stoją przed koniecznością odchudzenia dostarczanych funkcji tak, aby zadania zmieściły się w iteracji, stara się obecnie rozbić zadania z rejestru na elementy widziane z perspektywy niskiego poziomu. Chociaż ułatwia to przebieg procesu, zespół traci umiejętność patrzenia na projekt z szerszej perspektywy.
Specyfikacja przez przykłady — z perspektywy procesu — sprawdza się zarówno w ujęciu historyjek niskiego, jak i wysokiego poziomu. Gdy mamy przykład wysokiego poziomu, który mówi nam o tym, jak określona funkcja będzie przydatna, możemy zebrać dane przybierające formę specyfikacji wysokiego poziomu. Takie przykłady wysokiego poziomu pozwalają nam uzyskać obiektywną ocenę tego, czy udało się dostarczyć klientowi określoną funkcję.
Ismo Aro pracował w Nokia Siemens Networks nad projektem, podczas którego zespół zaczął mieć kłopoty wynikające z braku specyfikacji wyższego poziomu: Historyjki użytkownika muszą pasować do długości sprintu. Gdy kilka z nich zostaje zakończonych, przechodzą testy w odseparowaniu od pozostałych. Większa
104
Specyfikacja na przykładach
historyjka użytkownika właściwie nie zostaje przetestowana. Gdy historyjki zostały rozbite na drobniejsze fragmenty, na podstawie rejestru trudno było powiedzieć, czy naprawdę zostały ukończone. Podział większych historyjek na mniejsze, które mogą być dostarczane osobno, jest praktyką ze wszech miar słuszną. Niemniej konieczne jest również spojrzenie na zadania z poziomu historyjek wyższego szczebla, ponieważ tylko tak można upewnić się, że praca została wykonana poprawnie. Zamiast płaskim, liniowym rejestrem produktu musimy dysponować rejestrem w formie hierarchicznej, żeby móc spojrzeć na funkcję z kilku poziomów. Specyfikacje i testy niskiego poziomu powiedzą nam, czy udało nam się zachować odpowiednią logikę podziału zadania na mniejsze fragmenty. Testy akceptacyjne wyższego poziomu odpowiedzą na pytanie, czy poszczególne elementy — zebrane w jedną całość — składają się na funkcjonalność zgodną z oczekiwaniami.
Zadbaj, aby zespoły dostarczały kompletne funkcje Kiedy: Pracujesz nad dużymi projektami z częściami zespołów w różnych lokalizacjach
Za problemy opisane w części zatytułowanej „Dowiedz się, jakich wyników oczekują użytkownicy biznesowi” Wes Williams obwiniał podział pracy nad problemem. Zespoły dostarczyły poszczególne komponenty składowe systemu (w tym przypadku chodziło o warstwę domeny i interfejs użytkownika), co utrudniło podział pracy tak, aby mogły przedyskutować spodziewane rezultaty z klientami. Potrzebna była zatem reorganizacja pracy w zespołach, żeby można było dostarczyć kompletne funkcje. Williams wyjaśnia: Cała reorganizacja zajęła nam mniej więcej sześć miesięcy. Różnica była ogromna, zwłaszcza dlatego, że udało nam się uniknąć powielania pracy, wielu powtarzalnych zadań i znacznej liczby przeróbek. Na szczęście dysponowaliśmy bogatym zestawem testów, które okazały się niezwykle przydatne. Musieliśmy wprawdzie wrócić do niektórych zagadnień i dodać kilka funkcji, ale w tym przypadku chodziło głównie o uzupełnienie, a nie wprowadzanie zmian.
Gdy zespoły dostarczają kompletne funkcje, mogą bardziej zaangażować się w pracę z użytkownikami biznesowymi, by lepiej zidentyfikować zakres i to, co powinno zostać wytworzone. Dzieje się tak po prostu dlatego, że mają możliwość rozmowy o pełnej, kompletnej funkcjonalności. Więcej szczegółów na temat zespołów i funkcji znajdziesz w Feature Team Primer6.
6
http://www.featureteams.org.
Rozdział 5. Definiowanie zakresu na podstawie celów
105
Nawet gdy zespoły sprawują kontrolę wysokiego poziomu nad zakresem projektu, wciąż mają szansę wpływać na to, co konkretnie zostanie wytworzone. Dzieje się tak dzięki: Aktywnemu stawianiu wyzwań i dociekaniu prawdziwego znaczenia wymagań projektowych. Dążeniu do poznania rzeczywistych celów biznesowych. Pragnieniu zrozumienia, kto i dlaczego potrzebuje danej funkcji. Wynik pracy zespołu nie będzie tak dobry, jak mógłby być, gdyby właściwy zakres wynikający z celów biznesowych został zdefiniowany na samym początku projektu, jednak zastosowanie się do tych wytycznych zapobiega niepotrzebnym przeróbkom, które zostają wymuszone na zespole w późniejszym czasie, i gwarantuje, że użytkownicy biznesowi dostaną to, czego naprawdę potrzebują.
Więcej informacji Ostatnimi czasy w obszarze omawianej w tym rozdziale tematyki pojawiło się wiele innowacyjnych rozwiązań. Z myślą o działaniach spójnych z przesłaniem tej książki poruszyłem tu tylko tematy technik stosowanych przez członków zespołów, z którymi mogłem rozmawiać podczas przygotowywania materiałów do tej pozycji. Nowe techniki zasługują na wymienienie, ale moim zdaniem jest to materiał na osobną książkę. Jeśli jednak pragniesz poznać kilka nowoczesnych technik wspomagających definiowanie zakresu na podstawie celów biznesowych oraz mapowanie wzajemnych relacji, poszukaj źródeł omawiających: Wstrzykiwanie funkcjonalności (ang. feature injection) — technika iteracyjnego określania zakresu na podstawie celów biznesowych poprzez przykłady wysokiego poziomu. Mapowanie efektu (ang. effect mapping) — technika wizualizacji zakresu projektu poprzez hierarchiczną analizę celów, interesariuszy i funkcji. Mapowanie historyjki użytkownika (ang. user story mapping) — hierarchiczna technika mapowania dla historyjek użytkownika, która zapewnia „szerszą perspektywę” podczas definiowania zakresu. Niestety obecnie nie ma zbyt wielu opublikowanych materiałów traktujących o tych nowatorskich rozwiązaniach. O ile mi wiadomo, jedyną wydaną pracą na temat wstrzykiwania funkcji jest komiks7, a druga w kolejności wartościowa pozycja to zbiór skanów z notatnika Chrisa Mattsa w Picasie8. Jedyną pozycją na temat mapowania efektu jest drukowana książka w języku szwedzkim z kiepskim tłumaczeniem angielskim wydanym pod tytułem
7
Zajrzyj na stronę www.lulu.com/product/file-download/real-options-at-agile-2009/5949486, skąd można pobrać darmowy egzemplarz. 8 http://picasaweb.google.co.uk/chris.matts/FeatureInjection#.
106
Specyfikacja na przykładach
Effect Managing IT9 oraz dokument opublikowany przeze mnie w sieci10. Jeff Patton udostępnia wiele świetnych materiałów o pasywnych i reaktywnych problemach z definiowaniem zakresu na swoim blogu11. Wiem też, że pracuje nad książką traktującą o zwinnym projektowaniu produktu, w której — mam nadzieję — pojawi się obszerniejsze opracowanie wspomnianego zagadnienia.
Pamiętaj Gdy otrzymujesz wymagania zdefiniowane w formie zadań, zacznij szukać odpowiedzi. Zdobądź informacje potrzebne, by zrozumieć, w czym tkwi prawdziwy problem, a potem wszyscy razem zaprojektujcie rozwiązanie. Jeśli nie masz innego wyjścia, jak tylko zaakceptować otrzymane zadania, poproś o przykłady wysokiego poziomu, opisujące, z czego wynika przydatność funkcji. To pomoże Ci zrozumieć, kto i dlaczego ich potrzebuje, co będzie dobrym punktem wyjścia do zaprojektowania właściwych rozwiązań. Jeżeli chcesz zdefiniować właściwy zakres, myśl w kategoriach celu biznesowego kamienia milowego i interesariuszy, którzy mogą przyczynić się do jego zdefiniowania lub którzy mogą ponosić konsekwencje jego osiągnięcia. Zacznij od wyników działania systemu, aby sprawniej zaangażować użytkowników biznesowych. Dokonaj reorganizacji zespołów pracujących nad poszczególnymi komponentami tak, żeby mogły dostarczać kompletne funkcje. Zastanów się nad użytecznością nowych technik takich jak wstrzykiwanie funkcji, mapowanie historyjki użytkownika i mapowanie efektu, aby jeszcze skuteczniej definiować zakres na podstawie celów.
9
Mijo Balic, Ingrid Ottersten, Effect Managing IT, Copenhagen Business School Press, 2007. http://gojko.net/effect-map. 11 www.agileproductdesign.com. 10
6
Wspólne specyfikowanie
K
oncepcja specyfikacji przez przykłady różni się od tradycyjnych procesów tworzenia specyfikacji lub testów, zwłaszcza w kwestii dotyczącej współpracy osób zaangażowanych w wytwarzanie oprogramowania. Specyfikacja przez przykłady nie sprawdzi się, jeśli autorzy dokumentów będą pracować w odizolowaniu, nawet jeżeli uda się implementacja wszystkich innych wzorców opisanych w tej książce. W Bridging the Communication Gap skupiłem się na opisie dużych warsztatów specyfikacyjnych, w których uczestniczą wszystkie zespoły, uznając je za podstawowe narzędzie współpracy przy tworzeniu specyfikacji. Prawdopodobnie najważniejszą lekcją, jaką wyniosłem z analizy materiałów zbieranych do tej książki, jest przekonanie, że cała sprawa współpracy jest nieco bardziej złożona, niż mogłoby się wydawać na pierwszy rzut oka. Różne zespoły znajdujące się w różnych kontekstach podczas tworzenia specyfikacji wypracowują sobie unikalne sposoby współpracy. Może się okazać, że nawet zespoły z tej samej organizacji mają inne podejście. W tym rozdziale przedstawię typowe modele współpracy podczas definiowania specyfikacji. Omówię, jak wyglądają wieloosobowe warsztaty, spotkania w mniejszym gronie, a także najbardziej popularne alternatywy dla warsztatów. Mój opis pomoże Ci zrozumieć korzyści i wady różnych sposobów podejścia do współpracy nad tworzonymi specyfikacjami. Zajmę się także przedstawieniem dobrych praktyk związanych z przygotowaniem do współpracy oraz podsunę kilka pomysłów, jak wybrać odpowiedni model współpracy, pasujący do Twojego zespołu. Najpierw jednak zastanówmy się, czy współpraca przy tworzeniu specyfikacji jest w ogóle potrzebna. W celu właściwego przedstawienia przykładu współpracy przy tworzeniu specyfikacji, musimy zacząć od związanej z tym etapem praktyki: udoskonalania specyfikacji z wykorzystaniem przykładów ilustrujących. W rozdziale 7., w części „Uzupełnienie specyfikacji z wykorzystaniem przykładów ilustrujących: przykład” zapoznasz się z przykładem opisującym efekty warsztatów specyfikacji.
108
Specyfikacja na przykładach
Dlaczego podczas definiowania specyfikacji musimy ze sobą współpracować? Wspólne specyfikowanie to świetny sposób na wypracowanie wspólnych wniosków dotyczących tego, co właściwie należy wykonać, i zapewnienie, by specyfikacja objęła różne aspekty systemu. Współpraca pomaga również zespołom w tworzeniu przystępnych specyfikacji i testów, które łatwo utrzymać. Według Jodie Parker brak współpracy przy tworzeniu specyfikacji był jednym z jej największych problemów w czasie, gdy rozpoczęto wdrażanie specyfikacji przez przykłady w firmie LMAX. Oto co powiedziała moja rozmówczyni: Ludzie po prostu nie zdawali sobie sprawy z tego, jaką wartość może mieć zwykła rozmowa. Początkowo deweloperzy myśleli, że testerzy nie są zainteresowani żadnymi dyskusjami, ponieważ są to ludzie o ścisłych, technicznych umysłach. Jednak dzięki tym spotkaniom testerzy mogli dowiedzieć się, jak powinno przebiegać »przesłuchiwanie« kodu bazowego, i doradzić w sprawach potencjalnego wpływu tego działania na inne testy lub zmiany języka. Testerom wydawało się, że mają za dużo zajęć. O tym, jak cenne są te spotkania [współpraca nad stworzeniem specyfikacji], możesz przekonać się tylko wtedy, gdy zaczniesz je organizować. Nawet przy bogatej wiedzy członków zespołu dotyczącej domeny klienta, w której ma działać system projektowanego oprogramowania (a muszę powiedzieć, że nigdy nie spotkałem się z zespołem dysponującym idealnie bogatą wiedzą), nadal warto poświęcić czas na współpracę nad specyfikacją. Analitycy i testerzy może wiedzą, co chcą zanalizować i przetestować, ale już niekoniecznie muszą wiedzieć, jak zorganizować posiadane informacje tak, aby ułatwić automatyzację i prowadzenie procesu wytwarzania — to będą wiedzieć programiści. Marta Gonzalez Ferrero pracowała nad projektem, w którym to testerzy początkowo tworzyli wszystkie testy akceptacyjne, nie myśląc o nich jako o części specyfikacji. Nasza bohaterka stwierdza, że często okazywało się, że deweloperzy nie mogli w ogóle korzystać z testów: Na samym początku testerzy pracowali na tabelach FitNesse i przekazali je deweloperom. To stało się zarzewiem wielu konfliktów, ponieważ deweloperzy wracali do nich, twierdząc, że otrzymane dane nie są łatwe do zrozumienia ani łatwe do zautomatyzowania. Ostatecznie ludzie nauczyli się pracować razem. Brak współpracy przy definiowaniu specyfikacji i tworzeniu testów akceptacyjnych jest pewną drogą do testów kosztownych w utrzymaniu. Była to jedna z najważniejszych rzeczy, jakich nauczyła się podczas swojego projektu Lisa Crispin: Każda zmiana wiązała się z koniecznością zmodyfikowania ogromnej liczby testów [wykonywalnych specyfikacji]. Przy tak wielkim zbiorze testów trudno
Rozdział 6. Wspólne specyfikowanie
109
przeprowadzić refaktoryzację. Powinnam była pracować w parach z deweloperami, żeby ułatwić sobie projektowanie testów. Mogłabym łatwo formułować pytania. Widzę, gdy coś jest nie tak. Testerzy znali podstawowe koncepcje takie jak »Nie powtarzaj się«, ale nie dysponowali wystarczającą wiedzą dotyczącą narzędzi. Ponieważ Crispin nie współpracowała z deweloperami przy tworzeniu i automatyzacji wykonywalnych specyfikacji, tworzyła zbyt wiele specyfikacji, które nie były na tyle zautomatyzowane, żeby mogły ułatwić i uprościć obsługę elementów projektu w perspektywie długoterminowej. Wiele zespołów, z którymi rozmawiałem, na początku popełniało masę podobnych błędów. Gdy programiści sami tworzyli specyfikacje, nie kontaktując się w międzyczasie z innymi członkami zespołów, ich dokumenty były zbyt ściśle związane z projektem oprogramowania i trudne do zrozumienia. Jeśli dokumentację tworzyli testerzy (również pracujący w odosobnieniu), dokumenty były zorganizowane w sposób, który utrudniał utrzymanie systemów. Za to zespoły odnoszące sukcesy szybko przechodziły na inne modele wytwarzania oprogramowania, uwzględniające bardziej zaawansowane techniki współpracy.
Najpopularniejsze modele współpracy Mimo że wszystkie zespoły, z którymi rozmawiałem podczas zbierania materiałów do książki, ściśle współpracowały ze sobą podczas tworzenia specyfikacji, w szczegółach ich podejścia znacznie się różniły. Współpraca przybierała różne formy, od celowo organizowanych dużych warsztatów, w których uczestniczyły wszystkie zaangażowane w prace projektowe osoby, do spotkań warsztatowych w mniejszym gronie, a nawet nieformalnych rozmów w małych grupach. W dalszej części tego rozdziału przejdę do niektórych z najbardziej popularnych modeli współpracy uzupełnionych opisem korzyści uzyskanych dzięki ich wykorzystaniu przez zespoły.
Spróbuj zorganizować duże warsztaty dla wszystkich członków zespołu Kiedy: Zaczynasz wdrażać zasady specyfikacji przez przykłady
Warsztaty specyfikacji to intensywne, sterowane ćwiczenia, które koncentrują się na definiowaniu meritum domeny i zakresu. Ich celem jest sprawienie, by cały zespół wdrożeniowy, interesariusze biznesowi oraz eksperci ds. domen uzyskali spójną i wspólną wizję tego, co powinien robić system. Przebieg takich warsztatów opisuję szczegółowo w Bridging the Communication Gap. Warsztaty specyfikacji mają być gwarancją, że deweloperzy i testerzy będą mieli wystarczająco dużo informacji, aby zakończyć swoje prace w bieżącej iteracji.
Duże warsztaty, w których uczestniczy cały zespół, są jedną z najbardziej efektywnych metod dojścia do wspólnej wizji produktu i zdefiniowania zbioru przykładów, które ilustrują działanie jakiejś funkcji systemu.
110
Specyfikacja na przykładach
Podczas warsztatów programiści i testerzy mogą uzyskać wiele informacji na temat domeny biznesowej. Z kolei użytkownicy biznesowi zaczynają rozumieć ograniczenia techniczne systemu. Ponieważ w spotkaniu bierze udział cały zespół, czas interesariuszy biznesowych jest efektywnie wykorzystywany i znika potrzeba późniejszego transferu wiedzy. Aby ułatwić wdrożenie specyfikacji przez przykłady, zespół uSwitch pierwotnie korzystał z dużych warsztatów specyfikacji. Oto jak Jon Neale opisuje efekty: Warsztaty pomogły zwłaszcza biznesmenom, którzy zaczęli myśleć o niektórych bardziej niekonwencjonalnych ludzkich zachowaniach. Na przykład jeśli ktoś próbuje ubiegać się o pożyczkę poniżej pewnej kwoty, to mamy wówczas do czynienia z zupełnie innym scenariuszem [różniącym się od ubiegania się o pożyczkę w ogóle]. To zupełnie inna ranga reguł biznesowych, o których w innych okolicznościach do ostatniej chwili nikt by nawet nie wspomniał. Warsztaty specyfikacji sprawiły, że uwzględniliśmy te sytuacje już na samym początku projektu, dzięki czemu mogło wzrosnąć tempo pracy nad projektem. Interakcja z interesariuszami przydała się także zespołowi deweloperskiemu. Wymiana zdań natychmiast ustawiła cały proces — strony projektu od razu zaczęły więcej i częściej się ze sobą komunikować. Duże warsztaty mogą stać się prawdziwym koszmarem logistycznym. Jeśli nie uda Ci się zawczasu zarezerwować pewnych dat w kalendarzu, może się okazać, że ludzie uczestniczą w tym czasie w innych spotkaniach albo z różnych względów nie mogą się pojawić. Ustalony z wyprzedzeniem harmonogram regularnych spotkań rozwiązuje ten problem. Takie podejście sprawdza się najlepiej w przypadku menedżerów wyższych szczebli, którzy chcą przyczynić się do pracy nad produktem, ale często są zbyt zajęci. (Podpowiedź: dzwoń do sekretarek lub asystentów, którzy mogą pomóc Ci wybrać najlepszy czas na warsztaty). Jeśli masz problem z wyegzekwowaniem czasu użytkowników biznesowych lub zainteresowanych stron, spróbuj dopasować się do ich harmonogramu lub wykorzystaj ich obecność w czasie prezentacji produktów demonstracyjnych, gdy tak czy owak pojawiają się na spotkaniach projektu. Takie rozwiązanie jest również skuteczne wówczas, gdy użytkownicy biznesowi i zespół deweloperski nie znajdują się w jednej i tej samej lokalizacji. Duże warsztaty są świetnym sposobem przekazywania wiedzy i zespołowego dążenia do zrozumienia wymagań projektowych, dlatego z przekonaniem polecam ich organizację zespołom, które zaczynają wdrażanie reguł specyfikacji przez przykłady. Z drugiej strony nie można zapominać o tym, że takie warsztaty oznaczają, że uczestnicy muszą pogodzić się z poświęceniem sporej ilości swojego czasu. Gdy proces zaczyna dojrzewać, a zespół dysponuje już sporą wiedzą na temat domeny produktu, można zmienić system i zastosować jedno z łatwiejszych rozwiązań.
Rozdział 6. Wspólne specyfikowanie
111
Organizacja warsztatów specyfikacji w ramach warsztatów PBR Warsztaty PBR (ang. Product Backlog Refinement) to jeden z kluczowych elementów dobrze wdrożonych procesów Scruma. Przekonałem się jednak, że większość zespołów, które twierdzą, że wdrożyły tę metodykę, wcale nie organizuje warsztatów PBR. Spotkania poświęcone dopracowaniu scrumowego rejestru produktu zwykle wymagają uczestnictwa całego zespołu, który koncentruje się na rozbiciu większych obiektów z najwyższych warstw rejestru produktu na mniejsze, szczegółowej analizie rejestru i ponownym oszacowaniu historyjek. W książce zatytułowanej Practices for Scaling Lean and Agile† Bas Vodde i Craig Larman sugerują, że na warsztaty PBR należy przeznaczyć 5 – 10% czasu każdej iteracji. Opisanie wymagań poprzez wykorzystanie przykładów w trakcie warsztatów PBR jest łatwym sposobem rozpoczęcia wdrażania metodyki specyfikacji przez przykłady w zespołach posiadających spore doświadczenie w zastosowaniu reguł Scruma. Nie wiąże się to z koniecznością organizowania żadnych dodatkowych spotkań i układania specjalnego harmonogramu. Wszystko sprowadza się do innego podejścia do działań podejmowanych podczas trwania warsztatów. Oto jak wyglądają warsztaty specyfikacji zespołu Talia, pracującego dla Pyxis Technologies. André Brissette wyjaśnia przebieg procesu: Warsztaty są organizowane zazwyczaj wtedy, gdy Właściciel Produktu i Mistrz Młyna zgadzają się, że historyjka o najwyższym priorytecie z Rejestru Produktu nie jest wystarczająco uszczegółowiona. Jeśli na przykład jest to historyjka oszacowana na 20 punktów, w tym samym sprincie jest organizowane spotkanie. Wydaje nam się, że tego rodzaju sesja powinna odbywać się co tydzień lub co dwa tygodnie, bo dzięki niej upewniamy się, że historyjka znajdująca się na samym początku listy Rejestru produktu nie spowoduje większych problemów podczas pracy. Zapoznajemy się z historyjką. Pomiędzy Właścicielem Produktu i deweloperami dochodzi do wymiany opinii dotyczących wykonalności funkcji. Kilka przykładów trafia na tablicę. Określamy ryzyko techniczne i stopień ryzyka użyteczności, a deweloperzy muszą wykonać oszacowanie lub ocenę zakresu. Na tym etapie przechodzimy do pokera planującego. Jeśli wszyscy zgadzają się w kwestii zakresu funkcji i wysiłków, jakie trzeba będzie włożyć w jej opracowanie, na tym etapie warsztaty zostają zakończone. Jeśli jednak nie możemy dojść do porozumienia, próbujemy rozbić historyjkę na mniejsze elementy tak, aby wszystkie zadania mogły być łatwiej ocenione i oszacowane przy osiągnięciu akceptacji wszystkich uczestników. _______________ Craig Larman, Bas Vodde, Practices for Scaling Lean & Agile Development: Large, Multisite, and Offshore Product Development with Large-Scale Scrum, Pearson Education, 2010. †
Wypróbuj spotkania w mniejszym gronie („trzej amigos”) Kiedy: Domena wymaga składania częstych wyjaśnień
Powierzenie jednej osobie odpowiedzialności za pisanie testów, nawet jeśli towarzyszą temu procesowi spotkania przeglądu, nie jest dobrym podejściem, jeśli mamy do czynienia ze skomplikowaną domeną produktu, a testerzy i programiści często potrzebują dodatkowych wyjaśnień.
112
Specyfikacja na przykładach Organizuj mniejsze warsztaty, w których będzie uczestniczyć jeden deweloper, jeden tester i jeden analityk biznesowy.
O spotkaniach tego typu mówi się „trzej amigos”. Janet Gregory i Lisa Crispin sugerują podobny model współpracy w Agile Testing1; nazywają taką współpracę „potęgą trójki”. (Z kolei ja zwykle nazywałem takie warsztaty „trójkącikiem akceptacji”… do czasu, gdy ludzie nie zaczęli zwracać mi uwagi na ewentualne skojarzenia). Spotkanie trzech współpracowników często wystarcza, aby uzyskać dobry feedback ze strony ludzi patrzących na zagadnienie z trzech różnych perspektyw. Inaczej niż większe warsztaty specyfikacji, spotkanie w mniejszym gronie nie gwarantuje wypracowania wspólnego rozumienia tego zagadnienia w całym zespole, ale jego zorganizowanie jest łatwiejsze i nie wymaga planowania zawczasu. Spotkania w mniejszym gronie dają również uczestnikom większą elastyczność pracy. Organizowanie dużych warsztatów z jednym małym monitorem nie ma sensu, ale trzy osoby mogą zająć wygodne miejsca i korzystać z jednego, dużego ekranu. Aby spotkanie typu „trzej amigos” przebiegło sprawnie, wszyscy uczestnicy muszą mieć podobną wiedzę na temat domeny produktu. Jeśli tak nie jest, rozważ umożliwienie ludziom przygotowania się do spotkania, a nie organizowanie go na żądanie. Ian Cooper wyjaśnia: Problem z organizacją spotkania, w którym będą uczestniczyć tylko trzy osoby, polega na tym, że jeśli ludzie nie dysponują taką samą wiedzą na temat domeny, dyskusja będzie prowadzona przez osoby, które wiedzą najwięcej. Ten problem przypomina problem związany z parowaniem [programowaniem w parach]. Ludzie posiadający większą wiedzę o domenie potrafią zdominować dyskusję. Ludzie z mniejszą wiedzą czasami będą zadawać pytania, które mogą dotyczyć wielu ciekawych aspektów. Umożliwienie im wcześniejszego przygotowania się do spotkania pozytywnie wpływa na jakość wymiany opinii. Popularną sztuczką pozwalającą uniknąć utraty istotnych informacji podczas warsztatów specyfikacji jest stworzenie pewnego dokumentu, który bardzo przypomina format końcowej specyfikacji. W przypadku spotkania w mniejszym gronie, takiego jak opisywane tu spotkanie typu „trzej amigos”, można pracować przy jednym monitorze i klawiaturze, a także stworzyć jeden plik. Rob Park pracował w zespole pewnego dużego amerykańskiego ubezpieczyciela, który organizował takie spotkania. Park mówi: Efektem spotkania trzech amigos jest prawdziwy plik właściwości w formacie »Zakładając/Jeżeli/Wtedy«. Nie martwimy się o osprzęt ani żadne warstwy poniżej, ale w efekcie uzyskujemy kryteria akceptacji. Czasami dane nie są dość precy1
Lisa Crispin, Janet Gregory, Agile Testing: A Practical Guide for Testers and Agile Teams, Addison-Wesley Professional, 2009.
Rozdział 6. Wspólne specyfikowanie
113
zyjne — na przykład wtedy, gdy wiemy, że chcielibyśmy mieć realistyczny numer polisy, więc umieszczamy w jej miejscu notatkę lub jakieś dane zastępcze, choć jesteśmy świadomi, że po fakcie będziemy mieli trochę sprzątania. Jednak głównym wymogiem jest to, byśmy mieli te wszystkie testy w czymś, co przez wszystkich uznane jest za kompletny element, przynajmniej pod względem treści, zanim zaczniemy pracę nad kodem funkcji. Zespół Stuarta Taylora w TraderMedia organizuje nieformalne konsultacje na temat każdej historyjki i na tej podstawie powstają testy. Deweloper i tester pracują razem. Taylor wyjaśnia, jak przebiega proces: Gdy historyjka ma zostać odtworzona, deweloper wzywa QA i mówi: »Mam zamiar prześledzić tę historyjkę«, po czym przechodzą do rozmowy na temat tego, jak powinien wyglądać test. Deweloper informuje, że miał zamiar wykorzystać w tym celu TDD. Na przykład: »W polu numeru telefonicznego wykorzystam typ całkowity«. QA od razu reaguje: »A co się stanie, jeśli przed numerem umieszczę plusy albo nawiasy, albo poprzedzę numer zerami?«. QA zacznie pisać testy [akceptacyjne] w oparciu o biznesowe kryteria akceptacji, odwołując się do logiki testera i uwzględniając wartości graniczne. Testy zostaną przypilnowane przez BA i dewelopera. Podczas prezentacji to oni będą odpowiadać za wykonanie funkcji. Wspólna praca nad stworzeniem na wpół sformalizowanego testu pozwala wymienić się informacjami, które później nie zostaną zniekształcone podczas automatyzacji. Takie działanie przyczynia się również do dzielenia się wiedzą na temat tego, jak stworzyć dobrą specyfikację z przykładami. Taki układ jest możliwy tylko wówczas, gdy cały zespół siedzi przed jednym monitorem i z jedną klawiaturą. Nie próbuj opracowywać takich na wpół sformalizowanych dokumentów podczas warsztatów w obecności wszystkich członków zespołu, ponieważ nie znajdziesz sposobu, aby zaangażować wszystkich obecnych.
Zespoły, które pracują nad dojrzałymi produktami i które mają już szeroką wiedzę na temat domeny, nie muszą wcale organizować warsztatów lub choćby spotkań w mniejszym gronie w celu przedyskutowania kryteriów akceptacji historyjki. Deweloperzy i testerzy wcale nie muszą być zainteresowani umieszczaniem sporych ilości danych w specyfikacjach, a mniejszymi lukami funkcjonalnymi zajmują się na bieżąco w trakcie realizacji. Tego typu zespoły mogą spotykać się na nieformalnych spotkaniach lub przeglądach.
Programujcie w parach Kiedy: Pracujecie nad dojrzałymi produktami
Nawet wówczas, gdy deweloperzy dysponują wiedzą wystarczającą im do tego, aby poradzić sobie bez wielkich warsztatów, członkowie zespołu przyznają, że współpraca podczas tworzenia specyfikacji z przykładami bywa przydatna.
114
Specyfikacja na przykładach Analitycy mogą opisać właściwe zachowanie, ale to deweloperzy znają najlepszy sposób stworzenia testu, który później będzie można łatwo zautomatyzować i który pasuje do reszty systemu żyjącej dokumentacji.
Zespół Andrew Jackmana z BNP Paribas pracuje nad produktami, które należałoby uznać za względnie dojrzałe. Zespół eksperymentował z różnymi modelami tworzenia testów i stwierdził, że konieczne jest zaangażowanie zarówno analityka biznesowego, jak i deweloperów. Andrew wyjaśnia: Gdy deweloperzy pisali testy, łatwo było nie zrozumieć, czego dotyczy dana historyjka. Jeśli nie ma interakcji z analitykami biznesowymi, to masz do swojej dyspozycji jedynie perspektywę przedstawianą ci przez deweloperów. Przeszliśmy na model, w którym to analitycy pisali testy, i okazało się, że różnica jest ogromna! Chodzi o to, że taka historyjka analityka może wpływać na liczbę istniejących testów, ale oni tego nie mogą przewidzieć. Analitycy lubią pisać testy, które pokazują przepływ pracy dla jednej historyjki. Ogólnie prowadzi to do licznych powieleń, ponieważ sporo czynności jest po prostu takich samych. A zatem przenosimy część takiego przepływu do ich własnych testów. Niektóre zespoły — zwłaszcza te, w których analitycy biznesowi stanowią wąskie gardło procesu, lub te, gdzie ich zupełnie nie ma — łączą w pary testerów i programistów, powierzając im zadanie tworzenia testów. To daje testerom dobry przegląd tego, co będzie objęte wykonywalnymi specyfikacjami, i pomaga im zrozumieć, co trzeba sprawdzić oddzielnie. Zespół pracujący dla Songkick jest dobrym przykładem takiej grupy. Phil Cowans wyjaśnia, jak przebiega ten proces: QA nie tworzy testów [akceptacyjnych] dla deweloperów. Oni pracują razem. Osoba odpowiedzialna za kontrolę jakościową (QA) jest właścicielem specyfikacji wyrażonej poprzez plan testów i nie oddaje tej odpowiedzialności, dopóki funkcja nie zostanie dostarczona. Deweloperzy piszą pliki właściwości [specyfikacje], QA doradza im w zakresie tego, co powinno zostać w nich uwzględnione. QA wyszukuje dziury w plikach właściwości, wskazuje elementy, które nie mają pokrycia, i przygotowuje także skrypty testów na potrzeby testów nieautomatycznych. Parowanie podczas pisania specyfikacji jest tanim i skutecznym sposobem, aby otrzymać kilka różnych perspektyw dla testów i uniknąć sytuacji, w której część ludzi będzie miała klapki na oczach. W ten sposób testerzy mogą również poznać najlepsze metody tworzenia specyfikacji, które nadają się do łatwej automatyzacji, a programiści poznają ryzykowne obszary funkcjonalne, które wymagają szczególnej uwagi.
Rozdział 6. Wspólne specyfikowanie
115
Spraw, aby testerzy przed iteracją regularnie sprawdzali testy Kiedy: Analitycy tworzą testy
Niech Twoje specyfikacje sprawdza doświadczony deweloper.
Użytkownicy biznesowi z Bekk Consulting oraz z Norwegian Dairy Herd Recording System podczas tworzenia testów akceptacyjnych nie współdziałają z deweloperami, ale często angażują ich do przejrzenia testów. Według Mikaela Vika, starszego programisty w Bekk Consulting, takie podejście przynosi podobne wyniki: Przez cały czas ściśle współpracujemy [z użytkownikami biznesowymi], pracując nad testami narzędzia Cucumber. Gdy oni zabierają się za historyjki użytkowników i rozpoczynają proces tworzenia testów, zawsze do nas przychodzą i pytają, czy efekt ich pracy wygląda jak należy. Dajemy im wskazówki, jak powinny wyglądać kolejne kroki, a także przedstawiamy pewne propozycje tego, w jaki sposób język domeny Cucumbera może być rozszerzony, aby skutecznie wyrazić cel testów. Jeśli deweloperzy nie są zaangażowani w tworzenie specyfikacji, mogą poświęcić więcej czasu na implementowanie funkcji. Zauważ, że to zwiększa ryzyko tego, iż dane nie będą zawierać wszystkich informacji wymaganych do wdrożenia lub będą trudne do zautomatyzowania.
Spróbuj nieformalnych rozmów Kiedy: Interesariusze biznesowi są łatwo dostępni
Zespoły, które mają ten luksus dysponowania czasem użytkowników biznesowych i interesariuszy znajdujących się w pobliżu (chętnie i natychmiast odpowiadających na pytania), uzyskują bardzo dobre wyniki po zastosowaniu metody zachęcającej do nieformalnych rozmów i spotkań ad hoc. Nie trzeba organizować dużych, zaplanowanych warsztatów, zamiast tego każdy, kto miał swój udział w historyjce, może spotkać się z interesariuszami i użytkownikami biznesowymi na krótko przed rozpoczęciem jej implementacji.
Nieformalne rozmowy, w których uczestniczą tylko ludzie mający pracować nad zadaniem, wystarczą do ustalenia jasnej definicji tego, co zostanie wytworzone.
Wśród grupy osób znajdujących się w zbiorze „każdy, kto ma swój udział w historyjce”, znajdują się: Analitycy badający historyjkę. Programiści, którzy będą pracować nad implementacją. Testerzy, którzy będą wykonywać ręczne testy eksploracyjne.
116
Specyfikacja na przykładach
Podmioty zainteresowane i użytkownicy, którzy skorzystają z efektu końcowego tych prac i będą używać oprogramowania. Celem takich nieformalnych rozmów jest zagwarantowanie, że wszyscy zaangażowani będą tak samo rozumieć sens historyjki. W przypadku LMAX takie rozmowy toczą się w ciągu pierwszych kilku dni sprintu. Jodie Parker wyjaśnia: Rozmowy były prowadzone na żądanie. Masz swój pomysł i rysunki oraz naprawdę rozumiesz, jak będzie przebiegać implementacja. Jeśli nie napisałeś jeszcze testów akceptacyjnych, może popracować nad tym para składająca się z dewelopera i testera. Jeśli rozmowy nie odbyły się, funkcja zostanie opracowana, ale nie powstanie tak jak trzeba. Niektóre zespoły, tak jak zespół pracujący dla uSwitch.com, nie próbują na tym etapie uzyskać wszystkich kryteriów akceptacji. Definiują tylko wspólną bazę wyjściową i dają testerom i programistom wystarczająco dużo informacji, aby ci mogli rozpocząć pracę. Ponieważ mogą łatwo i szybko skontaktować się z użytkownikami biznesowymi, doprowadzenie do spotkania i krótka wymiana zdań w razie potrzeby nie jest żadnym problemem (patrz rozdział 12., gdzie znajdziesz więcej informacji na ten temat). Niektóre zespoły same podejmują decyzję, czy organizować nieformalną dyskusję, czy też zaplanować większy warsztat specyfikacji, w zależności od typu zmian wprowadzonych przez historyjkę. Z takiej metody korzysta Ismo Aro w Nokia Siemens Networks: Mamy umowę, żeby zaplanować przypadki testowe ATDD [specyfikacji]. To niekoniecznie jest formalne spotkanie. Jeśli zespół czuje, że przychodzi mu to naturalnie, nie ma przeciwwskazań, by nie organizować żadnego spotkania. Jeśli realizacja zadań przychodzi z większą trudnością i ludzie czują, że potrzebują większego udziału zainteresowanych stron, organizujemy spotkanie ATDD [warsztat specyfikacji]. Może to być spowodowane tym, że zespół ma bogatą wiedzę na temat domeny. Gdy dodajesz mały przyrost do istniejącej już funkcjonalności, łatwiej poznać przypadki testowe.
Przygotowanie współpracy Współpraca podczas tworzenia specyfikacji jest świetnym sposobem, aby zapewnić wzajemne zrozumienie i wyjaśnić sobie wszystkie zawiłości systemu, których ludzie nigdy nie zidentyfikowaliby, pracując w samotności. Jeśli temat dyskusji wymaga drobiazgowej analizy wstępnej lub członkowie zespołu nie dysponują taką samą wiedzą, zaczynanie wymiany opinii od podstaw może być nieefektywne i frustrujące. Aby rozwiązać ten problem, wiele zespołów wprowadziło fazę przygotowawczą, zilustrowaną na rysunku 6.1, która ma zagwarantować, że funkcja systemu zostanie opisana wystarczająco szczegółowo, by ułatwić owocną dyskusję.
Rozdział 6. Wspólne specyfikowanie
117
Rysunek 6.1. Zespoły dzielą się na ogół na cztery grupy, zależnie od tego, kiedy zaczęto prace z przykładami. Ci, którzy potrzebują więcej czasu na analizy i zadają pytania otwarte, zaczynają wcześniej
Przygotowanie polega na rozłożeniu pracy z zainteresowanymi stronami dla zdefiniowania pewnego wstępnego zestawu przykładów i szkicowej analizy. W zależności od dostępności członków zespołu przygotowaniem może zająć się jedna osoba — często jest to rola analityka — lub mniejsza grupa bardziej doświadczonych członków grupy.
Organizuj spotkania przygotowawcze Kiedy: W projekcie uczestniczy wielu interesariuszy
Kiedy zespoły współpracują z wieloma interesariuszami (na przykład wówczas, gdy z oprogramowania korzysta wiele działów wewnątrz firmy lub kilku klientów zewnętrznych decyduje o wymaganiach), spotkanie wprowadzające powinno odbyć się kilka dni przed rozpoczęciem iteracji. Niektóre zespoły nazywają to spotkanie spotkaniem wstępnego planowania.
Celem spotkania przygotowawczego jest zebranie pierwszych uwag dotyczących najbliższych historyjek i odfiltrowanie tych, które są istotniejsze, na potrzeby etapu planowania projektu.
Spotkanie wprowadzające nie ma dostarczyć kompletnych, szczegółowych specyfikacji, ale ma dać zespołowi dość czasu na zebranie feedbacku z zewnątrz dotyczącego kluczowych kwestii, które mogą być szybko zidentyfikowane. To nie jest spotkanie planowania iteracji lub codzienne spotkanie scrumowe. Zorganizowanie spotkania wprowadzającego kilka dni przed rozpoczęciem sprintu daje zespołowi możliwość zadawania niecodziennie dostępnym interesariuszom pytań otwartych przed rozpoczęciem konkretnej pracy nad doprecyzowaniem specyfikacji lub spotkaniem planowania. Wiele zespołów podczas wstępnego spotkania określa kryteria przyjęcia na wysokim poziomie — to znaczy w listach z wypunktowaniem zamiast w postaci szczegółowych przykładów. Dzięki temu później członkowie zespołów mogą skupić się na określeniu podstawowych przypadków, które będą testowane. W przypadku mniejszych zespołów, takich jak zespół z ePlan Services, w spotkaniu wstępnego planowania uczestniczą deweloperzy, interesariusze, menedżer projektu i właściciel produktu. W przypadku większych zespołów lub grup zespołów na spotkaniu pojawia się tylko kilka osób. W Sky Network Services, firmie dysponującej sześcioma zespołami, każdy z nich wysyła na spotkanie dwie lub trzy osoby.
118
Specyfikacja na przykładach
Zdobądź zaangażowanie interesariuszy Wspólny proces tworzenia specyfikacji sprawdza się, ponieważ pozwala korzystać z wiedzy zbiorowej użytkowników biznesowych i członków zespołu zajmującego się wytwarzaniem oprogramowania i stanowi gwarancję, że wszystkie zaangażowane osoby tak samo rozumieją treść specyfikacji. Wiele zespołów woli, aby podczas takich spotkań obecni byli analitycy biznesowi lub właściciele produktu, ale nie interesariusze reprezentujący klientów. W tych przypadkach zespoły zwykle dostarczają produkty, które spełniają oczekiwania analityków biznesowych lub właścicieli produktu. Jednak oczekiwania tych grup często różnią się od oczekiwań użytkowników końcowych. O ile mi wiadomo, analitycy biznesowi są częścią zespołu dostarczającego produkt, a nie przedstawicielami klientów.
W celu uzyskania jak najlepszych efektów w spotkaniach planowania wstępnego powinni uczestniczyć prawdziwi interesariusze, którzy mają być zaangażowani we wspólną pracę nad specyfikacjami. To właśnie oni podejmują przecież decyzje kluczowe dla projektu.
Jeżeli w projekcie uczestniczy wielu przedstawicieli zainteresowanych stron, wszystkie wymagania często przechodzą przez jedną osobę, zwykle nazywaną właścicielem produktu. Taki system dobrze sprawdza się w przypadku potrzeby zdefiniowania zakresu i priorytetów, ale nie tworzenia specyfikacji. Przekonał się o tym zespół Lisy Crispin z ePlan Services: Właściciel produktu chciał być właścicielem wszystkiego, czego się dało, ale jednocześnie nie potrafił wyjaśnić wszystkich szczegółów. Wykonuje pracę trzech lub czterech osób. Nikt nie ma takich możliwości, aby stać się przedstawicielem wszystkich stron, znającym się na wszystkim. Czasami potrzebowaliśmy konkretnej odpowiedzi, bez której nie ukończylibyśmy historyjki, a właściciel produktu nie był w stanie nam jej zapewnić. Nie potrafił na przykład odpowiadać na pytania dotyczące zagadnień księgowych. W takich sytuacjach i tak musiał rozmawiać bezpośrednio z innymi zainteresowanymi stronami, jeśli miał coś zrozumieć. Czuł, że niektóre rzeczy załatwialiśmy ponad jego głową, dlatego musieliśmy naprawdę umiejętnie balansować na granicy utrzymania odpowiedniego zaangażowania właściciela produktu i płynnej wymiany informacji z ludźmi, którzy mieli korzystać z przygotowywanej przez nas funkcjonalności. Jeśli pojawiała się różnica zdań, musieliśmy zbierać wszystkich w jednym pokoju, aby wspólnie zastanowić się nad rozwiązaniem. Jedna osoba nie może wiedzieć wszystkiego o wszystkim. Dysponowanie jedną osobą decyzyjną, która jest odpowiedzialna za ustalanie priorytetów, jest koniecznością, ale po odpowiedniej priorytetyzacji historyjek zespół musi starać się współpracować z zainteresowanymi
Rozdział 6. Wspólne specyfikowanie
119
stronami w sprawie specyfikacji dla poszczególnych historyjek. W Practices for Scaling Lean and Agile Larman i Vodde dokonują rozróżnienia między wyjaśnieniami i priorytetami. Twierdzą, że etap ustalania priorytetów powinien zakładać współpracę z jedną i tylko jedną osobą, podczas gdy uzyskiwanie wyjaśnień powinno leżeć w gestii zespołu. Ważne jest zaangażowanie interesariuszy końcowych, nawet jeśli zespołowi wydaje się, że ma wystarczającą wiedzę na temat domeny, żeby samemu stworzyć poprawne specyfikacje. Mike Vogel pracował nad projektem zarządzania danymi technicznymi, w którym deweloperzy mieli wystarczającą wiedzę na temat domeny i jej ograniczeń technicznych, żeby mówić, iż rozumieli ją lepiej niż użytkownicy końcowi. Aby skończyć projekt na czas, byli jednak często zmuszani do ograniczenia współpracy z interesariuszami lub zrezygnowania z ich udziału w pracy nad specyfikacją — co Vogel uznał za jeden z ich największych błędów: Za bardzo zaangażowaliśmy się w proces testowania i określenia kryteriów akceptacji. Udało nam się opracować system metaprogramowania, który pozwolił nam pracować szybciej, jako że znajdowaliśmy się pod sporą presją czasu. Jednak okazało się, że w systemie były pewne subtelności, których do końca nie rozumieliśmy ani my sami, ani nasz klient i których nikt nie był w stanie zidentyfikować na podstawie testów. Jeśli to możliwe, postaraj się, aby w pracy nad specyfikacją uczestniczyli prawdziwi interesariusze. Dzięki temu będziesz mieć pewność, że uzyskane wskazówki pochodzą z autorytatywnego i niezawodnego źródła, a zapotrzebowanie na analizy wykonywane z góry zmniejszy się. W większych organizacjach może to wymagać zastosowania pewnych technik perswazji i odwołania się do działań dyplomatycznych, jednak efekty końcowe uzasadniają użycie tych środków. Jeśli w Twoim zespole jest właściciel produktu, popracujcie razem nad umożliwieniem bezpośrednich kontaktów z interesariuszami bez ingerowania w zakres zarządzania projektem przez właściciela produktu.
Dobrze przygotuj się do wstępnych spotkań z interesariuszami Kiedy: Interesariusze nie są dostępni na miejscu
Zespoły pracujące nad projektem, w którym interesariusze nie są łatwo dostępni na miejscu, powinny dysponować przynajmniej jedną osobą, której zadaniem będzie wczesne przygotowywanie szczegółowych przykładów.
W ankietowanych zespołach osoba pracująca nad przygotowaniem zawczasu materiałów do przykładów była na ogół analitykiem biznesowym lub testerem. Ktoś taki pracował z interesariuszami nad analizą wymagań, uzyskaniem zgody w kwestii struktury przykładów i uchwyceniem wartości najważniejszych przypadków. Zespoły pracujące na niejasnych wymaganiach, potrzebujące wielu analiz i wyjaśnień, również oddelegowywały jedną osobę do przygotowania gruntu dla reszty.
120
Specyfikacja na przykładach
W większości zespołów pierwsze przykłady często przeglądał także jeden deweloper, którego zadaniem było zapewnienie feedbacku dotyczącego aspektów technicznych. Taki system gwarantował, że zespół już na początku pracy nad projektem wykrywał najbardziej rzucające się w oczy luki funkcjonalne i uzyskiwał odpowiedzi na kilka podstawowych pytań. Interesariusze mogli bowiem przekazać odpowiedzi dość wcześnie, dzięki czemu zespół nie stawał w miejscu podczas wspólnego przeglądu historyjek. Wielu zespołom na początku nie udało się wdrożenie tego systemu, zwłaszcza gdy w ich przypadku proces zależał od iteracji ograniczonych czasowo. Wydaje się logiczne, że wszystko, co jest związane z konkretną historyjką, powinno być wykonane w ramach jednego sprintu lub jednej iteracji. Jeżeli jednak domena jest nieco bardziej skomplikowana, wysiłki zmierzające do zamknięcia etapu budowy specyfikacji i rozwoju produktu w jednej iteracji mogą doprowadzić do sytuacji, w której programiści będą często utykać w martwym punkcie. Zespół Sierra pracujący dla BNP Paribas próbował zastosować ramy czasowe dla wszystkich elementów zamkniętych w jednej i tej samej iteracji, jednak okazało się, że w ten sposób nie można pracować wystarczająco wydajnie. Analityk biznesowy zespołu zaproponował rozwiązanie zakładające przygotowanie systemu według wstępnych ustaleń dokonywanych zawsze zawczasu — zanim reszta zespołu zabrała się do pracy. Andrew Jackman wyjaśnia: Nasz kierownik projektu, właściwie pełniący rolę właściciela produktu, przygotował wcześniej historyjki, które mamy opracować. Wspólnie z analitykiem biznesowym pracowali nad materiałami do kolejnej iteracji, umieszczając je na tablicy. Później analityk biznesowy zajął się przygotowaniem testów akceptacyjnych. Kiedyś tak nie robiliśmy, ale gdy deweloperzy próbowali pisać testy [akceptacyjne], nagle pojawiały się znaki zapytania i okazywało się, że brakuje nam analizy. Zebranie wstępnych przykładów przed iteracją pozwoliło również członkom zespołu lepiej przygotować się do wspólnych rozmów. Podobny system zastosował zespół Iana Coopera z Beazley. Analitycy biznesowi zespołu oraz interesariusze mają swoje siedziby w Stanach Zjednoczonych, ale zespół deweloperski pracuje w Wielkiej Brytanii. Ian Cooper mówi: Biorąc pod uwagę charakter produktu oraz fakt, że pracujemy z myślą o rynku amerykańskim, różnica stref czasowych stała się problemem i w efekcie nie mamy łatwego realnego dostępu do klienta. Analitycy biznesowi pełnią dla nas funkcję pośredników i często zbierają pytania, na które odpowiedzi uzyskujemy później. Deweloperzy wiedzą wszystko o domenie, więc to analitycy i programiści prowadzili show. Testerzy tak naprawdę w ogóle nie uczestniczyli w pracach. Stwierdziliśmy, że łatwiejszym rozwiązaniem jest powierzenie analitykom wstępnej analizy potrzeb, która była gotowa na pierwsze spotkanie. Testerzy najczęściej śledzą wszystkie możliwe scenariusze i proszą o szczegóły dotyczące przypadków
Rozdział 6. Wspólne specyfikowanie
121
brzegowych. Mają więcej czasu na zapoznanie się z dokumentami i ich zrozumienie, a potem zastanowienie się nad ewentualnymi problemami. Dzięki temu mogą znacznie bardziej zaangażować się w prace. Gdy interesariusze nie mogą uczestniczyć we wspólnej pracy nad specyfikacjami, wówczas znacznie wzrasta ryzyko tego, że zespół, którego zadaniem jest przygotowanie produktu, nie zrozumie swoich celów. Aby zmniejszyć to ryzyko, zespoły z użytkownikami niedostępnymi na miejscu przeprowadzały więcej analiz wstępnych niż te, które miały bezpośredni dostęp do użytkowników biznesowych. Taki system wymaga, aby analitycy skupili więcej wysiłku na wstępnych ustaleniach z użytkownikami biznesowymi i interesariuszami, a inni członkowie zespołu przejęli niektóre zadania analityków. Jeśli zdecydujesz się rozpocząć analizy przed rozpoczęciem iteracji, zadbaj, żeby odpowiedzialność za ten etap została przypisana dedykowanemu członkowi zespołu, unikając wciągnięcia w te działania całej reszty zespołu. Taki system usuwa potrzebę definiowania zakresu iteracji.
Niech członkowie zespołu przejrzą historyjki na wczesnym etapie Kiedy: Analitycy/eksperci ds. domeny są wąskim gardłem procesu
Jeśli analitycy i eksperci specjalizujący się w określonej tematyce stanowią wąskie gardło procesu, nie będą mogli przeprowadzać zbyt wielu analiz przed rozpoczęciem odpowiedniej iteracji. Taka sytuacja nie musi wcale być wielkim problemem, jeśli interesariusze są łatwo dostępni i mogą szybko odpowiedzieć na pytania lub jeśli produkt jest na tyle dojrzały, że braki funkcjonalne nie dadzą o sobie znać na późniejszym etapie wytwarzania oprogramowania. Z drugiej strony jeśli zespół stwierdzi, że nie ma wystarczających informacji, aby napisać wykonywalne specyfikacje, ktoś musi wcześniej wykonać odpowiednie analizy. Tym kimś wcale nie musi być analityk biznesowy czy ekspert. Równie dobrze zadanie to można powierzyć testerowi lub deweloperowi.
Programiści i testerzy mogą pomóc w zmniejszeniu obciążenia ekspertów domeny (gdy to właśnie oni są wąskim gardłem procesu) i wykonać wstępny przegląd projektu w celu zidentyfikowania najczęściej powtarzających się problemów. Dzięki temu poprawia się wydajność, a system wspomaga tworzenie interdyscyplinarnych zespołów.
Clare McLennan pracowała nad projektem reklamy internetowej, w którym interesariusze pochodzili z Niemiec, a zespół pracował z biura znajdującego się w Nowej Zelandii (czyli różnica czasu między nimi wynosiła prawie 12 godzin). Testerzy grali w tym przypadku role lokalnych analityków. Nie mogli podejmować decyzji za klientów, dlatego pracowali nad zadaniami, wyprzedzając pracę zespołu. McLennan mówi:
122
Specyfikacja na przykładach
Aby uniknąć problemów wynikających z różnic stref czasowych, musieliśmy mieć pewność, że dobrze rozumiemy wszystkie szczegóły związane z historyjką. Jeśli testerzy zapoznawali się z historyjką i stwierdzali, że ma ona dla nich sens, przerywali pracę programisty, aby uzyskać także od niego odpowiednią opinię. Zespół Global Talent Management z Ultimate Software musi radzić sobie z sytuacją, gdy właściciel produktu jest zajęty, a reszta zespołu pomaga przy analizach. „Komórka” składająca się z dwóch programistów i testera przygląda się każdej historyjce na wczesnym etapie i przygotowując się do spotkania z właścicielem produktu, formułuje pytania otwarte. Maykel Suarez dowodzi, że taki system pomógł bardziej efektywnie wykorzystywać czas każdej z zaangażowanych osób: Większy zespół, składający się z mniej więcej 17 osób, położył duży nacisk na proces podejmowania decyzji. W naszym rozwiązaniu utworzyliśmy specjalne komórki decyzyjne. Taka komórka (jeden tester i dwóch programistów) pozwala szybciej podejmować decyzje. Proces przepływu umożliwił pracę nad tymi spotkaniami przygotowawczymi w okresach krótszych niż dwutygodniowe iteracje — zazwyczaj składały się na nie zaledwie dwie lub trzy historyjki. Tym samym spotkanie trzech osób trwające 15 – 30 minut i odbywające się co 3 – 5 dni nie wydawało się stratą czasu i zasobów.
Przygotuj tylko wstępne przykłady Kiedy: Interesariusze są łatwo dostępni
Podczas prac nad projektami, w których interesariusze są łatwo dostępni i mogą bezpośrednio odpowiadać na pytania, zespoły nie poświęcają zbyt wiele czasu na przygotowanie z wyprzedzeniem szczegółowych przykładów. Nadal jednak uważają, że wcześniejsze opracowanie kilku wstępnych przykładów jest przydatne, ponieważ pozwala określić podstawową strukturę jeszcze przed rozpoczęciem dyskusji.
Identyfikowanie wstępnych przykładów pozwala przygotować podstawową strukturę i pomaga w kreowaniu bardziej efektywnych dyskusji.
André Brissette często korzysta z przykładów dostarczonych przez klientów zewnętrznych, rozpoczynając prace nad specyfikacjami projektu Talia w Pyxis Technologies. André jest interesariuszem biznesowym zespołu projektowego i sam współpracuje z klientami zewnętrznymi. Kiedy klienci proponują nową funkcję, przekazują mu przykłady tego, jak wyobrażają sobie działanie systemu. Te same przykłady stają się częścią przyszłych specyfikacji. Zespół uSwitch pracuje w tym samym miejscu co interesariusze, dlatego nie potrzebuje jakiegoś specjalnego wstępnego planowania. Każdy członek zespołu może zaproponować nową historyjkę podczas szybkiego spotkania. Osoba, która wychodzi z propozycją, często wcześniej przygotowuje podstawowe przykłady.
Rozdział 6. Wspólne specyfikowanie
123
Gdy wstępne przykłady są dostępne już na początku prac projektowych, wszelkie rozmowy na temat historyjek przebiegają o wiele sprawniej, ponieważ zespół nie musi eksperymentować z najlepszą strukturą lub przykładami dla zilustrowania wymogów lub identyfikacji kluczowych atrybutów. Ludzie mogą za to skupić się na zrozumieniu wstępnych przykładów i ich rozbudowywaniu.
Nie utrudniaj dyskusji przez przesadne przygotowania Wstępne przygotowanie nie powinno zastępować rzeczywistej wspólnej pracy nad definiowaniem specyfikacji. Powinieneś dążyć po prostu do zapewnienia bardziej efektywnej współpracy. Zdarzało się, że zespoły na tym wstępnym etapie przygotowywały zbyt wiele danych, ponieważ testerzy tworzyli specyfikacje wykonań z uwzględnieniem perspektywy sprawdzania kombinatorycznego funkcjonalności oraz regresji, definiując w testach wszystkie możliwe argumenty wejściowe.
Skomplikowane specyfikacje są trudne do zrozumienia, co sprawia, że większość zapoznających się z nimi ludzi nie będzie w stanie zidentyfikować w nich żadnych luk funkcjonalnych czy wskazać niespójności.
Efekt analizy wstępnej złożonych specyfikacji będzie przypominał wynik przekazania deweloperom tradycyjnych wymagań zdefiniowanych przez analityków. Zamiast ze sobą współpracować, aby zadbać o to, by wszyscy tak samo rozumieli dany temat, deweloperzy po prostu akceptują wymagania, co prowadzi do nieporozumień i zwiększa ryzyko tego, że ewentualne braki funkcjonalne zostaną zidentyfikowane dopiero na późnym etapie procesu. Zespół Jodie Parker w LMAX przesadził z przygotowaniami, czego efektem były przykłady, które wydawały się kompletne. W efekcie ludzie w ogóle zrezygnowali z wymiany opinii i dyskusji, a to z kolei spowodowało pojawienie się luk funkcjonalnych w specyfikacji. Parker zaleca przygotowanie zawczasu tylko „stosownej” liczby przykładów: Ponieważ stykaliśmy się z tym procesem po raz pierwszy, nasi deweloperzy najpierw stwierdzili, że nie mają wystarczająco dużo informacji, aby móc rozpocząć pracę. Wówczas analitycy biznesowi opisali ze szczegółami dosłownie wszystkie elementy, co skończyło się tym, że mieliśmy związane ręce. Kiedy nadszedł czas rozwoju z wykorzystaniem kart, zabrakło kreatywności, nikt nie był w stanie zaproponować prostszego rozwiązania, ponieważ wszystko było nad wyraz dokładnie opisane. Jeśli zapoznajesz się z kartą i mówisz: »OK, wszystko rozumiem«, zabierasz się po prostu do pracy, mimo że możesz mieć milion założeń. Jeśli czytasz kartę i myślisz sobie: »Nie jestem do końca pewien…«, wówczas to zmusza cię do dyskusji na temat funkcji. Na początku iteracji przygotowujesz sobie szkic, a następnie rozmawiasz z innymi o różnych szczegółach takiej, a nie innej implementacji oraz jej skutkach. Potem testerzy zaczynają zastanawiać się, jak to wpłynie na testy. Analitycy biznesowi myślą wyłącznie o tym, co ma zdarzyć się w najbliższej
124
Specyfikacja na przykładach
przyszłości, i zastanawiają się, jak dopasuje się to do reszty. Jeśli jednak przygotujesz tylko »stosowną« liczbę przykładów, deweloper, analityk biznesowy i człowiek od zapewnienia jakości produktu staną razem przy tablicy i naprawdę zaangażują się w wymianę opinii na temat tego, jak system musi działać. Niezależnie, czy decydujesz się oddelegować kogoś do pracy nad wstępnymi przykładami tydzień wcześniej, czy zorganizujesz spotkanie przygotowawcze w celu zdefiniowania pytań otwartych, pamiętaj, że celem jest przygotowanie się do dyskusji, która ma odbyć się później, a nie jej zastąpienie.
Wybór modelu współpracy Moim zdaniem nie istnieje jeden, pasujący do wszystkich okoliczności typ heurystyczny systemu, który pomógłby Ci w wybraniu najlepszego modelu dla Twojego zespołu przy jednoczesnym zachowaniu równowagi między wstępną pracą zleconą indywidualnie komuś z zespołu i bardziej praktycznymi działaniami sterowanej współpracy. Po analizie efektywności zespołów, które korzystały z podobnych rozwiązań, proponuję wybrać rozwiązanie na podstawie następujących kryteriów decyzyjnych: Jak oceniasz poziom dojrzałości produktu? Jak oceniasz zakres wiedzy członków zespołu na temat domeny produktu? Jak zaawansowanej analizy wymagają typowe zmiany? Jakie są odległości pomiędzy użytkownikami biznesowymi a zespołem programistów? Czy interesariusze są łatwo dostępni w celu przedyskutowania i zweryfikowania przykładów? Gdzie znajduje się wąskie gardło procesu? Produkty niedojrzałe wymagają wczesnego organizowania dużych warsztatów i wykonywania analiz. W tym przypadku ważny jest aktywny udział testerów i deweloperów w tworzeniu specyfikacji, ponieważ system bazowy zmienia się bardzo często, a ludzie ci mają wiedzę, której brakuje użytkownikom biznesowym. Prace nad produktami dojrzałymi nie wymuszają takiej liczby wstępnych analiz, co umożliwia zastosowanie innego modelu współpracy. Dojrzały produkt prawdopodobnie oznacza mniejszą liczbę niespodzianek. Analitycy biznesowi i właściciele produktów najprawdopodobniej dobrze wiedzą, na co pozwala zastosowanie technologii, a tym samym stanowią dobre źródło pierwszych, wstępnych przykładów przygotowywanych jeszcze przed rozpoczęciem fazy realizacji projektu. Jeśli zespół jest stosunkowo nowy lub jeśli testerzy i deweloperzy nie mają bogatej wiedzy na temat domeny biznesowej, warto zorganizować duże warsztaty. Tego rodzaju spotkania, w których uczestniczą wszystkie osoby zaangażowane w prace projektowe, są doskonałym sposobem, aby skutecznie przekazywać wiedzę na temat zakresu działalności biznesowej klienta wszystkim członkom zespołu. Gdy zespół zdobędzie więcej doświad-
Rozdział 6. Wspólne specyfikowanie
125
czeń z domeną, wystarczą spotkania w mniejszym gronie, ukierunkowane na konkretne zagadnienia. Jeśli typowe zmiany wymagają dużej liczby analiz, wówczas ktoś, kto pełni rolę analityka, powinien pracować dla zespołu, przygotowując szczegółowe przykłady z wyprzedzeniem i pozostając w stałym kontakcie z interesariuszami. W przeciwnym razie każda dyskusja podczas warsztatów zakończy się szybko zbyt wielką liczbą pytań otwartych. Jeżeli zespół ma opracować stosunkowo niewielkie objętościowo i na ogół dobrze rozumiane funkcje, wystarczy przygotowanie zawczasu kilku podstawowych przykładów, które zapewnią bardziej płynny przebieg późniejszych dyskusji. Zespoły pracujące dla użytkowników biznesowych nieznajdujących się w tej samej lokalizacji — w porównaniu z tymi, które mogą liczyć na natychmiastowe reakcje użytkowników biznesowych i odpowiedzi na zadawane im pytania otwarte — zazwyczaj wcześniej wykonują więcej pracy. Jeśli użytkownicy biznesowi w ogóle nie mogą uczestniczyć w warsztatach specyfikacji, większość pytań i luk funkcjonalnych musi być zidentyfikowana i omówiona przed rozpoczęciem właściwej iteracji. I wreszcie ostatnia uwaga. Nie ma sensu przeciążanie członków zespołu, którzy i tak są wąskim gardłem procesu. Zespoły, w których takim wąskim gardłem są testerzy, w prace wykonywane przed rozpoczęciem właściwej iteracji powinny bardziej zaangażować deweloperów i analityków biznesowych. Podobnie gdy wąskim gardłem procesu są zespoły analityków biznesowych i ekspertów z danej dziedziny, do wstępnej analizy powinni bardziej przyłożyć się testerzy.
Pamiętaj Specyfikacja przez przykłady bazuje przede wszystkim na współpracy pomiędzy użytkownikami biznesowymi i członkami zespołu wytwarzającego produkt. Każdy członek zespołu odpowiada w równym stopniu za stworzenie właściwych specyfikacji. Programiści i testerzy są odpowiedzialni za swój wkład w specyfikacje dotyczące realizacji technicznej i aspektów walidacji. Większość zespołów współpracuje ze sobą podczas tworzenia specyfikacji w dwóch etapach: Ktoś odpowiada za początkowe przygotowanie, tj. wstępne przykłady funkcji, a następnie osoby mające swój udział w tworzeniu danej funkcji omawiają szczegóły prac, dodając kolejne przykłady, których zadaniem jest doprecyzowanie lub uzupełnienie specyfikacji. Równowaga w zakresie prac przygotowawczych i rzeczywistej pracy wykonanej w trakcie współpracy zależy od kilku czynników: dojrzałości produktu, poziomu wiedzy z określonej dziedziny członków zespołu wytwarzającego oprogramowanie, charakteru typowych proponowanych zmian, istnienia wąskich gardeł procesu oraz dostępności użytkowników biznesowych.
126
Specyfikacja na przykładach
7
Wykorzystanie przykładów ilustrujących
P
odanie przykładów jest dobrym sposobem unikania niejasności i precyzyjnego komunikowania. Używamy przykładów w codziennych rozmowach i tekście pisanym, nawet zupełnie nieświadomie. Gdy przeszukałem internet pod kątem zastosowania wyrażenia for example, wyszukiwarka Google zwróciła ponad 210 milionów stron, na których znajdowała się ta fraza. W tradycyjnych specyfikacjach przykłady pojawiają się i znikają kilka razy na przestrzeni całego procesu wytwarzania oprogramowania. Analitycy biznesowi często otrzymują przykłady istniejących zamówień, faktur i raportów od użytkowników biznesowych. Tego rodzaju dokumenty zostają przetworzone na abstrakcyjne wymogi projektowe. Deweloperzy wymyślają przykłady, żeby odkryć przypadki brzegowe, a następnie doprecyzowują je na podstawie wyjaśnień użytkowników biznesowych oraz analityków, by w dalszej kolejności przekonwertować te przypadku na język kodu, bez rejestrowania przykładów. Testerzy projektują przypadki testowe, które również są przykładami — przykładami oczekiwanego działania systemu. Zachowują swoje przykłady dla siebie, nie dzieląc się tą wiedzą z programistami i analitykami. Każdy wymyśla swoje przykłady, ale nie ma gwarancji, że takie przykłady są spójne, nie mówiąc już o ich kompletności. W inżynierii oprogramowania to właśnie dlatego efekt końcowy tak często różni się od tego, co przewidywano na początku. Aby nie dopuścić do takiej sytuacji, musimy dążyć do unikania błędnej interpretacji między rolami i zachować jedno, jedyne źródło prawdy. Przykłady są dobrym narzędziem pozwalającym ustrzec się przed problemami z komunikacją. Możemy uniknąć gry w głuchy telefon, jeśli zadbamy o uchwycenie wszystkich przykładów użycia — od początku do końca — i będziemy korzystać z nich konsekwentnie na etapie analizy, rozwoju i testowania produktu. Marta Gonzalez Ferrero pracowała jako główny tester w Beazley, kiedy firma wprowadziła specyfikację przez przykłady. Według niej zespół zajmujący się wytwarzaniem oprogramowania brał na siebie więcej pracy, niż był w stanie wykonać, i często zdarzało się, że członkowie zespołu stwierdzali, iż potrzebują znacznie więcej informacji, niż posiadają na
128
Specyfikacja na przykładach
początku procesu implementacji. Sytuację dodatkowo komplikował fakt, że w firmie pracowano w sześciotygodniowych iteracjach, a zespół deweloperów i analitycy biznesowi znajdowali się na różnych kontynentach. Kryteria akceptacji, które programiści otrzymywali od analityków, były dość abstrakcyjne (np. „Upewnij się, że dla tej jednostki biznesowej wyświetlane są wszystkie poprawne produkty”). Gdyby w połowie iteracji okazało się, że jakiegoś ważnego elementu brakuje, mogłoby to poważnie zakłócić wydanie produktu. Jedna iteracja zakończyła się stwierdzeniem klienta, że zespół dostarczył coś zupełnie innego od tego, czego się spodziewał. Ostatni tydzień każdej iteracji był zarezerwowany na potrzeby modelu: właściwie czegoś, co można by nazwać demonstracją iteracji. Ferrero pojechała do Stanów Zjednoczonych, żeby uczestniczyć w jednym takim modelu, i przez dwa dni dopracowywała z analitykami wymagania z przykładów ilustrujących. W rezultacie zespół zobowiązał się do wykonania podczas następnej iteracji o 20% mniejszej liczby zadań. I wreszcie dostarczył to, co obiecywał klientowi. „Poprawiło się morale zespołu” — stwierdziła Ferrero. „Wcześniej [deweloperzy] pracowali z poczuciem, że wszystkie zadania trzeba było wykonywać na bieżąco, a i tak musieliśmy czekać na informacje zwrotne od analityków biznesowych”. Według Ferrero gdy zespół zaczął opisywać wymagania za pomocą przykładów, liczba koniecznych przeróbek znacznie spadła. Zespół Marty Gonzalez Ferrero nie był jedynym, który zauważył pozytywną zmianę. Prawie wszystkie opisane w tej książce zespoły potwierdziły, że wykorzystanie przykładów ilustrujących wymagania jest metodą o wiele bardziej skuteczną niż specyfikowanie przy użyciu abstrakcyjnych instrukcji. Ponieważ przykłady są konkretne i jednoznaczne, są też idealnym narzędziem do tworzenia precyzyjnych wymagań projektowych — to właśnie dlatego sięgamy po nie w celu wyjaśniania znaczeń podczas codziennej komunikacji. W książce zatytułowanej Exploring Requirements1 Gerald Weinberg i Donald Gause stwierdzili, że jedną z najlepszych metod sprawdzenia, czy wymagania są kompletne, jest wypróbowanie tzw. przypadków testowych czarnej skrzynki (ang. black-box test cases). Jeśli nie mamy wystarczająco dużo informacji, aby zaprojektować odpowiednie przypadki testowe, na pewno nie mamy dość informacji, by stworzyć system. Opisywanie wymagań na podstawie przykładów ilustrujących jest sposobem wyjaśnienia, czego oczekujemy od działającego systemu przy stopniu prawdopodobieństwa bliskim pewności. Przykłady wykorzystane do zilustrowania wymagań są dobrymi testami czarnej skrzynki. Z mojego doświadczenia wynika, że znacznie szybsze jest zilustrowanie wymagań za pomocą przykładów niż ich implementacja. Przekonanie, że nie mamy wystarczająco dużo informacji, uzyskamy znacznie szybciej, próbując zilustrować coś na podstawie przykładów, niż wtedy, gdy pokusimy się o taką samą konstatację po nieudanej próbie implementacji oprogramowania. Zamiast wychodzić od wadliwej historyjki i przekonać się o tym, że jest niekompletna, w połowie iteracji, możemy wykryć problemy już na etapie współpracy nad zdefiniowaniem specyfikacji, gdy mamy jeszcze czas, aby coś z tym fantem zrobić — i gdy użytkownicy biznesowi są nadal dostępni. 1
Gerald M. Weinberg, Donald C. Gause, Exploring Requirements: Quality Before Design, Dorset House, New York 1989.
Rozdział 7. Wykorzystanie przykładów ilustrujących
129
W maju 2009 roku przeprowadziłem trzygodzinne warsztaty specyfikacji z wykorzystaniem metodyki specyfikacji przez przykłady2 podczas ćwiczeń Progressive .NET. W zajęciach uczestniczyło wówczas około pięćdziesięciu osób, głównie programistów i testerów. Zajęliśmy się symulacją pewnej typowej sytuacji: klient kieruje zespół na stronę swojego konkurenta i prosi o skopiowanie niektórych funkcji. Z jakiejś popularnej strony internetowej skopiowałem zasady gry w blackjacka i poprosiłem uczestników, aby zilustrowali je za pomocą przykładów. Pomimo że owe „wymagania” zostały pobrane z prawdziwej strony i mieściły się na jednym arkuszu papieru, okazały się niejednoznaczne, niekompletne i zawierały także pewne zbędne elementy. Z mojego doświadczenia wynika, że właśnie tak wyglądają wszelkie wymagania, jeśli zostały spisane prostym tekstem w dokumencie programu Word. Uczestnicy zajęć zostali podzieleni na siedem zespołów, w których tylko jedna osoba dysponowała jakąś wiedzą na temat gry. Po warsztatach wszyscy uczestnicy zgodzili się, że omawianie realistycznych przykładów pomogło im w identyfikacji niespójności i braków funkcjonalnych. Dzięki wykonaniu ćwiczenia z feedbackiem (patrz ramka) zmierzyłem poziom wspólnego zrozumienia zagadnienia. Sześć na siedem zespołów udzieliło tych samych odpowiedzi w trudnych przypadkach granicznych, choć większość ludzi w zespole wcześniej zupełnie nie dysponowała żadną wiedzą na temat domeny (blackjacka). Ilustrowanie wymagań za pomocą przykładów jest bardzo skutecznym sposobem komunikowania wiedzy z danej dziedziny i jest gwarancją, że wszyscy uczestnicy procesu uzyskają te same dane. Miałem okazję obserwować ten proces podczas pracy nad prawdziwymi projektami, podobnie jak wiele zespołów, z którymi rozmawiałem podczas zbierania materiałów do tej książki. Ilustrowanie wymagań za pomocą przykładów to pomysł prosty, ale jego praktyczne zastosowanie wcale nie jest łatwe. Znalezienie odpowiedniego zestawu przykładów do zilustrowania wymogów może okazać się nie lada wyzwaniem. W tym rozdziale zacznę od przedstawienia tego zagadnienia w szerszej perspektywie, wykorzystując konkretny przykład procesu. Następnie udzielę kilku podpowiedzi dotyczących definiowania odpowiedniego zestawu przykładów do zilustrowania funkcji biznesowych. Wreszcie podsunę kilka pomysłów dotyczących ilustrowania przekrojowych funkcjonalności i koncepcji, które trudniej uchwycić z zastosowaniem wymiernych wartości. Ćwiczenia z feedbackiem Ćwiczenia z feedbackiem są dobrym sposobem, by sprawdzić, czy grupa ludzi tak samo rozumie informacje znajdujące się w specyfikacji. Gdy ktoś omawia jakiś przypadek szczególny po zdefiniowaniu historyjki, osoba prowadząca warsztaty powinna poprosić uczestników, aby opisali, jak według nich powinien działać system. Następnie cała grupa porównuje odpowiedzi. Jeśli wszystkie do siebie pasują, oznacza to, że wszyscy tak samo rozumieją zapisy w specyfikacji. Jeśli do siebie nie pasują, warto podzielić na grupy uczestników udzielających podobnych odpowiedzi i poprosić, aby jedna osoba z każdej z nich omówiła zebrane odpowiedzi. Dyskusja pozwoli odkryć źródło nieporozumień.
2
Patrz http://gojko.net/2009/05/12/examples-make-it-easy-to-spot-inconsistencies.
130
Specyfikacja na przykładach
Uzupełnienie specyfikacji z wykorzystaniem przykładów ilustrujących: przykład Aby stało się jasne, w jaki sposób wymagania można zilustrować przykładami, rzućmy okiem na przykład opisujący działalność fikcyjnej firmy: ACME OnlineShop. Będzie to jedyna nieistniejąca firma w tej książce — musiałem ją wymyślić, aby przykład był możliwie prosty. Wyobraźmy sobie, że ACME to mały sklep internetowy, którego zespół deweloperski rozpoczął warsztaty specyfikacji. Barbara, analityk biznesowy, spędziła w tym tygodniu kilka dni, współpracując z Owenem, właścicielem firmy, aby obmyślić wspólnie kilka wstępnych przykładów. To ona zarządza obecnie warsztatami i przedstawia zespołowi pierwszą historyjkę. BARBARA: Następnym elementem z listy jest darmowa dostawa. Przygotowaliśmy z Manningiem specjalną ofertę, dzięki której możemy zaoferować bezpłatną dostawę ich książek. Przykład wygląda w skrócie tak: Jeśli użytkownik zakupi książkę wydawnictwa Manning, powiedzmy, że będzie to Specyfikacja na przykładach, koszyk zaproponuje kupującemu bezpłatną dostawę. Jakieś pytania? Dawid, deweloper, dostrzega potencjalną lukę funkcjonalną. Pyta: Czy to bezpłatna dostawa do dowolnego miejsca na świecie? A co by było, gdyby klient mieszkał na jakiejś wyspie w Ameryce Południowej? Taka darmowa dostawa będzie kosztować nas dużo więcej, niż zarobimy na sprzedaży książki. BARBARA: Nie, oferta nie dotyczy dostaw na cały świat. Mówimy o wysyłce na adres w kraju. Tessa, testerka, prosi o inny przykład. Mówi: Pierwszą rzeczą, jaką sprawdziłabym, gdyby system trafił do mnie, byłoby uzyskanie odpowiedzi na pytanie, czy oferujemy bezpłatną dostawę wszystkich książek. Możemy dodać jeszcze jeden przypadek, aby pokazać, że oferta bezpłatnej dostawy jest dostępna tylko dla książek wydawnictwa Manning? BARBARA: Jasne. Weźmy na przykład Agile Testing wydawnictwa Addison-Wesley. Jeśli użytkownik ma w koszyku tę książkę, system nie zaproponuje dostawy bez opłat. Wydaje mi się, że jest to stosunkowo proste rozwiązanie i nie ma co nad nim rozmyślać. Czy ktoś może zasugerować jakiś inny przykład? Możemy pobawić się z danymi, które sprawiają, że sugestia systemu nie pojawi się? DAWID: Nie ma żadnych liczbowych warunków brzegowych, ale możemy zastanowić się, co powinno stać się z zamówieniem, gdy w koszyku znajdzie się lista pozycji. Gdy na przykład w koszyku będą dwa tytuły, tj. Agile Testing i Specyfikacja przez przykłady? BARBARA: Wtedy darmowa wysyłka dotyczy obu książek. Jeśli w koszyku znajduje się książka wydawnictwa Manning, klient ma możliwość darmowej dostawy. DAWID: Rozumiem. A co, jeśli kupię Specyfikację przez przykłady i lodówkę? Taka dostawa będzie nas kosztować więcej, niż zyskamy ze sprzedaży książki.
Rozdział 7. Wykorzystanie przykładów ilustrujących
131
BARBARA: To może być problem. Nie rozmawiałam o tym z Owenem. Wrócimy do tej sytuacji. Czy macie jeszcze jakieś wątpliwości? DAWID: Żadnych poza tą, o której właśnie wspomnieliśmy. BARBARA: OK. Czy mamy wystarczająco dużo informacji, aby rozpocząć pracę? Oczywiście jeśli nie uwzględnimy problemu z lodówką? DAWID I TESSA: Tak. BARBARA: Świetnie. W sprawie problemu z lodówką odezwę się do was na początku przyszłego tygodnia.
Przykłady powinny być precyzyjne Dobre przykłady pomagają unikać niejasności. W związku z tym nie może być w nich miejsca na nieporozumienia. Każdy przykład powinien jasno określać kontekst i opisywać, jak system ma działać w określonych warunkach, a najlepiej zawierać opis czegoś, co da się łatwo sprawdzić.
Nie używaj w swoich przykładach systemu zamkniętych odpowiedzi (tak/nie) Kiedy: Bazowe koncepcje nie są definiowane osobno
Podczas opisywania procesów wiele zespołów, z którymi rozmawiałem, nadmiernie upraszczało przykłady poprzez wykorzystanie zwykłych odpowiedzi o zamkniętym charakterze (tak/nie). Takie zachowanie może być mylące i dać ludziom złudne poczucie, że tak samo rozumieją pewne zagadnienia, podczas gdy prawda jest inna. Na przykład zespół TechTalk miał ten problem podczas ilustrowania wymagań dotyczących powiadomień e-mailowych internetowego systemu refundacji. Zespół opracował przykłady warunków, skutkujących w wysłaniu automatycznej korespondencji elektronicznej, ale w ogóle nie poruszono tematu treści listów. „Klient oczekiwał od nas, że e-mail będzie zawierać także informację o nieuzyskaniu refundacji oraz postanowienie, a my tego nie przewidzieliśmy” — powiedział Gaspar Nagy, deweloper, który pracował nad systemem. W swoim czasie prowadziłem warsztaty specyfikacji dla dużego banku inwestycyjnego. Zespół miał omówić proces przekierowywania płatności do różnych systemów. Ludzie zaczęli od tabeli, w której pojawiały się kolejne przykłady, z warunkami opisanymi po lewej i spisem różnych podsystemów po prawej, uzupełniając poszczególne kolumny testem „tak” lub „nie” w zależności od tego, czy docelowy system miał wykonać transakcję, czy nie. Poprosiłem ich o umieszczenie w kolumnie „tak/nie” najważniejszych atrybutów wiadomości wysyłanych do każdego z systemów. W tym momencie pojawiło się kilka interesujących przypadków, których większość deweloperów nie rozumiała. Na przykład zamiast aktualizacji transakcji jeden z systemów oczekiwał dwóch komunikatów: jednego o anulowaniu bieżącej transakcji i drugiego o wygenerowaniu nowej.
132
Specyfikacja na przykładach Zwróć uwagę na przykłady zawierające proste zamknięte odpowiedzi (tak/nie) i postaraj się zmodyfikować je na tyle, by były bardziej precyzyjne.
Możesz pozostawić odpowiedzi „tak/nie”, o ile podstawowe założenie jest omówione w innym miejscu, tj. gdy na przykład jeden zestaw przykładów mówi Ci, czy wiadomość ma zostać wysłana, czy nie, a druga grupa przykładów opisuje jej treść.
Unikaj używania abstrakcyjnych klas równoważności Kiedy: Możesz zdefiniować konkretny przykład
Użycie klas równoważności (takich jak „mniej niż 10”) lub zastosowanie zmiennych może prowadzić do stworzenia iluzji powszechnego zrozumienia. Jeśli nie wybierzesz konkretnych wartości, ludzie mogą na przykład nie mieć pewności, czy wartości ujemne zostały uwzględnione, czy może są pominięte. Gdy wśród parametrów pojawiają się klasy równoważności, oczekiwane rezultaty muszą być określone jako formuły ze zmiennymi reprezentującymi wartości wejściowe. W ten sposób tak naprawdę kopiujemy opis funkcji. Nie uwzględniamy konkretnego przykładu, który pomoże nam ją zweryfikować. Tracimy zalety opisu warunków z wykorzystaniem przykładów ilustrujących. Na potrzeby automatyzacji klasy wartości muszą być przekonwertowane na konkretne liczby, co oznacza, że każdy, kto automatyzuje walidacje, będzie musiał zmodyfikować specyfikacje, tworząc kod automatyzacji. A to jest równoznaczne ze wzrostem ryzyka nieporozumień i błędnych interpretacji. Z mojego doświadczenia wynika, że elementy, które na etapie wymagań wydają się oczywiste, często stają się źródłem późniejszych kłopotów. Niejasne koncepcje są omawiane i badane. Natomiast te, które wydają się oczywiste — chociaż różne osoby mogą je różnie rozumieć — niezauważone powodują problemy.
Zamiast korzystać z klas równoważności, zawsze wprowadzaj do przykładów konkretne wartości. Dzięki nim możliwa jest automatyzacja walidacji specyfikacji bez potrzeby wprowadzania zmian, masz też gwarancję, że różne osoby z zespołu tak samo rozumieją opisane zagadnienia.
Możesz bezpiecznie używać klas równoważności jako oczekiwanych rezultatów, gdy próbujesz opisać proces niedeterministyczny. Na przykład stwierdzenie, że wynik działania powinien mieścić się w zakresie 0,1 – 0,2 sprawia, że specyfikacja nadaje się do przetestowania. Konkretne wartości poprawiają precyzję testów, jeśli masz do czynienia z procesem deterministycznym. A zatem postaraj się odwoływać do konkretnych wartości, nawet jeśli chodzi o wartości wejściowe.
Rozdział 7. Wykorzystanie przykładów ilustrujących
133
Przykłady powinny być kompletne Powinniśmy dysponować wystarczająco dużą liczbą przykładów, aby opisać cały zakres funkcji. Oczekiwane zachowanie w podstawowych przypadkach zdarzeń i proste przykłady to dobry początek, ale rzadko stanowią one sumę tego, co powinno zostać zaimplementowane. Oto kilka pomysłów na rozszerzenie początkowego zestawu przykładów tak, aby opisywał pełny obraz funkcjonalności.
Eksperymentuj z danymi
Gdy dysponujesz zestawem przykładów, który wydaje Ci się kompletny, przyjrzyj się strukturze przykładów i spróbuj wymyślić taką poprawną kombinację danych wejściowych, jakiej wprowadzenie może doprowadzić do złamania reguły. Takie spojrzenie pomoże Ci dostrzec coś, co w innych warunkach pozostałoby niezauważone, dzięki czemu będziesz mógł poprawić specyfikację, tak by była bardziej kompletna i pewniejsza.
Jeśli przykłady obejmują wartości liczbowe, spróbuj użyć dużych i małych liczb przy zmiennych warunkach brzegowych. Zobacz, co stanie się, jeśli na wejściu pojawi się zero lub liczba ujemna. Jeśli przykłady obejmują jednostki, rozważ, czy można użyć więcej niż jednego obiektu, czy przykład bez jednostki nadal nadaje się do wykorzystania i co się stanie, jeśli ta sama jednostka pojawi się dwukrotnie. Podczas wspólnego tworzenia specyfikacji spodziewam się, że zwłaszcza testerzy pomogą w definiowaniu przykładów takich jak te wspomniane we wcześniejszym akapicie. Testerzy powinni dysponować wystarczającym doświadczeniem i znać odpowiednie techniki oraz heurystykę prowadzącą do zidentyfikowania przypadków potencjalnie problematycznych. Nawet jeśli zbierzesz wiele technicznych przypadków granicznych, które zidentyfikujesz, nie wystarczą one do zdefiniowania przykładów nadających się do zastosowania w specyfikacji. Nie ma w tym nic dziwnego. Nie poświęcaj im za dużo czasu, chyba że chcesz zdefiniować komunikaty o błędach wyświetlane w reakcji na pojawienie się nieprawidłowych argumentów (w tym przypadku są to jak najbardziej poprawne przykłady takiej funkcji). Przeanalizowanie różnych przypadków pomoże Ci w zidentyfikowaniu niespójności i przypadków granicznych, których wcześniej mogłeś w ogóle nie dostrzec. Eksperymentowanie z danymi wiąże się z ryzykiem tego, że uzyskasz zbyt wiele przykładów nieróżniących się specjalnie wartością wyjściową. To właśnie dlatego tak ważne jest rozpoczęcie kolejnego procesu, jakim jest udoskonalenie specyfikacji (opisane w następnym rozdziale).
Pytaj, czy istnieje alternatywna metoda sprawdzenia funkcjonalności Kiedy: Pracujesz ze złożoną/starą infrastrukturą
W złożonych systemach informatycznych łatwo przegapić miejsce, do którego należy wysłać informację.
134
Specyfikacja na przykładach Aby sprawdzić, czy posiadasz odpowiedni zestaw przykładów opisujących historyjkę, poproś użytkowników biznesowych o wskazanie alternatywnej metody weryfikacji poprawności implementacji.
„Jak inaczej można to sprawdzić?” — to dobre pytanie, które prowokuje do wymiany zdań. Bas Vodde sugeruje również pytanie: „Czy może zdarzyć się jeszcze coś innego?”. Kiedy zadałem to pytanie w trakcie tych samych warsztatów specyfikacji, na których omawialiśmy użycie odpowiedzi zamkniętych, odkryliśmy istnienie hurtowni danych starszego typu, gdzie — jak twierdzili niektórzy obecni — powinny trafić informacje na temat transakcji (inni utrzymywali, że hurtownia powinna zostać zignorowana). To odkrycie skłoniło nas do rozpoczęcia szerszej dyskusji i zamknięcia luki funkcjonalnej. Pascal Mestdach zebrał podobne doświadczenia podczas realizacji projektu Central Patient Administration dla IHC. Członkowie zespołu często wpadali w kłopoty, gdy okazywało się, że klienci spodziewali się, iż podczas migracji dane zapisane w nowej aplikacji zostaną przesłane również do starszych aplikacji. Tymczasem zespół nie rozumiał tych wymagań. Seria pytań dotycząca alternatywnych metod sprawdzenia funkcji ujawniła oczekiwania, zgodnie z którymi użytkownicy chcieli zobaczyć nowe informacje w istniejącym systemie. Poproszenie o przedstawienie alternatywnej metody sprawdzenia funkcjonalności jest również dobrym sposobem, by doprowadzić do omówienia najlepszego miejsca automatyzacji walidacji.
Przykłady powinny być realistyczne Niejasności i niespójności pojawiają się podczas przedstawiania funkcji za pomocą przykładów ilustrujących, ponieważ przykłady prowadzą do skoncentrowania dyskusji na rzeczywistych przypadkach zamiast na abstrakcyjnych zasadach. Aby metoda mogła się sprawdzić, użyte przykłady muszą być realistyczne. Zmyślone, uproszczone lub abstrakcyjne przykłady nie będą zawierały wystarczająco dużo szczegółów lub nie będą przedstawiały wystarczającego zakresu możliwości. Uważaj na abstrakcyjne jednostki, takie jak „klient A”. Znajdź prawdziwego użytkownika wyróżniającego się cechami charakterystycznymi, które chcesz zilustrować, albo, jeszcze lepiej, skoncentruj się na charakterystycznej cesze, a nie na kliencie.
Unikaj generowania zmyślonych danych Kiedy: Podczas prac nad projektem opartym na danych
W przypadku projektów dotyczących danych, w których wiele zależy od niewielkich wariacji i niespójności, ważne jest wykorzystanie prawdziwych danych.
Mike Vogel z Knowledgent Group pracował nad projektem typu greenfield z metadanymi pozyskiwanymi w systemie ETL trafiającymi do repozytorium wykorzystywanego podczas
Rozdział 7. Wykorzystanie przykładów ilustrujących
135
badań farmaceutycznych. Zespół zastosował metodę specyfikacji przez przykłady, ale zarówno klienci, jak i zespół sięgali po wymyślone przykłady ilustrujące funkcję, zamiast użyć rzeczywistych próbek danych. Mike mówi, że takie rozwiązanie nie pomogło zespołowi uniknąć nieścisłości: Oni [przedstawiciele klienta] wymyślali abstrakcyjne przykłady. Nie pokazywali nam prawdziwych kombinacji danych. Zakładali, że mogą zrobić pewne rzeczy, i nie uwzględniali ich w przykładach. Gdy w układzie pojawiły się dane z rzeczywistych systemów, zawsze czekało na nas mnóstwo niespodzianek. Wykorzystanie nieprawdziwych danych stanowi jeszcze większy problem w przypadku projektów, które dotyczą starszych systemów, ponieważ starsze dane często nie odpowiadają zasadom oczekiwanej spójności (i w ogóle zasadom logiki). Jonas Bandi pracował w TechTalk, odpowiadając za odtwarzanie starszych aplikacji do zarządzania danymi w szkole, gdzie znaczna złożoność wynikała z konieczności zrozumienia zależności i charakteru istniejących struktur danych. Zespół spodziewał się, że specyfikacja przez przykłady pomoże mu uchronić się przed bumerangami (patrz „Uważaj na bumerangi” w rozdziale 4.) i błędami. Tak się jednak nie stało. Ludzie pracujący nad systemem wymyślali własne przykłady w oparciu o swój poziom wiedzy w tej domenie. Tymczasem prawdziwe dane często zawierały wyjątki, które ich zaskakiwały. Bandi mówi: Nawet gdy scenariusze [wyniki testów] były poprawne i wszystko wyglądało dobrze, wciąż pojawiało się sporo błędów, które wynikały z zastosowania danych pochodzących ze starszych aplikacji. Aby zmniejszyć ryzyko takich zaskakujących niespodzianek pojawiających się w późnej fazie iteracji, spróbuj użyć prawdziwych danych z istniejącego systemu, zamiast wymyślać zupełnie nowe. Wykorzystanie prawdziwych danych może wymagać automatycznego usuwania informacji poufnych, a to ma wpływ na strategie zarządzania danymi na potrzeby procesu automatyzacji. Kilka dobrych rozwiązań tego problemu znajdziesz w części zatytułowanej „Zarządzanie danymi testowymi” w rozdziale 9.
Pozyskaj podstawowe przykłady bezpośrednio od klientów Kiedy: Pracujesz dla klientów korporacyjnych
Zespoły pracujące nad wytwarzaniem oprogramowania, które ma trafić do kilku klientów, rzadko mogą liczyć na luksus zaangażowania przedstawicieli wszystkich odbiorców podczas warsztatów specyfikacji. Menedżerowie produktu zbierają wymagania różnych klientów i podejmują decyzje dotyczące planów wydania. Tu mogą pojawić się dwuznaczności i nieporozumienia. Możemy dysponować idealnie precyzyjnymi i jasnymi przykładami, które nie oddają pełnego zakresu funkcji oczekiwanych przez klientów.
136
Specyfikacja na przykładach Zadbaj o to, aby przykłady użyte do zilustrowania specyfikacji były realistyczne. Realistyczne przykłady zawierają dane, które pochodzą od klientów.
W tym przypadku możemy zastosować ten sam trik, którym posłużyliśmy się w celu zapewnienia takiego samego rozumienia sensu historyjek przez członków zespołu pracującego z zewnętrznymi interesariuszami. André Brissette zaczyna od e-maili do klientów, uznając je za punkt wyjścia do dyskusji na temat automatycznych dialogów w systemie Talia: Otrzymywałem e-maile mniej więcej takiej treści: »Byłoby łatwiej, gdybym mógł zapytać o to Talię. Usłyszałbym, że…, a potem będę w stanie zrobić...«. W tym przypadku użytkownik sam przedstawił pierwszy fragment dialogu. Brissette archiwizuje wiadomości e-mail i wykorzystuje je w funkcji pierwszych przykładów dla zilustrowania wymaganych funkcji systemu Talia. Dzięki temu ma gwarancję, że wymagania interesariuszy są spełnione. Zapoznaj się z rysunkiem 7.1, gdzie przedstawiono przykład uzyskanej specyfikacji. Taki przykład najlepiej później nieco dopracować. Zapoznaj się z częścią „Skrypty to nie specyfikacje” w rozdziale 8. Zespół Adama Knighta w RainStor wykorzystuje to podejście do opracowania systemu archiwizacji danych dla danych strukturalnych. Ludzie z zespołu współpracują z klientami, aby zdobyć realistyczne dane i pozyskać wiedzę na temat oczekiwanych celów dla zapytań reprezentatywnych. Gdy klient nie może podać im konkretnego przypadku użycia, zespół stara się uzyskać opis przykładów, czasem organizując w tym celu warsztaty, w których uczestniczą klienci. Typowym przykładem, gdy klienci nie są w stanie przedstawić konkretnego przypadku użycia, jest zachowanie sprzedawców, którzy nie mają jeszcze chętnych na system, ale chcą wbudowania pewnej określonej funkcji, ponieważ przewidują, że dzięki niej łatwiej będzie można sprzedać produkt. Jednym z takich przykładów wniosków zewnętrznych był system działający analogicznie do systemów archiwizacji poczty e-mail. Knight wyjaśnia: Klienci analizowali system archiwizacji poczty e-mail i stwierdzili, że nasz system musi pracować w ten sam sposób. System archiwizacji poczty elektronicznej może obsługiwać tysiące e-maili, ale w naszym systemie może pojawić się kilka miliardów rekordów. Chcecie mieć taki sam poziom szczegółowości? Co z logowaniem? To jest najtrudniejszy w realizacji element wymagań. Generalnie staramy się naciskać na klientów i pozyskać konkretne przykłady. Organizujemy pokazy wersji demonstracyjnych, które prezentują szkielet zachowań, i w ten sposób radzimy sobie z problemem. Aby uniknąć niejasności i nieporozumień pomiędzy tym, jak menedżer produktu widzi potrzeby klientów, a tym, czego klienci naprawdę potrzebują, podczas komunikowania się
Rozdział 7. Wykorzystanie przykładów ilustrujących
137
Rysunek 7.1. Przykład okna dialogu z klientem użytego jako specyfikacja podczas projektowania systemu Talia
z klientami nalegaj, by przedstawili przykłady. Można wykorzystać je do rozpoczęcia dyskusji podczas warsztatów specyfikacji. Przykłady powinny zostać uwzględnione w ostatecznych wykonywalnych specyfikacjach, aby zagwarantować, że oczekiwania klientów zostaną spełnione.
Przykłady powinny być zrozumiałe Typowym błędem popełnianym przez zespoły, które dopiero zaczynają swoją przygodę ze specyfikacją przez przykłady, jest ilustrowanie wymagań przy użyciu złożonych i zbyt zawiłych przykładów, skoncentrowanych na uchwyceniu realistycznych przypadków ze wszystkimi szczegółami. W efekcie powstają ogromne objętościowo, trudne do zrozumienia tabele z dziesiątkami kolumn i wierszy. Tak rozbudowane przykłady sprawiają, że trudno jest oszacować spójność i kompletność specyfikacji. Jednym z głównych powodów, dla których osobiście w roli wymagań wolę przykłady, a nie abstrakcyjne instrukcje, jest to, że przykłady naprowadzają mnie na luki funkcjonalne i niespójności. Doprecyzowywanie ułatwia zidentyfikowanie braków. To wymaga zrozumienia całego zestawu przykładów składających się na określoną funkcję. Jeżeli przykłady trudno
138
Specyfikacja na przykładach
zrozumieć, nie będziemy w stanie ocenić ich kompletności i spójności. Oto kilka pomysłów na to, jak uniknąć tego problemu, nie rezygnując równocześnie z precyzyjności i realizmu przykładów.
Unikaj pokusy zbadania wszelkich możliwych kombinacji Gdy zespoły zaczynają opisywać wymagania na podstawie przykładów ilustrujących, testerzy często przestają rozumieć cel tego procesu i domagają się pokrycia wszystkich możliwych kombinacji argumentów. Nie ma sensu śledzenia przykładów, które ilustrują wszystkie możliwe przypadki. W ten sposób nie wpływa się na lepsze zrozumienie wymagań.
Gdy starasz się przedstawić wymagania z wykorzystaniem przykładów, szukaj takich przykładów, które wywołają owocną dyskusję i pomogą w lepszym zrozumieniu wymagań.
Zdecydowanie odradzam autorytarne odrzucanie przykładów uznanych za przykłady przypadków brzegowych. Jeśli ktoś sugeruje przypadek graniczny, a inni obecni stwierdzają, że został on już uwzględniony, powody tego stanu rzeczy mogą być dwa: albo osoba wychodząca z tą propozycją nie do końca rozumie sens gotowych już przykładów, albo rzeczywiście znalazła coś, co ma istotny wpływ na istniejący opis, a inni tego nie widzą. W obu przypadkach warto przedyskutować przykład, by mieć pewność, że wszyscy obecni w pomieszczeniu tak samo dobrze rozumieją znaczenie przykładów zaproponowanych jako przypadki brzegowe.
Szukaj ukrytych koncepcji Jeśli zastosujesz zbyt wiele przykładów ilustrujących jedną funkcję lub użyte przez Ciebie przykłady są zbyt złożone, często oznacza to, że powinny zostać zmienione i opisane na wyższym poziomie abstrakcji.
Przyjrzyj się przykładom i spróbuj zidentyfikować ukryte lub zasugerowane w nich koncepcje. Spraw, aby te koncepcje zostały zdefiniowane bezpośrednio i samodzielnie. Taka modyfikacja przykładów sprawi, że staną się one łatwiejsze do zrozumienia, co umożliwi stworzenie lepszego projektu oprogramowania.
Poszukiwanie koncepcji brakujących i ukrytych w domniemaniach twórców, a także zadbanie o ich wydobycie i wykorzystanie podczas projektowania systemu jest jednym z kluczowych elementów wytwarzania oprogramowania zależnego od domeny przeznaczenia3. Prowadziłem kiedyś warsztaty zespołu, który pracował nad stworzeniem nowej wersji podsystemu księgowego i miał stopniowo przenosić transakcje ze starego systemu do nowego produktu. Spotkanie zorganizowano głównie w celu przedyskutowania wymagań dotyczących migracji holenderskich transakcji. Pojawiające się przykłady zapisywaliśmy na tablicy, 3
Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley Professional, Boston 2003.
Rozdział 7. Wykorzystanie przykładów ilustrujących
139
która szybko zapełniła się do granic możliwości. Gdy zaczęliśmy analizować zdefiniowane przykłady, odkryliśmy, że próbujemy wyjaśnić trzy rzeczy: „Jak zdecydować, które transakcje dotyczą kontrahentów z Holandii?”, „Skąd mamy wiedzieć, które transakcje powinny zostać przeniesione?” oraz „Co się dzieje z transakcją, która została przeniesiona?”. Ponieważ ilustrowaliśmy wszystkie te rzeczy w tym samym czasie, mieliśmy do czynienia z eksplozją kombinacji różnych przypadków. Podczas analizy mającej na celu dokonanie syntezy przykładów zidentyfikowaliśmy dwie ukryte koncepcje: lokalizację transakcji i stan migracji. Następnie rozbiliśmy ten komponent na trzy części i zdefiniowaliśmy oddzielny, skoncentrowany zestaw przykładów dla zilustrowania każdej z nich. Mieliśmy zatem specyfikację mówiącą nam, czy transakcja jest holenderska (czyli jak zorientować się, gdzie dokonano transakcji). Inny skoncentrowany zestaw przykładów ilustrował wpływ lokalizacji transakcji na stan migracji. W tym zestawie użyliśmy holenderskich transakcji tylko raz, bez konieczności przechodzenia przez wszystkie przypadki, które mówią, czym wyróżnia się „holenderska transakcja”. Trzeci zestaw przykładów pozwolił nam zilustrować różnicę w przetwarzaniu przenoszonych i nieprzenoszonych transakcji. Przedstawiony podział specyfikacji pozwolił zespołowi znacznie poprawić projekt systemu, ponieważ trzy różne zestawy przykładów jasno wskazywały na koncepcję modułową. Następnym razem, gdy pojawiło się wymaganie dotyczące migracji grupy transakcji, ludzie mogli skupić się na zmianie definicji migracji danych opisujących transakcje. To, co dzieje się z transakcją po migracji, nie zmienia się. Podobnie nie zmienia się sposób lokalizacji transakcji. Rozdzielenie tych pojęć ułatwiło również konstruktywną dyskusję na temat lokalizacji transakcji, ponieważ mieliśmy do czynienia z małym, specjalnym zestawem przykładów. Odkryliśmy, że niektórzy ludzie myśleli, iż o lokalizacji decyduje zarejestrowana siedziba spółki, której akcje są przedmiotem obrotu. Inni uważali, że najważniejsza jest lokalizacja giełdy, na której handluje się akcjami. Szukanie brakujących elementów i podniesienie poziomu abstrakcji nie różni się od tego, z czym mamy do czynienia w codziennej komunikacji. Spróbuj przekazać komuś prostą instrukcję, np. „Jeśli przyjedziesz samochodem, zarezerwuj sobie wcześniej parking”, bez użycia słowa kluczowego „samochód”. Zamiast tego skup się na właściwościach samochodu. Jedna z definicji samochodu może na przykład brzmieć: „pojazd transportowy z czterema kołami, czterema drzwiami, czterema miejscami siedzącymi, napędzany silnikiem na ropę”. Jednak istnieją przecież samochody dwudrzwiowe, inne rodzaje silników, pojazdy z różną liczbą miejsc i tak dalej. Wymienienie wszystkich tych cech doprowadziłoby do sytuacji, w której wszystkie te instrukcje byłyby absurdalnie skomplikowane. Dlatego właśnie tworzy się koncepcje wyższego szczebla, które mają poprawić komunikację. To, jak wygląda konkretny samochód, nie ma znaczenia dla instrukcji dotyczącej rezerwacji parkingu. Ważne jest to, czy ktoś przyjedzie samochodem, czy nie.
140
Specyfikacja na przykładach
Ilekroć widzisz w specyfikacji zbyt wiele przykładów lub przykłady te są skomplikowane, konieczne jest podniesienie poziomu abstrakcji dla tych opisów, a następnie określenie podstawowych pojęć w osobnym zestawie. Przez zilustrowanie wymagań przy użyciu precyzyjnych, realistycznych przykładów i ukształtowanie ich w taki sposób, żeby były łatwe do zrozumienia, możemy umiejętnie uchwycić istotę wymaganej funkcjonalności. Dzięki temu jesteśmy też pewni, że badamy wymagania, podając wystarczającą liczbę szczegółów niezbędnych dla programistów i testerów, którzy muszą mieć dość danych, aby rozpocząć prace. Te przykłady mogą zastąpić abstrakcyjne wymogi w procesie dostawy oprogramowania i pełnić rolę specyfikacji, celu dla rozwoju i weryfikacji dla testów akceptacyjnych.
Ilustrowanie wymagań niefunkcjonalnych Ilustrowanie przykładami pojedynczych wymagań funkcjonalnych jest czynnością dość intuicyjną, ale wiele zespołów ma trudności z tym samym zadaniem w przypadku funkcjonalności przekrojowej lub trudnej do opisania na podstawie nieregularnych podpowiedzi interesariuszy. Na większości moich warsztatów specyfikacji przez przykłady zawsze pojawia się co najmniej jedna osoba, która twierdzi, że coś takiego jest możliwe w przypadku „funkcjonalnych” wymagań, ale nie ma mowy, że sprawdzi się także przy „niefunkcjonalnych”, ponieważ ta druga grupa wymagań nie jest definiowana tak precyzyjnie. Do tej pory nie widziałem jeszcze ani jednego wymogu niefunkcjonalnego, którego nie dałoby się zilustrować za pomocą przykładów. Nawet użyteczność, chyba najbardziej ogólnikowa i najbardziej subiektywna cecha oprogramowania, nadaje się do zilustrowania. Poproś Twojego eksperta ds. użyteczności, żeby pokazał Ci stronę internetową, która mu się podoba — będzie to dobry, realistyczny przykład. Zatwierdzanie takich przykładów może mieć formę zautomatyzowaną, ale przykład jest wystarczająco realny i wystarczająco precyzyjny, aby stanowić podstawę do wyczerpującej dyskusji. Na kolejnych stronach znajdziesz kilka pomysłów, które pomogą Ci uchwycić wymagania niefunkcjonalne i zdefiniować je przez przykłady.
Zdobądź precyzyjne wymagania wydajnościowe Kiedy: Wysoka wydajność jest funkcją kluczową
Ponieważ testy wydajności często wymagają przygotowania oddzielnego środowiska i sprzętu podobnego do tego, który będzie wykorzystywany w produkcji, wielu systemów zależnych od wydajności nie można uruchamiać na sprzęcie, z którego na co dzień korzystają deweloperzy. Nie znaczy to jednak, że zespoły powinny pominąć dyskusję na temat wymagań wydajnościowych.
Jasno zdefiniowane kryteria wydajności, zilustrowane za pomocą przykładów, pomogą Ci w osiągnięciu takiego samego spojrzenia na to zagadnienie, a także w zapewnieniu deweloperom jasnego celu dla implementacji.
Rozdział 7. Wykorzystanie przykładów ilustrujących
141
Jakie wymagania są niefunkcjonalne? Cechy takie jak wydajność, użyteczność czy czasy reakcji są często nazywane niefunkcjonalnymi, ponieważ nie są związane z izolowanymi funkcjami. Generalnie zgadzam się z taką praktyką kategoryzacji wymagań na funkcjonalne i niefunkcjonalne, ale opis tego podziału jest chyba tematem na zupełnie inną książkę. Wiele cech zazwyczaj trafiających do kategorii niefunkcjonalnych nosi znamiona funkcjonalnych. I tak na przykład wymagania eksploatacyjne w zakresie wydajności mogą dotyczyć funkcji buforowania, ograniczeń w zakresie stabilności i tak dalej. Z mojego doświadczenia wynika, że większości ludzi, gdy słyszy termin niefunkcjonalny, przychodzą do głowy wymagania funkcjonalne o charakterze przekrojowym (na przykład zagadnienie bezpieczeństwa) albo nieciągłe, ale mierzalne (na przykład wydajność). Dan North zwraca uwagę na fakt†, że wymagania wymienione w kategorii niefunkcjonalnych zwykle każą sądzić, że jest interesariusz, którego zespół jeszcze nie zidentyfikował. †
W prywatnej wymianie opinii.
W przypadku RainStor wydajność stanowi kluczową cechę narzędzi archiwizacji danych, dlatego członkowie zespołu dbają o szczegółowe definiowanie wymagań eksploatacyjnych. Wymagania są gromadzone w formie następujących nakazów: „System musi zaimportować X rekordów w czasie Y minut na procesorach typu Z”. Następnie deweloperzy uzyskują dostęp do dedykowanego sprzętu testowego lub przekazują produkt testerom, którzy odpowiadają za sprawdzenie wydajności i przekazanie informacji zwrotnej.
Pamiętaj, że wyrażenie „szybciej niż obecny system” nie jest dobrym wymogiem wydajności. Powiedz ludziom, o ile szybciej i jak chcesz to osiągnąć.
Wykorzystaj uproszczone prototypy interfejsów użytkownika Układu interfejsu użytkownika i jego użyteczności nie da się łatwo określić na podstawie przykładów pasujących do tablic prawdy bądź zautomatyzowanych testów. Jednak to nie znaczy, że nie możemy omówić go przez przykłady. Często tworzę papierowe prototypy, które są połączone z fragmentami interfejsu użytkownika i wydrukami stron internetowych. Prześledzenie jednego lub dwóch przykładów jest dobrym sposobem zapewnienia, że mamy na ekranie wszystkie informacje, których potrzebuje klient. Użytkownikom biznesowym często trudno przychodzi wychodzenie poza interfejs użytkownika, ponieważ to właśnie z nim pracują na co dzień. To dlatego bumerangi pojawiają się często dopiero wtedy, gdy klient widzi działanie programu na ekranie monitora.
Zamiast rozmawiać o ukrytym przetwarzaniu danych, konkretniejszy przekaz od użytkownika można uzyskać dzięki wykorzystaniu przykładowych interfejsów użytkownika.
142
Specyfikacja na przykładach
Kilka zespołów, z którymi rozmawiałem, korzystało z narzędzia o nazwie Balsamiq Mockups4, sieciowej/desktopowej aplikacji pozwalającej zaprojektować uproszczone interfejsy użytkownika. Moim zdaniem łatwiej jest pracować z papierowymi prototypami, ponieważ możemy użyć wydruków wybranych fragmentów i robić na nich dowolne notatki, jednak system software’owy sprawdzi się lepiej, gdy będziemy chcieli podzielić się naszą pracą. Na RainStor Adam Knight posunął się jeszcze dalej, tworząc interaktywny prototyp, na którym można było w obecności klientów sprawdzić niejasne wymogi. Oto co zauważył: Zamiast przygotowywać prototyp papierowy, my łączymy kilka przykładowych prototypowych interfejsów z linią poleceń, wykorzystując skrypty powłoki. Następnie dokonujemy sprawdzenia ich działania w obecności klientów, prosząc ich, aby przekazywali nam szczegółowe informacje na temat tego, jak użyliby nowej funkcji w naszym systemie. Ten interaktywny warsztat pozwolił zebrać funkcjonalne przykłady, które zespół programistów później wykorzystał do zobrazowania wymagań. Zespoły mogą skorzystać również z tej metody, aby określić zakres projektu. (Patrz „Nie patrz na projekt wyłącznie z perspektywy najniższego poziomu” w rozdziale 5.).
Wypróbuj model QUPER Kiedy: Wymagania zmieniają się i są skalowalne
Kiedy analiza wymagań nie prowadzi do konkretnych, precyzyjnych wyników, trudno, żeby można było na tej podstawie rozpocząć jakiś sensowny spór. Kiedy po raz ostatni uczestniczyłeś w jakiejś ważnej dyskusji na temat tego, dlaczego strony internetowe powinny ładować się w czasie krótszym niż dwie sekundy? Dlaczego dwie sekundy, a nie trzy albo jedna? Najczęściej tego typu wymagania są po prostu przyjmowane — bez dyskusji lub roztrząsania w dążeniu do zrozumienia przyczyn. Podczas konferencji Oresund Developer w 2009 roku Björn Regnell przedstawił QUPER5, interesujący model służący do obrazowania wymagań projektowych, które nie są ciągłe, ale zajmują pozycje na ruchomej skali (np. czas uruchamiania i czasy reakcji). Nie wypróbowałem tego modelu podczas realizacji rzeczywistego projektu, ale jako że propozycja prowokuje do pewnych ciekawych przemyśleń, postanowiłem wspomnieć o niej w tej książce. QUPER pozwala wizualizować wymagania o skali ruchomej wzdłuż osi kosztów, wartości i jakości. Dzięki zastosowaniu modelu mielibyśmy być w stanie oszacować punkty przełomu (ang. breakpoints) w zakresie kosztów, korzyści i barier znajdujące się na ruchomej skali, prowokując szerszą dyskusję na ich temat.
4
www.balsamiq.com/products/mockups. Patrz http://oredev.org/videos/supporting-roadmapping-of-quality-requirements oraz „IEEE Software” 2008, nr 3/4. 5
Rozdział 7. Wykorzystanie przykładów ilustrujących
143
Model QUPER zakłada, że określone wymagania pozwalają oszacować wartości korzyści na krzywej S, na której znajdują się trzy ważne punkty (tzw. punkty przełamania). Użyteczność to punkt, w którym produkt o niskiej użyteczności staje się w pełni użyteczny. Na przykład taki punkt użyteczności w przypadku czasu uruchamiania telefonu komórkowego oznacza czas jednej minuty. Różnicowanie opisuje moment, w którym funkcja staje się równoznaczna z uzyskaniem przewagi konkurencyjnej, która będzie wpływać na marketing produktu. Na przykład takim punktem różnicowania w przypadku czasu startu systemu telefonu komórkowego jest pięć sekund. Nasycenie to punkt, w którym wzrost jakości staje się nadmiarowy. Nie ma znaczenia dla użytkownika, czy telefon uruchomi się w pół sekundy, czy w jedną sekundę, przez co jedna sekunda staje się możliwym punktem nasycenia dla czasu uruchomienia telefonu komórkowego. Regnell przekonuje, że przekroczenie granicy punktu nasycenia oznacza, że inwestujemy nasze zasoby w niewłaściwym miejscu. Kolejnym założeniem tego modelu jest przypuszczenie, że wzrost jakości nie prowadzi do liniowego wzrostu kosztów. W pewnym momencie realizacji projektu koszty zaczynają szybko rosnąć. Być może trzeba będzie otworzyć produkt w innej technologii lub wzrost kosztów będzie miał znaczący wpływ na architekturę. Te punkty graniczne są nazywane barierami kosztów modelu.
Zdefiniowanie barier i punktów przełamania dla wymagań przybierających formę ruchomej skali pozwala nam na rozpoczęcie znaczącej dyskusji na temat dopasowania produktu do rynku oraz oczekiwań w tym zakresie.
Możemy wykorzystać punkty przełamania i bariery, żeby zdefiniować jakieś istotne z naszego punktu widzenia cele różnych faz projektu i sprawić, że wymagania na ruchomej skali będą mierzalne. Regnell zaproponował skupienie się raczej na ciągach wartości, a nie wartościach punktowych, ponieważ te pierwsze lepiej sprawdzają się w przypadku ciągłego charakteru wymagań jakościowych. Na przykład cel dla funkcji, która po prostu musi działać tak samo jak w konkurencyjnym oprogramowaniu, powinien najprawdopodobniej znajdować się w pobliżu punktu przełamania użyteczności, na pewno nie dalej niż punkt różnicowania. Cel dla funkcji unikalnej powinien znajdować się gdzieś między punktem różnicowania i nasycenia. Wizualizacja barier kosztów na tej samej krzywej pomoże interesariuszom zrozumieć, jak bardzo mogą przesunąć cele bez konieczności inwestowania znacznie większych kwot, niż oczekiwali.
Wykorzystaj listę kontrolną podczas dyskusji Kiedy: Pojawiają się obawy przekrojowe
Często zdarza się, że klienci czują się bezpieczniej, gdy nakładają jakiś ogólny wymóg o naturze globalnej. Uczestniczyłem w wielu projektach, w których wymagania dotyczące charakterystyki wydajności zostały narzucone globalnie. (Tak jak w przykładzie: „Wszystkie strony internetowe będą ładować się w czasie krótszym niż sekunda”). W większości przypadków wdrożenie takiego wymogu (oraz innych podobnych globalnych wymagań) jest stratą pieniędzy. Najczęściej to tylko strona główna i kilka kluczowych funkcji powinno
144
Specyfikacja na przykładach
ładować się w czasie krótszym niż sekunda. Wiele innych stron może ładować się wolniej. W języku modelu QUPER tylko czas ładowania małej liczby głównych stron musi znajdować się w pobliżu punktu różnicowania. Inne strony mogą ładować się w czasie bliższym punktu użyteczności. Problem polega na tym, że tego typu wymogi określane są na początku projektu, kiedy wciąż jeszcze nie wiemy, jak tak naprawdę będzie wyglądać produkt. Zamiast przyjmować bezrefleksyjnie takie wymogi, Christian Hassa proponuje zastosować wymogi przekrojowe w formie listy kontrolnej do dyskusji. Hassa mówi: Łatwo powiedzieć: »System powinien zareagować w ciągu 10 milisekund«, gdy takie stwierdzenie dotyczy globalnie całego systemu, chociaż taki poziom reakcji wcale nie jest niezbędny dla wszystkich funkcji. Co dokładnie system musi zrobić w czasie 10 milisekund? Czy ma wysłać e-mail, nagrać czynność, czy zareagować? Tworzymy warunki akceptacji dla każdej funkcji, myśląc o tych niefunkcjonalnych kryteriach.
Lista kontrolna na potrzeby dyskusji jest gwarancją, że podczas analizy historyjki uwzględnisz wszystkie ważne pytania dotyczące wymagań. Możesz użyć jej do podjęcia decyzji, które z tych przekrojowych zagadnień dotyczą rozpatrywanej historyjki, a potem skupić się na zobrazowaniu wspomnianych aspektów.
Stwórz przykład referencyjny Kiedy: Wymagania są niemożliwe do oszacowania
Użyteczność jest trudna do oszacowania, co wynika z faktu, iż jest to wartość subiektywna i zależy od wielu czynników. Jednak to wcale nie znaczy, że nie można jej zobrazować przykładem. W rzeczywistości może być zdefiniowana tylko w ten sposób. Użyteczność i podobne niepoliczalne funkcje, takie jak grywalność i poziom zabawy, w obszarze projektowania gier wideo są wartościami o kluczowym znaczeniu. Tego rodzaju cechy nie mogą być łatwo określone w dokumentacji, która zawiera szczegóły tradycyjnych wymagań. Supermassive Games, studio gier wideo z siedzibą w Wielkiej Brytanii, stosuje zwinną metodykę w procesie wytwarzania gier. Zespoły studia używają list kontrolnych w celu zapewnienia, że różne aspekty jakości zostaną szczegółowo opisane. Jednak same listy nie wystarczą, aby poradzić sobie z niepewnością i subiektywnością wspomnianych cech. Harvey Wheaton, dyrektor studia Supermassive Games, stwierdził podczas swojej prezentacji na konferencji SPA2010, że wspomniane cechy mają „ulotną jakość”6. Według Wheatona pracownicy studia zazwyczaj koncentrują się na dążeniu do osiągnięcia jakości jednej z funkcji na ostatecznym poziomie na pierwszym etapie projektowania. Później zespół może wykorzystać ten osiągnięty poziom jako przykład tego, co oznacza „ukończenie”:
6
http://gojko.net/2010/05/19/agile-in-a-start-up-games-development-studio.
Rozdział 7. Wykorzystanie przykładów ilustrujących
145
Pracujemy nad czymś, co nazywamy »pionowym plastrem«, na możliwie najwcześniejszym etapie procesu, zwykle na końcu fazy przedprodukcyjnej. Ten pionowy plaster to niewielki element gry (np. jeden poziom, część poziomu, intro gry) o ostatecznej (nadającej się do przekazania klientowi) jakości. Zazwyczaj plaster pionowy uzupełniany jest »plastrem poziomym«, czyli szerokim kawałkiem całej gry, zblokowanej i w niskiej jakości, aby dać innym wyobrażenie o skali i klimacie gry. Na podstawie grafiki referencyjnej lub koncepcyjnej można wyciągnąć wiele wniosków, które pozwolą zbudować sobie opinię na temat wyglądu i jakości produktu końcowego. Zatrudniamy ludzi specjalnie w tym celu, aby stworzyli wysokiej jakości grafikę, która pokazuje, jak będzie wyglądać gra. Zamiast próbować oszacować za pomocą wartości liczbowej funkcje, które mają ulotną jakość, Supermassive Games tworzy przykład, w odniesieniu do którego członkowie zespołu mogą porównywać swoje działania.
Budowanie przykładu referencyjnego jest skutecznym sposobem zilustrowania niepoliczalnych cech z wykorzystaniem przykładów.
Podsumowując: zamiast używać kategoryzacji i mówić o „wymaganiach niefunkcjonalnych” w celu unikania trudnych rozmów, zespoły powinny zadbać o to, aby osiągnąć poziom identycznego rozumienia oczekiwań użytkowników biznesowych względem systemu, w tym także zagadnień przekrojowych. Nawet jeśli przykłady będące efektem takiego działania nie będą później łatwo poddawać się automatyzacji, pierwsze rozmowy i wykorzystanie przykładów do przedstawienia niedwuznacznych oczekiwań będzie stanowić gwarancję, że zespół zajmujący się wytwarzaniem oprogramowania skoncentruje się na opracowywaniu odpowiedniego produktu.
Pamiętaj Dzięki konsekwentnemu posługiwaniu się jednym zestawem przykładów — rozpoczynając od etapu definiowania specyfikacji, przez proces wytwarzania oprogramowania, aż po jego testowanie — zagwarantujesz, że wszyscy tak samo będą rozumieć produkt, który ma zostać dostarczony. Przykłady wykorzystywane do zilustrowania funkcji powinny być precyzyjne, kompletne, realistyczne i zrozumiałe. Realistyczne przykłady pomagają wychwytywać niespójności oraz luki funkcjonalne szybciej niż w fazie implementacji. Gdy masz już zestaw wstępnych przykładów, poeksperymentuj z danymi i poszukaj alternatywnych sposobów testowania funkcji, aby zakończyć tworzenie specyfikacji.
146
Specyfikacja na przykładach
Gdy przykłady są złożone, gdy nie dysponujesz za dużą liczbą przykładów lub musisz liczyć się ze zbyt wielką liczbą czynników, poszukaj ukrytych koncepcji i spróbuj wyjaśnić przykłady na wyższym poziomie abstrakcji. Użyj zestawu ukierunkowanych przykładów ilustrujących nowe koncepcje niezależnie od reszty.
8
Udoskonalanie specyfikacji W swojej naturalnej formie diament jest matowym, przezroczystym kryształem, który przypomina fragment rozbitego szkła. Aby przemienił się w klejnot, trzeba go wyciąć tak, żeby przybrał kształty upodabniające go do klejnotu, a następnie wyszlifować, faseta po fasecie.
— Edward Jay Epstein, The Diamond Invention1
W
ymiana zdań będąca efektem współpracy jest świetnym sposobem budowania konsensusu w zakresie wypracowania wspólnego zrozumienia, ale nie wystarczy, aby na tej podstawie prowadzić choćby odrobinę bardziej skomplikowane projekty. Trzeba zadbać o archiwizowanie wiedzy w sposób, który pozwoli uniezależnić się od pamięci krótkotrwałej członków zespołu, chyba że zespół jest bardzo mały, a projekt bardzo krótki. Wykonanie zdjęcia tablicy, na której znajdują się notatki z dyskusji dotyczącej kluczowych przykładów, jest prostym sposobem gromadzenia wiedzy, ale warto pamiętać, że przykłady są tylko surowym materiałem. Są jak nieoszlifowane diamenty — bardzo cenne, ale nawet w przybliżeniu nie tak bardzo jak diamenty oszlifowane. Oddzielenie prawdziwych diamentów od zwykłych skał, ich szlifowanie oraz podział na klejnoty o mniejszych gabarytach, które łatwiej sprzedać, prowadzi do znacznego zwiększenia ich wartości. To samo można powiedzieć o najważniejszych przykładach, których używamy do zilustrowania wymogów projektowych. Stanowią świetny punkt wyjścia, ale w celu uzyskania maksymalnych korzyści musimy je udoskonalić. Dopracować, aby pokazać najważniejsze punkty jasno i wyraźnie, a także stworzyć specyfikacje, które zespoły będą mogły wykorzystać — zarówno dziś, jak i w przyszłości. Jedną z najczęstszych przyczyn nieudanego wdrożenia specyfikacji przez przykłady jest brak cierpliwości przy przetwarzaniu surowych przykładów. Dyskusja na temat specyfikacji często zachęca do eksperymentowania. Odkrywamy coś nowego i zmieniamy przykłady 1
http://www.edwardjayepstein.com/diamond/chap11.htm.
148
Specyfikacja na przykładach
tak, żeby móc spojrzeć na nie na wyższym poziomie abstrakcji. To może prowadzić do powstania kilku naprawdę świetnych przykładów, ale w efekcie możemy także zabrnąć w mnóstwo ślepych zaułków albo utonąć w morzu odrzuconych pomysłów. Nie musimy wcale wyłapywać wszystkich tych przykładów, z którymi będziemy mieli styczność gdzieś w połowie drogi, ani rejestrować naszej trasy prowadzącej do celu. Z drugiej strony zwykłe rejestrowanie kluczowych przykładów, które chcielibyśmy zachować bez żadnego wyjaśnienia, nie pomoże nam w sprawnym opisaniu specyfikacji każdemu, kto nie uczestniczył w dotychczasowych dyskusjach. Osiągające sukces zespoły nie używają surowych przykładów. Udoskonalają specyfikacje na ich podstawie. Umieją wyodrębnić istotę najważniejszych przykładów i ująć ją w jasną, jednoznaczną definicję, dzięki czemu implementacja staje się kompletna i nie zawiera żadnych niepotrzebnych szczegółów. Kryterium akceptacji jest następnie rejestrowane i opisywane tak, że każdy jest w stanie zrozumieć specyfikację, jeśli tylko na nią spojrzy. Specyfikacja z przykładami zawiera warunki satysfakcji, oczekiwane działanie funkcji, a także jej test akceptacyjny. Specyfikacje z przykładami są testami akceptacyjnymi Dobra specyfikacja przez przykłady jest w gruncie rzeczy testem akceptacyjnym opisanej funkcji.
W najlepszym przypadku specyfikacja z przykładami powinna jednoznacznie określać wymaganą funkcjonalność z perspektywy biznesu, a nie to, jak system będzie ją realizować. To daje deweloperom swobodę poszukiwań i wyboru najlepszego możliwego rozwiązania, które spełnia wymagania. Aby można było skutecznie zrealizować te cele, specyfikacja powinna być: Precyzyjna i testowalna. Prawdziwa (ma nie być skryptem). Skoncentrowana na funkcjonalności biznesowej, a nie wytwarzaniu oprogramowania. Gdy funkcjonalność zostanie wdrożona, definiująca ją specyfikacja będzie służyć innemu celowi. Stanie się dokumentem opisującym działanie systemu i ostrzeże nas o pojawieniu się regresji funkcjonalnej. Aby specyfikacja stała się użyteczną długoterminową dokumentacją funkcjonalną, musi być napisana tak, żeby gdy ktoś weźmie ją do ręki kilka miesięcy lub nawet kilka lat później, łatwo zrozumiał wszystkie „co?”, „dlaczego?” i „jak?”. Jeśli specyfikacja ma sprawnie realizować te cele, powinna być: Oczywista. Zogniskowana (ostra). Utrzymana w języku domeny. W tym rozdziale skupiamy się na sposobach udoskonalania specyfikacji, aby osiągnąć wszystkie wymienione cele. Najpierw jednak, by naszkicować konkretną perspektywę dla tych
Rozdział 8. Udoskonalanie specyfikacj
149
działań, przedstawię przykłady dobrych i złych specyfikacji. Pod koniec tego rozdziału zajmiemy się udoskonaleniem kiepskiej specyfikacji z zastosowaniem się do wskazówek zawartych w tym rozdziale.
Przykład dobrej specyfikacji Poniżej przedstawiono bardzo dobrze opisaną specyfikację z przykładami. Darmowa dostawa
Darmowa dostawa jest proponowana klientom VIP po zakupie pewnej liczby książek. Darmowa dostawa nie jest oferowana zwykłym klientom lub klientom VIP, którzy kupują coś innego niż książki. Zakładając, że minimalna liczba książek uprawniająca do darmowej dostawy wynosi pięć, spodziewamy się, że: Przykłady Rodzaj klienta
Zawartość koszyka z zakupami
Dostawa
VIP
5 książek
Darmowa, standardowa
VIP
4 książki
Standardowa
Zwykły
10 książek
Standardowa
VIP
5 pralek
Standardowa
VIP
5 książek, 1 pralka
Standardowa
Ta specyfikacja jest oczywista. Często pokazuję ten przykład na konferencjach czy na warsztatach i nigdy nie musiałem dodawać żadnego wyjaśnienia. Tytuł i akapit wprowadzający tłumaczą strukturę przykładów, tak aby czytelnicy nie musieli odrywać się od specyfikacji w celu zrozumienia określonej reguły. W specyfikacji znajdują się także realistyczne przykłady, które sprawiają, że można ją poddać testowaniu. Co więcej, wyjaśnia ona zachowanie systemu w przypadkach brzegowych, na przykład wtedy, gdy ktoś kupuje dokładnie 10 książek. Przedstawiony przykład to specyfikacja, a nie skrypt objaśniający, jak można przetestować przykłady. Nie mówi nic o przepływie pracy programu lub ograniczeniach sesji. Nie wyjaśnia, w jaki sposób książki są kupowane, tylko to, jak działa dostępny mechanizm realizacji dostawy. Nie podsuwa żadnych szczegółów dotyczących implementacji. To wszystko pozostawia się deweloperom, od których oczekujemy wyboru najlepszego możliwego rozwiązania. Przedstawiona specyfikacja koncentruje się na konkretnej regule — tej dotyczącej darmowej dostawy. Obejmuje tylko atrybuty właściwe dla tej reguły.
150
Specyfikacja na przykładach
Przykład złej specyfikacji Porównaj przedstawioną wcześniej specyfikację z tą zaprezentowaną na rysunku 8.1. To doskonały przykład bardzo kiepskiej specyfikacji2.
Rysunek 8.1. Niejasna specyfikacja
Mimo że w tej wersji specyfikacja ma tytuł, a pomiędzy tabelami pojawia się tekst, rzekomo wyjaśniający ich zawartość, to jednak opis ma wyłącznie marginalny wpływ na zrozumienie specyfikacji. Dlaczego ten dokument ma w nazwie słowo „prosty”? Nie mamy wątpliwości, że dotyczy wynagrodzenia pracowników, ale… o czym on właściwie mówi? Naprawdę trudno powiedzieć, co wyjaśnia ta specyfikacja. Czytając dane testowe, musimy cofnąć się, aby zrozumieć reguły. Wygląda na to, że produkt ma sprawdzać, czy odcinki wynagrodzenia są drukowane z unikalnymi numerami, rozpoczynając od numeru, który zostaje podany jako parametr. Wydaje się również sprawdzać dane wydrukowane na każdym odcinku. Wyjaśnia też, że jeden odcinek jest drukowany dla jednego pracownika. 2
Przykład pochodzi z prawdziwego projektu i znalazł się pierwotnie w materiałach pomocy FitNesse. Wykorzystaliśmy go podczas warsztatów udoskonalania specyfikacji w czerwcu 2010 roku, które odbyły się w Londynie. Ostatecznie w nowej dystrybucji FitNesse został on zmieniony.
Rozdział 8. Udoskonalanie specyfikacj
151
W przedstawionym dokumencie znajdujemy wiele pozornie przypadkowych informacji komplikujących przekaz — dane osobowe oraz adresy nie są tak naprawdę wykorzystywane w żadnym (innym niż pierwsza tabela) miejscu w dokumencie. Identyfikatory bazy danych pojawiają się w tabelach, ale dla reguł biznesowych są bez znaczenia. Wykorzystuje się je w tym przypadku w celu dopasowania danych dotyczących zatrudnionych pracowników do Inspektora płac, wprowadzając do opisu przykładu pojęcia techniczne dotyczące oprogramowania. Inspektor płac został oczywiście wymyślony tylko na potrzeby testów. Kiedy przeczytałem tę specyfikację po raz pierwszy, wyobraziłem sobie Petera Sellersa ubranego jak inspektor Clouseau, dokonującego inspekcji odcinków, kiedy te pojawiają się na drukarce. Jestem pewien, że to nie ma nic wspólnego z koncepcją biznesową. Inną ciekawą kwestią są puste komórki w części walidacyjnej tej specyfikacji oraz dwie tabele Inspektora płac, które wydają się niepowiązane. Ten przykład pochodzi z opisu FitNesse, a puste komórki powodują wydrukowanie wyników testu na potrzeby diagnostyki bez sprawdzania czegokolwiek. W ten sposób specyfikacja staje się testem automatycznym, który musi nadzorować człowiek — co skutecznie wyklucza zastosowanie jej w funkcji narzędzia automatyzacji. Puste komórki w FitNesse są zwykle oznaką niestabilności testów, a także sygnałem, że czegoś brakuje. Albo zautomatyzowany test pobiera dane z systemu w niewłaściwym miejscu, albo ukryta jest w nim jakaś zasada, która sprawia, że wyniki testów są niepowtarzalne i niewiarygodne. Język używany w specyfikacji jest niespójny, co sprawia, że trudno zrozumieć jakiś związek pomiędzy danymi wejściowymi i wyjściowymi. Co to za wartość w dolnej części tabeli? 1001? Nagłówek kolumny mówi, że chodzi o jakąś liczbę. To technicznie poprawny, ale całkowicie bezużyteczny kawałek informacji. W innej komórce tabeli znajduje się numer odcinka, ale dlaczego akurat taki? Jaki jest związek między tymi dwoma numerami? Zakładając, że adresy znalazły się w specyfikacji dlatego, że odcinki z wypłatą są drukowane wraz z adresem do automatycznego pakowania kopert, test bazujący na tej specyfikacji nie sprawdza co najmniej jednej bardzo ważnej rzeczy: czy właściwi ludzie otrzymają pensję o właściwej wysokości. Jeśli pierwsza osoba z listy otrzyma dwie wypłaty, test zakończy się wynikiem pozytywnym. Jeśli system zamieni pensje pracowników, test także zakończy się wynikiem pozytywnym. Jeśli na poleceniach wypłaty znajdą się przyszłe daty, nasi pracownicy mogą długo nie otrzymać swoich pieniędzy, ale test i w tym przypadku zakończy się wynikiem pozytywnym. W tym miejscu docieramy do prawdziwego znaczenia pustych komórek. Nie ustalono porządku przelewów. To luka funkcjonalna, która sprawia, że taki system trudno przetestować tak, żeby otrzymać powtarzalne wyniki. Autor tej strony FitNesse postanowił obejść tę trudność techniczną w specyfikacji, a nie w warstwie automatyzacji, i stworzył test, który daje fałszywe wyniki. Bez większej wiedzy na temat kontekstu trudno powiedzieć, czy ten test sprawdza tylko jedną rzecz. Jeśli system wydruku przelewów jest wykorzystywany do czegokolwiek innego, wolałbym wyjść od zasady unikalnych numerów przelewów i zacząć od skonfigurowania tej wartości na oddzielnej stronie. Jeśli zaś system ma drukować tylko przelewy, wówczas prawdopodobnie element ten znajdzie się w części testującej wydruk przelewu.
152
Specyfikacja na przykładach
W dalszej części tego rozdziału zajmiemy się udoskonaleniem tego okropnie sformułowanego dokumentu. Najpierw jednak przejdźmy do zdefiniowania, co właściwie oznacza termin „dobra specyfikacja”.
Na co należy zwrócić uwagę podczas udoskonalania specyfikacji? We wstępie do tego rozdziału określiłem cele dobrych specyfikacji. Oto kilka niezłych pomysłów na to, jak je osiągnąć. Przykłady powinny być precyzyjne i testowalne Specyfikacja musi być obiektywną miarą sukcesu, czymś, co bez dwuznaczności powie nam, kiedy zakończymy fazę wytwarzania oprogramowania. Musi zawierać sprawdzalne informacje — kombinacje parametrów i oczekiwanych wyników, które można przetestować w systemie. Aby specyfikacja mogła spełnić te kryteria, musi bazować na precyzyjnych, realnych przykładach. Patrz część zatytułowana „Przykłady powinny być precyzyjne” w rozdziale 7., gdzie znajdziesz opis kilku dobrych technik wykorzystywanych w celu zagwarantowania, że zastosowane zostaną precyzyjne przykłady. Skrypty to nie specyfikacje Użytkownicy biznesowi często wyobrażają sobie wykonanie jakiegoś działania za pośrednictwem interfejsu użytkownika lub w kilku etapach, wyjaśniając, jak użyliby systemu, aby coś osiągnąć, a myślą w kategoriach tego, co taki system powinien robić. Tego typu przykłady to skrypty, a nie specyfikacje. Skrypt wyjaśnia, jak coś można przetestować. Opisuje funkcje biznesowe na bazie niższego poziomu interakcji z systemem. Skrypt wymaga od czytelnika, by dokonał wstecznej inżynierii, wychodząc od działań i zrozumienia, co jest naprawdę ważne i co dokładnie jest ilustrowane. Skrypty powodują również narzucenie testom ograniczeń przepływu pracy i sesji, które przecież w przyszłości mogą się zmienić, nawet gdy nie zmienią się podstawowe reguły biznesowe. Specyfikacja wyjaśnia, co robi system. W najbardziej bezpośredni sposób skupia się na funkcji biznesowej. Specyfikacje są krótsze, ponieważ bezpośrednio opisują koncepcje biznesowe. To sprawia, że łatwiej (w porównaniu ze skryptami) się je czyta i łatwiej je zrozumieć. Dane są również dużo bardziej stabilne niż skrypty, ponieważ nie będą zmieniać się wraz ze zmianami ograniczeń przepływu pracy i sesji. Oto przykład skryptu:
Zaloguj się jako użytkownik: Tom. 2. Przejdź do strony głównej. 3. Wyszukaj frazę Specyfikacja przez przykłady. 4. Dodaj pierwszy wynik wyszukiwania do koszyka. 5. Wyszukaj Beautiful Testing. 1.
Rozdział 8. Udoskonalanie specyfikacji
153
Dodaj drugi wynik do koszyka. 7. Sprawdź, czy liczba elementów w koszyku równa się: 2.
6.
Ten skrypt mówi nam, jak wygląda działanie systemu, ale bezpośrednio nie wyjaśnia, co specyfikujemy. Weź kartkę papieru i spróbuj napisać, co dokładnie opisuje ta specyfikacja, zanim zaczniesz czytać następny akapit. Czy w ogóle udało Ci się coś zapisać? Jeśli tak, to czy nie wydaje Ci się, że jest to właśnie jedna jedyna rzecz, która mogłaby być opisywana przez ten przykład? Przywołany przykład tak naprawdę może dotyczyć różnych aspektów działania systemu. Jedną z możliwości jest to, że skrypt informuje nas o tym, że do koszyka może trafić wiele obiektów. Inną, równie prawdopodobną opcją jest taka, w której dowiadujemy się, że po zalogowaniu się użytkownika do systemu jego koszyk jest pusty. Trzecia opcja? Może chodzi o to, że zarówno pierwszy wynik wyszukiwania — Specyfikacja przez przykłady — jak i drugi — Beautiful Testing — może zostać dodany do koszyka z zakupami? Trzeba przyznać, że zamieszczony skrypt jest przykładem bardzo precyzyjnym i testowalnym. Możemy go wykonać i sprawdzić, czy system działa zgodnie z oczekiwaniami. Problem tego skryptu polega na tym, że nie zawiera on żadnych informacji na temat tego, jaką właściwie funkcję systemu opisuje. Pierwotnie autorzy skryptu mogli dokładnie wiedzieć, co system ma zrobić, gdy dokonywali pierwszej implementacji funkcji. Sześć miesięcy później nie będzie to już takie oczywiste. Przedstawiony skrypt nie jest dobrym narzędziem komunikacji. Nie możemy stwierdzić, czego właściwie dotyczy ani która część systemu działa nie tak. Jeśli test bazujący na tym skrypcie nagle zaczyna kończyć się niepowodzeniem, ktoś będzie musiał spędzić dużo czasu na analizie różnych obszarów kodu. Etap logowania użytkownika o nazwie „Tom” jest najprawdopodobniej niezbędny ze względu na ograniczenia przepływu na stronie internetowej. Jeśli ten przykład nie ilustruje reguły biznesowej związanej z tym użytkownikiem w szczególności, fakt, że to właśnie Tom loguje się do systemu, jest właściwie bez znaczenia. Jeśli to konto użytkownika zostanie z jakiegoś powodu zablokowane, test będzie kończyć się błędem, co wcale nie jest jednoznaczne z błędem systemu. Ktoś straci mnóstwo czasu, starając się dojść przyczyn tego stanu rzeczy. Zapisywanie kryteriów akceptacji za pomocą skryptów, a nie specyfikacji w perspektywie długoterminowej niesie za sobą spore straty czasu. A przecież można zaoszczędzić ten czas, jeśli przeznaczymy kilka minut na modyfikację i restrukturyzację przykładów na wczesnym etapie. Szukając pomysłów na to, jak udoskonalić skrypty tak, aby stały się bardziej przydatnymi specyfikacjami, zajrzyj do części „Udoskonalanie w praktyce” na końcu tego rozdziału. Rick Mugridge i Ward Cunningham podsuwają swoim czytelnikom wiele przydatnych wskazówek na temat restrukturyzacji skryptów w celu uczynienia ich lepszymi specyfikacjami w książce zatytułowanej Fit for Developing Software (Prentice Hall, 2005).
154
Specyfikacja na przykładach
Nie twórz opisów w formie przepływów Zwróć baczną uwagę na opisy przepływów (w formie: „najpierw zrób to, potem tamto…”). Jeśli nie jest to opis rzeczywistego przebiegu procesu, często stanowi znak, że reguła biznesowa jest obrazowana za pomocą skryptów. Takie skrypty w dłuższej perspektywie utrzymania systemu spowodują wiele problemów serwisowych.
Unikaj opisów tego, jak system powinien pracować. Zamień je raczej na opis tego, co system powinien robić.
Zespół Iana Coopera w Beazley zdał sobie z tego sprawę po mniej więcej sześciu miesiącach od rozpoczęcia implementacji specyfikacji przez przykłady. Podczas retrospektywy zespołu ludzie zaczęli mówić, że testy akceptacyjne są zbyt kosztowne w utrzymaniu. Szukając sposobów zmniejszenia kosztów, zespół przeprowadził restrukturyzację skryptów, zamieniając je w specyfikacje. Cooper mówi: Modele, z których korzystaliśmy przy robieniu testów, nie różniły się od testów ręcznych, przekonwertowanych na skrypty. Nasze pierwsze testy przypominały skrypty. Testy miały formę sekwencji z kilkoma sprawdzianami na końcu procesu. Kiedy zmieniliśmy podejście, nastawiając się raczej na to, »co powinno być zrobione«, wszystko stało się dużo łatwiejsze. Opisywanie testów akceptacyjnych tak, że przypominają skrypty, a nie specyfikacje, to jeden z najczęściej popełnianych błędów, jakie mogą stać się udziałem zespołów w początkowych stadiach projektowych. Skrypty sprawdzają się stosunkowo dobrze jako cele w krótkich iteracjach, ponieważ ludzie pamiętają, co opisuje skrypt, kiedy wdrażają go po raz pierwszy. Jednak po jakimś czasie skrypty stają się trudne do utrzymania i zrozumienia. Zanim pojawią się problemy, może minąć kilka miesięcy, ale kiedy już do tego dojdzie, będziesz musiał ponieść poważne konsekwencje.
Specyfikacje powinny dotyczyć funkcjonalności biznesowej, a nie projektu oprogramowania W najlepszym przypadku specyfikacja nie powinna podpowiadać projektu oprogramowania. Powinna raczej wyjaśniać funkcjonalność biznesową bez opisywania tego, w jaki sposób zostanie ona zrealizowana w oprogramowaniu. Taki system służy dwóm celom: Umożliwia programistom znalezienie aktualnie najlepszego możliwego rozwiązania. Umożliwia programistom poprawienie projektu w przyszłości. Specyfikacje skupiające się na funkcjonalności biznesowej bez opisywania realizacji sprawiają, że wybrane rozwiązanie będzie można łatwo zmienić w przyszłości. Specyfikacja, która nic
Rozdział 8. Udoskonalanie specyfikacj
155
nie mówi o projektowaniu oprogramowania, nie będzie musiała zostać zmieniona, gdy dojdzie do poprawienia konstrukcji. Takie specyfikacje ułatwiają przyszłe zmiany, pełniąc rolę stałej. Możemy uruchomić niezmodyfikowane testy bazujące na tych specyfikacjach po poprawieniu projektu oprogramowania, aby upewnić się, że cała zaimplementowana funkcjonalność nadal jest obecna w systemie.
Unikaj tworzenia specyfikacji, które są ściśle powiązane z kodem
Specyfikacje, które są ściśle powiązane z kodem i odwzorowują implementację oprogramowania, prowadzą do powstawania niepewnych testów.
Zmiany w projekcie oprogramowania sprawiają, że testy zwracają błędy, nawet gdy funkcja opisywana przez test nie ulega zmianie. Specyfikacje przez przykłady, które prowadzą do powstawania niepewnych testów, podnoszą koszty utrzymania, zamiast ułatwiać zmiany. Zwraca na to uwagę Aslak Hellesøy, który twierdzi, iż była to jedna z kluczowych lekcji, jakie wyniósł z wdrożenia specyfikacji przez przykłady: Pisaliśmy zbyt wiele testów akceptacyjnych, które czasami były zbyt ściśle powiązane z kodem. Nie tak ściśle jak testy jednostkowe, ale jednak… W najgorszym przypadku aktualizacja skryptów testowych po wielkim refaktoringu trwała osiem godzin. Musieliśmy wiele nauczyć się na temat tego, jak znaleźć równowagę między liczbą testów i tym, jaką mają formę.
Zwróć szczególną uwagę na nazwy i koncepcje w specyfikacjach, które pochodzą z implementacji oprogramowania i nie istnieją w domenie biznesowej. Chodzi tu na przykład o identyfikatory baz danych, nazwy usług technicznych lub nazwy klas obiektów, które nie są nazwami pierwszego rzędu używanymi w domenie, oraz koncepcje i pojęcia wymyślone wyłącznie dla celów automatyzacji. Dokonaj restrukturyzacji specyfikacji, aby uniknąć umieszczania w nich wspomnianych pojęć, a w dłuższej perspektywie będą one znacznie łatwiejsze do zrozumienia i utrzymania.
Testy techniczne są ważne i nie zamierzam nikogo zniechęcać do stosowania testów, które są ściśle powiązane z projektem oprogramowania. Jednak takie testy nie powinny być mieszane z wykonywalnymi specyfikacjami. Częstym błędem popełnianym przez zespoły rozpoczynające wdrażanie specyfikacji przez przykłady jest rezygnacja z wszystkich testów technicznych, takich jak te na poziomie jednostki lub integracji, a następnie oczekiwanie, że wykonywalne specyfikacje obejmą wszystkie aspekty systemu. Wykonywalne specyfikacje pomagają nam w dostarczaniu odpowiedniej funkcjonalności biznesowej. Testy techniczne pozwalają sprawdzić, czy patrzymy na system pod kątem niskopoziomowych aspektów jakości technicznej systemu. Potrzebujemy i wykonywalnych specyfikacji, i testów technicznych, ale nie powinniśmy ich mieszać. Narzędzia do automatyzacji testów technicznych znacznie lepiej nadają się do testów technicznych niż narzędzia, których używamy do automatyzacji wykonywalnych specyfikacji. Pozwalają zespołowi znacznie łatwiej utrzymać testy techniczne.
156
Specyfikacja na przykładach
Oprzyj się pokusie obejścia trudności technicznych w specyfikacjach Kiedy: Pracujesz na starym systemie
Stare systemy często charakteryzują się wieloma dziwactwami o charakterze technicznym i trudno wprowadzić w nich jakiekolwiek zmiany. Użytkownicy muszą znaleźć jakieś sposoby, by poradzić sobie z tymi niedogodnościami, a potem trudno odróżnić prawdziwe procesy biznesowe od rozwiązań prowizorycznych. Niektóre zespoły, włączając prowizoryczne poprawki do specyfikacji, wpadają w pułapkę. Takie działanie przywiązuje specyfikacje nie tylko do implementacji, lecz również do problemów technicznych, które były powodem poprawek. Takie specyfikacje są nieskuteczne w funkcji koordynatora zmian w istniejących systemach. Szybko stają się drogie w utrzymaniu. Jedna mała zmiana w kodzie może wymagać godzin aktualizacji wykonywalnych specyfikacji. Johannes Link pracował nad projektem, w którym na potrzeby uruchomienia podstawowych scenariuszy testowych konieczne było zdefiniowanie 200 różnych obiektów. Zależności te zostały określone w wykonywalnych specyfikacjach, a nie przeniesione na warstwę automatyki. Rok później utrzymanie testów stało się tak kosztowne, że zespół zaczął domagać się zmian. Link mówi: Zmiana jednej funkcji prowadziła do problemów w wielu testach. Nie mogliśmy sobie pozwolić na wdrożenie żadnych nowych wymagań, ponieważ w kategorii testów oznaczałoby to ogromne koszty, a wiedzieliśmy, że nie można zrezygnować z testów, by utrzymać niski wskaźnik błędów. Większość narzędzi automatyzacji3 wykonywalnych specyfikacji oddziela specyfikację od procesu automatyzacji (więcej na ten temat w części zatytułowanej „Jak to działa?” na początku rozdziału 9.). Specyfikacja ma formę czytelną dla człowieka, a proces automatyzacji jest realizowany za pomocą odrębnej warstwy automatyzacji kodu języka programowania.
Problemy natury technicznej rozwiązuj w warstwie automatyzacji. Nie próbuj rozwiązywać ich w specyfikacjach testowych.
Dzięki temu system będzie można łatwiej zmienić i usprawnić. Rozwiązywanie problemów technicznych w warstwie automatyzacji pozwala na korzystanie z zalet funkcji i narzędzi języka programowania podczas opisywania i utrzymywania procesów walidacji technicznych. Programiści mogą stosować techniki i narzędzia w celu ograniczenia duplikowania, tworzyć kod łatwy w utrzymaniu, umożliwiający łatwe modyfikacje. Jeśli obejścia techniczne znajdą się w warstwie automatyzacji, specyfikacje nie zmienią się w konsekwencji poprawy projektu technicznego i prowizoryczne rozwiązania nie będą już potrzebne. 3
Zajrzyj na stronę http://specificationbyexample.com, gdzie znajdziesz więcej informacji na temat narzędzi wspierających automatyzację.
Rozdział 8. Udoskonalanie specyfikacj
157
Specyfikacje przeniesione do warstwy automatyzacji stają się krótsze i łatwiejsze do zrozumienia. Powstała w efekcie specyfikacja będzie wyjaśniać koncepcje biznesowe na wyższym poziomie abstrakcji, koncentrując się na aspektach, które są ważne pod kątem określonego zestawu przykładów (więcej na ten temat w części zatytułowanej „Specyfikacje powinny być ostre” w dalszej części tego rozdziału).
Nie pozwól uwięzić się przez szczegóły interfejsu użytkownika Kiedy: Pracujesz nad projektami internetowymi
Na pierwszych etapach wdrażania specyfikacji przez przykłady wiele zespołów marnowało mnóstwo czasu na opisywanie nieistotnych przykładów zawierających informacje o mało ważnych szczegółach interfejsu użytkownika. Pracowały one według wytycznych procesu specyfikacji przez przykłady dla samego procesu, a nie w celu poszerzenia swojej wiedzy na temat specyfikacji.
Interfejs użytkownika ma formę wizualną, więc łatwo na jego temat rozmawiać. Widziałem projekty, w których zespoły i klienci godzinami opisywali linki menu nawigacji. A przecież ten element interfejsu użytkownika praktycznie nie jest związany z żadnym ryzykiem i ten czas można przeznaczyć na przedyskutowanie o wiele ważniejszych funkcji. Phil Cowans miał podobne doświadczenia w Songkick, gdy zespół zaczął wdrażanie specyfikacji przez przykłady, i jego zdaniem był to jeden z kluczowych wczesnych błędów. Na początku długo testowaliśmy trywialne elementy interfejsu użytkownika, ponieważ to było łatwe. Nie przeznaczaliśmy za dużo czasu na analizowanie przypadków brzegowych i alternatywnych ścieżek prowadzących przez aplikację. Całkiem łatwo sprawdzić coś, co widać, ale w końcu i tak musisz zadbać o to, aby mieć jak największą wiedzę na temat tego, co robi oprogramowanie, a nie tego, jak wygląda interfejs użytkownika. Myślenie w kategoriach historyjek użytkownika i ścieżek prowadzących przez aplikację naprawdę pomaga. Zamiast rozwodzić się nad szczegółami interfejsu użytkownika, lepiej pomyśleć o „podróżach” użytkownika przechodzącego po różnych stronach internetowych. Podczas wspólnego definiowania specyfikacji zainwestuj czas w działania dotyczące poszczególnych części specyfikacji w stopniu zależnym od ich znaczenia dla biznesu klienta. Elementy, które są ważne i z których zastosowaniem wiąże się większe ryzyko, powinny być szczegółowo zbadane. Te, które nie są tak ważne, być może wcale nie muszą być tak dokładnie opracowane.
Specyfikacje powinny być oczywiste Gdy test specyfikacji wykonywalnej kończy się niepowodzeniem z powodu regresji funkcjonalnej, ktoś musi mu się przyjrzeć, zrozumieć, co poszło nie tak, i dojść do tego, jak można to poprawić. Coś takiego może zdarzyć się kilka lat po napisaniu oryginalnej specyfikacji, gdy jej autorzy nie pracują już nad tym samym projektem. To właśnie dlatego specyfikacja powinna być oczywista i niewymagająca dodatkowych tłumaczeń.
158
Specyfikacja na przykładach
Oczywiście zadbanie o to, aby specyfikacja była oczywista, pomaga również w unikaniu nieporozumień już na etapie projektowania określonej funkcji.
Użyj opisowego tytułu i wyjaśnij cel, stosując krótkie zdania
Na początkowym etapie tworzenia specyfikacji wystarczy tylko kilka słów, by później zaoszczędzić sporo czasu.
Jeżeli specyfikacja zawiera tylko wartości wejściowe i oczekiwane wyniki, każdy, kto zapoznaje się z tym dokumentem, będzie musiał odtworzyć reguły biznesowe z przykładów. Ważne jest wybranie opisowego tytułu specyfikacji. Powinien on podsumowywać intencje. Pomyśl o tym, jaką frazę wpisałbyś w okno wyszukiwarki Google, aby odszukać dokument, który znajdowałby się gdzieś w internecie, i właśnie tej frazy użyj jako tytułu. Pozwoli to na łatwe odnalezienie odpowiedniego dokumentu tym, którzy będą szukać wyjaśnienia pewnej funkcji. Czytający specyfikację musi również rozumieć jej strukturę i kontekst. Wyjaśnij w kilku słowach cel specyfikacji i strukturę przykładów — niech wyjaśnienie nie będzie dłuższe niż kilka zdań — i umieść opis w nagłówku. Sztuka umiejętnego tworzenia opisu polega na tym, aby na początku zapisać tylko przykłady, a potem spróbować wyjaśnić je komuś innemu. Zapisz to, co powiedziałeś podczas wyjaśniania przykładów. Masz swój nagłówek specyfikacji.
Pokaż i milcz Kiedy: Ktoś pracuje nad specyfikacją samodzielnie W celu: Sprawdzenia, czy specyfikacja jest oczywista i nie wymaga dodatkowych tłumaczeń
Jeśli chcesz sprawdzić, czy specyfikacja jest oczywista i nie wymaga wyjaśnień, poproś kogoś o zapoznanie się z dokumentem. Czy potrafi zrozumieć dokument, kiedy Ty nie pomagasz mu i nie dodajesz od siebie ani słowa wyjaśnienia?
Aby mieć pewność, że specyfikacja jest oczywista, poproś drugą osobę o wyjaśnienie, co z niej zrozumiała. Sprawdź, czy to, co słyszysz, pasuje do Twoich intencji. Jeśli pokazuję komuś moją specyfikację i stwierdzam, że muszę ją wyjaśnić, zapisuję swoje wyjaśnienie i umieszczam je w nagłówku. Wyjaśnianie przykładów często pozwala mi wybrać kilka bardziej znaczących nazw lub dodać do przykładów jakiś upraszczający komentarz.
Rozdział 8. Udoskonalanie specyfikacj
159
Nie upraszczaj nadmiernie przykładów Wiele zespołów popełnia błąd, poszerzając specyfikację tak, by uwzględnić wszystkie możliwe kombinacje parametrów wejściowych zaraz po stworzeniu podstawowej infrastruktury automatyzacji. Wszyscy członkowie zespołów tłumaczyli swoje zachowanie tym, że testerzy próbowali zweryfikować dodatkowe przykłady poprzez ponowne wykorzystanie systemu automatyzacji. Problem w tym, że oryginalne przykłady kluczowe gubią się w takim przypadku w morzu innych wartości. Specyfikacje stają się trudne do zrozumienia, co oznacza, że nie są już dłużej oczywiste.
Specyfikacja, która właściwie definiuje trzy kluczowe przykłady, jest o wiele bardziej użyteczna niż taka, która kiepsko opisuje setkę przykładów.
Dodatkowym problemem przy tym podejściu może być to, że uruchomienie większej liczby przykładów, aby zweryfikować te same przypadki, wymaga więcej czasu, a więc spowalnia wykonanie testu i daje zespołowi zajmującemu się wytwarzaniem oprogramowania rzadszy feedback. Zespół Lisy Crispin natknął się na ten problem podczas pracy nad zautomatyzowaną kontrolą zgodności, uzupełnioną zasadami zdefiniowanymi przez podmioty regulujące, które wcale nie musiały być zgodne z żadną logiką. Crispin współpracowała z właścicielem produktu, aby zdefiniować algorytmy radzące sobie z wieloma permutacjami, czego efektem była lista wielu skomplikowanych wykonywalnych specyfikacji, przygotowana z wyprzedzeniem na potrzeby kilku sprintów. Gdy deweloperzy dostali te specyfikacje do rąk, poczuli się przytłoczeni. Crispin wyjaśnia: Oni [deweloperzy] spojrzeli na testy [wykonywalne specyfikacje] i poczuli się zdezorientowani. Nie byli w stanie dostrzec lasu spoza drzew. Nie mogli użyć testów, bo nie wiedzieli, co powinno znaleźć się w kodzie. Stwierdziliśmy, że testy powinny pozwolić nam zbudować sobie ogólne pojęcie, ale niekoniecznie powinny zawierać wszystkie możliwe szczegóły. W specyfikacji powinny znaleźć się wyłącznie kluczowe przykłady reprezentatywne. Dzięki temu dokument będzie krótki i łatwy do zrozumienia. Główne przykłady zwykle obejmują: Reprezentatywny przykład ilustrujący każdy istotny aspekt funkcjonalności biznesowej. Za stworzenie tego typu przykładów zwykle będą odpowiadać użytkownicy biznesowi, analitycy lub klienci. Przykład ilustrujący każdy ważny techniczny przypadek brzegowy, taki jak techniczne warunki graniczne. Zwykle tego typu przykłady są przygotowywane przez deweloperów, gdy próbują zabezpieczyć się na wypadek luk funkcjonalnych lub niespójności.
160
Specyfikacja na przykładach
Użytkownicy biznesowi, analitycy czy klienci będą odpowiadać za poprawne oczekiwane zachowanie. Przykład omawiający każdy szczególnie kłopotliwy obszar przewidywanej implementacji, tj. elementy takie jak przypadki, w których pojawiały się błędy w przeszłości, i warunki brzegowe, które mogły nie zostać wyraźnie zilustrowane w poprzednich przykładach. Za zdefiniowanie tych przykładów zazwyczaj odpowiadają testerzy, podczas gdy użytkownicy biznesowi, analitycy czy klienci będą określać poprawne zachowanie systemu. Istnieją oczywiście korzyści powtórnego wykorzystania struktury automatyzacji zdefiniowanej dla kluczowych przykładów, co ma na celu wsparcie testerów pragnących wykonać większą liczbę testów. Czasami najprostszy sposób na poznanie zachowania systemu z różnymi wartościami granicznymi zakłada dołożenie większej liczby przykładów do istniejących specyfikacji. Może to sprawić, że specyfikacje będą dłuższe, bardziej nieostre i trudniejsze do zrozumienia. Zamiast komplikować główną specyfikację, utwórz oddzielny test automatyczny i umieść kilka odwołań do niego w głównym dokumencie. Jeśli korzystasz z systemu obsługi żyjącej dokumentacji umieszczonej w sieci globalnej, do połączenia specyfikacji możesz użyć łącza internetowego. W systemach opartych na plikach należy użyć ścieżki do pliku lub skrótu w opisie specyfikacji. Nowy test może mieć taką samą strukturę jak specyfikacja podstawowa i omawiać wiele dodatkowych przykładów. Główna specyfikacja funkcji będzie nadal użyteczna jako narzędzie komunikacji i zapewni szybką wymianę informacji. Dodatkowe testy mogą sprawdzać dowolne kombinacje z myślą o bardziej rozległych testach. Specyfikacja podstawowa może być poddana walidacji po każdej zmianie, aby zapewnić szybki feedback. Testy dodatkowe mogą być uruchamiane na żądanie, przez całą noc, dając zespołowi przekonanie o poprawności pozostałych elementów. Nie próbuj sprawdzać każdego elementu Powszechną przyczyną nadmiarowego uszczegóławiania przykładów jest strach analityków lub klientów przed oskarżeniem o niedopilnowanie implementacji brakującej funkcji. W przypadku procesu wspólnego tworzenia specyfikacji odpowiedzialność za poprawność specyfikacji również jest wspólna. Nie ma zatem powodu, aby obawiać się roli kozła ofiarnego. André Brissette dyrektor produktu dla systemu Talia w Pyxis zwraca uwagę na kilka ważnych lekcji, jakie opanował: Zdecyduj, co objąć testami, na podstawie warunków powodzenia dla historyjki. Jeśli myślisz, że dzięki tym testom naprawdę możesz pokryć warunki powodzenia, wówczas jesteś na dobrej drodze. Jeśli jest to nierealne, masz problem. Jeżeli wraz z końcem sprintu lub kiedyś, na jakimś etapie w przyszłości okaże się, że coś przegapiłeś, jedna rzecz jest jasna i oczywista: To, co zrobiłeś, warunkowało sukces i w gruncie rzeczy był to kontrakt zawarty pomiędzy wszystkimi zainteresowanymi stronami. Na tamtym etapie to [dodatkowa funkcja] nie było potrzebne. Jako analityk nie musisz brać winy na siebie.
Rozdział 8. Udoskonalanie specyfikacj
161
Zacznij od podstawowych przykładów, a następnie rozszerz zakres przez eksplorowanie Kiedy: Opisujesz reguły za pomocą wielu kombinacji parametrów
Aby rozwiązać problem opisany w poprzednim podrozdziale, zespół Lisy Crispin postanowił przed rozpoczęciem pracy nad historyjką tworzyć tylko specyfikacje wysokiego poziomu, pozostawiając szczegółowe testy na później. Tester i deweloper wybrali razem „ścieżkę szczęścia”, kiedy zaczęli prace nad historyjką. Następnie deweloper zajął się automatyzacją historyjki i napisał kod, umożliwiając testerom ponowne użycie zestawu narzędzi automatyzacji na bazie dodanych przypadków testowych. Później testerzy zajęli się eksploracją systemu i eksperymentowaniem z różnymi przykładami. Gdy zidentyfikowali przypadek prowadzący do nieudanych testów, wrócili do programistów, aby ci rozszerzyli specyfikację i rozwiązali problem.
Zamiast niepotrzebnie nadmiernie komplikować specyfikację, podstawowe przykłady pomagają znaleźć ścieżkę szczęścia i właściwie wprowadzić strukturę automatyzacji.
Następnie, w zależności od oceny ryzyka takiego działania, można przetestować dodatkowe przykłady, a także stopniowo poszerzać specyfikację. To ciekawe rozwiązanie pozwalające zająć się przypadkami, w których pierwotnie klasy równoważności nie są łatwe do określenia, a implementacja prowadzi do pojawienia się przypadków brzegowych. Specyfikacje powinny być ostre Specyfikacja powinna opisywać jedną rzecz — regułę biznesową, funkcję lub etap procesu. Takie zogniskowane na jednym elemencie specyfikacje są łatwiejsze do zrozumienia niż te, które definiują szereg związanych z nimi reguł. Specyfikacja powinna być również skoncentrowana tylko na kluczowych atrybutach przykładów, ważnych dla danego elementu, którego działanie przedstawiamy. Takie zogniskowanie przynosi dwie istotne korzyści: specyfikacje są krótkie, więc łatwiejsze do zrozumienia niż te dłuższe i bardziej niejasne. Są również łatwiejsze w utrzymaniu. Specyfikacja, która obejmuje kilka reguł biznesowych, będzie zmieniać się wraz ze zmianą w każdym z omawianych obszarów systemu. Przez to automatyczne testy oparte na specyfikacji częściej będą kończyć się niepowodzeniem. Co gorsza, w takiej sytuacji trudniej będzie zidentyfikować źródło problemu.
162
Specyfikacja na przykładach
Zastosuj wzorzec „Zakładając/Jeżeli/Wtedy” W celu: Sprawienia, by testy były łatwiejsze do zrozumienia
Podstawowa reguła dotycząca specyfikacji zakłada, iż powinna ona zawierać opis kontekstu, definiować pojedyncze działanie, a także spodziewane warunki końcowe.
Dobrym sposobem na zapamiętanie tej reguły jest zastosowanie modelu Zakładając/Jeżeli/ Wtedy (ang. Given-When-Then) lub Przygotuj/Działaj/Zapewnij (ang. Arrange-Act-Assert). Ten pierwszy model jest typowym formatem ułatwiającym określanie zachowania systemu, spopularyzowanym przez pierwsze artykuły na temat BDD. Wymaga od nas tworzenia scenariuszy zachowania systemu w trzech częściach: Zakładając warunek wstępny, Jeżeli dochodzi do określonego działania, Wtedy osiągnięte zostaną określone warunki końcowe. Niektóre narzędzia automatyzacji takie jak Cucumber4 i SpecFlow5 wykorzystują właśnie taki język do generowania wykonywalnych specyfikacji (patrz rysunek 8.1, gdzie znajdziesz przykład modelu). Nawet w przypadku różnych innych narzędzi, które używają tabelarycznych, tekstowych lub opartych na słowach kluczowych systemów, tworzenie struktur specyfikacji naśladującej model „Zakładając/Jeżeli/Wtedy” jest doskonałym pomysłem. Kluczowe znaczenie ma wyzwolenie pojedynczego działania. W ten sposób gwarantujemy, że specyfikacja koncentruje się tylko na tej jednej akcji. Jeżeli specyfikacja wymienia szereg działań, czytelnik pragnący zrozumieć efekt końcowy będzie musiał je przeanalizować i zrozumieć, jak działania te wpływają na siebie dla osiągnięcia efektu końcowego. Jeśli zestaw działań jest ważny w perspektywie przepływu biznesowego, prawdopodobnie jest na tyle istotny, aby mieć nazwę i zostać uznany za pojęcie wyższego poziomu, dlatego powinien być wychwycony w metodzie wyższego poziomu w kodzie domeny. Ta metoda nadrzędna może być wymieniona w specyfikacji. Specyfikacja może określać kilka warunków wstępnych i warunków końcowych (kilka pozycji w części Zakładając/Wtedy), jeśli tylko wszystkie są bezpośrednio związane z funkcją opisywaną przez test. Poniższy przykład testu Cucumbera zawiera dwa warunki wstępne i dwa warunki końcowe: Scenariusz: Nowy użytkownik, podejrzana transakcja
Zakładając, że użytkownik nie ma historii wcześniejszych transakcji oraz że krajem rejestracji konta użytkownika jest Wielka Brytania, jeżeli użytkownik złoży zamówienie i wybierze Stany Zjednoczone jako miejsce dostawy, wtedy transakcja zostanie oznaczona jako podejrzana, ale użytkownik będzie widział status zamówienia: „w realizacji”. 4 5
http://www.cukes.info. http://specflow.org.
Rozdział 8. Udoskonalanie specyfikacj
163
Potencjalną pułapką modelu języka „Zakładając/Jeżeli/Wtedy” jest podobieństwo do prozy , które często zachęca ludzi do myślenia o przepływach interakcji zamiast o bezpośrednim wyrażaniu funkcjonalności biznesowej. Skorzystaj z porady opisanej w części „Skrypty to nie specyfikacje” wcześniej w tym rozdziale, aby uniknąć potencjalnych problemów.
Nie definiuj jawnie wszystkich zależności w specyfikacji Kiedy: Musisz poradzić sobie ze skomplikowanymi zależnościami/ integralnością referencyjną
W projektach zależnych od danych, które wymagają złożonej konfiguracji, obiekty rzadko mogą być tworzone w kompletnym oderwaniu od siebie. Na przykład zasady walidacji domeny dla metody płatności mogą wymagać istnienia klienta, który z kolei musi mieć ważne konto, i tak dalej.
Wiele zespołów popełniło błąd umieszczenia w specyfikacji wszystkich konfiguracji i ustawień dla wszystkich przesłanek. Mimo że to sprawia, iż specyfikacja staje się jasna i kompletna z perspektywy konceptualnej, automatycznie staje się jednak trudna w odbiorze i niełatwa do zrozumienia.
Ponadto każda zmiana jakiegokolwiek obiektu lub atrybutu w konfiguracji doprowadzi do błędu testu bazującego na takiej specyfikacji, nawet jeśli nie jest on bezpośrednio związany z określoną regułą. Jasne i wyraźne opisanie wszystkich zależności może również doprowadzić do ukrycia problemów związanych z danymi, co jest szczególnie niebezpieczne w przypadku projektów bazujących na danych. Jonas Bandi pracował nad projektem nowej wersji istniejącego systemu zarządzania danymi dla szkół, w którym jednym z największych problemów było zrozumienie znaczenia istniejących danych. Zespół stworzył specyfikacje, które ustalały cały kontekst dynamicznie. Kontekst w tej specyfikacji został oparty na założeniu zespołu, a nie na realnych układach danych. Gdy gdzieś w połowie iteracji doszło do uruchomienia kodu i połączenia z danymi pochodzącymi z istniejącego systemu, zespół wykrył wiele luk i niespójności wymogów (patrz sekcja „Przykłady powinny być realistyczne” w rozdziale 7.). Zespół Bekk Consulting pracujący dla Norwegian Dairy Herd Recording System musiał zmierzyć się z podobnym problemem, ale w innym obszarze. W tym przypadku projekt również dotyczył zarządzania danymi, z wieloma obiektami wymagającymi złożonej konfiguracji. Początkowo zespół definiował cały kontekst w każdej kolejnej wykonywalnej specyfikacji. A to wymagało umiejętności idealnego odgadywania wszystkich zależności. Gdyby brakowało jakichś danych, testy oparte na specyfikacji kończyłyby się niepowodzeniem z powodu ograniczeń integralności danych, nawet jeśli kod zostałby prawidłowo zaimplementowany. Tego rodzaju problemy mogą być lepiej rozwiązane w warstwie automatyzacji, a nie w specyfikacji. Przenieś wszystkie zależności, które nie są związane z celem specyfikacji, do
164
Specyfikacja na przykładach
warstwy automatyki i utrzymaj specyfikację zogniskowaną na najważniejszych atrybutach i obiektach. Zapoznaj się z akapitem „Zarządzanie danymi testowymi” w rozdziale 9., gdzie znajdziesz kilka podpowiedzi rozwiązań problemów zarządzania danymi technicznymi.
Zastosuj ustawienia domyślne w warstwie automatyzacji
Przenieś odpowiedzialność za tworzenie prawidłowego obiektu do warstwy automatyzacji.
W warstwie automatyzacji można wstępnie zapełnić obiekty sensownymi danymi domyślnymi i skonfigurować zależności tak, żeby nie trzeba było określać ich bezpośrednio w specyfikacji. To pozwala nam skupić się jedynie na ważnych atrybutach specyfikacji, co czyni je o wiele łatwiejszymi do zrozumienia i utrzymania. Na przykład zamiast wymagać podania wszystkich danych adresowych do skonfigurowania konta klienta i wszystkich atrybutów do poprawnego zarejestrowania karty kredytowej, możemy uznać, że przed dokonaniem płatności użytkownik ma 100 dolarów dostępne na karcie. Cała reszta może być wykonana dynamicznie przez warstwę automatyzacji. Takie domyślne wartości można ustawić w warstwie automatyzacji lub wprowadzić przez plik konfiguracji globalnej, w zależności od tego, czy użytkownicy biznesowi będą mieli możliwość ich zmiany.
Nie polegaj na domyślnych wartościach w każdym przypadku Kiedy: Pracujesz z obiektami o wielu atrybutach
Mimo że bazowanie na rozsądnych atrybutach sprawia, iż specyfikacje są łatwiejsze do napisania i zrozumienia, niektóre zespoły posuwają się za daleko. Usuwanie powieleń na ogół jest dobra praktyką programowania, ale okazuje się, że nie zawsze jest równie dobre dla specyfikacji.
Jeśli kluczowy atrybut przykładu jest identyczny z domyślną wartością dostarczaną przez warstwę automatyzacji, zawsze warto określić go autorytarnie, chociaż może być pominięty.
Dzięki temu specyfikacja będzie zawierać kompletny kontekst potrzebny temu, kto będzie się z nią zapoznawał, ale także pozwoli nam na zmianę ustawień domyślnych w warstwie automatyzacji. Ian Cooper ostrzega: Nawet jeżeli [atrybut przykładu] jest w gruncie rzeczy taki sam jak wartość domyślna, nie polegaj na tej równoważności. Zdefiniuj go bezpośrednio. Dzięki temu można w dowolnym momencie zmienić wartości domyślne. W tej sytuacji nie ma żadnych wątpliwości, co jest ważne. Kiedy czytasz specyfikacje, szybko zorientujesz się, że przykład definiuje te wartości produktu, i wtedy możesz zapytać: »Dlaczego to jest takie ważne?«.
Rozdział 8. Udoskonalanie specyfikacj
165
Specyfikacje powinny być napisane w języku domeny Specyfikacje funkcjonalne są ważne zarówno dla użytkowników, jak i analityków biznesowych oraz testerów i deweloperów, a także dla każdego, kto próbuje zrozumieć działanie systemu. Aby specyfikacja była łatwa w odbiorze i czytelna dla wszystkich tych grup, musi być napisana w języku, który zrozumie każdy. Język używany w specyfikacji musi być również spójny, a terminologia — konsekwentna. Pozwoli to zminimalizować potrzebę tłumaczenia i zmniejszyć prawdopodobieństwo nieporozumień. Język wszechobecny (patrz ramka) idealnie odpowiada na te potrzeby, spełniając oba wymagania. Upewnij się, że podczas definiowania specyfikacji posługujesz się językiem wszechobecnym, i uważaj na nazwy klas lub pojęcia, które wydają się wymyślone na potrzeby testowania i brzmią jak koncepcje implementacji oprogramowania. Język wszechobecny Zespoły zajmujące się wytwarzaniem oprogramowania często na potrzeby projektu tworzą swój własny żargon, bazując przy tym na technicznych koncepcjach implementacji. Taki żargon różni się od żargonu używanego przez użytkowników biznesowych, co wymusza ciągłe tłumaczenia, gdy przedstawiciele tych grup się spotykają. W takiej sytuacji role tłumaczy biorą na siebie analitycy biznesowi, stając się tym samym wąskim gardłem procesu komunikacji. Podczas wymiany zdań zdefiniowanych z użyciem obu żargonów zdarza się, że jakieś informacje giną w tłumaczeniu, a to prowadzi do nieporozumień. Eric Evans zaproponował w swojej książce zatytułowanej Domain-Driven Design†, aby zamiast tworzyć warunki sprzyjające rozwijaniu się obu żargonów, opracować wspólny język będący podstawą do osiągnięcia konsensusu i zrozumienia domeny. Nazwał ten język wszechobecnym (ang. Ubiquitous Language). _______________ Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley Professional, 2003. †
Poprzez zapewnienie, by specyfikacje spełniały założenia określone w niniejszym rozdziale, możemy zagwarantować sobie dobry cel dla rozwoju oprogramowania i dysponowanie dokumentacją, która będzie miała sporą wartość jako długoterminowe narzędzie komunikacji. Te elementy będą naszymi cennymi zasobami w czasie trwania całego projektu wytwarzania systemu oraz w trakcie stopniowego budowania żyjącej dokumentacji.
Udoskonalanie specyfikacji w praktyce Zajmijmy się teraz poprawieniem kiepskiej specyfikacji, z którą zapoznałeś się na początku tego rozdziału. Po pierwsze, powinniśmy nadać jej piękny opisowy tytuł, np. „Wydruk potwierdzenia wypłaty”, aby mieć pewność, że łatwo do niej dotrzemy, jeśli będzie nam później potrzebna. Trzeba też dodać akapit, który wyjaśni cel zdefiniowania tej specyfikacji. Zidentyfikowaliśmy następujące zasady:
166
Specyfikacja na przykładach
System drukuje jedno potwierdzenie dla jednego pracownika, zawierające imię i nazwisko zatrudnionej osoby, jej adres i wysokość wynagrodzenia. System drukuje datę płatności. Numery potwierdzeń są unikalne, począwszy od następnej wolnej liczby potwierdzenia w porządku rosnącym. Potwierdzenia są drukowane w porządku alfabetycznym, według nazwiska pracownika. Na potwierdzeniu znajdujemy nazwisko beneficjenta, kwotę oraz termin płatności. Na potwierdzeniu nie ma nazwy ani wysokości pensji — to są atrybuty pracownika. Jeśli drukujemy potwierdzenia w ramach korespondencji, która będzie wysyłana automatycznie, możemy powiedzieć, że potwierdzenie będzie zawierać również adres używany do automatycznego adresowania kopert. Narzućmy wykorzystanie wszechobecnego języka i konsekwentnie wybranych terminów. Kombinacja imienia i nazwiska oraz adresu powinna wystarczyć do dopasowania pracowników do ich potwierdzeń — nie potrzebujemy identyfikatorów bazy danych. Możemy ułatwić testowanie systemu, zgadzając się na zasady porządkowe (jakiekolwiek wybierzemy). Na przykład załóżmy, że potwierdzenia będą drukowane w porządku alfabetycznym według nazwiska pracownika. Możemy zaproponować to rozwiązanie klientowi, zapewniając, że dzięki temu nasza specyfikacja będzie bardziej spójna. Aby specyfikacja nie wymagała dodatkowych wyjaśnień, wyciągnijmy kontekst i umieśćmy go w nagłówku. Data płatności oraz następny dostępny numer porządkowy potwierdzenia stanowią część kontekstu, podobnie jak dane dotyczące wysokości wynagrodzenia pracowników. Musimy też zadbać, aby liczba ta była jednoznaczna, tak by ludzie, którzy będą czytać tę specyfikację, nie gubili się w domysłach. Użyjmy terminu „Następny wolny numer potwierdzenia”. Możemy również postarać się, aby specyfikacja była łatwiejsza do zrozumienia, wyróżniając kontekst wizualnie, tak by pokazać, że ma ona wstępnie przygotowywać dane, a nie przeprowadzać ich testowanie. Działanie, które będzie konsekwencją wykonania wydruku, wcale nie musi być opisane w specyfikacji. Wypłata wynagrodzeń może być wykonywana domyślnie z wykorzystaniem danych z tabeli, w której sprawdza się wyniki dotyczące płac. To jest przykład podkreślający to, co testujemy, a nie jak. Nie ma potrzeby uzupełniania specyfikacji o dodatkowy krok, w którego opisie przeczytamy: „A teraz wypłacamy pensje”. Inspektor płac jest elementem wymyślonym specjalnie na potrzeby tej specyfikacji i narusza zasadę wszechobecnego języka. Nie jest to jakieś specjalistyczne pojęcie domeny, więc wyjaśnijmy to, co robi, tak, żeby wszyscy potrafili to zrozumieć. Ponieważ chcemy zagwarantować, by każdy, kto automatyzuje walidację, sprawdzał wszystkie wydrukowane potwierdzenia, użyjmy zwrotu „Wszystkie potwierdzenia wydrukowane”. W przeciwnym razie ktoś mógłby użyć części podzbioru, system mógłby drukować każde potwierdzenie dwa razy, a my byśmy tego nie zauważyli. Poprawiona wersja specyfikacji została przedstawiona na rysunku 8.2. Ta wersja jest krótsza i nie ma w niej zupełnie przypadkowego bałaganu, jaki widzieliśmy w pierwszej specyfikacji. Jest przy tym o wiele łatwiejsza do zrozumienia. Po udosko-
Rozdział 8. Udoskonalanie specyfikacj
167
Rysunek 8.2. Poprawiona wersja specyfikacji pokazanej na rysunku 8.1. Zwróć uwagę, że ta specyfikacja jest krótsza i nie wymaga dodatkowych wyjaśnień oraz zawiera jednoznaczny tytuł
naleniu tej specyfikacji możemy próbować odpowiedzieć sobie na pytanie: „Czy czegoś nam brakuje?”. O tym, czy specyfikacja jest kompletna, możemy przekonać się, eksperymentując z argumentami wejściowymi i starając się zdefiniować przypadki brzegowe, które mogą być danymi poprawnymi, ale naruszającymi obowiązujące reguły. (Nie ma potrzeby przetestowania poprawności danych pracowników, bo to należy sprawdzić w innej części systemu). Jedną z zasad heurystycznych stosowaną na potrzeby takich eksperymentów z danymi jest odwołanie się do numerycznych warunków brzegowych. Co się na przykład stanie, jeśli wynagrodzenie pracownika wynosi „0”? Wartość zerowa jest poprawna. Pracownik może przebywać na bezpłatnym urlopie lub wypłata jego pensji jest wstrzymana albo już dla nas nie pracuje. Czy potwierdzenie przelewu wypłaty z wartością zerową powinno być drukowane? Jeśli mamy trzymać się zasady „jeden przelew dla jednego pracownika”, wszyscy nasi pracownicy, nawet ci, których zwolniliśmy przez ostatnie lata i którzy nie otrzymują pensji, wciąż będą dostawać potwierdzenia przelewów o wartości zerowej. W takiej sytuacji moglibyśmy zaproponować użytkownikom biznesowym zawężenie warunków, żeby system nie drukował potwierdzeń, których drukować nie musi. W zależności od tego, czy system wypłat z listy płac jest jedynym przypadkiem użycia specyfikacji „Wydruk potwierdzenia wypłaty”, może pojawić się potrzeba dalszego jej ulepszenia i podzielenia na kilka specyfikacji. Jedna z nich mogłaby opisywać zmodyfikowany model funkcji wydruku, na przykład zakładający zastosowanie unikalnych kolejnych numerów potwierdzeń. Inna specyfikacja mogłaby opisywać funkcje typowe dla listy płac, na przykład zliczanie liczby wydrukowanych potwierdzeń albo sprawdzanie prawidłowości wypłacanego wynagrodzenia i tak dalej.
168
Specyfikacja na przykładach
Tu nie chodzi o narzędzia Wiele osób narzeka na FitNesse, podkreślając fakt, że to narzędzie zawiera niepoprawne wykonywalne specyfikacje, takie jak ta pokazana na rysunku 8.1. Narzędzia takie jak Concordion zostały opracowane właśnie w celu wyeliminowania problemów tego typu. Inne narzędzia — na przykład Cucumber — mają przekonać nas do tekstowego modelu Zakładając/Jeżeli/Wtedy, który ma pozwolić nam uniknąć pułapki złożonych tabel, trudnych do zrozumienia. Zanim wyciągniesz pochopne wnioski i stwierdzisz, że jakieś narzędzie rozwiązuje Twoje problemy, powinieneś wiedzieć, że widziałem podobne kiepskie specyfikacje napisane przy użyciu niemal każdego z najbardziej popularnych narzędzi. Problem nie ma swojego źródła w narzędziu. Według tej samej logiki — rozwiązaniem nie jest także narzędzie samo w sobie. Największe zagrożenie dla procesu zawsze znajdziesz w zespole, który nie stara się uczynić specyfikacji zrozumiałą. Poprawienie specyfikacji nie jest wielkim wysiłkiem, ale efekt takiego udoskonalenia będzie miał ogromną wartość.
Korzyści z udoskonalania specyfikacji czasem nie stają się natychmiast oczywiste, ponieważ to dzięki współpracy udaje nam się doprowadzić do sytuacji, w której wszyscy tak samo rozumieją oczekiwaną funkcję. Dlatego wiele zespołów nie docenia znaczenia udoskonalania specyfikacji i ostatecznie kończy z ogromnymi zbiorami dokumentów, które są trudne do zrozumienia. Udoskonalanie specyfikacji na podstawie kluczowych przykładów jest ważnym krokiem, którego wykonanie stanowi gwarancję, że nasze dane mają wartość długoterminową jako narzędzie komunikacji i stworzą dobre podstawy dla systemu żyjącej dokumentacji.
Pamiętaj Nie spoczywaj na laurach, ograniczając się do użycia pierwszego zestawu przykładów; wykorzystaj przykłady do udoskonalenia specyfikacji. Aby maksymalnie wykorzystać przykłady, specyfikacja zbudowana na ich podstawie powinna być precyzyjna i testowalna, oczywista na tyle, by nie wymagać dodatkowych wyjaśnień, zogniskowana, sformułowana w języku domeny i powinna dotyczyć funkcji biznesowej. Unikaj skryptów i mówienia w specyfikacji o projektowaniu oprogramowania. Nie próbuj opisywać w specyfikacji każdego możliwego przypadku. Specyfikacje nie są zamiennikami testów regresji kombinatorycznej. Zacznij od jednego przykładu dla każdego ważnego zbioru przypadków i dodaj do specyfikacji przykłady ilustrujące poszczególne obszary zainteresowania programistów i testerów. Zdefiniuj język wszechobecny i używaj go podczas tworzenia specyfikacji, projektów oprogramowania i testów.
9
Automatyczna walidacja bez zmiany specyfikacji
P
o udoskonaleniu specyfikacji funkcji stanie się ona jasnym celem dla implementacji oraz precyzyjną metodą sprawdzenia warunków ukończenia. Udoskonalona specyfikacja pozwoli nam także w przyszłości sprawdzić, czy nasz system po każdej zmianie nadal ma wymaganą funkcjonalność. Ze względu na poziom szczegółowości, który otrzymujemy dzięki zilustrowaniu specyfikacji poprzez przykłady, ręczne wykonywanie wszystkich testów w krótkich iteracjach staje się niemożliwe, nawet w przypadku projektów średniej wielkości. Rozwiązanie jest oczywiste: musimy zautomatyzować możliwie największą liczbę tych testów. Prawidłowa automatyzacja walidacji specyfikacji z przykładami jest czymś zupełnie innym niż tradycyjna automatyzacja testów typowych dla projektów informatycznych. Jeśli podczas automatyzacji konieczna okaże się poważna zmiana specyfikacji, znów będzie trzeba zacząć bawić się (głuchym) telefonem, a korzyści wynikające z udoskonalenia specyfikacji zostaną utracone. Najlepiej byłoby, gdybyśmy zautomatyzowali procesy walidacji naszych specyfikacji bez zniekształcania zawartych w nich informacji. Taki warunek wprowadza jednak dodatkowy zestaw wyzwań, które uzupełniają listę trosk wynikających z potrzeby automatyzacji testów. W tym rozdziale udzielę kilku wskazówek na temat rozpoczęcia procesu automatyzacji walidacji specyfikacji bez wprowadzania zmian i tego, jak kontrolować długoterminowe koszty utrzymania zautomatyzowania. Potem omówię dwa obszary, które powodowały najwięcej problemów ankietowanym przeze mnie zespołom: automatyzację interfejsów użytkownika i zarządzanie danymi automatycznych przebiegów testowych. Działania, które przedstawię w tym rozdziale, mogą być zastosowane w połączeniu z każdym narzędziem. Nie będę omawiać szczegółów w podziale na narzędzia, ale jeśli interesuje Cię poruszony temat, zajrzyj na stronę http://specificationbyexample.com, skąd można pobrać dodatkowe artykuły. Najpierw jednak odpowiemy sobie na pytanie, które często słyszę i widzę przy okazji lektury list dyskusyjnych i forów — czy w ogóle potrzebujemy tego typu automatyzacji? Ponieważ automatyzacja jest problemem czysto technicznym, ten rozdział będzie bardziej techniczny niż inne. Jeśli nie jesteś programistą lub specjalistą ds. automatyzacji, może
170
Specyfikacja na przykładach
Jak to działa? Wszystkie najpopularniejsze narzędzia do automatyzacji wykonywalnych specyfikacji współpracują z dwoma rodzajami artefaktów: specyfikacjami w postaci czytelnej dla człowieka oraz kodem automatyzacji w języku programowania. W zależności od narzędzia specyfikacje mogą mieć postać zwykłego tekstu, HTML lub innego formatu, rozumianego przez człowieka. Narzędzia „wiedzą”, jak wydobyć dane wejściowe i oczekiwane wyniki ze specyfikacji tak, aby przekazać je do kodu automatyzacji i oszacować, czy wyniki odpowiadają oczekiwaniom. Kod automatyzacji, wraz narzędziami zwanymi fiksturami (ang. fixtures) lub definicjami kroków (ang. step definitions), odwołuje się do API aplikacji, współdziała z bazą danych lub wykonuje działania za pośrednictwem interfejsu użytkownika aplikacji. Kod automatyzacji zależy od specyfikacji, ale nie na odwrót. To właśnie tak narzędzia te pozwalają na automatyzację walidacji specyfikacji bez ich zmiany. Niektóre narzędzia wymagają od zespołów przechowywania przykładów w kodzie języka programowania i generowania na tej podstawie specyfikacji czytelnych dla człowieka. Z technicznego punktu widzenia osiągają ten sam efekt, ale takie narzędzia skutecznie uniemożliwiają tworzenie lub aktualizację specyfikacji każdemu, kto nie potrafi biegle posługiwać się kodem języka programowania.
się okazać, że będziesz mieć trudności ze zrozumieniem kilku jego części. W takim wypadku proponuję, żebyś zapoznał się z dwiema pierwszymi, a potem pominął resztę. Nie stracisz niczego, co by mogło naprawdę Cię zainteresować.
Czy automatyzacja jest w ogóle potrzebna? Koszt utrzymania wykonywalnych specyfikacji w ujęciu długoterminowym jest jednym z największych problemów, z którymi muszą poradzić sobie zespoły wdrażające specyfikację przez przykłady. Narzędzia do automatyzacji wykonywalnych specyfikacji błyskawicznie ewoluują i stają się coraz lepsze, ale pod względem łatwości obsługi i integracji z narzędziami wytwarzania oprogramowania wciąż daleko im do bardziej uznanych aplikacji służących do wykonywania testów jednostkowych. Automatyzacja oznacza również obciążenie zespołu dodatkową pracą. To często prowadzi do dyskusji na temat tego, czy automatyzacja jest niezbędna i czy w ogóle przypadkiem nie kosztuje więcej, niż jest warta. Argumentem przeciwko zastosowaniu automatyzacji jest fakt zwiększania w ten sposób obciążenia pracą zespołów zajmujących się wytwarzaniem i utrzymaniem oprogramowania oraz to, że zespoły mogą wypracować sobie takie samo wyobrażenie zakresu niezbędnych prac dzięki wykorzystaniu przykładów ilustrujących bez automatyzacji. Phil Cowans stwierdza, że taki pogląd prowadzi do rezygnacji z długoterminowych korzyści wynikających z wdrożenia specyfikacji przez przykłady: Może się wydawać, że musisz stworzyć dwa razy więcej kodu, by zdefiniować tę samą funkcjonalność. Ale liczba linii kodu nie jest prawdopodobnie czynnikiem ograniczającym w procesie rozwoju, więc takie myślenie jest dość naiwne.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
171
Nie uwzględniasz przy tym faktu, że automatycznie poświęcasz mniej czasu na utrzymywanie tego, co właśnie wykonałeś, lub nie bierzesz pod uwagę czasu niezbędnego na wyjaśnianie nieporozumień pomiędzy deweloperami i testerami. Uogólniając, automatyzacja jest ważna dla większych zespołów, ponieważ stanowi bezstronną, obiektywną metodę sprawdzającą kryteria ukończenia. Ian Cooper przywołuje w tym miejscu pasującą analogię: Gdy jestem zmęczony i zmywam naczynia, nie mam już ochoty wycierać ich do sucha. Wszystko umyłem. To prawie koniec. Missus patrzy na to i wcale nie myśli, że skończyłem. Dla niej »zrobione« będzie wtedy, gdy naczynia będą suche i odstawione na miejsce, a zlew pusty. [Automatyzacja] zmusza deweloperów do uczciwego podejścia do swojej pracy. Nie mogą robić tylko tych części, które ich interesują. Automatyzacja ma również ogromne znaczenie w perspektywie długoterminowej, ponieważ pozwala nam częściej sprawdzać większą liczbę przypadków. Pierre Veragen stwierdza, że menedżerowie w jego firmie szybko zrozumieli, jak wielką ma wartość: Nagle menedżerowie zorientowali się, że zamiast metody sprawdzania jednej lub trzech wartości w czasie całego testu, mamy teraz coś, co pozwala sprawdzić 20 lub 30 pozycji więcej i co pozwoli łatwiej wskazać źródła problemów. Niektóre zespoły obniżyły koszty automatyzacji, przenosząc ją do kategorii narzędzi technicznych. Gdy zbierałem materiały do tej książki, byłem bardzo zaskoczony, że Jim Shore, jeden z liderów społeczności promującej metodykę zwinną oraz jeden z pierwszych praktyków specyfikacji przez przykłady, zrezygnował z automatyzacji wykonywalnych specyfikacji z powodu wysokich kosztów metody1. Jim Shore stwierdził, że z jego doświadczeń wynika, iż ilustrowanie przy użyciu przykładów przynosi większe korzyści niż automatyzacja walidacji bez zmiany specyfikacji: Moje doświadczenia z FIT i innymi zwinnymi narzędziami do testów akceptacyjnych każą mi stwierdzić, że kosztują one więcej, niż są warte. Uzyskanie konkretnych przykładów od prawdziwych klientów i ekspertów biznesowych ma o wiele większą wartość niż ta, jaką można uzyskać przy użyciu narzędzi wykorzystujących »język naturalny«, takich jak FIT i jemu podobne. 1
Część naszej korespondencji została opublikowana w internecie. Sprawdź następujące adresy: http:// jamesshore.com/Blog/Alternatives-to-Acceptance-Testing.html, http://jamesshore.com/Blog/The-Problems-WithAcceptanceTesting.html oraz http://gojko.net/2010/03/01/are-tools-necessary-for-acceptance-testing-or-are-they-just-evil/. W sieci znajdziesz także łącza do opinii innych członków społeczności na temat tych artykułów. Gorąco zachęcam do zapoznania się z tymi materiałami, a zwłaszcza z argumentacją Shore’a dotyczącą alternatyw dla automatyzacji wykonywalnych specyfikacji.
172
Specyfikacja na przykładach
Z kolei na podstawie własnych doświadczeń mogę powiedzieć, że upór przy niestosowaniu automatyzacji wykonywalnych specyfikacji może — w perspektywie krótkoterminowej — zaoszczędzić Twój czas, ale uniemożliwi zespołowi wykorzystanie niektórych z najważniejszych długoterminowych korzyści specyfikacji przez przykłady. Przy podejmowaniu decyzji o automatyzacji walidacji specyfikacji przy użyciu narzędzi technicznych lub takiego, które dotyczy wykonywalnych specyfikacji, rozważ znaczenie korzyści, jakie zamierzasz uzyskać. W tym pierwszym przypadku mamy do czynienia z łatwiejszą automatyzacją i obniżeniem kosztów utrzymania, ale tracimy możliwość wykorzystania narzędzi technicznych do komunikacji z użytkownikami biznesowymi w późniejszym czasie. Otrzymujemy bardzo dobre testy regresji, ale specyfikacje będą dostępne tylko dla deweloperów. Taka sytuacja — w zależności od kontekstu — może nie być możliwa do zaakceptowania. Automatyzacja walidacji specyfikacji bez zmian jest kluczowym elementem prowadzącym do uzyskania żyjącej dokumentacji. Bez niej nie możemy zagwarantować poprawności specyfikacji czytelnej dla człowieka. W przypadku wielu zespołów długoterminowe korzyści wynikające z wdrożenia specyfikacji przez przykłady sprowadzają się do zalet żyjącej dokumentacji. Zamiast rezygnować z automatyzacji, która zachowuje oryginalne specyfikacje, możemy raczej popracować nad zmniejszeniem kosztów jej zachowania. Wiele dobrych metod stosowanych w celu zmniejszenia kosztów utrzymania automatyzacji w dłuższej perspektywie znajdziesz w części zatytułowanej „Zarządzanie warstwą automatyzacji” w dalszej części tego rozdziału, a także w rozdziale 10.
Rozpoczęcie automatyzacji Zautomatyzowana walidacja wykonywalnych specyfikacji różni się od testów jednostkowych, rejestrowanej i wykorzystującej skrypty automatyzacji funkcjonalnej, do której przywykli deweloperzy i testerzy. Automatyzacja przy zachowaniu czytelności treści wymaga od zespołów nauczenia się korzystania z nowych narzędzi i zdefiniowania najlepszego sposobu wykorzystania automatyzacji w systemie. Na kolejnych stronach znajdziesz kilka pomysłów dotyczących tego, jak zacząć proces automatyzacji, a także opis niektórych typowych błędów, popełnianych przy tej okazji przez zespoły, z którymi rozmawiałem.
Aby poznać narzędzia, wypróbuj je najpierw w prostym projekcie Kiedy: Pracujesz z istniejącym systemem
Kilka zespołów wykorzystało jakiś prosty projekt lub impuls testowy (ang. spike)2, aby dowiedzieć się, jak najlepiej używać nowego narzędzia automatyzacji. Jeśli masz jakieś małe zlecenie, relatywnie niezależne od pozostałych projektów, wówczas wykorzystanie go w funkcji poletka doświadczalnego może okazać się naprawdę dobrym pomysłem. 2
W kilku dostępnych na polskim rynku pozycjach spotyka się różne definicje słowa spike. Patrz np. Mariusz Chrapko, Scrum. O zwinnym zarządzaniu projektami, s. 155, 186 (tam: historyjka badawcza). Rzecz w tym, że nie zawsze musi chodzić o historyjkę, a istotą rozwiązania jest przetestowanie jakiegoś scenariusza lub rozwiązania w możliwie nieskomplikowanych warunkach, po odrzuceniu niepotrzebnych zmiennych. Patrz także http://www.extremeprogramming.org/rules/spike.html — przyp. tłum.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
173
Mały projekt minimalizuje ryzyko i pomaga w lepszym skupieniu się na wyciąganiu wniosków z nauki wykorzystania narzędzia, a nie zmusza do radzenia sobie ze złożonymi integracjami i regułami biznesowymi.
To podejście okazuje się szczególnie skuteczne, jeśli chcesz wdrożyć specyfikację przez przykłady w tym samym czasie co zwinną metodykę wytwarzania oprogramowania. Zespół uSwitch zastosował tę metodę przy wprowadzaniu Cucumbera, innego popularnego narzędzia do automatyzacji wykonywalnych specyfikacji. Cały zespół rozpoczął proces przenoszenia istniejących testów do nowego narzędzia. Dzięki temu wszyscy członkowie zespołu mogli szybko nabrać wprawy w posługiwaniu się nowym narzędziem. Stephen Lloyd mówi, że dzięki temu wszyscy zrozumieli także, jak wielką wartością są wykonywalne specyfikacje: Zdaliśmy sobie sprawę, że istnieje cały dodatkowy poziom testów, które trzeba zrobić, i że testy przeprowadzane na koniec cyklu nie mają sensu. Mniejszy projekt jest okazją do poznania i wyćwiczenia nowych umiejętności bez większego ryzyka, jakie trzeba byłoby ponieść w przypadku pracochłonnego, trwającego już projektu, dlatego w tym przypadku uzyskanie zgody kierownictwa może być o wiele łatwiejsze niż w sytuacji, gdybyś wnioskował o eksperymentowanie z projektem większym, którego realizacja automatycznie wiąże się z o wiele większym ryzykiem. Dobrym pomysłem może być uzyskanie opinii zewnętrznego konsultanta na temat osiągniętych efektów. Gdy stworzysz coś, co może być przedmiotem analizy, zewnętrzni konsultanci będą w stanie zapewnić znacznie bardziej sensowny feedback i będą mogli zaproponować lepsze rozwiązania. Wcześniej zespół będzie miał również szansę wypróbowania narzędzi i poznania pewnych podstaw, tak aby członkowie mogli zrozumieć bardziej zaawansowane techniki i lepiej wykorzystać czas pracy konsultanta.
Zaplanuj automatyzację z wyprzedzeniem Zespoły pracujące nad systemami, które nie zostały zawczasu przygotowane do testów automatycznych, tuż po rozpoczęciu automatyzacji wykonywalnych specyfikacji powinny spodziewać się spadku produktywności. Nawet bez nauki podstaw użycia nowego narzędzia automatyzacja walidacji początkowo zwiększa obciążenia projektowe. Koszty automatyzacji ponosi się z wyprzedzeniem — musisz przygotować się, że podczas uruchomiania procesów automatyzacji czeka Cię dużo pracy. Zakres prac obejmuje stworzenie podstawowych elementów automatyki, wypracowanie najlepszej formy wykonywalnych specyfikacji i najlepszych metod integracji z systemem, rozwiązywanie problemów ze stabilnością testów, środowisk dedykowanych i wiele innych zadań. W tym rozdziale (a także w rozdziale 10.) mówimy o większości spośród
174
Specyfikacja na przykładach
wymienionych tu zagadnień, jednak przede wszystkim najważniejsze jest to, by zrozumieć, że po rozpoczęciu automatyzacji wydajność zespołu bez wątpienia ulegnie pogorszeniu. Gdy uda się zaakceptować nową sytuację, a struktura wykonywalnych specyfikacji ustabilizuje się, będzie można wykorzystać ponownie podstawowe elementy automatyzacji podczas prac nad nowymi specyfikacjami. W miarę dojrzewania projektu automatyzacja będzie wiązać się z coraz mniejszym wysiłkiem, a wydajność zespołu poszybuje w górę. W kilku znanych mi projektach deweloperzy nie uwzględnili tej zmiany podczas szacowania kosztów implementacji historyjki. Jednak warto pamiętać, że na pierwszym etapie wdrażania automatyzacja wykonywalnych specyfikacji będzie wymagać większego wysiłku niż implementacja niezbędnych zmian w kodzie produkcyjnym.
Zadbaj, aby zawczasu przygotować się na spadek wydajności. Zespół powinien obniżyć nieco poprzeczkę zakresu w celu umożliwienia wdrożenia automatyzacji w ramach jednej iteracji.
Jeśli takiego planowania zabraknie, automatyzacja przedłuży się i przeniesie na następną iterację, zakłócając naturalny cykl. O niekorzystnych konsekwencjach braku planowania przekonał się André Brissette, dyrektor produktu Talia w Pyxis Technologies: Gdybym miał zrobić to jeszcze raz, od początku byłbym bardziej wymagający w kwestii pisania testów [wykonywalnych specyfikacji]. Wiedziałem, że tworzenie takich testów będzie dla zespołu wyzwaniem, więc byłem cierpliwy. Mogłem także przeznaczyć większą część sprintu [iteracji] na testy. Moglibyśmy je uruchomić, a następnie porozmawiać o wykonywalnych specyfikacjach. Zespół mógłby stwierdzić: »Tak naprawdę nie mamy czasu na uczenie się, ponieważ jesteśmy nieźle obciążeni w tym sprincie«. W rzeczywistości jedną z przyczyn tego, że byli tak obciążeni, było to, że sam naciskałem na wykonanie w tym sprincie wielu funkcji. W związku z tym wdrażanie testów przebiegało powoli i minęło wiele iteracji, zanim opracowaliśmy wreszcie przyzwoity zestaw specyfikacji. Być może bardziej opłacalne byłoby rozbicie tego muru już na samym starcie i lepiej byłoby założyć zrealizowanie na początku mniejszej liczby funkcji. Następnym razem wybiorę właśnie takie rozwiązanie. Jeśli rozłożysz integrację tego rodzaju na dłuższy czas, ponosisz jej koszty, nie odczuwając korzyści. Ostatecznie projekt jest droższy. Jednym z pomysłów na to, aby sprawnie zaplanować wpływ pierwszego obciążenia automatyzacją, jest potraktowanie jej jak zestawu narzędzi stanowiących oddzielny produkt z własnym rejestrem, a następnie przeznaczenie pewnej części czasu zespołu na potrzeby pracy nad tym „produktem”. By wszystko było jasne: produkt podstawowy i zestaw narzędzi automatyzacji powinny być opracowane i dostarczone przez ten sam zespół, co ma stanowić gwarancję, że zespół zapozna się z warstwą automatyzacji. Radzę potraktować testy jak osobny produkt wyłącznie w celu ograniczenia ich negatywnego wpływu na dostarczany produkt podstawowy.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
175
Nie opóźniaj i nie odsuwaj od siebie prac związanych z automatyzacją Ze względu na konieczność poniesienia dodatkowych kosztów niektóre zespoły próbują opóźniać wdrożenie automatyzacji. Zdefiniowały specyfikacje z przykładami, a potem napisały kod, odkładając automatyzację na później. Wydaje się, że ten problem dotyczy projektów, w których zespoły rozwoju i automatyzacji testów pracowały niezależnie lub korzystały z pomocy zewnętrznych konsultantów, zajmujących się automatyzacją testów. To powodowało konieczność wielu przeróbek i bywało źródłem niepokojów i zamieszania. Deweloperzy oznaczali historyjki użytkowników jako ukończone bez obiektywnego, zautomatyzowanego kryterium. Kiedy testy akceptacyjne ostatecznie zostały zautomatyzowane, często pojawiały się z nimi różnego rodzaju problemy, a historyjki trzeba było odsyłać do poprawek. Kiedy automatyzacja jest dokonywana wraz z implementacją, deweloperzy muszą zaprojektować system tak, aby był zdatny do testowania. Gdy automatyzacją zostają obciążeni testerzy lub konsultanci, deweloperzy nie dbają o to, by dokonać implementacji w sposób, który ułatwia walidację. A to prowadzi do bardziej kosztownej i trudniejszej automatyzacji. W konsekwencji testy wydłużają się na następną iterację, zakłócając naturalny rytm pracy, gdy tylko pojawiają się powracające problemy.
Zamiast opóźniać automatyzację wykonywalnych specyfikacji z powodu dodatkowego nakładu pracy, zajmij się rozwiązywaniem problemów, żeby zadania wykonywane później stawały się coraz łatwiejsze.
Odkładanie automatyzacji jest tylko lokalną optymalizacją. Można szybciej poradzić sobie z historyjką (biorąc pod uwagę proces wytwarzania produktu), ale koniec końców problemami trzeba będzie się zajmować ponownie, gdy powrócą. David Evans często przy tej okazji przywołuje analogię z miejskimi autobusami: autobus mógłby jeździć dużo szybciej, gdyby nie musiał stawać na przystankach i zabierać pasażerów, ale wówczas tak naprawdę straciłby rację bytu.
Unikaj automatyzacji istniejących skryptów testów ręcznych Tworzenie wykonywalnej specyfikacji na podstawie skryptów testów ręcznych na początku może wydawać się czymś logicznym. Takie skrypty opisują już pracę systemu i testerzy i tak je uruchamiają, więc automatyzacja na pewno im pomoże, prawda? Nie bardzo. W rzeczywistości jest to jeden z najpowszechniej popełnianych błędów. Listy weryfikujące dla testów wykonywanych ręcznie i automatycznie są tworzone na podstawie całkiem różnego zestawu ograniczeń. Czas poświęcony na przygotowywanie kontekstu w testowaniu ręcznym często jest kluczowym wąskim gardłem. W przypadku testów automatycznych najwięcej czasu poświęca się na próby zrozumienia tego, co się stało, że test zakończył się niepowodzeniem. Żeby na przykład przygotować się do skryptu testowego, który sprawdza zasady zarządzania kontami użytkowników, tester może musieć zalogować się do aplikacji administracyjnej, utworzyć nowy profil użytkownika, zalogować się do aplikacji klienta jako nowy
176
Specyfikacja na przykładach
użytkownik i zmienić hasło po pierwszym użyciu. Aby uniknąć wielokrotnego powtarzania tych operacji w trakcie testu, tester wykorzysta ten sam kontekst na potrzeby kilku ręcznych skryptów. A zatem nowy użytkownik zostanie utworzony jeden raz, po czym jego konto zostanie zablokowane. Trzeba sprawdzić, czy użytkownik na pewno nie może się zalogować, po czym następuje zresetowanie hasła i sprawdzenie, czy konto zostało odblokowane. Później można ustalić pewne preferencje użytkownika i sprawdzić, czy system poprawnie zmienia stronę startową. Takie podejście pomaga testerowi przejść cały skrypt szybciej. W przypadku testu automatycznego czas spędzony na tworzeniu nowego profilu użytkownika nie jest już problemem. Zautomatyzowane testy zazwyczaj sprawdzają o wiele większą liczbę przypadków niż testy manualne. Kiedy działają prawidłowo, nikt tak naprawdę ich nie obserwuje. Jeśli jednak test automatyczny kończy się niepowodzeniem, ktoś musi sprawdzić, co poszło nie tak. Jeśli test jest opisany jako ciąg współzależnych etapów, bardzo trudno będzie zrozumieć, co jest prawdziwą przyczyną problemu, ponieważ kontekst ulega płynnym zmianom. Prawdopodobieństwo tego, że przebieg pojedynczego skryptu sprawdzającego dziesięć różnych rzeczy zakończy się błędem, jest większe niż prawdopodobieństwo błędu mniejszego, ukierunkowanego testu, ponieważ na ten pierwszy może wpływać wiele różnych obszarów kodu. W poprzednim przykładzie opisującym zarządzanie kontem użytkownika, jeśli przestaje działać funkcja resetowania hasła, nie będziemy w stanie poprawnie ustawić preferencji użytkownika. W konsekwencji test strony startowej również skończy się błędem. Gdybyśmy mieli dziesięć różnych, mniejszych, skupionych na poszczególnych zagadnieniach i niezależnych testów zamiast jednego wielkiego skryptu, błąd w funkcji resetowania hasła nie wpływałby na wyniki testów preferencji użytkownika. Podział sprawi, że testy będą bardziej odporne na zmiany, i zmniejszy koszty utrzymania ich sprawności. Dzięki temu będziemy mogli także szybciej zidentyfikować ewentualne problemy.
Zamiast po prostu automatyzować skrypty ręczne, pomyśl o tym, co taki skrypt sprawdza, i opisz to zestawem niezależnych, dedykowanych testów. W ten sposób znacznie zmniejszysz obciążenia automatyzacji i utrzymania sprawności.
Zdobądź zaufanie dzięki testom interfejsu użytkownika Kiedy: Członkowie zespołu są nastawieni sceptycznie do wykonywalnych specyfikacji
Wiele narzędzi do automatyzacji wykonywalnych specyfikacji umożliwia integrację z oprogramowaniem w warstwie poniżej interfejsu użytkownika. To zmniejsza koszty utrzymania i sprawia, że automatyzacja jest łatwiejsza do wdrożenia, oraz zapewnia szybszą wymianę informacji (patrz część zatytułowana „Automatyzacja pod skórą aplikacji” w dalszej części tego rozdziału). Jednak ani użytkownicy biznesowi, ani testerzy pierwotnie mogą nie mieć wielkiego zaufania do takiej automatyzacji. Nie widząc zmieniających się obrazów na własne oczy, nie wierzą, że właśnie w tym czasie faktycznie przebiega testowanie poprawnego kodu.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
177
Gdy zaczynasz dopiero wdrażanie specyfikacji przez przykłady, a ludzie z Twojego zespołu nie ufają automatyzacji, spróbuj wykonać specyfikację z poziomu interfejsu użytkownika. Pamiętaj, że nie powinieneś zmieniać specyfikacji, by opisać interakcje z interfejsem, ale możesz ukryć te funkcje w warstwie automatyzacji.
Sprawienie, że użytkownicy biznesowi zaufają wykonywalnym specyfikacjom, było jednym z kluczowych wyzwań stojących przed zespołem pracującym nad projektem Norwegian Dairy Herd Recording System. Børge Lotre, menedżer w Bekk Consulting, który został zaangażowany na potrzeby tego projektu, mówi, że zaufanie trzeba było budować stopniowo, w miarę wzrostu liczby sprawdzianów w wykonywalnych specyfikacjach: Oni [użytkownicy biznesowi] nalegali na wykonanie testów manualnych, które miały uzupełniać Cucumbera. Myślę, że widzą wartość testów Cucumbera, ponieważ nie są w stanie [ręcznie] testować starych wymagań za każdym razem, gdy dodawana jest nowa funkcjonalność. Wykonywalne specyfikacje zasadniczo powinny być automatyzowane z wykorzystaniem interfejsu użytkownika tylko w ostateczności, ponieważ takie rozwiązanie spowalnia feedback i znacznie zwiększa złożoność warstwy automatyzacji. Z drugiej strony wykonywanie zautomatyzowanych specyfikacji poprzez interfejs użytkownika może być dobrym wyborem, jeśli na początku projektu chcemy zdobyć zaufanie nietechnicznych użytkowników. Uczyń warstwę automatyzacji elastyczną, tak aby można było przejść na integrację poniżej poziomu zewnętrznej warstwy aplikacji. Automatyzacja wykonywalnych specyfikacji przez interfejs użytkownika jest dobrym rozwiązaniem również podczas pracy z istniejącym, dojrzałym systemem, który nie ma czystej integracji API (w tym przypadku jedyną słuszną metodą automatyzacji testów jest model end-to-end, począwszy od interfejsu, do którego dostęp ma użytkownik, i walidacja wyników w bazie danych albo ponownie przy użyciu interfejsu użytkownika). Uelastycznienie warstwy automatyzacji również jest w tym przypadku dobrym pomysłem, bo prawdopodobnie będziesz chciał przenieść ją na poziom niższy od interfejsu użytkownika, gdy tylko architektura stanie się bardziej sprawdzalna. Zaprezentowanie ludziom ekranów aplikacji podczas testów automatycznych, oprócz tego, że ma oczywisty cel, jakim jest budowa zaufania, czasami pomaga im w dochodzeniu do dodatkowych przykładów. Z moich doświadczeń oraz wniosków z analiz wielu studiów przypadku zebranych na potrzeby tej książki wynika, że wykonywanie testów za pośrednictwem interfejsu użytkownika nie za dobrze poddaje się skalowaniu. Liczbę testów wykonywanych za pośrednictwem interfejsu użytkownika możesz zmniejszyć, gdy już przekonasz do nich swoich interesariuszy. Jeśli zdecydujesz się na automatyzację specyfikacji za pośrednictwem interfejsu użytkownika, wykorzystaj podpowiedzi opisane w części zatytułowanej „Automatyzacja interfejsów użytkownika” na kolejnych stronach tego rozdziału, aby jak najlepiej wykorzystać zalety tej metody i zagwarantować sobie, że w razie potrzeby będziesz w stanie przenieść automatyzację poniżej interfejsu użytkownika.
178
Specyfikacja na przykładach
Zarządzanie warstwą automatyzacji Kontrolowanie kosztów utrzymania dla systemu żyjącej dokumentacji jest jednym z największych długoterminowych wyzwań, jakie stoją przed zespołami, z którymi rozmawiałem w czasie zbierania materiałów do książki. Ważnym elementem tego wyzwania jest efektywne zarządzanie automatyzacją. W tej części przedstawię kilka dobrych rozwiązań stosowanych przez ankietowane przeze mnie zespoły w celu zmniejszenia długoterminowych kosztów utrzymania warstw automatyzacji. Z przedstawionych porad możesz skorzystać niezależnie od tego, jakie narzędzie automatyzacji wybierzesz.
Nie traktuj kodu automatyzacji jak kodu drugiej kategorii Jednym z najczęstszych błędów popełnianych przez niektóre zespoły jest traktowanie specyfikacji lub powiązanego z nimi kodu automatyzacji jako mniej ważnych od kodu produkcyjnego. W efekcie zdarza się, że zadania automatyzacji zostają przekazane mniej zdolnym programistom i testerom, a warstwa automatyzacji jest traktowana po macoszemu — nie przykłada się do niej tyle uwagi i pracy, ile wymaga kod produkcyjny. W wielu przypadkach wynika to z niewłaściwego postrzegania specyfikacji przez przykłady i uznania, że w tej metodyce automatyzacja testów funkcjonalnych pełni rolę wiodącą (stąd właśnie różne terminy używane wymiennie: zwinne testowanie akceptacyjne czy ATDD). W konsekwencji deweloperom wydaje się, że sam kod testu nie jest już tak ważny. Wes Williams powiedział, że to przypomina mu jego wczesne doświadczenia z narzędziami wspomagającymi testowanie jednostkowe: Myślę, że mamy tu do czynienia z podobną krzywą zależności co w przypadku JUnit. Zaczęliśmy robić to samo z testami JUnit i wszyscy zgadzali się co do jednego: »Hej, ludzie, JUnit to kod. Powinien być czysty«. Jeśli tak nie było, miałeś problemy z konserwacją. Następną rzeczą, jakiej się nauczyliśmy, było przekonanie się, że strony z kodem [wykonywalne specyfikacje] w gruncie rzeczy są »kodem«. Phil Cowans uznał, że był to jeden z najważniejszych błędów popełnionych przez jego zespół we wczesnej fazie wdrażania specyfikacji przez przykłady w Songkick: Twój zestaw testowy jest pełnoprawną częścią kodu i musi być pielęgnowany tak samo jak normalny kod aplikacji. Teraz myślę, że testy [akceptacyjne] mają pierwszorzędne znaczenie, a kod [produkcyjny] jest w tym kontekście mniej ważny. Testy są kanonicznym opisem tego, co robi aplikacja. Ostatecznie sukces w większym stopniu zależy od stworzenia właściwego produktu niż poprawnej metody wytworzenia oprogramowania. Jeśli testy są opisem tego,
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
179
co robi kod, nie są po prostu bardzo ważną częścią procesu wytwarzania oprogramowania, ale bardzo ważnym elementem budowania produktu i zrozumienia tego, co udało się zbudować, a także utrzymania kontroli nad złożonością produktu. Dojście do tego zajęło nam prawdopodobnie cały rok. Clare McLennan mówi o tym, jak ważne jest powierzenie prac nad zaprojektowaniem i stworzeniem warstwy aplikacji najzdolniejszym członkom zespołu: Kiedy któregoś dnia pojawiłam się ponownie, jeden z deweloperów stwierdził, że ma wątpliwości, czy przypadkiem projekt konstrukcji zestawów testów integracyjnych nie jest ważniejszy niż projekt produktu. Innymi słowy, zestaw testów musi zostać przemyślany równie dobrze jak rzeczywisty produkt, ponieważ musi być utrzymywany przez cały czas. Jednym ze źródeł sukcesu systemu testowego było to, że znałam strukturę i mogłam odczytać kod. Zazwyczaj do pracy nad testami i systemem testowania deleguje się młodszego programistę. Jednak budowa poprawnych zautomatyzowanych systemów testowych nie jest łatwa. Młodsi programiści mają tendencję do wyboru niewłaściwych przybliżeń i tworzą coś, czemu nie można w pełni zaufać. Oddeleguj do pracy najlepszych architektów, jakich masz. Mają prawo powiedzieć: »Jeśli zmienimy to w naszym projekcie, będzie on znacznie lepszy i łatwiejszy do przetestowania«. Nie odważyłbym się stwierdzić, że kod automatyzacji jest ważniejszy niż kod produkcji. Ostatecznie oprogramowanie powstaje, ponieważ kod produkcji pomaga w osiągnięciu jakiegoś celu biznesowego. Najlepszy istniejący zestaw automatyzacji nie zadecyduje o sukcesie projektu bez dobrego kodu produkcyjnego.
Specyfikacje z przykładami — te, które kończą w żyjącej dokumentacji — będą żyć o wiele dłużej niż kod produkcyjny. Dobry system żyjącej dokumentacji będzie miał kluczowe znaczenie, gdy przyjdzie do kompletnego przepisania kodu produkcyjnego w lepszej technologii. Przeżyje każdy kod.
Opisz procesy walidacji w warstwie automatyzacji Większość narzędzi do automatyzacji wykonywalnych specyfikacji współpracuje ze specyfikacjami w postaci zwykłego tekstu lub tekstu w formacie HTML. Dzięki temu możliwa jest zmiana specyfikacji bez potrzeby rekompilacji lub jakiejkolwiek modyfikacji kodu języka programowania. Z kolei warstwa automatyzacji jest kodem języka programowania, który wymaga ponownego skompilowania i modyfikacji, jeśli dojdzie do zmian. Wiele zespołów próbowało dokonać uniwersalizacji warstwy automatyzacji w celu uniknięcia konieczności wprowadzania częstych zmian. Zespoły tworzyły w warstwie automatyzacji tylko komponenty wielokrotnego użytku niskiego poziomu, takie jak komendy automatyzacji interfejsu użytkownika, a następnie opisywały procesy walidacji przy użyciu skryptów, takich jak przepływy sieciowe na stronie, posługując się tymi poleceniami.
180
Specyfikacja na przykładach
Wymownym sztandarowym przykładem tego problemu są specyfikacje, które zawierają pojęcia interfejsu użytkownika (np. kliknięcie łącza lub otwarcie okna) lub, co gorsza, komendy niskiego poziomu automatyzacji, takie jak rozkazy Selenium. I tak na przykład zespół Global Talent Management w Ultimate Software zdecydował w którymś momencie o przeniesieniu całego przepływu pracy z warstwy automatyzacji do specyfikacji testowych. Wykorzystano w tym celu specjalnie opracowane narzędzie typu open source do automatyzacji interfejsu użytkownika o nazwie SWAT. Polecenia SWAT były wystawiane dalej bezpośrednio jako fikstury. Zostały one pogrupowane w znaczące przepływy pracy domeny dla specyfikacji. Takie rozwiązanie na początku ułatwiło tworzenie specyfikacji, ale później stało się źródłem wielu problemów z konserwacją. Oto co powiedzieli mi Scott Berger i Maykel Suarez: Istnieje centralny zespół, który zajmuje się SWAT i pisze makra. W pewnym momencie okazało się, że utrzymanie zespołu jest niemożliwe. Używaliśmy makr, bazując na makrach. To sprawiło, że trudno było nam wykonać refaktoryzację [testów]. Koszmar. Założenia [w kontekście testu] byłyby regionem złożonym, jednak po rozszerzeniu stałby się on ogromny. Przeszliśmy do implementowania przepływu w fiksturach. Dla każdej strony [specyfikacji] mamy odpowiadającą jej fiksturę.
Zamiast opisywać procesy walidacji w specyfikacjach, powinniśmy umieszczać je w warstwie automatyzacji. Uzyskane w ten sposób specyfikacje będą bardziej jednoznaczne i łatwiejsze do zrozumienia.
Opisanie procesów walidacji (czyli tego, jak coś jest testowane, w przeciwieństwie do tego, co jest testowane) w warstwie automatyzacji sprawia, że ta warstwa staje się bardziej skomplikowana i trudniejsza do utrzymania, ale w tej kwestii przychodzą nam z pomocą narzędzia programistyczne, takie jak IDE. Gdy zespół Bergera opisywał przebiegi jako komponenty wielokrotnego użytku w specyfikacjach zdefiniowanych prostym tekstem, zasadniczo programowanie przebiegało z wykorzystaniem zwykłego tekstu, bez wsparcia jakichkolwiek narzędzi programistycznych. Możemy użyć narzędzi programistycznych do utrzymania implementacji procesów walidacji skuteczniej, niż gdyby zostały one opisane w postaci zwykłego tekstu. Równie łatwo możemy wykorzystać te same zautomatyzowane procesy walidacji ponownie w innych powiązanych specyfikacjach. Patrz ramka „Trzy poziomy automatyzacji interfejsu użytkownika” w tym rozdziale, gdzie znajdziesz więcej informacji na ten temat.
Nie powielaj logiki biznesowej w warstwie automatyzacji testów
Emulacja części przepływów biznesowych aplikacji lub logiki warstwy automatyzacji może ułatwić automatyzację testów, ale w ten sposób warstwa automatyzacji stanie się bardziej skomplikowana i trudniejsza w utrzymaniu. Co gorsza, otrzymane wyniki testów mogą być wtedy mniej wiarygodne.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
181
W prawdziwym przepływie produkcyjnym mogą znaleźć się błędy, które nie zostały powtórzone w warstwie automatyzacji. Przykład, który zależy od tego przepływu, doprowadzi do błędu, gdy będzie wykonywany w prawdziwym systemie, ale zautomatyzowane testy zakończą się wynikiem pozytywnym, zapewniając zespołowi fałszywe przekonanie, że wszystko jest w porządku. Jest to jeden z najważniejszych pierwszych wniosków zdefiniowanych na podstawie doświadczeń z pierwszej ręki przez Tima Andersena z Iowa Student Loan: Zamiast tworzyć fałszywe pożyczki na podstawie kodu pomocnika testowania, zmodyfikowaliśmy nasz kod testowy, aby wykorzystać aplikację do konfigurowania pożyczki w stanie poprawnym. Mogliśmy usunąć prawie jedną trzecią naszego kodu testowego [warstwy automatyzacji], gdy udało się skonfigurować abstrakcyjną warstwę testową dla kredytobiorców z rzeczywistej aplikacji. Nauczka? Nie tworzyć fałszywych stanów. Taki fikcyjny stan jest podatny na błędy i charakteryzuje się wyższymi kosztami utrzymania. Wykorzystaj prawdziwy, istniejący i działający system. Mieliśmy do czynienia z kilkoma testami przerwanymi błędami. Przyjrzeliśmy się im i stwierdziliśmy, że dzięki nowemu modelowi obecnie wykorzystywane testy znalazły kilka błędów. Na starszych, pracujących systemach wykorzystanie kodu produkcyjnego do automatyzacji może czasem doprowadzić do bardzo złych praktyk z wykorzystaniem pewnych niekonwencjonalnych sztuczek. Na przykład jeden z moich klientów rozbudowywał produkt innej firmy, który mieszał logikę biznesową z kodem interfejsu użytkownika, ale my nie mogliśmy nic na to poradzić. Moi klienci mieli tylko ograniczony dostęp do kodu źródłowego komponentów. Ktoś wcześniej skopiował i wkleił części funkcjonalności innych twórców do fikstur testowych, usuwając wszystkie powiązania z interfejsem użytkownika. Gdy dostawca z innej firmy aktualizował swoje klasy, pojawiały się problemy. Przepisałem te fikstury, żeby zainicjować klasy okien niezależnego projektu i uzyskać dostęp do zmiennych prywatnych przy użyciu odbicia do uruchomienia prawdziwego procesu biznesowego. Nigdy więcej nie zrobię czegoś takiego podczas pracy nad kodem produkcyjnym! W tym przypadku był to jednak wybór mniejszego zła. Usunęliśmy 90% kodu fikstur i od czasu do czasu musieliśmy poprawiać automatyzację, gdy autor źródła zmieniał sposób wykorzystania zmiennych prywatnych, ale takie rozwiązanie oznaczało o wiele mniej pracy, niż gdybyśmy przez cały czas musieli kopiować i modyfikować ogromne obszary kodu. Dzięki temu nasze testy były wiarygodne.
Automatyzuj wzdłuż granic systemu Kiedy: Integracje są skomplikowane
Jeśli pracujesz nad projektem złożonego heterogenicznego systemu, ważne, abyś dobrze wiedział, gdzie znajdują się granice Twojej odpowiedzialności. Specyfikuj i automatyzuj testy wzdłuż tych granic.
182
Specyfikacja na przykładach
W przypadku złożonych systemów heterogenicznych zawarcie w zautomatyzowanym teście całego przepływu w formacie end-to-end może być naprawdę trudne, a może nawet niemożliwe. Gdy rozmawiałem z Robem Parkiem, dowiedziałem się, że jego zespół pracuje nad integracją z systemem zewnętrznym, który przekształcał głos na dane. Prześledzenie całego procesu przepływu dla każdego testu automatycznego w tym przypadku byłoby działaniem niepraktycznym, jeśli w ogóle możliwym. Zespół nie pracował jednak nad rozpoznawaniem głosu, a jego zadaniem była po prostu integracja systemów. Zadania członków zespołu zależały od tego, co działo się z komunikatami głosowymi po konwersji na dane. Park mówi, że zespół postanowił wyizolować system i przygotować alternatywną ścieżkę dostarczania danych wejściowych, która miała ułatwić automatyzację: Pracujemy nad funkcją dla Interactive Voice Response. Numery polis i identyfikacja są automatycznie przekazywane do aplikacji z systemu IVR, tak więc ekrany są już wypełniane jakimiś danymi. Po spotkaniu trzech amigos stało się oczywiste, że potrzebujemy strony testowej, która przygotowuje dane wysłane przez IVR. Zamiast automatyzować takie przykłady od końca do końca, włączając w to także systemy zewnętrzne, zespół Parka zebrał dane zewnętrzne pochodzące z systemu, odizolował je i przygotował automatyczne testy sprawdzające poprawność tej części systemu, za którą był odpowiedzialny. To pozwoliło mu zweryfikować wszystkie ważne reguły biznesowe z pomocą wykonywalnych specyfikacji. Użytkownicy biznesowi naturalnie będą myśleć o akceptacji pracy całościowej. Zautomatyzowane testy, które nie uwzględniają systemów zewnętrznych, nie dają im pewności, że projektowana funkcja działa poprawnie we wszystkich okolicznościach. Integracja powinna być sprawdzana przez odrębne testy integracji technicznej. W tym przypadku wystarczyłoby nagranie prostej, przygotowanej zawczasu wiadomości, a następnie sprawdzenie, co dzieje się z nią w czasie procesu. Taki test pozwoliłby sprawdzić, czy wszystkie elementy poprawnie ze sobą „rozmawiają”. Ponieważ wszystkie reguły biznesowe są określane i testowane osobno, nie trzeba uruchamiać testów integracyjnych wysokiego poziomu dla wszystkich najważniejszych przypadków użycia. Więcej wskazówek na temat tego, jak radzić sobie z dużymi systemami o rozbudowanej infrastrukturze, znajdziesz w następnym rozdziale.
Nie sprawdzaj logiki biznesowej za pomocą interfejsu użytkownika Tradycyjne narzędzia do automatyzacji testów pracują głównie poprzez manipulowanie obiektami interfejsu użytkownika. Większość narzędzi automatyzacji dla wykonywalnych specyfikacji może zejść poniżej poziomu interfejsu użytkownika i komunikować się bezpośrednio z interfejsami programowania aplikacji.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
183
Jeśli uruchomienie zautomatyzowanej specyfikacji dla funkcji od końca do końca za pośrednictwem interfejsu użytkownika nie jest jedynym sposobem zbudowania zaufania, nie rób tego.
Automatyzacja interfejsu użytkownika zazwyczaj zajmuje znacznie więcej czasu i na ogół jest znacznie droższa w utrzymaniu niż automatyzacja na poziomie usług lub API. Z wyjątkiem użycia automatyzacji interfejsu użytkownika do zyskania sobie zaufania klienta (jak opisano wcześniej w tym rozdziale), zawsze gdy to możliwe, zejście poniżej poziomu interfejsu użytkownika jest o wiele lepszym sposobem weryfikacji logiki biznesowej.
Automatyzacja pod skórą aplikacji Kiedy: Sprawdzasz ograniczenia sesji i przepływu
Przepływ procesu i reguły sesji często można sprawdzić tylko na warstwie interfejsu użytkownika. Jednak to wcale nie oznacza, że jedyną opcją automatyzacji tych sprawdzianów jest uruchomienie przeglądarki internetowej. Zamiast automatyzować specyfikacje poprzez przeglądarkę, kilka zespołów pracujących nad wytworzeniem aplikacji internetowych oszczędziło sporo czasu i wysiłku, przechodząc od razu „pod skórę” aplikacji — do warstwy HTTP. Tim Andersen wyjaśnia, na czym polega to rozwiązanie: Chcemy wysłać mapę mieszającą, która bardzo przypomina żądanie HTTP. Mamy wartości domyślne, które zostaną przepisane z danymi ważnymi dla testu, a my testowaliśmy, w zasadzie kierując się tam, dokąd zmierzały nasze żądania HTTP. W ten sposób działały nasze fikstury, poprzez żądanie HTTP z obiektem. To właśnie tak stosowaliśmy rzeczywisty stan i prawdziwe obiekty. Nieuruchamianie przeglądarki pozwala na wykonywanie automatycznych testów równolegle i o wiele szybciej. Christian Hassa zastosował podobne rozwiązanie, ale on zszedł o jeden poziom niżej, do sterowników sieciowych wewnątrz aplikacji. W ten sposób uniknął wywołań HTTP i mógł liczyć na szybsze uzyskanie informacji zwrotnych. Wyjaśnia: Powiązaliśmy części [specyfikacji] bezpośrednio z interfejsem użytkownika przy użyciu Selenium, a inne części bezpośrednio z kontrolerem MVC. To pierwsze zadanie wymagało od nas sporo pracy, dlatego nie mogę powiedzieć, że oszczędność pracy to podstawowa zaleta tej techniki. Gdybym mógł wybrać powiązanie wszystkich specyfikacji z kontrolerem lub powiązanie ograniczonego zestawu specyfikacji z interfejsem użytkownika, zawsze wybrałbym to pierwsze rozwiązanie. Wiązanie z interfejsem użytkownika jest według mnie rozwiązaniem opcjonalnym;
184
Specyfikacja na przykładach
niepowiązanie wszystkich specyfikacji, które są istotne z perspektywy systemu, nie jest możliwe. Ponadto powiązanie z interfejsem jest także działaniem oznaczającym o wiele większe koszty.
Automatyzacja tuż pod skórą aplikacji jest dobrą metodą ponownego wykorzystania prawdziwych przepływów biznesowych i uniknięcia dublowania elementów w warstwie automatyzacji. Uruchamianie testów bezpośrednio z wykorzystaniem wezwań HTTP — a nie przez przeglądarkę — znacznie przyspiesza walidację i umożliwia wykonywanie równoległych testów.
Biblioteki automatyzacyjne przeglądarki często są powolne i blokują profile użytkowników, więc takie testy trzeba byłoby uruchamiać kolejno na jednej maszynie. Tymczasem istnieje wiele narzędzi i bibliotek bezpośredniej automatyzacji HTTP, takich jak WebRat3, Twill4 i Selenium 2.0 HtmlUnit driver5. Wiele nowoczesnych zestawów MVC umożliwia automatyzację poniżej warstwy HTTP, czyniąc takie testy jeszcze wydajniejszymi. Narzędzia te pozwalają na wykonanie równoległych testów szybciej i z większą niezawodnością, ponieważ w porównaniu z modelem automatyzacji przeglądarki charakteryzują się mniejszą liczbą „ruchomych części”. Chociaż mówiąc o interfejsach użytkownika, skupiłem się głównie na przykładach aplikacji internetowych, te same wskazówki mają zastosowanie w odniesieniu do innych rodzajów interfejsów użytkownika. Automatyzacja „tuż pod skórą” aplikacji pozwala nam zweryfikować ograniczenia przepływu i sesji, a jednocześnie skrócić czas sprzężenia zwrotnego (w porównaniu z czasem straconym na uruchamianie testów za pośrednictwem interfejsu użytkownika). Po ogólnym opisie zarządzania automatyzacją nadszedł czas, by odnieść się do dwóch szczególnych obszarów, które dla wielu zespołów były źródłem problemów z automatyzacją: zarządzania interfejsami użytkownika i danymi.
Automatyzacja interfejsów użytkownika Dla zespołów, których procesy analizowałem na potrzeby tej książki, automatyzacja interfejsów użytkownika była największym wyzwaniem wdrożenia specyfikacji przez przykłady. Prawie wszystkie zespoły, z którymi rozmawiałem, wcześnie popełniły ten sam błąd. Testy, które miały być zautomatyzowane poprzez interfejsy użytkownika, zdefiniowano w serii technicznych kroków, często bezpośrednio zapisując polecenia automatyzacji interfejsu użytkownika w specyfikacjach. Biblioteki automatyzacji interfejsu użytkownika pracują w języku obiektów ekranowych, w zasadzie w obszarze projektowania oprogramowania. Bezpośrednie opisywanie specyfikacji w tym języku jest sprzeczne z kluczowymi regułami udoskonalania specyfikacji
3
http://wiki.github.com/brynary/webrat. http://twill.idyll.org. 5 http://seleniumhq.org/docs/09_webdriver.html#htmlunit-driver. 4
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
185
Wybór zakresu automatyzacji W Bridging the Communication Gap zalecałem automatyzację wszystkich specyfikacji. Dzięki możliwości wymiany opinii z wieloma różnymi zespołami podczas przygotowywania tej książki dziś już jestem przekonany, że istnieją pewne sytuacje, w których automatyzacja się nie opłaca. Gaspar Nagy podsunął mi dwa dobre przykłady: Jeśli koszt automatyzacji będzie zbyt wysoki w stosunku do korzyści z kryterium akceptacji — takiego jak wyświetlanie dającej się sortować siatki — kontrolka interfejsu użytkownika [widget] będzie umożliwiać sortowanie w wersji domyślnej, zaraz po uruchomieniu. Aby sprawdzić, czy dane są naprawdę posortowane, potrzebujesz sporej liczby testów przypadków brzegowych. Najlepiej pokryć ten element szybkimi testami ręcznymi. Nasza aplikacja wymagała także funkcjonalności w trybie offline. Specjalne przypadki brzegowe w trybie offline mogą być trudne do automatyzacji i testowanie ręczne chyba jest dobrym wyborem. W obu tych przypadkach szybki manualny test może wpłynąć na podwyższenie poziomu zaufania do systemu, który będzie do przyjęcia dla klientów. W dłuższej perspektywie koszt automatyzacji znacznie przewyższyłby oszczędność czasu. Weryfikacja przykładów układu graficznego aplikacji w większości przypadków nie jest dobrym obszarem automatyzacji. Taka automatyzacja jest technicznie możliwa, ale dla wielu zespołów ewentualne korzyści nie uzasadniają poniesionych kosztów. Automatyzacja referencyjnych przykładów użyteczności (takich jak te zaproponowane w części „Stwórz przykład referencyjny” w rozdziale 7.) jest praktycznie niemożliwa. Użyteczność i przyjemność z korzystania z produktu wymaga ludzkiej oceny i subiektywnego pomiaru. Inne dobre egzemplifikacje sprawdzianów, które nie są chyba warte automatyzacji, dotyczą funkcji takich jak intuicyjność lub oceny wyglądu albo łatwości użytkowania. Nie znaczy to jednak, że o takich wymaganiach nie warto rozmawiać, ilustrować ich przykładami lub przechowywać w systemie specyfikacji. Wręcz przeciwnie. Omówienie tych przykładów zagwarantuje Ci, że wszyscy będą mieli takie samo wyobrażenie tych elementów, choć bardziej efektywnie można sprawdzić wyniki ręcznie. Automatyzacja możliwie szerokiego obszaru otaczającego nietestowane automatycznie funkcje może pomóc nam w skupieniu testów ręcznych na niewielkiej liczbie aspektów działania systemu, w których wstępna automatyzacja lub prace konserwacyjne w dłuższej perspektywie byłyby kosztowne.
(patrz „Skrypty to nie specyfikacje” i „Specyfikacje powinny dotyczyć funkcjonalności biznesowej, a nie projektu oprogramowania” w rozdziale 8.). Takie działanie sprawia, że specyfikacje stają się trudne do zrozumienia, ale i utrudnia długoterminowe utrzymanie zautomatyzowanych testów. Pierre Veragen pracował w zespole, który musiał wyrzucić wszystkie testy po małej zmianie w interfejsie użytkownika: Testy interfejsu użytkownika były zorientowane na zadanie (kliknij, wskaż), a zatem ściśle powiązane z implementacją GUI, a nie zorientowane na aktywność. W testach znajdowało się sporo powieleń. Testy FitNesse zorganizowaliśmy tak,
186
Specyfikacja na przykładach
żeby odpowiadały ustawieniom interfejsu użytkownika. Kiedy interfejs użytkownika został zaktualizowany, trzeba było zaktualizować także wszystkie te testy. Model translacji zmienił się z koncepcyjnego na techniczny. Mała zmiana w graficznym interfejsie użytkownika, dodanie wstążki, a wszystko się psuje. Nie było żadnej możliwości zaktualizowania testów. Poczynione wcześniej inwestycje w testy zostały zmarnowane, ponieważ łatwiej było wyrzucić wszystkie testy, niż dokonać ich aktualizacji. Zespół zdecydował się zająć raczej restrukturyzacją architektury aplikacji, aby umożliwić sobie łatwiejsze testowanie. Jeśli zdecydujesz się na automatyzację walidacji niektórych specyfikacji poprzez interfejs użytkownika, efektywne zarządzanie warstwą automatyzacji będzie prawdopodobnie jednym z kluczowych zadań zespołu. Oto kilka dobrych pomysłów dotyczących automatyzacji testów za pośrednictwem interfejsu użytkownika przy zachowaniu zalety łatwości ich utrzymania.
Określ funkcjonalność interfejsu użytkownika na wyższym poziomie abstrakcji W dłuższej perspektywie przeniesienie do warstwy automatyzacji translacji z języka biznesowego na język obiektów interfejsu użytkownika pomaga uniknąć problemów z utrzymaniem. To w gruncie rzeczy oznacza zdefiniowanie testów interfejsu użytkownika na wyższym poziomie abstrakcji. Aslak Hellesøy mówi, że była to jedna z kluczowych lekcji, jakie bardzo szybko musiał opanować jego zespół: Zdaliśmy sobie sprawę, że gdybyśmy pisali testy na wyższym poziomie, moglibyśmy osiągnąć wiele korzyści. To pozwoliło nam zmieniać implementację bez konieczności zmiany wielkiej liczby skryptów funkcji. Testy były dużo łatwiejsze do odczytania, co wynikało z ich niewielkiej długości. Mieliśmy setki takich testów i wystarczył tylko rzut oka, by o wiele łatwiej zorientować się, gdzie jesteśmy. Były o wiele bardziej odporne na zmiany. Lance Walton opisuje podobne doświadczenia, które spowodowały, że jego zespół zdecydował się na utworzenie klas w warstwie integracji, reprezentujących operacje ekranów interfejsu użytkownika, a następnie podniesienie poziomu abstrakcji do przepływu pracy, a potem do działań nadrzędnych. Wyjaśnia: Przeszliśmy przez przewidywalną ścieżkę tworzenia testów według modelu »wpisz to, kliknij przycisk« z dużą liczbą powtórzeń w różnych testach. Zespół miał naturalny instynkt do refaktoryzacji i zdał sobie sprawę, że potrzebujemy reprezentacji ekranów. Staram się trzymać podstawowych reguł programowania ekstremalnego: Jeśli masz małe wyrażenie, które ma własne znaczenie, dokonaj refaktoryzacji do metody i nadaj jej nazwę. Do przewidzenia było to, że będziemy
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
187
musieli logować się do każdego testu i że testy powinny być wielokrotnego użytku. Nie bardzo wiedziałem jeszcze, jak to zrobić, ale wiedziałem, że tak się stanie. Więc wpadliśmy na pomysł zastosowania klas ekranu. Następnie zdaliśmy sobie sprawę, że wykonywaliśmy tę samą sekwencję stron — to był proces przepływu. Kolejnym ważnym etapem było zrozumienie, że przepływ pracy wciąż miał wiele wspólnego z rozwiązaniem, które zaprojektowaliśmy, więc uznaliśmy, że trzeba zapomnieć o procesie przepływu i skupić się na tym, co użytkownik chce osiągnąć. Mieliśmy zatem strony, które zawierały detale, mieliśmy wyższy poziom zadania, potem, jeszcze wyżej, cały przebieg, a na samej górze znajdował się cel, który chce zrealizować użytkownik. Kiedy dotarliśmy do tego poziomu, testy powstawały już bardzo szybko. Co więcej, były to testy odporne na zmiany. Reorganizacja warstwy automatyki tak, aby obsługiwała działania — i skupienie się podczas testów na specyfikacjach, a nie na skryptach — pomogło znacznie zmniejszyć koszty utrzymania zautomatyzowanych testów. Walton wyjaśnia: Na początku trzeba było się zalogować, aby można było cokolwiek zobaczyć. Na jakimś etapie wydawało się, że przed logowaniem można dostrzec całą masę różnych rzeczy, a żądanie logowania pojawi się tylko po kliknięciu specjalnego łącza. Jeśli masz mnóstwo testów, które wymagają logowania, najpierw musisz poradzić sobie z problemem wynikającym z tego, że jeśli nie usuniesz etapu logowania, wszystkie testy zakończą się błędem. Ale musisz się zalogować po przejściu przez łącze, więc cała masa testów będzie z tego powodu bezużyteczna. Jeśli przeprowadzisz takie rozumowanie, fakt, że test loguje się jako konkretna osoba, nie oznacza, że robi to natychmiast — po prostu przechowujesz tę informację i używasz danych, gdy zostaniesz poproszony o zalogowanie się. Testy przechodzą bez problemów. Oczywiście potrzebne są dodatkowe testy, aby sprawdzić, kiedy istnieje wymóg logowania, ale to już inna sprawa. Wszystkie testy, które mają sprawdzać, czy użytkownicy mogą osiągnąć swój cel, będą poprawne, nawet z tą dość istotną zmianą. Uświadomienie sobie, że tak łatwo możemy wprowadzić te zmiany, było dla mnie zaskakującym i oszałamiającym przeżyciem. I rzeczywiście zacząłem dostrzegać naszą moc w zakresie kontrolowania tych spraw. Fakt, że użytkownik musi być zalogowany, aby wykonać określone działanie, został oddzielony od rzeczywistego działania, jakim było wypełnienie formularza logowania, wysłanie go i zalogowanie się. To warstwa automatyzacji decydowała o tym, kiedy ma być wykonane to działanie w ramach przepływu pracy (i czy w ogóle trzeba je wykonać). W ten sposób testy oparte na specyfikacji stały się znacznie bardziej odporne na zmiany. Działanie to podniosło również poziom abstrakcji dla aktywności związanych z interfejsem użytkownika, co pozwoliło czytelnikom łatwiej zrozumieć całą specyfikację.
188
Specyfikacja na przykładach Definiowanie funkcji interfejsu użytkownika na wyższym poziomie abstrakcji pozwala zespołom uniknąć konieczności translacji koncepcji biznesowych i interfejsu użytkownika. Dzięki temu testy akceptacyjne stają się również łatwiejsze do zrozumienia i bardziej odporne na zmiany, co prowadzi do zmniejszenia kosztów utrzymania w dłuższej perspektywie.
Wskazówki dotyczące takiej organizacji automatyzacji testów interfejsu użytkownika, aby można było zachować wszystkie zalety udoskonalenia specyfikacji i zmniejszenia długoterminowych kosztów utrzymania, znajdziesz w ramce z nagłówkiem „Trzy poziomy automatyzacji interfejsu użytkownika” w dalszej części tego rozdziału.
Funkcjonalność interfejsu użytkownika sprawdzaj tylko ze specyfikacją interfejsu użytkownika Kiedy: Interfejs użytkownika zawiera złożoną logikę
Jeśli Twoje wykonywalne specyfikacje mają postać opisu interakcji z elementami interfejsu użytkownika, specyfikuj jedynie funkcjonalność interfejsu użytkownika.
Jedynym przykładem sytuacji, w której testy opisane na niższym poziomie technicznym nie spowodowały w późniejszym czasie ogromnych problemów z utrzymaniem, był projekt zespołu Sierra pracującego dla BNP Paribas w Londynie. Zespół dysponował zestawem wykonywalnych specyfikacji opisanych jako interakcje z elementami interfejsu użytkownika. Ta sytuacja różniła się od innych, w których takie testy stawały się źródłem kłopotów, tym, że zespół Sierra specyfikuje jedynie funkcjonalność interfejsu użytkownika, a nie bazową logikę domeny biznesowej. Testy zespołu Sierra na przykład sprawdzały obowiązkowe pola formularza i funkcji realizowanych w JavaScripcie. Wszystkie ich specyfikacje logiki biznesowej są zautomatyzowane poniżej interfejsu użytkownika. Podniesienie poziomu abstrakcji z pewnością uczyni takie testy łatwiejszymi do odczytania i utrzymania. Z drugiej strony znacznie bardziej skomplikuje strukturę warstwy automatyzacji. Ponieważ zespół Sierra miał stosunkowo niewiele tych testów, tworzenie i utrzymywanie inteligentnej warstwy automatyki prawdopodobnie zajęłoby więcej czasu, niż trwałaby modyfikacja skryptów, gdy dojdzie do zmiany w interfejsie użytkownika. Ważne jest również zrozumienie, że zespół obsługuje też wewnętrzny interfejs użytkownika back-office, gdzie układ nie zmienia się tak bardzo jak w przypadku ogólnodostępnych stron internetowych, w przypadku których interfejs użytkownika jest jedną wielką „witryną sklepową”.
Unikaj zarejestrowanych testów interfejsu użytkownika Wiele tradycyjnych narzędzi do automatyzacji testów oferuje funkcje nagrywania i odtwarzania automatyzacji interfejsu użytkownika. Chociaż taka funkcjonalność wydaje się na początku atrakcyjna, w kontekście specyfikacji przez przykłady jest prawdziwie koszmarnym wyborem. Jest to jeden z tych obszarów, w których automatyzacja wykonywalnych specyfikacji całkowicie różni się od tradycyjnych automatycznych testów regresji.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
189
Jeśli tylko możesz, unikaj automatyzacji z wykorzystaniem narzędzi nagrywających. Zarejestrowane skrypty, poza tym, że są niemal całkiem niemożliwe do zrozumienia, charakteryzują się także tym, że są bardzo trudne w utrzymaniu. Narzędzia tego typu ograniczają koszty tworzenia skryptu, ale znacznie podnoszą koszt jego utrzymania.
Zespół Pierre’a Veragena dysponował 70 000 linijek zapisanych skryptów dla testów regresji interfejsu użytkownika. Ponowne nagranie skryptów po poważnych zmianach interfejsu zajęło kilku osobom sześć miesięcy. Tak wolny feedback całkowicie wyeliminuje wszelkie zalety wykonywalnych specyfikacji. Poza tym automatyzacja w modelu „nagraj i odtwórz” zakłada istnienie gotowego interfejsu użytkownika, a specyfikacja przez przykłady zostaje wdrożona, zanim powstanie pierwszy element oprogramowania. Niektóre zespoły pierwotnie nie rozumiały różnicy między tradycyjnymi testami regresji i specyfikacją przez przykłady i próbowały wykorzystać narzędzia do rejestrowania i odtwarzania. Opowieść Christiana Hassy może być modelowym przykładem: Nasze testy wciąż jeszcze były niepewne i musieliśmy liczyć się ze sporym nakładem pracy, aby je utrzymać. Testy Selenium były nagrywane, dlatego pojawiały się w grze za późno. Najpierw staraliśmy się nagrywać to, co otrzymywaliśmy na końcu sprintu. Potem próbowaliśmy przejść na formę nieco bardziej abstrakcyjną, żeby zarejestrowane testy uczynić zdatnymi do wielokrotnego użytku i sprawić, że będą pewniejsze. Na koniec to i tak tester musiał dochodzić do tego, jak przeprowadzić test. O tym, jak tester interpretuje oczekiwania użytkowników, dowiadywaliśmy się bardzo późno. Po drugie, wciąż byliśmy spóźnieni z tym, co miało być testowane. Właściwie to rejestrowanie testów tylko pogorszyło sytuację, bo trzeba było cały ten proces obsługiwać. Sześć miesięcy później odkryliśmy, że używane skrypty nie dają się utrzymać. Korzystaliśmy z tego rozwiązania przez kilka miesięcy i próbowaliśmy poprawić ten proces, ale tak naprawdę ta metoda się nie sprawdzała, więc zrezygnowaliśmy z niej, zanim dotarliśmy do końca projektu. Pisane przez nas testy nie były zorganizowane tak samo, jak to robimy teraz — nasze podejście bardziej przypominało sposób, w jaki klasyczny tester sam organizowałby swoje testy — mnóstwo warunków wstępnych, potem trochę pewników, a rzeczy do zrobienia stawały się warunkami do następnego testu.
Ustaw kontekst w bazie danych
Nawet jeśli jedynym sposobem automatyzacji wykonywalnych specyfikacji jest wykorzystanie interfejsu użytkownika, wiele zespołów przekonuje się, że można znacznie przyspieszyć wykonywanie testu dzięki przygotowaniu kontekstu bezpośrednio w bazie danych.
Na przykład podczas automatyzowania specyfikacji opisującej przebieg procesu zatwierdzania artykułów przez redaktorów możemy wstępnie utworzyć modele artykułów, wykorzystując
190
Specyfikacja na przykładach
Trzy poziomy automatyzacji interfejsu użytkownika Jeśli chcesz stworzyć wykonywalne specyfikacje, które są automatyzowane przez interfejs użytkownika, zastanów się nad opisaniem specyfikacji na następujących trzech poziomach: Poziom reguł biznesowych — Co pokazuje ten test? Na przykład: Darmowa dostawa proponowana klientom, którzy zamówią co najmniej dwie książki. Poziom przepływu pracy użytkownika — Jak użytkownik może wykorzystać funkcję poprzez interfejs na wyższym poziomie aktywności? Na przykład: Umieść dwie książki w koszyku zakupowym, wprowadź dane adresowe i sprawdź, czy w opcjach dostawy znajduje się dostawa bez opłat. Poziom techniczny aktywności — Jakie kroki techniczne są wymagane, aby przejść przez kolejne etapy przepływu pracy? Na przykład: Otwórz stronę domową sklepu, zaloguj się jako użytkownik testowy przy użyciu hasła testowego, przejdź do strony /ksiazka, kliknij pierwszą grafikę z klasą CSS ksiazka, poczekaj na załadowanie się strony, kliknij łącze Kup teraz i tak dalej. Specyfikacje powinny być opisane na poziomie reguł biznesowych. Warstwa automatyzacji powinna zająć się poziomem przepływu poprzez łączenie bloków stworzonych na poziomie technicznym aktywności. Takie testy będą łatwe do zrozumienia, ich tworzenie będzie działaniem efektywnym. Gotowe testy będą stosunkowo niedrogie w utrzymaniu. Więcej informacji na temat trzech poziomów testów interfejsu użytkownika znajdziesz w moim artykule zatytułowanym How to implement UI testing without shooting yourself in the foot†. _______________ http://gojko.net/2010/04/13/how-to-implement-ui-testing-without-shooting-yourself-inthe-foot-2. †
wywołania do bazy danych. Jeśli korzystasz z trzech warstw (opisanych w poprzedniej ramce), niektóre części warstwy przepływu pracy mogą zostać zaimplementowane poprzez interfejs użytkownika, a inne można zoptymalizować dla użycia API domen lub połączenia z bazą danych. Zespół Global Talent Management pracujący dla Ultimate Software wykorzystuje to rozwiązanie, dzieląc pracę tak, aby testerzy mogli nadal efektywnie uczestniczyć w procesie. Scott Berger wyjaśnia: W najlepszym wypadku deweloper pisze i automatyzuje ścieżkę szczęścia z warstwą tej automatyzacji bazy danych, która przygotowuje dane. Następnie rozszerza ją o dodatkowe przypadki użycia. Poprzez wczesną automatyzację całej ścieżki deweloperzy wykorzystują swoją wiedzę na temat zoptymalizowania testów. Gdy pierwszy przykład zostaje zautomatyzowany, testerzy i analitycy mogą łatwo uzupełnić specyfikację, dodając więcej przykładów na poziomie reguł biznesowych. Ustalanie kontekstu w bazie danych prowadzi nas do drugiego wielkiego wyzwania, przed jakim stawały badane przeze mnie zespoły zajmujące się automatyzowaniem wyko-
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
191
nywalnych specyfikacji: zarządzania danymi. Niektóre zespoły uwzględniały bazy danych w ciągłych procesach walidacji, aby uzyskać większe zaufanie do swoich systemów lub ponieważ ich domeny charakteryzują się zależnością od danych. Stwarza to nowe wyzwania dla automatyzacji.
Zarządzanie danymi testowymi Aby wykonywalne specyfikacje były wystarczająco jednoznaczne i na tyle oczywiste, by nie wymagały dodatkowych wyjaśnień, muszą zawierać wszystkie dane, które są wymagane do zilustrowania funkcji za pomocą przykładów, ale pomijać dodatkowe informacje. Jednak by w pełni zautomatyzować przykłady w kontekście systemu, który korzysta z bazy danych, z powodu referencyjnych kontroli integralności często potrzebujemy dodatkowych danych. Kolejny problem ze zautomatyzowanymi testami wykorzystującymi dane przechowywane w bazie danych polega na tym, że jeden test może zmienić dane wymagane w innym teście, sprawiając, że wynikom testu nie będzie można zaufać. Z drugiej strony aby uzyskać szybki feedback, nie możemy usuwać i odtwarzać całej bazy za każdym razem na potrzeby pojedynczego testu. Efektywne zarządzanie danymi testowymi ma kluczowe znaczenie dla zapewnienia pewności poprawności działania systemów opartych na danych i przyspieszenia procesu ciągłej walidacji oraz zapewnienia jej powtarzalności i wiarygodności. W tej części rozdziału przedstawię kilka dobrych praktyk, które ankietowane przeze mnie zespoły wykorzystywały podczas zarządzania danymi testowymi na potrzeby wykonywalnych specyfikacji.
Unikaj wykorzystywania danych wstępnie wypełnionych Kiedy: Definiujesz logikę, która nie bazuje na danych
Ponowne wykorzystanie istniejących danych może sprawić, że specyfikacje będą trudniejsze do zrozumienia.
Gdy wykonywalne specyfikacje są automatyzowane tak, aby korzystać z bazy danych, zgromadzone w niej dane stają się częścią kontekstu automatyzacji. W niektórych testach wykorzystywano użyte już raz dane zgodnie z bieżącymi potrzebami, zamiast koncentrować się na sposobie automatyzacji informacji kontekstowych wprowadzanych do bazy danych przed testem. Taka automatyzacja jest łatwiejsza, ale sprawia, że specyfikacje są trudniejsze do zrozumienia. Każdy, kto zapoznaje się z tak zdefiniowanymi specyfikacjami, musi także zrozumieć sens i znaczenie danych zaczerpniętych z bazy. Channing Walton odradza taki model działania: Tworzenie baz danych poprzez wstępne zdefiniowanie zestawu standardowych danych wyjściowych zawsze przyprawia o ból głowy. Trudno bowiem zrozumieć, co to za dane, dlaczego się tam znalazły i do czego się je wykorzystuje. Gdy test kończy się niepowodzeniem, trudno poznać przyczynę. Ponieważ dane testowe są
192
Specyfikacja na przykładach
szeroko udostępniane, testy wzajemnie na siebie wpływają. Ludzie szybko tracą orientację. Taka optymalizacja jest przedwczesna. Pisz testy, które będą agnostyczne wobec danych. Jeśli system zaprojektowany jest w taki sposób, aby nie wymagał wielu referencyjnych konfiguracji danych, wówczas specyfikacje mogą być zautomatyzowane w sposób definiujący tylko minimalny zestaw informacji kontekstowych. Patrząc na to z drugiej strony równania, specyfikacja przez przykłady prowadzi zespoły do projektowania komponentów ukierunkowanych o niskim stopniu powiązań, co jest jedną z najważniejszych zasad projektowania obiektowego. Tymczasem spełnienie tej zasady w przypadku systemów bazujących na danych nie jest łatwe.
Spróbuj wykorzystać wstępnie przygotowane dane referencyjne Kiedy: W systemach bazujących na danych
Definiowanie pełnego kontekstu dla systemów opartych na danych jest zadaniem trudnym i podatnym na błędy. Prawdopodobnie nie jest to najlepsze rozwiązanie pod kątem tworzenia ostrych specyfikacji. Rozwiązanie to wypróbował zespół Gaspara Nagya. Okazało się, że specyfikacje stały się trudne do odczytania i utrzymania: Mieliśmy test akceptacyjny, w którym musieliśmy przygotować pewne dane w bazie danych, aby przejść na kolejny etap. Kiedy stworzyliśmy opis konfiguracji, stwierdziliśmy, że wygląda jak mała baza danych. W tekście nie użyliśmy słowa »tabela«, ale… tam były tabele. Deweloperzy nie mieli problemów ze zrozumieniem tej specyfikacji, ale nie można jej było pokazać przedstawicielowi przedsiębiorcy. Mieliśmy na przykład tabelę dla poszczególnych krajów. Nie chcieliśmy kodować żadnej logiki państw w automatyzacji testów, więc dla każdego testu określiliśmy kraje, które były dla niego istotne. Okazało się, że to było naprawdę głupie z naszej strony, bo i tak zawsze wykorzystywaliśmy Węgry i Francję. Mogliśmy tylko załadować wszystkie kraje świata do bazy danych z uwagą »domyślne kraje w systemie«. Dysponowanie domyślnym zestawem danych byłoby pomocne. Marco Milone zidentyfikował podobny problem, gdy pracował nad pewnym projektem w branży nowych mediów: Na początku, tylko po to, żeby wreszcie zmusić testy do pracy, wiele rzeczy robiliśmy nie tak. W teście zdefiniowano metody setUp() i tearDown(), ale były one strasznie zaśmiecone. Zaczęliśmy centralizację konfiguracji bazy danych i nadrzędne egzekwowanie kontroli zmian. Testy przynosiły nam po prostu wyniki sprawdzianów, a my nie zajmowaliśmy się wprowadzaniem danych do testów. Dzięki temu testy były o wiele szybsze i o wiele łatwiejsze do zrozumienia i zarządzania.
Rozdział 9. Automatyczna walidacja bez zmiany specyfikacji
193
W systemach bazujących na danych tworzenie wszystkiego od podstaw nie jest dobrym pomysłem. Z drugiej strony ukrywanie informacji może spowodować ogromne komplikacje. Potencjalnym rozwiązaniem tego problemu ze złotym środkiem jest metoda zastosowana przez zespoły w Iowa Student Loan. Programiści wypełnili wstępnie tylko dane referencyjne, które się nie zmieniały. Tim Andersen wyjaśnia szczegóły tego rozwiązania: W czasie kompilacji odtworzyliśmy bazę danych od zera. Następnie wypełniliśmy ją danymi konfiguracyjnymi i danymi testowymi dla domeny. Każdy test jest odpowiedzialny za tworzenie i czyszczenie danych transakcyjnych.
Korzystanie z wstępnie przygotowanych danych referencyjnych to dobra strategia mająca na celu uczynienie specyfikacji krótszymi i łatwiejszymi do zrozumienia przy jednoczesnym przyspieszeniu feedbacku i uproszczeniu warstwy automatyzacji.
Jeśli zdecydujesz się korzystać ze wstępnie wypełnionych danych referencyjnych, zapoznaj się z częścią rozdziału 10. zatytułowaną „Wykonaj szybkie testy danych referencyjnych”, aby dowiedzieć się, jak sprawić, by takie testy były bardziej rzetelne.
Wyciągnij prototypy z bazy danych Kiedy: W starych, dojrzałych systemach bazujących na danych
Niektóre domeny są tak skomplikowane, że nawet ze wstępnie skonfigurowanymi danymi referencyjnymi utworzenie nowego obiektu od podstaw byłoby zadaniem skomplikowanym i narażającym na niepotrzebne błędy. Jeśli musisz rozwiązać ten problem podczas pracy nad projektem typu greenfield, gdzie model domeny znajduje się pod Twoją kontrolą, to może być znak, że model domeny jest niepoprawny (patrz „Słuchaj swojej żyjącej dokumentacji” w rozdziale 11.). W dojrzałych systemach bazujących na danych zmiana modelu może być nie do przyjęcia. W takich przypadkach zamiast tworzyć zupełnie nowy obiekt od podstaw, spraw, aby warstwa automatyzacji klonowała istniejący obiekt i zmieniała jego odpowiednie właściwości. Børge Lotre i Mikael Vik zastosowali to rozwiązanie podczas prac dla Norwegian Dairy Herd Recording System. Oto co powiedzieli: Uzyskanie prawidłowego tła dla testu tak, żeby było możliwie kompletne, okazało się prawdziwym wyzwaniem ze względu na złożoność domeny. Gdybyśmy testowali zachowanie krowy i zapomnieli zdefiniować przypadek testowy, w którym krowa miała trzy cielaki, nie wiedzielibyśmy nawet o tym, że kod nie spełnia założeń, i nie zauważylibyśmy naszego błędu przed ręcznym testem na rzeczywistych danych. Dlatego stworzyliśmy generator tła, w którym można było wygenerować prawdziwą krowę i pobrać powiązane z nią dane z bazy. Pobrane właściwości były następnie wykorzystywane jako podstawa dla nowego testu Cucumbera.
194
Specyfikacja na przykładach
Takie rozwiązanie okazało się przydatne nie tylko wtedy, gdy chcieliśmy odtworzyć okoliczności prowadzące do błędu, ale przydało się również, gdy zaczęliśmy analizę nowych wymagań. Gdy zespół Bekka identyfikuje brakujący przypadek testowy, w prawdziwej bazie danych znajdowany jest dobry przykład reprezentacyjny, a potem używa się „generatora tła”, by na bazie rzeczywistych właściwości przygotować automatyczny test akceptacyjny. Takie podejście gwarantuje, że skomplikowane obiekty będą mieć wszystkie istotne cechy oraz będą zawierać odnośniki do powiązanych, prawdziwych obiektów. Dzięki temu sprawdziany kryteriów walidacyjnych przynoszą o wiele bardziej poprawne informacje. Aby szybciej uzyskać informacje zwrotne z wykonywalnych specyfikacji, generator tła pobiera cały kontekst obiektu, który umożliwia uruchamianie testów na podstawie bazy danych znajdującej się w pamięci.
Znajdź reprezentatywny przykład w bazie danych i korzystaj z jego właściwości, aby przygotować testy.
Gdy opisane rozwiązanie stosuje się do tworzenia obiektów na bieżąco podczas testowania, zamiast tworzyć kontekst dla testu (w połączeniu z rzeczywistą bazą danych), można również uprościć konfigurację wymaganą na potrzeby odpowiednich jednostek w wykonywalnych specyfikacjach. Zamiast określać wszystkie właściwości obiektu, możemy określić tylko te, które są niezbędne, aby znaleźć dobry prototyp. Dzięki temu otrzymana specyfikacja jest łatwiejsza do zrozumienia. Automatyzacja walidacji specyfikacji bez ich zmiany różni się koncepcyjnie od tradycyjnej automatyzacji testów. I to właśnie dlatego tak wiele zespołów ma z tym tak wielkie problemy, kiedy zaczynają swoją przygodę z wdrożeniem specyfikacji przez przykłady. Automatyzujemy specyfikacje, aby uzyskać szybki feedback, ale naszym głównym celem powinno być stworzenie wykonywalnych specyfikacji, które są łatwo dostępne i czytelne dla człowieka, a nie tylko takich, które nadają się do automatyzacji procesu walidacji. Gdy nasze specyfikacje stają się wykonywalne, możemy często przeprowadzać walidacje, aby stworzyć system żyjącej dokumentacji. Tymi zagadnieniami zajmiemy się w dwóch następnych rozdziałach.
Pamiętaj Udoskonalane specyfikacje należy zautomatyzować zgodnie z zasadą jak najmniejszych zmian. Warstwa automatyzacji powinna określać sposób testowania; specyfikacje powinny zawierać opis tego, jak coś powinno być testowane. Wykorzystaj warstwę automatyzacji do translacji między językiem biznesu i koncepcjami interfejsu użytkownika, API oraz bazami danych. Twórz komponenty wielokrotnego użytku wyższego poziomu, których będzie można użyć w specyfikacjach. Jeśli to możliwe, wykonuj automatyzację poniżej poziomu interfejsu użytkownika. Jeśli nie musisz, nie polegaj za bardzo na posiadanych, gotowych danych.
10
Częsta walidacja Jeśli za bardzo zboczysz ze swojego pasa ruchu, zostaniesz natychmiast przywołany do porządku donośnym, wibrującym łup, łup, łup…
— David Haldane1
W
1950 roku kalifornijski Departament Transportu przyznał, że ma pewien problem ze znacznikami pasów ruchu na autostradach. Otóż namalowane na jezdni linie szybko ulegały zatarciu i co sezon trzeba je było odtwarzać. Prace odtworzeniowe wiązały się ze sporymi kosztami, powodowały zakłócenia w ruchu i wystawiały na niebezpieczeństwo ludzi, którym powierzano zadanie malowania nowych pasów. Problemem zainteresował się dr Elbert Dysart Botts, który najpierw zaczął eksperymentować z bardziej odblaskową farbą. Ten kierunek prac okazał się jednak ślepą uliczką. Szukając rozwiązań nieszablonowych, Botts wymyślił wystające nad płaszczyznę jezdni znaczniki pasa, które dziś nazywamy kropkami Bottsa. Kropki Bottsa są widoczne w dzień i w nocy, niezależnie od pogody. Nie ścierają się tak łatwo jak malowane znaczniki. Najechanie na kropki Bottsa, gdy kierowcy zbaczają z wyznaczonego toru jazdy, powoduje pojawienie się charakterystycznych wibracji oraz dudniących dźwięków, przez co działają one nie tylko na zmysł wzroku. Taka informacja zwrotna — wibracje i dźwięk — okazała się jednym z najważniejszych elementów zwiększających bezpieczeństwo na drogach, ostrzegając nieuważnych kierowców o potencjalnym zagrożeniu, gdy nieświadomie zmieniają pas ruchu. Odpowiedniki kropek Bottsa zostały wprowadzone także do inżynierii oprogramowania jako jedna z oryginalnych dwunastu praktyk programowania ekstremalnego, nazywanych ciągłą integracją (ang. continuous integration, CI). System ciągłej integracji ma ostrzegać nieuważnych członków zespołów programistycznych, że zaczynają dryfować w niewłaściwym kierunku, zbaczając z wyznaczonej drogi prowadzącej do uzyskania produktu, który powinni tworzyć i opakować zgodnie z wymogami klienta. Dedykowany system ciągłej integracji odpowiada za regularne kompilacje i testowanie produktu w celu zapewnienia, że system 1
http://articles.latimes.com/1997-03-07/local/me-35781_1_botts-dots.
196
Specyfikacja na przykładach
nie działa poprawnie tylko i wyłącznie na komputerze programisty. Dzięki wymuszaniu podejmowania szybkich decyzji, które mają przeciwdziałać ewentualnym problemom, ciągła integracja pozwala trzymać się gdzieś w środkowej części „pasa ruchu”, żeby w razie potrzeby delikatnie, bez niepotrzebnych kosztów można było skorygować kurs. Ciągła integracja jest gwarancją, że gdy produkt wykonywany jest w zgodzie z kanonami, będzie tym właściwym. Takie same zasady obowiązują na etapie procesu wytwarzania oprogramowania. Gdy stworzymy właściwy produkt, chcemy, żeby nic złego się z nim nie stało. Jeśli proces wytwarzania produktu prowadzi nas na manowce i w efekcie zbaczamy z wyznaczonego kursu, problem możemy rozwiązać znacznie łatwiej i taniej, jeżeli szybko uświadomimy sobie zagrożenie i nie pozwolimy, aby problemy zaczęły się kumulować i nakładać na siebie. W takiej sytuacji z pomocą przychodzi nam częsta walidacja wykonywalnych specyfikacji. Dzięki serwerowi ciągłej integracji2 możemy regularnie sprawdzać poprawność wszystkich specyfikacji i uzyskać pewność, że badany system nadal spełnia wszystkie założenia. Ciągła integracja jest dobrze udokumentowaną dobrą praktyką inżynierii oprogramowania i wielu innym autorom udało się umiejętnie przedstawić i wytłumaczyć ze szczegółami jej zasady. Nie chciałbym zatem niepotrzebnie dublować ich pracy. Nie zamierzam powtarzać instrukcji konfigurowania systemu ciągłej kompilacji i integracji. Myślę jednak, że nawiązanie do szczególnych wyzwań częstej walidacji wykonywalnych specyfikacji jest istotne dla tematyki omawianej w mojej książce. Wiele zespołów, które wdrożyły zasady specyfikacji przez przykłady w celu uzupełnienia istniejących metod inżynierii oprogramowania, stwierdza, że wykonywalne specyfikacje należy konfrontować z prawdziwymi bazami danych, zawierającymi rzeczywiste dane, usługami zewnętrznymi lub działającą stroną internetową. Funkcjonalne testy akceptacyjne pozwalają sprawdzać funkcjonalność wielu składników, a jeśli systemu nie tworzy się od razu z myślą o ułatwieniu testów, takie sprawdziany często wymagają istnienia całego, kompletnego systemu, zintegrowanego i uruchomionego w swoim unikalnym środowisku. Konsekwencją tego stanu rzeczy jest zidentyfikowanie trzech typów problemów częstej walidacji, które dają o sobie znać niezależnie od innych, charakterystycznych dla ciągłej integracji problemów z (jednostkowymi) testami technicznymi: Zawodność mająca swoje źródło w zależnościach środowiskowych — testy jednostkowe są w dużej mierze niezależne od środowiska testowego, ale wykonywalne specyfikacje mogą zależeć w dużym stopniu od reszty „ekosystemu”. Pewne cechy tego środowiska mogą sprawiać, że testy kończą się niepowodzeniem, nawet jeśli kod programowania jest poprawny. Aby móc ufać w poprawność wyników testów akceptacyjnych, musimy rozwiązać problemy środowiskowe lub złagodzić wpływ zmiennych środowiskowych na wyniki testów, czyniąc je niezawodnymi. Wolniejszy feedback — funkcjonalne testy akceptacyjne w przypadku projektów typu brownfield często będą pracować o rząd wielkości wolniej niż testy jednostkowe. 2
Oprogramowanie, które automatycznie tworzy, kompiluje i wykonuje testy, gdy dojdzie do zmiany jakiejkolwiek części kodu w systemie kontroli wersji. Jeśli nigdy nie słyszałeś o takim serwerze, wpisz do wyszukiwarki Google hasło: CruiseControl, Hudson lub TeamCity.
Rozdział 10. Częsta walidacja
197
Pakiet testów jednostkowych uznałbym za wolny, gdyby jego wykonanie trwało dłużej niż kilka minut. Każdy test trwający ponad 10 minut uznałbym za zdecydowanie zbyt powolny i zacząłbym poważnie zastanawiać się, jak go przyspieszyć. Z drugiej strony widziałem takie paczki testów akceptacyjnych, których wykonanie trwało kilka godzin, a skrócenie tego czasu było niemożliwe bez zmniejszenia wiarygodności wyników. Taki niespieszny feedback zmusza nas do znalezienia jakiegoś rozwiązania, dzięki któremu uda się na żądanie i szybko zgromadzić istotne informacje przynajmniej z wybranych elementów systemu. Zarządzanie testami, które zakończyły się wynikami negatywnymi — duża liczba wyrywkowych testów funkcjonalnych, które zależą od wielu zmiennych, wymaga od zespołów, szczególnie tych dopiero wdrażających metodykę specyfikacji przez przykłady, odpowiedniego zarządzania nieudanymi testami zamiast natychmiastowego wprowadzania poprawek. W tym rozdziale wyjaśnię, jak z opisanymi problemami radziły sobie zespoły ankietowane na potrzeby tej książki.
Zmniejszenie zawodności Walidacja, do której nie mamy zaufania, może wpłynąć negatywnie na wzajemne zaufanie członków zespołu — podważa wiarę w produkt i w proces specyfikowania przez przykłady. Analizowanie sporadycznych błędów, które nie wynikają z prawdziwych problemów, jest ogromną stratą czasu. Jeśli coś takiego będzie zdarzać się regularnie, deweloperzy zaczną to wykorzystywać. W efekcie usłyszysz wymówki o „marnotrawieniu czasu”, aby nie zajmować się problemami z walidacją. I tak prawdziwe błędy rozgoszczą się w produkcie — niezauważone — negując sens ciągłej walidacji. W starszych, odziedziczonych projektach rzadko zdarza się łatwe i szybkie zastosowanie automatycznych testów funkcjonalnych, dlatego wykonywalne specyfikacje mogą wymagać zautomatyzowania za pośrednictwem niepewnych interfejsów użytkownika lub cierpią w konsekwencji niedeterministycznych procesów asynchronicznych. Taka sytuacja staje się wyjątkowo problematyczna, gdy deweloperzy potrzebują argumentów, które pomogłyby przekonać ich do udziału w procesie, i widzą jedynie ograniczone korzyści testów funkcjonalnych (innymi słowy: „przecież to nie mój problem…”). Clare McLennan doświadczyła tego typu problemów w swoim zespole: „Deweloperzy nie dbali o testy, bo te nie były stabilne, a my potrzebowaliśmy ich wiedzy, żeby móc sprawić, by stały się stabilne”. Pojawił się problem pierwszeństwa typu „jajko czy kura”. Aby przekonać deweloperów do zaangażowania się w pracę zespołu, Clare McLennan musiała udowodnić im, jak wielką wartość mają wykonywalne specyfikacje. Najpierw jednak wykonywalne specyfikacje musiały mieć solidne fundamenty, których stworzenie wymagało współpracy ze strony deweloperów wpływających na wygląd systemu i zoptymalizowanie specyfikacji pod kątem zautomatyzowania testów.
198
Specyfikacja na przykładach
Aby zapewnić sobie długofalowe korzyści z wdrożenia specyfikacji przez przykłady, wiele zespołów musiało sporo zainwestować w uwiarygodnienie procesów walidacji. W tym rozdziale przedstawię kilka dobrych pomysłów na realizację tego zadania.
Znajdź najbardziej irytujący Cię element, napraw go, a następnie powtórz całą operację Kiedy: Pracujesz w systemie z kiepskim wsparciem dla testów automatycznych
Jedną z najważniejszych rzeczy dotyczących zrozumienia warunków zwiększenia niezawodności systemu przygotowywanego pod kątem testów automatycznych jest to, że musisz uświadomić sobie, iż nic, co najlepsze, nie zdarzy się z dnia na dzień. Wprowadzanie zmian do starych, odziedziczonych po poprzednich zespołach, dojrzałych systemów jest zadaniem trudnym. Gdyby było inaczej, nie mówiłoby się o nich, że są „dojrzałe”. Gdy jakiś produkt powstawał przez lata i w tym czasie w ogóle nie myślano o testach, nie stanie się od razu czysty, tj. pozbawiony błędów i gotowy do testowania. Szybkie wprowadzanie zbyt wielu istotnych zmian doprowadzi do destabilizacji systemu, zwłaszcza jeśli nadal nie mamy dobrego pokrycia testami funkcjonalnymi. To poważnie zakłóciłoby rytm pracy nad rozwojem produktu.
Zamiast próbować rozwiązać problem jednym, genialnym posunięciem, o wiele lepszą strategią jest wprowadzenie wielu mniejszych zmian w kolejnych iteracjach.
Zespół Clare McLennan zdał sobie na przykład sprawę, że wolne przetwarzanie danych testowych prowadzi do błędu przekroczenia czasu oczekiwania. Administrator bazy danych poprawił jej wydajność i zorientował się, że niektóre testy uruchamiały się, zanim część danych zdążyła się zaktualizować. A zatem system przekazywał stare dane! Zespół przygotował specjalne komunikaty systemowe, dzięki którym można było mieć pewność, że system przekazuje dalej najnowsze dane z bazy tak, aby można było rozpocząć testowanie we właściwym momencie i uniknąć fałszywych wyników negatywnych. Gdy wyeliminowano jedno źródło entropii, zespół odkrył inny problem, który wynikał z wygasającej ważności plików cookie protokołu HTTP. Wprowadzono zatem nową definicję czasu operacyjnego, żeby możliwa była dowolna zmiana czasu systemowego. (Patrz część „Wprowadź operacyjny czas działania” dalej w tym rozdziale). W ramach strategii zakładającej zwiększenie stabilności automatycznych testów Clare McLennan sugeruje zastosowanie podejścia przyrostowego: Znajdź to, co cię najbardziej irytuje, i napraw to. Pojawi się inny problem, a potem jeszcze inny. W końcu, jeśli będziesz kontynuował usuwanie tych najbardziej irytujących błędów, stworzysz stabilny system, który będzie charakteryzował się naprawdę sporą niezawodnością.
Rozdział 10. Częsta walidacja
199
Iteracyjne podejście do poprawy stabilności jest dobrym sposobem budowania wiarygodności procesu walidacji, bez zakłócania rytmu pracy. Pozwala ono również na uczenie się i adaptację do jednoczesnej pracy na rzecz zwiększenia testowalności systemu.
Określ niestabilne testy, korzystając z historii testów ciągłej integracji Kiedy: Modernizujesz i dopasowujesz automatyczne testy do starego systemu
W przypadku systemów starszych, odziedziczonych po innych zespołach, nieprzystosowanych do automatyzacji testów, często trudno zdecydować, od czego zacząć iteracyjne modernizowanie, ponieważ niestabilność systemu wynika z wielu przyczyn. Dobrze wtedy przeanalizować historię testów. Większość systemów ciągłej kompilacji ma obecnie funkcję śledzenia historycznych wyników testów.
Gdy wykonywalne specyfikacje zostaną połączone z systemem ciągłej kompilacji, historia testów pomoże nam zidentyfikować najmniej stabilne testy lub całe grupy testów.
Przez wiele lat zupełnie nie zwracałem uwagi na tę funkcję, gdyż pracowałem głównie nad projektami typu greenfield, tworzonymi od zera i umożliwiającymi automatyczne testowanie, lub zajmowałem się systemami, w których stosunkowo niewielkie zmiany gwarantowały wystarczającą stabilność. W takich projektach śledzenie historii wykonania testów do niczego się nie przydaje: testy albo zawsze kończą się pozytywnym wynikiem, albo poprawia się je zaraz po tym, jak kończą się negatywnym. Gdy po raz pierwszy próbowałem modernizacji automatycznego testowania w systemie, który od czasu do czasu sygnalizował błędy przekroczenia limitu czasu, problemy z łącznością sieciową lub problemy z bazami danych czy niespójnym przetwarzaniem, zapoznanie się z historią testów pomogło mi zidentyfikować najistotniejsze elementy, mające rzeczywisty wpływ na zwiększenie stabilności. Historia zawierająca informację o nieudanych testach podpowiadała mi, którymi elementami systemu należy zająć się w pierwszej kolejności.
Utwórz dedykowane środowisko ciągłej walidacji Jeśli Twoja aplikacja musi zostać przygotowana i uruchomiona na potrzeby testów funkcjonalnych, pierwszym krokiem do osiągnięcia powtarzalności wyników testów jest zabezpieczenie dedykowanego środowiska testowego. Jeśli ciągła walidacja ma pozwolić Ci na zgromadzenie wiarygodnych danych, konieczne jest spełnienie warunku powtarzalności testów. W niektórych większych organizacjach zdobycie nowych komputerów jest trudniejsze niż zatrudnienie w stołówce firmowej znanego truciciela jako kucharza, ale musisz mieć świadomość, że walka o lepszy sprzęt jest słuszna. Wiele zespołów próbowało korzystać z tego samego środowiska testowego w wielu kontekstach — na potrzeby demonstracji funkcji użytkownikom biznesowym, przeprowadzania testów ręcznych i ciągłej walidacji. Takie rozwiązanie jest jednak gwarancją regularnych problemów ze spójnością danych.
200
Specyfikacja na przykładach
Bez zapewnienia dedykowanego środowiska trudno jest orzec, czy test zakończył się niepowodzeniem z powodu błędu, czy może dlatego, że ktoś zmienił jakiś komponent w środowisku testowym, czy to system jest po prostu niestabilny. Dedykowane środowisko testowe eliminuje nieplanowane zmiany i zmniejsza prawdopodobieństwo tego, że niestabilne środowisko negatywnie wpłynie na wyniki testów.
Zastosuj w pełni zautomatyzowaną procedurę instalacji Gdy stworzymy już dedykowane środowisko testowe, musimy mieć pewność, że oprogramowanie będzie instalowane w sposób gwarantujący powtarzalność. Konfiguracja niezapewniająca odtwarzalności wyników testów jest drugą najczęstszą przyczyną niestabilności wyników testów. W przypadku wielu starszych systemów konfiguracja oprogramowania jest zadaniem trudnym, wykonywanym zazwyczaj w nocy, przy współudziale kilku osób pojonych ogromnymi ilościami kawy i… najlepiej, żeby ci ludzie dysponowali magiczną różdżką. Gdy taka nocna sesja ma odbywać się raz w roku, pospolite ruszenie jest do przyjęcia. Jednak gdy podobną operację trzeba powtarzać raz na dwa tygodnie, wówczas odczuwamy niemal fizyczny ból. W przypadku ciągłej walidacji, która wymaga identycznego środowiska w każdym z kilku wykonywanych dziennie testów, automatyzacja wspomagana magią jest zwyczajnie nie do zaakceptowania. Bez w pełni zautomatyzowanego systemu konfiguracji i instalacji oprogramowania, który jest gwarantem wiarygodności aktualizowanego systemu, często będziemy musieli radzić sobie z sytuacją, gdy kilka testów nagle zacznie kończyć się błędami. I wtedy ktoś będzie musiał poświęcić kilka godzin, szukając przyczyny problemów, przy licznych reakcjach w stylu: „Ale przecież na moim sprzęcie to działa…”.
W pełni zautomatyzowana procedura konfiguracji będzie gwarantem pojedynczej, standardowej metody aktualizacji. Dzięki niej będziesz mieć również pewność, że wszyscy deweloperzy pracują na sprzęcie ze standardowym układem komponentów systemowych, wykorzystywanych w identycznym środowisku testowym.
Przedstawione rozwiązanie eliminuje zależność wykonywalnych specyfikacji od unikalnych środowisk i czyni ciągłą walidację procesem dużo bardziej niezawodnym. Ułatwia także rozwiązywanie ewentualnych problemów, ponieważ deweloperzy mogą wykorzystać dowolne środowisko każdego komputera do odtworzenia okoliczności pojawienia się błędów. Aby system walidacji dobrze spełniał swoje zadanie, musi być w pełni zautomatyzowany. Żadna dodatkowa interwencja obsługi nie powinna być wymagana ani nawet dozwolona. (Zauważ, że mówię o w pełni zautomatyzowanej konfiguracji, którą można uruchamiać na żądanie, niekoniecznie rozpoczynanej automatycznie). Programów instalacyjnych, które wymagają Twojej ciągłej obecności przy konsoli administratora, półautomatycznych i ręcznie uruchamianych skryptów i tego typu narzędzi nie można uznać za w pełni zautomatyzowany system. Dotyczy to w szczególności zautomatyzowanej konfiguracji baz danych.
Rozdział 10. Częsta walidacja
201
Znam wiele zespołów, które twierdziły, że posługują się systemem automatycznym… do czasu, gdy okazywało się, że ktoś i tak musi później uruchomić ręcznie skrypty bazy danych. W pełni zautomatyzowana konfiguracja instalacji wiąże się również z innymi korzyściami, takimi jak możliwość łatwiejszego uaktualniania systemów produkcyjnych. W dłuższej perspektywie umożliwia to zaoszczędzenie mnóstwa czasu. Regularna reinstalacja jest dobrą praktyką, niezależnie od wpływu tych działań na specyfikację przez przykłady.
Utwórz uproszczonych „dublerów” systemów zewnętrznych Kiedy: Pracujesz z zewnętrznymi źródłami danych referencyjnych
Wiele zespołów ma problemy z zewnętrznymi źródłami danych referencyjnych lub systemami zewnętrznymi, które wpływają na procesy wewnętrzne. (Mówiąc zewnętrzne, mam na myśli systemy, które znajdują się poza kontrolą zespołów, niekoniecznie systemy należące do innej organizacji). W dużych firmach z sieciami złożonych systemów jeden zespół może odpowiadać tylko za jedną część przepływu, a system testowy zespołu musi wchodzić w interakcje z systemami innych zespołów. Problem w tym, że te inne zespoły mają do wykonania własne zadania i własne testy, więc zewnętrzne serwery testowe nie zawsze są dostępne, nie zawsze też będą przekazywać pewne lub prawidłowe dane.
Stwórz niezależne źródło sztucznie generowanych danych, które będzie imitowało interakcję z prawdziwym systemem zewnętrznym.
Zespół Roba Parka pracujący dla dużego ubezpieczyciela ze Stanów Zjednoczonych tworzył system, który pobierał dane referencyjne z zewnętrznego automatycznego serwera polis. Jeśli serwer nie działał, wszystkie wykonywalne specyfikacje zwracały niewłaściwe wyniki. Do testów funkcjonalnych zespół używał alternatywnej wersji usługi zewnętrznej. Ta prostsza wersja odczytywała dane z pliku znajdującego się na dysku lokalnym. Takie rozwiązanie pozwoliło zespołowi testować system nawet wtedy, gdy serwer zewnętrzny był niedostępny. Stworzenie niezależnego źródła danych odniesienia pozwoliło również zespołowi zdobyć pełną kontrolę nad danymi referencyjnymi. Informacje na temat wygasłych polis nie były zatem przekazywane przez prawdziwy system, więc testy, których wykonanie zależało od takiej polisy, nie kończyłyby się błędem. Prostszą wersją „dublera” źródła danych odniesienia może być choćby plik konfiguracyjny, który pozwoliłby uniknąć problemów z chwilowym brakiem synchronizacji. Zespół gromadził dane w pliku XML, który był sprawdzany w systemie kontroli wersji, dzięki czemu możliwe było łatwe śledzenie zmian i kompilowanie poprawnej wersji danych testowych z kodem we właściwej wersji. Coś takiego byłoby niemożliwe w przypadku wykorzystywania wyłącznie systemu zewnętrznego. Lokalna usługa, która pobiera dane z pliku, pracuje również szybciej niż system zewnętrzny, przyspieszając wymianę informacji zwrotnych. W wykorzystaniem „dublerów” zewnętrznych danych wiąże się ryzyko. Bo co stanie się, gdy prawdziwy system z czasem ewoluuje i kopia nie będzie już źródłem prawdziwych
202
Specyfikacja na przykładach
danych? Aby tego uniknąć, musisz regularnie sprawdzać, czy kopia ciągle robi to, co oryginalny system. Jest to szczególnie ważne, gdy „dubler” reprezentuje system innej firmy, nad którym nie masz żadnej kontroli.
Odizoluj wybrane systemy zewnętrzne Kiedy: Na Waszą pracę mają wpływ systemy zewnętrzne
Całkowite odizolowanie systemu nie zawsze jest dobrym pomysłem. Gdy ma on swój udział w bardziej złożonym procesie, kiedy systemy zewnętrzne są czymś więcej niż tylko źródłem danych referencyjnych, „dubler” musiałby zawierać części rzeczywistych funkcji systemów zewnętrznych. Stworzenie takiego zastępnika oznaczałoby spore obciążenie zespołu dodatkową pracą i sprawiłoby pewne kłopoty w zakresie utrzymania i konserwacji. Zespół Iana Coopera w Beazley zastosował w takiej sytuacji pewne ciekawe, pragmatyczne rozwiązanie. Selektywnie wyłączał dostęp do niektórych usług zależnie od celów wykonywalnych specyfikacji. Dzięki temu testy wykonywano znacznie szybciej niż normalnie, a jednocześnie wciąż angażowano w pracę minimalny zestaw zewnętrznych rzeczywistych systemów. Takie rozwiązanie nie chroniło zespołu w pełni przed wpływem czynników zewnętrznych, ale rozwiązywanie problemów stało się o wiele łatwiejsze. Jeśli test kończył się niepowodzeniem, przynajmniej było wiadomo, jakie zewnętrzne źródło mogło przyczynić się do tego stanu rzeczy.
Odizolowanie wybranych usług zewnętrznych może przyspieszyć niektóre testy i ułatwić rozwiązywanie problemów.
Wypróbuj walidację wielostopniową Kiedy: Pracujesz w dużych grupach lub z grupami w różnych lokalizacjach
W przypadku systemów starych, odziedziczonych po innych zespołach, uruchamianie wszystkich wykonywalnych specyfikacji często trwa dłużej, niż wynosi średni czas pomiędzy dwiema zmianami bazowego kodu źródłowego. W związku z tym czasami trudno jest powiązać problem z konkretną zmianą. Jeśli przy tym samym projekcie pracuje kilka zespołów, zwłaszcza jeśli znajdują się one w różnych lokalizacjach, liczba problemów może urosnąć do trudnych do zaakceptowania wielkości. Jeśli jeden zespół na przykład uszkodzi bazę danych, inne nie będą mogły przetestować swoich zmian, dopóki problem nie zostanie rozwiązany. Może minąć kilka godzin, zanim ktoś w ogóle zorientuje się, że pojawił się jakiś problem, określi, co trzeba poprawić, i ponownie uruchomi testy, aby potwierdzić, że wszystko jest już w porządku. Kompilacja z błędami zawsze będzie „problemem kogoś innego”, a bardzo szybko okaże się, iż pakiet ciągłej walidacji przez dłuższy czas nie będzie nadawał się do użycia. W takiej sytuacji równie dobrze moglibyśmy zrezygnować z wykonywania testów.
Rozdział 10. Częsta walidacja
203
Zastosuj wieloetapową walidację. Każdy zespół powinien dysponować własnym środowiskiem ciągłej walidacji; wszelkie zmiany powinny być najpierw testowane w tym niezależnym środowisku.
Najpierw zintegruj zmiany z innymi zmianami tego samego zespołu. Jeśli kompilacja przejdzie testy pozytywnie, wprowadź zmiany do centralnego środowiska ciągłej walidacji, gdzie zostaną zintegrowane ze wszystkimi zmianami innych zespołów. To podejście w większości przypadków rozwiązuje problem z błędami jednego zespołu, wpływającymi na dzieło innych. Nawet jeśli centralne środowisko zawiera błędy i ktoś próbuje je poprawić, poszczególne zespoły mogą nadal korzystać z własnych środowisk, aby testować swoje zmiany. W zależności od czasu wykonania wszystkich wykonywalnych specyfikacji możemy albo wykonać pełny pakiet testów w obu środowiskach, albo po prostu uruchomić reprezentatywny podzbiór testów w jednym ze środowisk, aby szybko uzyskać potrzebne wyniki. Na przykład Global Talent Management Team w Ultimate Software uruchamia większość swoich testów tylko w lokalnych środowiskach zespołu. Wolniejsze testy nie zostają uruchomione w centralnym środowisku właśnie z myślą o potrzebie uzyskania szybkiego feedbacku.
Wykonaj testy w transakcjach Kiedy: Wykonywalne specyfikacje modyfikują dane referencyjne
Transakcje bazy danych mogą zagwarantować oddzielenie [testów] od zewnętrznych źródeł zakłóceń.
Transakcje mogą zapobiec temu, że nasz proces znajdzie się pod wpływem innych procesów uruchomionych w tym samym czasie, i sprawiają, że rośnie powtarzalność testów. Jeśli podczas testu tworzymy profil użytkownika, wówczas kolejny test może zakończyć się niepowodzeniem z powodu unikalnego ograniczenia w zakresie nazwy użytkownika w bazie danych. Jeśli uruchamiamy taki test wewnątrz transakcji i cofamy zmiany wraz z jego zakończeniem, dane dotyczące użytkownika nie będą przechowywane w bazie, a więc dwa wykonania testów będą od siebie niezależne. W wielu przypadkach takie rozwiązanie jest dobrą praktyką inżynierii oprogramowania, ale może się zdarzyć, że nie uda się go zastosować w pewnych specyficznych kontekstach transakcyjnych (na przykład jeśli sprawdzenie z ograniczeniami bazy danych jest odraczane do momentu wykonania transakcji lub w przypadku zagnieżdżonych transakcji autonomicznych). Takie zaawansowane tematy dotyczące cech transakcji wykraczają poza zakres tej książki. W każdym przypadku kontrola transakcji powinna odbywać się poza specyfikacją. Kontrola transakcji bazy danych jest problemem o charakterze przekrojowym i najlepiej wykonywać ją w warstwie automatyzacji, a nie w opisie wykonywalnych specyfikacji.
204
Specyfikacja na przykładach
Wykonaj szybkie testy danych referencyjnych Kiedy: W systemach opartych na danych
W systemach opartych na danych wykonywalne specyfikacje zależą w znacznym stopniu od danych referencyjnych. Zmiany danych referencyjnych, takich jak konfiguracja przepływu pracy, mogą doprowadzić do przerwania testu, nawet jeśli funkcja jest poprawna. Tego rodzaju problemy są trudne do rozwiązania.
Przygotuj całkowicie odrębną grupę testów w celu sprawdzenia, czy dane referencyjne ciągle wyglądają tak, jak tego oczekujesz.
Takie testy można uruchamiać „na szybko” przed uruchamianiem wykonywalnych specyfikacji. Jeśli taka grupa szybkich testów się nie powiedzie, nie ma sensu uruchamiać innych. Szybkie testy pozwolą również natychmiast zidentyfikować problemy z danymi referencyjnymi i równie szybko je naprawić.
Oczekuj zdarzeń, zamiast nastawiać się na określony czas trwania Wydaje się, że jednym z najbardziej problematycznych obszarów wykonywalnych specyfikacji są procesy asynchroniczne. Nawet gdy części procesu wykonywane są w tle, na różnych komputerach albo z kilkugodzinnym opóźnieniem, użytkownik biznesowy widzi cały proces jako pojedynczą sekwencję zdarzeń. W przypadku Songkick ta sprawa dotyczyła jednego z kluczowych wyzwań wdrożenia specyfikacji przez przykłady. Phil Cowans wyjaśnia: Przetwarzanie asynchroniczne było dla nas prawdziwym utrapieniem. Ze względu na ograniczenia wydajności dużą część przetwarzania asynchronicznego wykonujemy w tle i mieliśmy z nim wiele problemów, ponieważ testy przynoszą wyniki niemal natychmiast. Przetwarzanie w tle nie miało miejsca, zanim test nie przeszedł do następnego etapu. Niezawodna walidacja procesów asynchronicznych wymaga planowania i starannego projektowania w warstwie automatyki (a często także w systemie produkcyjnym). Częstym błędem popełnianym przez twórców w systemach asynchronicznych jest odczekanie jakiegoś czasu na coś, co ma się wydarzyć. O popełnianiu takiego błędu świadczy uwzględnienie w czasie testu etapu typu: „Poczekaj 10 sekund”. To niewłaściwe. Dlaczego? Z kilku powodów. Testy tego typu mogą zakończyć się błędem, nawet gdy funkcja została zaimplementowana poprawnie, ale środowisko ciągłej walidacji znajduje się pod dużym obciążeniem. Wykonanie ich w innym środowisku może wymagać więcej czasu, więc wówczas testy stają się zależne od konkretnej instalacji. Gdy sprzęt składający się na środowisko ciągłej walidacji jest znacznie mocniejszy niż komputery, z których korzystają deweloperzy, ci ostatni nie będą w stanie przetestować zmian w swoich systemach w tych samych wartościach dla limitów czasu. Wiele zespołów ustawia wysokie limity czasu testów, aby uczynić
Rozdział 10. Częsta walidacja
205
je bardziej odpornymi na zmiany środowiska. Wówczas takie testy niepotrzebnie opóźniają uzyskanie informacji zwrotnej. I tak na przykład, jeśli test bezwarunkowo czeka minutę na zakończenie procesu, mimo że ten trwa zaledwie 10 sekund, niepotrzebne opóźnienie przekazania informacji zwrotnej wynosi 50 sekund. Małe opóźnienia mogą nie być problemem w przypadku pojedynczych testów, ale akumulują się dla większych pakietów testów. Przy dwudziestu takich testach mamy już opóźnienie całego zestawu sięgające ponad 15 minut… a to już spora różnica.
Oczekuj zdarzeń, a nie uzależniaj się od upłynięcia określonego czasu. W ten sposób Twoje testy staną się o wiele bardziej wiarygodne, a Ty nie będziesz opóźniać feedbacku dłużej, niż to konieczne.
Zawsze gdy to możliwe, uzależniaj testy od kolejki komunikatów lub częstej kwerendy bazy danych lub choćby usługi działającej w tle, aby regularnie sprawdzać, czy określony proces dobiegł już końca.
Uczyń przetwarzanie asynchroniczne rozwiązaniem opcjonalnym Kiedy: Pracujesz nad projektami typu greenfield
Podczas budowy systemu od podstaw mamy możliwość świadomego zaprojektowania go tak, aby obsługiwał łatwiejsze testowanie. W zależności od konkretnej konfiguracji może on albo przekazać do kolejki wiadomości polecenie przeprowadzenia transakcji w tle, albo wykonać test bezpośrednio. Możemy wówczas odpowiednio skonfigurować środowisko ciągłej walidacji, tak żeby uruchomić wszystkie procesy synchronicznie.
Jedną z dobrych metod radzenia sobie z utrzymaniem stabilności testów jest uczynienie asynchronicznego przetwarzania tylko jedną z alternatyw.
Takie rozwiązanie prowadzi do sytuacji, w której wykonywalne specyfikacje są uruchamiane o wiele bardziej niezawodnie i szybciej. Ale to oznacza, że funkcjonalne testy akceptacyjne nie sprawdzają systemu kompleksowo, tj. od początku do końca (ang. end-to-end). Jeśli wyłączysz asynchroniczne przetwarzanie na potrzeby testów funkcjonalnych, pamiętaj, aby napisać dodatkowe testy techniczne w celu sprawdzenia, czy asynchroniczne przetwarzanie przebiega poprawnie. Chociaż może to brzmieć jak podwojenie nakładów pracy, w rzeczywistości wcale tak nie jest. Testy techniczne mogą być krótkie, skoncentrowane wyłącznie na technicznym przebiegu pracy systemu i mogą nie weryfikować funkcji biznesowych (które będą sprawdzane osobno w ramach testów funkcjonalnych). Kilka dobrych rozwiązań technicznych w zakresie automatycznej walidacji procesów asynchronicznych znajdziesz w książce zatytułowanej Growing Object Oriented Software, Guided by Tests3. 3
Steve Freeman, Nat Pryce, Growing Object-Oriented Software, Guided by Tests, Addison-Wesley Professional, 2009.
206
Specyfikacja na przykładach
Nie wykorzystuj wykonywalnych specyfikacji w funkcji walidacji kompleksowej typu end-to-end Kiedy: W projektach typu brownfield
Wiele zespołów, zwłaszcza tych pracujących nad istniejącymi, dojrzałymi systemami, wykorzystuje wykonywalne specyfikacje zarówno w funkcji testów funkcjonalnych, jak i testów integracyjnych typu end-to-end. Takie działania dają im większą pewność, że system działa poprawnie, ale jednocześnie sprawiają, że feedback dociera do nich znacznie wolniej, a koszty utrzymania wyraźnie rosną. Problemem z takim podejściem jest to, że w tym układzie zbyt wiele elementów jest testowanych jednocześnie. Tego typu testowanie od końca do końca (ang. end-to-end) polega na sprawdzaniu logiki biznesowej procesu, integracji z infrastrukturą techniczną oraz tego, jak przebiega współpraca poszczególnych komponentów systemu. Wiele zmieniających się stanów komponentów prowadzi do sytuacji, w której zmiana jednego z nich doprowadza do przerwania testu. To oznacza również, że musimy przetestować cały system i prześledzić wszystkie procesy od początku do końca, aby wykonać walidację każdego pojedynczego przypadku, nawet jeśli moglibyśmy przetestować tylko wybraną część strumienia.
Nie testuj w tym samym czasie zbyt wielu elementów za pomocą jednej wykonywalnej specyfikacji.
Większość procesów asynchronicznych składa się z kilku etapów. Każdy z nich cechuje się określoną logiką biznesową, którą należy definiować przy zastosowaniu wykonywalnych specyfikacji. Większość zawiera zadania czysto techniczne, takie jak wysyłanie do kolejki komunikatów lub zapisywanie do bazy danych. Zamiast sprawdzać wszystko przy użyciu jednej dużej specyfikacji — co będzie trwało dość długo — przed wdrożeniem procesu pomyśl raczej o następujących działaniach: Wyraźnie oddziel logikę biznesową od kodu infrastruktury (np. wypchnięcie do kolejki komunikatów, zapis w bazie danych). Określ i przetestuj logikę biznesową niezależnie na każdym z etapów, izolując ewentualnie infrastrukturę, jak opisano wcześniej w tym rozdziale. To sprawia, że napisanie i wykonanie testów staje się o wiele łatwiejsze. Testy mogą być uruchamiane synchronicznie i nie muszą w tym czasie pobierać danych z prawdziwych baz danych lub prawdziwej kolejki. Te testy dadzą Ci pewność, że zaimplementowałeś właściwą logikę biznesową. Przeprowadź wdrożenie technicznych testów integracyjnych dla kodu infrastruktury, kolejki lub implementacji bazy danych z repozytoriów. Te testy mogą być całkiem proste, ponieważ nie mają sprawdzać skomplikowanej logiki biznesowej. Dzięki temu krokowi zyskujesz pewność, że prawidłowo wykorzystujesz posiadaną infrastrukturę.
Rozdział 10. Częsta walidacja
207
Przygotuj jeden test integracyjny typu od końca do końca, który sprawdza, czy wszystkie komponenty poprawnie wymieniają ze sobą informacje. Możesz wykonać prosty scenariusz biznesowy, który odwołuje się do wszystkich komponentów systemu, modułów w kolejce czekających na odpowiedź lub kwerend do bazy danych w celu sprawdzenia wyniku. Dzięki temu zdobędziesz pewność, że konfiguracja się sprawdza. Jeśli używasz przykładów wysokiego poziomu (zgodnie z moją sugestią z części „Nie patrz na projekt wyłącznie z perspektywy najniższego poziomu” w rozdziale 5.), to właśnie one są dobrymi kandydatami do tego testu. Przechodząc przez wszystkie elementy listy — od logiki biznesowej, przez infrastrukturę, do testów przekrojowych typu end-to-end — zazwyczaj spodziewałbym się zmniejszenia liczby testów i sporego wzrostu czasu wykonania poszczególnych testów. Przez wyizolowanie skomplikowanych testów logiki biznesowej i oddzielenie ich od infrastruktury poprawiamy niezawodność.
Szybsze uzyskiwanie informacji zwrotnej Większość zespołów przekonała się, że uruchamianie wszystkich wykonywalnych specyfikacji po każdej zmianie systemu jest nierealne. Duża liczba testów (zwłaszcza gdy można je wykonywać, tylko odwołując się do strony internetowej, bazy danych lub usługi zewnętrznej) sprawia, że informacje zwrotne pełnego testu docierają do nas zbyt późno. W celu efektywnego wsparcia procesu wytwarzania oprogramowania i ułatwienia zmian większość badanych przeze mnie zespołów zmieniała swoje systemy ciągłej walidacji tak, żeby zapewnić sobie feedback w kilku etapach i jak najszybciej uzyskać najważniejsze dane. Oto kilka strategii stosowanych w celu skrócenia czasu sprzężenia zwrotnego przez zespoły, z którymi rozmawiałem, zbierając materiały do tej książki.
Wprowadź operacyjny czas działania Kiedy: Musisz radzić sobie z ograniczeniami czasowymi
W zautomatyzowanych testach funkcjonalnych częstym źródłem problemów z synchronizacją informacji zwrotnej są ograniczenia czasowe. Zadania kończące dzień zwykle uruchamia się o północy, a wszystkie inne testy, które od nich zależą, będą odpowiadać za opóźnienie feedbacku, ponieważ na pierwsze wyniki trzeba byłoby czekać 12 godzin. Nagłówki mówiące o przechowywaniu danych w pamięci podręcznej mogą wpływać na to, czy dokument zostaje pobrany z systemu wewnętrznego typu backend, czy nie, a w celu prawidłowego przetestowania tej funkcji trzeba czasami czekać kilka dni na wyniki. Dobrym rozwiązaniem tego problemu jest wprowadzenie do systemu tzw. operacyjnego czasu działania, konfigurowalnego zamiennika zegara systemowego.
System powinien synchronizować czas z zegarem operacyjnym zawsze wtedy, gdy potrzebuje informacji o aktualnej godzinie i dacie. Dzięki temu możliwe byłoby swobodne „podróżowanie w czasie” na przestrzeni testu. Ten sposób prowadzi wprawdzie do niewielkiego wzrostu złożoności systemu, ale jednocześnie pozwala bardzo szybko go przetestować.
208
Specyfikacja na przykładach
Szybkim, uproszczonym sposobem wprowadzenia czasu operacyjnego jest automatyzacja zmiany zegara środowiska testowego, która nie wymaga żadnych zmian w projekcie. Strzeż się jednak aplikacji, które przechowują w pamięci podręcznej informacje o czasie systemowym, ponieważ mogą one wymagać ponownego uruchomienia systemu po aktualizacji zegara. Zmiana zegara systemowego może sprawić, że wyniki testów będą wprowadzać zamieszanie, jeśli ten czas będzie wykorzystywany w innym miejscu systemu, na przykład w raportach z realizacji testów. Bardziej kompleksowym rozwiązaniem jest wbudowanie funkcji czasu operacyjnego do oprogramowania produkcyjnego. Wprowadzenie funkcji czasu operacyjnego rozwiązuje również problem danych tracących ważność. Na przykład w testach, w których wykorzystuje się wygasające kontrakty, mogą dobrze działać przez sześć miesięcy, a potem nagle, gdy kontrakty wygasają, zaczynają zwracać komunikaty o błędach. Jeśli system obsługuje zmiany czasu operacyjnego, możemy mieć pewność, że tego typu kontrakty nigdy nie wygasną, a tym samym zmniejszyć koszty utrzymania oprogramowania. Potencjalne ryzyko związane z wprowadzeniem czasu operacyjnego wiąże się z ewentualnymi problemami z synchronizacją z systemami zewnętrznymi, na które nie mamy wpływu. Aby rozwiązać ten problem, stosuje się „dublerów” testowych lub test wykonuje się w odizolowanym środowisku (zgodnie z sugestiami w tym rozdziale).
Podziel duże zestawy testów na mniejsze moduły Po kilku miesiącach lub wręcz latach kompletowania wykonywalnych specyfikacji wiele zespołów zebrało pakiety licznych testów, których wykonanie zajmuje kilka godzin. Ponieważ w tym czasie uruchamia się setki testów, ludzie godzą się ze świadomością, że wyniki testów spłyną do nich dość późno. Nie zauważają, gdy jakiś test trwa na przykład 20 minut dłużej niż normalnie. Takie problemy szybko się akumulują i feedback staje się jeszcze bardziej opóźniony.
Zamiast dużym zestawem wykonywalnych specyfikacji, których wykonanie zajmuje sześć godzin, wolałbym raczej dysponować dwunastoma mniejszymi pakietami, wykonywanymi nie dłużej niż 30 minut. Większe partie testów dzielę na mniejsze grupy, bazując przy tym na podziale obszarów funkcjonalnych.
Jeśli mam naprawić problem w podsystemie rachunkowości, mogę na przykład szybko uruchomić tylko testy dotyczące grupy funkcji i przekonać się, czy problem zniknął. Nie muszę wtedy czekać sześciu godzin na zakończenie wszystkich testów. Jeśli wykonanie jednej grupy testów nagle zaczyna trwać 10 minut dłużej niż zwykle, zorientuję się, że coś jest nie tak, gdy tylko zerknę na historię testów dla danej grupy. Dziesięciominutowy przyrost w perspektywie sześciu godzin nie jest tak widoczny jak dziesięciominutowe wydłużenie testu trwającego zwykle pół godziny. Dzięki temu mam kontrolę nad tempem uzyskiwania feedbacku, ponieważ od razu zaczy-
Rozdział 10. Częsta walidacja
209
nam szukać sposobów optymalizacji konkretnego zestawu testowego, którego wykonanie trwa dłużej niż zazwyczaj. Poprzez podział dużego pakietu testowego na kilka mniejszych udało mi się ostatnio pomóc klientowi w uświadomieniu sobie faktu, iż tylko jeden obszar funkcjonalny jego systemu powodował bardzo duże opóźnienia. Udało nam się ostatecznie zmniejszyć te opóźnienia z niemal godziny do zaledwie dziewięciu minut. Dziel i rządź!
Unikaj wykorzystywania do testów baz danych przechowywanych w pamięci Kiedy: W systemach bazujących na danych
Niektóre zespoły pracujące nad systemami bazującymi na danych próbowały przyspieszyć wymianę informacji poprzez uruchamianie testów ciągłej walidacji na bazie danych przechowywanej w pamięci. Takie rozwiązanie pozwala systemowi wykonywać kod SQL, ale jednocześnie sprawia, że wszystkie połączenia SQL są znacznie szybsze. Co więcej, stanowi gwarancję, że testy są lepiej izolowane, bo każdy z nich jest uruchamiany z własną bazą danych przechowywaną w pamięci. Wiele zespołów stwierdza jednak, że w praktyce wykonanie takich testów kosztuje o wiele więcej, niż uzasadniałyby długoterminowe korzyści. Wykonywalna specyfikacja zawierająca powiązanie z bazą danych najprawdopodobniej jest jednocześnie funkcjonalnym testem akceptacyjnym i testem integracyjnym typu end-to-end. Ktokolwiek zdefiniował ją w ten właśnie sposób, chce zapewne sprawdzić również wykonanie kodu SQL. Niewielkie różnice w treści poleceń SQL pomiędzy prawdziwą bazą danych produkcji i implementacją bazy danych w pamięci mogą doprowadzić do uzyskania mylących wyników. To często wymaga utrzymywania dwóch zestawów plików SQL i równoległego zarządzania nimi w dwóch źródłach.
Jeśli korzystasz z bazy danych przechowywanej w pamięci, test integracyjny typu end-to-end sprawdzi, czy system może pracować poprawnie w odniesieniu do bazy danych w pamięci, a nie tej, która zostanie użyta w produkcji.
Wspomniałem już wcześniej, że istnieje lepsze rozwiązanie. Wykonywanie testów w transakcjach gwarantuje ich lepsze odizolowanie. Mieszanie testów integracyjnych typu end-to-end oraz funkcjonalnych testów akceptacyjnych może nie być najlepszym pomysłem (jak wspomniano wcześniej w tym rozdziale), ale jeśli naprawdę chcesz to zrobić, wówczas korzystaj z prawdziwej bazy danych i poszukaj sposobów przyspieszenia jej działania. Zespół Iowa Student Loan używał bazy przechowywanej w pamięci do wykonywania testów, ale po jakimś czasie zrezygnował z tego rozwiązania. Tim Andersen wyjaśnia przyczyny tej decyzji: Na potrzeby naszej bazy danych wykorzystywaliśmy SQL Server, ale potem zastąpiliśmy go aplikacją o nazwie Hypersonic, żeby móc uruchomiać bazę w pamięci. W ten sposób zaoszczędziliśmy 2 minuty 45-minutowej kompilacji.
210
Specyfikacja na przykładach
Kiedy dodaliśmy do bazy indeksy, SQL Server w rzeczywistości pracował szybciej! Hypersonic wymagał większego nakładu sił do jego obsługi i nie poprawiał w jakiś wyraźny sposób czasu kompilacji. Jeśli testowanie prawdziwych danych trwa za długo, oznacza to prawdopodobnie, że system będzie działać równie powoli także w produkcji, dlatego poprawa wydajności działania bazy danych na potrzeby testów koniec końców i tak przyniesie korzyści w dłuższej perspektywie. Należy pamiętać, że kontekstem tej wskazówki są systemy oparte na danych, gdzie często wymagane jest wykonanie specyficznego kodu bazy danych. Wykorzystanie baz danych przechowywanych w pamięci może być świetnym rozwiązaniem dla przyspieszenia testów agnostycznych baz danych.
Oddziel testy szybkie od wolnych Kiedy: Niewielka część testów zajmuje większość czasu przeznaczonego na ich wykonanie
Jeśli wykonywanie niewielkiego podzbioru testów zajmuje większość czasu przeznaczonego na walidację, być może dobrym pomysłem jest częste uruchamianie tylko zestawu szybszych testów.
Wiele zespołów uporządkowało swoje wykonywalne specyfikacje, dzieląc je na dwie lub trzy grupy na podstawie szybkości wykonania. Na przykład w RainStor konieczne było uruchamianie części testów z bardzo dużymi zestawami danych w celu sprawdzenia sprawności systemu. Zespół stworzył więc pakiet funkcjonalny, który jest uruchamiany po każdej kompilacji, a jego wykonanie trwa mniej niż godzinę. Nocą uruchamiane są także scenariusze klientów, czerpiące z realistycznych danych pozyskanych od klientów. Dłuższe testy są uruchamiane w każdy weekend. Chociaż taka metoda nie zapewnia za każdym razem pełnej walidacji, to znacznie zmniejsza ryzyko tego, że zmiana spowoduje pojawienie się nowych problemów, zapewniając jednocześnie stosunkowo szybki feedback.
Utrzymaj stabilność uruchamianych na noc pakietów testów Kiedy: Niemrawe testy są rozpoczynane w nocy
Dużym problemem z opóźnieniem wykonania powolnych testów jest fakt, że wszelkie identyfikowane przez nie błędy nie zostaną odkryte natychmiast ani szybko naprawione. Jeśli wykonywany w nocy test kończy się wynikiem negatywnym, dowiemy się o tym dopiero rano i dopiero wtedy podejmiemy jakieś działania, co oznacza, że tak naprawdę efekty poznamy następnego dnia. Jednak ślimacze tempo uzyskiwania informacji zwrotnej na podstawie nowej kompilacji może maskować dodatkowe problemy wprowadzone w ciągu dnia.
Uruchamiaj testy w nocnych sesjach tylko wtedy, gdy prawdopodobieństwo wystąpienia błędu jest niskie.
Rozdział 10. Częsta walidacja
211
Dobrym pomysłem gwarantującym utrzymanie stabilności pakietów testów uruchamianych w nocy jest przeniesienie każdego testu kończącego się niepowodzeniem do specjalnej grupy (patrz część zatytułowana „Stwórz pakiet znanych nieudanych testów regresji” dalej w tym rozdziale). Innym pomysłem jest dodawanie testów do nocnego pakietu tylko wtedy, gdy przez jakiś czas zwracają one wyniki pozytywne. Statystyki historii testów (wspomniane wcześniej w tym rozdziale) mogą pomóc nam zdecydować, kiedy test jest wystarczająco stabilny, żeby można go było przenieść na „nocną zmianę”. Jeżeli testy są zbyt powolne, by mogły być wykonywane w sposób ciągły, możliwym rozwiązaniem jest wykonywanie ich tylko okresowo, na żądanie, aż do czasu, gdy staną się wystarczająco stabilne do wykonywania opóźnionego. Z tego rozwiązania korzysta Adam Knight z RainStor: Testy były wykonywane ręcznie dopóty, dopóki nie zostały uznane za względnie stabilne. Wówczas przenieśliśmy je do zestawu testów nocnych. Podział testów okazał się ze wszech miar korzystny. Jeśli test kończy się niepowodzeniem, zajmujemy się poprawianiem błędów. Usunięcie poważnego błędu staje się naszym priorytetem. Przez dodanie specyfikacji do nocnych pakietów testów dopiero wówczas, gdy zmniejsza się prawdopodobieństwo zakończenia testu niepowodzeniem, zespół RainStor zmniejsza ryzyko błędów w testach o wolniejszym feedbacku dla funkcji, które akurat znajdują się jeszcze w fazie rozwoju. To znacznie zmniejszyło koszty utrzymania pakietów nocnych. Zespołowi wciąż udaje się wyłapywać nieoczekiwane i nieprzewidziane zmiany, które pojawiają się w produkcie dość rzadko. W tym świetle wolniejszy feedback informacji o tych funkcjach jest wynikiem możliwego do zaakceptowania kompromisu w ramach dążenia do niższych kosztów utrzymania.
Stwórz pakiet aktualnej iteracji Typowym przypadkiem dzielenia pakietu długo trwających testów na mniejsze i krótsze zestawy jest stworzenie pakietu aktualnej iteracji. Taki zestaw zawiera wykonywalne specyfikacje, które mogą być adresatem zmian na danym etapie wytwarzania produktu.
Dysponowanie wyizolowanym pakietem testów aktualnej iteracji pozwala otrzymywać bardzo szybki feedback w najbardziej zmiennym i najważniejszym obszarze systemu, w którym dokonywane są bieżące zmiany.
Gdy pakiet aktualnej iteracji zostanie oddzielony od reszty testów, możemy bezpiecznie umieścić w nim nawet testy funkcjonalności, które zostały zaplanowane, ale nie są jeszcze
212
Specyfikacja na przykładach
zaimplementowane. Uruchamianie wszystkich testów dla bieżącej iteracji pozwoli nam łatwiej śledzić postęp rozwoju. Będziemy też dokładnie wiedzieć, kiedy skończymy. Pakiet aktualnej iteracji może często (jako całość) kończyć się błędem, ale to nie będzie miało wpływu na ogólną walidację regresji. Innym wariantem tego rozwiązania, w sytuacji gdy musimy częściej potwierdzać aktualne wymagania, jest stworzenie pakietu dla bieżącej wersji produktu. Zwróć uwagę na fakt, że wiele narzędzi automatyzacji umożliwia tworzenie równoległych hierarchii, przez co specyfikacja może w tym samym czasie znajdować się w różnych pakietach.
Wykonuj testy równolegle Kiedy: Możesz stworzyć kilka środowisk testowych
Jeśli należysz do szczęśliwców pracujących w firmie, w której stworzenie alternatywnych środowisk testowania nie jest problemem, po podziale większej grupy testów na mniejsze spróbuj wykonywać je równolegle. W ten sposób uzyskasz najszybszy możliwy feedback.
Jeżeli niektóre testy muszą być uruchamiane niezależnie od innych i nie można wykonywać ich równolegle, niezmiennie warto rozdzielić je na osobne pakiety. Takie rozwiązanie w zakresie ciągłej integracji i walidacji zostało zastosowane przez Jodie Parker z LMAX: Specjalna kompilacja wykonuje wszystkie testy jednostkowe i analizy statystyczne w ciągu 3 minut. Jeśli nie ma żadnego błędu, kolejne komponenty wykonują testy, które muszą być uruchamiane po kolei, a nie równolegle. Potem 23 komputery wirtualne wykonują testy akceptacyjne równolegle. Następnie startujemy z testem wydajności. Wykonanie [wykonywalnych specyfikacji] zwykle zajmuje od 8 do 20 minut. Na końcu, po wykonaniu pewnej liczby testów, do pracy zabiera się przedstawiciel kontroli jakości, do którego należy rozpoczęcie pobieżnych testów typu smoke test i testów eksploracyjnych w celu zapewnienia informacji zwrotnej z przebiegu rozwoju produktu. Jeśli commit do repozytorium kończy się niepowodzeniem, wszyscy muszą przerwać swoją pracę (całkowite embargo) i skoncentrować się na zidentyfikowaniu błędu. Jeśli nie masz paranoi na punkcie bezpieczeństwa albo nie działasz w ramach ograniczeń prawnych, które uniemożliwiają Ci przekazywanie kodu komukolwiek poza firmą, do wykonywania testów równoległych możesz wykorzystać coraz powszechniejsze usługi przetwarzania w chmurze. Przygotowanie kodu do zdalnego przetwarzania może zająć trochę czasu, ale takie rozwiązanie umożliwi Ci wykonywanie testów jednocześnie na bardzo dużej liczbie
Rozdział 10. Częsta walidacja
213
komputerów. W Songkick zespół używa chmury Amazon EC2 na potrzeby testów akceptacyjnych. Phil Cowans przyznaje, że takie rozwiązanie pomogło zespołowi istotnie skrócić czas kompilacji: Wykonanie całego zestawu testów na jednym komputerze zajmuje 3 godziny, ale my zdecydowaliśmy się na testy równoległe. Właśnie dowiedzieliśmy się, jak wykorzystać do tego celu chmurę EC2 i skrócić czas wykonania testów do 20 minut. Niektóre systemy ciągłej integracji, takie jak TeamCity4, zapewniają obecnie w standardzie wykonywanie testów w chmurze EC2. To sprawia, że wykorzystanie chmur przetwarzania w ramach ciągłej integracji staje się jeszcze łatwiejsze. Istnieją także nowe usługi oferujące automatyzację poprzez usługi w chmurach — przykładem może tu być Sauce Labs, na który warto zwrócić szczególną uwagę.
Spróbuj wyłączyć testy, z których wykonaniem wiąże się mniejsze ryzyko Kiedy: Feedback z testów jest bardzo niemrawy
Zespół w uSwitch zastosował unikalne rozwiązanie, które pozwala mu radzić sobie z opóźnieniami uzyskiwania informacji zwrotnej podczas uruchamiania pakietów testowych, na których zakończenie trzeba długo czekać. Zespół rezygnuje z testów, z których wykonaniem wiąże się większe ryzyko, po implementacji testowanych przez nie funkcji. Damon Morgan wyjaśnia: Czasami piszesz testy akceptacyjne (dobrze sprawdzające się jako źródło wiedzy na temat aktualnego kierunku, w jakim zmierza proces rozwoju produktu), które po tym, gdy funkcja zostanie już zaimplementowana, nie są już tak samo ważne jak wcześniej. Coś, co nie przekłada się w sposób istotny na kwestie związane z zarabianiem pieniędzy — na przykład funkcja wysyłania opóźnionych wiadomości e-mail — tak naprawdę nie jest rdzeniem funkcjonalności strony internetowej, choć ją uzupełnia… [Wykonywalne specyfikacje] świetnie sprawdzały się jako element stymulowania procesu wytwarzania oprogramowania, ale na późniejszym etapie ich wartość jako pakietów testów regresyjnych nie była już tak samo duża jak dawniej. Więcej kłopotów sprawiało ich utrzymanie niż odrzucenie. Mamy te testy w naszym systemie kontroli źródła, ale po prostu ich nie uruchamiamy. Gdyby doszło do rozszerzenia funkcjonalności, wciąż będziemy mogli modyfikować gotowy test.
4
http://www.jetbrains.com/teamcity.
214
Specyfikacja na przykładach
Moim zdaniem jest to rozwiązanie dość kontrowersyjne. Uważam, że jeśli test wart jest uruchomienia, niezmiennie warto go uruchamiać przez cały czas5. Większość testów zespołu uSwitch jest uruchamiana przez interfejs użytkownika webowego, co oznacza, że ich wykonanie trwa dość długo oraz że są one dość drogie w utrzymaniu. I to właśnie te kwestie zaważyły na decyzji zespołu. W przypadku systemu nie zawsze wymagającego uruchamiania pełnego zestawu testów wolałbym raczej automatyzację, która wygląda nieco inaczej i nie jest tak kosztowna (patrz podrozdział „Automatyzacja pod skórą aplikacji” w rozdziale 9.). Jednym z powodów tego, że zespół w uSwitch może pozwolić sobie na rezygnację z niektórych testów, jest fakt, iż dysponuje on zainstalowanym na stronie internetowej oddzielnym systemem monitorowania doświadczenia użytkownika, który informuje, czy użytkownicy zaczynają widzieć błędy, lub alarmuje, gdy częstotliwość korzystania z jakiejś funkcji nagle spada. Po omówieniu zagadnień związanych z szybkością uzyskiwania informacji zwrotnej oraz dążeniem do bardziej wiarygodnych wyników testów nadszedł czas, aby zająć się tematem dużo bardziej kontrowersyjnym. W miarę rozrastania się systemu dokumentacji wiele zespołów zaczyna zdawać sobie sprawę, że czasami trzeba zaakceptować testy, które kończą się niepowodzeniem. W następnej części przedstawię kilka dobrych pomysłów dotyczących radzenia sobie z testami informującymi o błędach, których nie można od razu poprawić.
Zarządzanie testami, które kończą się niepowodzeniem W Bridging the Communication Gap stwierdziłem, że test, który kończy się niepowodzeniem, powinien zostać natychmiast poprawiony. Jednak w świetle doświadczeń zebranych przeze mnie na potrzeby tej książki moje spojrzenie na tę kwestię uległo pewnej zmianie. Niektóre badane przeze mnie zespoły dysponowały setkami lub tysiącami testów ciągłej walidacji i sprawdzały dzięki nim różne funkcje, które powstawały na przestrzeni wielu lat. Według Pierre’a Veragena system kalkulacji w firmie Weyerhaeuser (o którym wspominałem w części „Wyższa jakość produktu” w rozdziale 1.) jest stale analizowany przez ponad 30 000 testów. Regularna, częsta walidacja tak dużej liczby specyfikacji umożliwia wychwytywanie wielu błędów. Z drugiej strony wykonywanie tak licznych testów często może oznaczać wolny feedback. A to znaczy, że problemy i błędy nie będą wychwytywane natychmiast i równie szybko rozwiązywane lub poprawiane. Czasami koniecznością będzie jak najszybsze uzyskanie wyjaśnień i opinii użytkowników biznesowych lub okaże się, że zidentyfikowane błędy mają niższy priorytet niż zmiany, które trzeba wprowadzić w ramach bieżącej iteracji. Tym samym może się zdarzyć, że nie będziemy w stanie naprawić wszystkich błędów zaraz po ich rozpoznaniu. Wówczas niektóre testy z zestawu ciągłej walidacji będą nieudane i przez jakiś czas trzeba będzie ten stan rzeczy akceptować. Gdy zestaw testów zawiera testy z błędami, ludzie mają skłonność do ignorowania dodatkowych problemów, które mogą wynikać 5
Szczerze mówiąc, pożyczyłem tę koncepcję od Davida Evansa, dlatego ewentualny cytat należałoby przypisać jemu.
Rozdział 10. Częsta walidacja
215
z faktu odłożenia zmian w testach kończących się niepowodzeniem. Dlatego pozostawienie ich samym sobie nie jest dobrym pomysłem. W dalszej części rozdziału znajdziesz kilka wskazówek dotyczących zarządzania regresją funkcjonalną w systemie.
Stwórz pakiet znanych nieudanych testów regresji Podobnie jak w przypadku pomysłu stworzenia oddzielnego pakietu wykonywalnych specyfikacji dla bieżącej iteracji, wiele zespołów tworzy pakiety zawierające testy, których prawdopodobieństwo niepowodzenia uznawane jest za wysokie.
Gdy odkryjesz, że jakiś test regresyjny kończy się niepowodzeniem, i zdecydujesz, że nie będziesz nic od razu zmieniał, przeniesienie go do osobnego zestawu umożliwi zachowanie poprawności reszty testów z głównego zestawu walidacyjnego.
Grupowanie nieudanych testów w oddzielnym pakiecie pozwala także śledzić liczbę takich problematycznych komponentów i zapobiec rozluźnieniu reguły dotyczącej czasowych awarii, o których zapomina się zaraz po tym, jak „wychodzą z więzienia”, a które zbierają się w pokaźny stosik i pewnego dnia dadzą o sobie znać ponownie. Stworzenie osobnego zestawu nieudanych testów pozwala także uruchamiać je wszystkie co jakiś czas dla ponownego sprawdzenia. Nawet jeśli test okazuje się nieudany, warto sprawdzić, czy nie pojawiają się jakieś dodatkowe błędy. W RainStor niezmiennie zaznacza się takie testy jako zawierające błędy, ale nadal są one wykonywane w celu sprawdzenia dalszej regresji funkcjonalnej. Adam Knight mówi: Pewnego dnia może się okazać, że test kończy się wynikiem negatywnym z powodu końcowych zer po przecinku. Jeśli następnego dnia sytuacja się powtórzy, pewnie wcale nie będziesz chcieć tego sprawdzać, bo wiesz, że test i tak się nie powiedzie. Ale może się również zdarzyć, że test zwróci całkowicie niewłaściwy wynik liczbowy. Potencjalne ryzyko związane z pakietem dla nieudanych testów regresji wiąże się z tym, że może się on stać łatwym wytłumaczeniem dla problemów z jakością produktu, które zostaną zidentyfikowane na późnym etapie dostarczania produktu. Wykorzystaj pakiet tylko na potrzeby znanych błędów i wyłącznie jako tymczasowe miejsce przetrzymywania tych testów, które wymagają dalszych wyjaśnień. Późne wychwytywanie błędów jest znakiem ostrzegawczym świadczącym o istnieniu jakiegoś innego problemu z procesem. Dobra strategia umożliwiająca uniknięcie złapania się w tę pułapkę zakłada ograniczenie liczby testów, które mogą być przenoszone do pakietu znanych błędów regresji. Niektóre narzędzia (na przykład Cucumber) zawierają funkcję zautomatyzowanego sprawdzania limitów tego pakietu. Utworzenie oddzielnego pakietu, w którym będą zbierane wszystkie nieudane testy, jest dobrym posunięciem z perspektywy zarządzania projektem, ponieważ w ten sposób możemy je monitorować i podjąć właściwe działania, jeśli tylko stos urośnie do niemożliwych
216
Specyfikacja na przykładach
do akceptacji rozmiarów. Jeden lub dwa mniej ważne problemy mogą nie być wystarczającym powodem, aby zatrzymać proces wytwarzania produktu, ale jeśli pakiet urośnie do kilkudziesięciu testów, to znaczy, że nadszedł czas, aby przerwać bieżące prace i oczyścić stos, zanim sprawy wymkną się spod kontroli. Jeśli test spędza dużo czasu w pakiecie znanych nieudanych testów regresji, może to być argument za przerwaniem prac nad rozwijaną właśnie funkcją, ponieważ wygląda na to, że nikt się nią za bardzo nie przejmuje.
Sprawdzaj automatycznie, które testy są wyłączone Kiedy: Nieudane testy zostają zneutralizowane, a nie trafiają do oddzielnego pakietu
Niektóre zespoły nie przenoszą nieudanych testów do oddzielnego pakietu, ale neutralizują je tak, aby znany nieudany test nie blokował ogólnej walidacji. Problem z tym podejściem wynika z faktu, że o takim „wyłączonym” teście łatwo zapomnieć. Osobny pakiet pozwala nam monitorować problemy i gwarantuje, że błędy w końcu zostaną poprawione albo że nie będziemy marnować czasu na usuwanie podobnego błędu, zanim nie zajmiemy się wyeliminowaniem przyczyny — źródła problemów. Nie możemy zrobić tego samego z testami, które zostały zneutralizowane. Dodatkowym problemem jest to, że ktoś może zdecydować o „wyłączeniu” testu sygnalizującego ważny problem systemu, nie rozumiejąc, iż wysoki priorytet problemu każe zająć się nim od razu.
Jeśli masz „wyłączone” testy, monitoruj je automatycznie.
Zespół Iowa Student Loan dysponuje automatycznym testem, sprawdzającym, które testy zostały wyłączone. Tim Andersen wyjaśnia: Ludzie wyłączali testy z różnych powodów: czekaliśmy na jakąś decyzję albo pisaliśmy nowy test i nie byliśmy pewni, jak w tym kontekście traktować ten pierwszy, albo przez jakiś czas zastanawialiśmy się nad jakąś funkcją, a potem nigdy do tej rozmowy nie wracaliśmy, albo po prostu zapominało się o włączeniu wcześniej wyłączonego testu. Czasami testy były wyłączane, ponieważ ktoś jeszcze nad nimi pracował albo nie dotyczyły żadnego konkretnego fragmentu kodu. Do wynajdywania testów, które zostały wyłączone, użyliśmy FitNesse. Przygotowaliśmy specjalną stronę, która sprawdzała wszystkie nazwy testów. Wykorzystywaliśmy te informacje do stworzenia listy testów, które zostały celowo wyłączone, i umieszczaliśmy znacznik JIRA [systemu śledzenia] obok każdego z nich. Tym samym lista testów wyłączonych bardzo przypomina kolejny test. Musi zgadzać się z grupą testów, o których mówiłeś, że są wyłączone. Na końcu iteracji sprawdzamy listę wyłączonych testów i wtedy można powiedzieć: »To nie ma już zastosowania, ten test po prostu usuwamy« albo »W tej kwestii mamy rozbieżne opinie i tak naprawdę nie usłyszeliśmy jeszcze, co na ten temat myślą klienci biznesowi«. W takim przypadku będziemy musieli poprawić test.
Rozdział 10. Częsta walidacja
217
Jeśli zdecydujesz się na tymczasowe wyłączenie testów kończących się niepowodzeniem, zamiast przenosić je do osobnego pakietu, upewnij się, że będziesz mógł łatwo je monitorować, i zadbaj, by nikt o nich nie zapomniał. W przeciwnym razie tworzony przez Ciebie system żyjącej dokumentacji szybko stanie się nieaktualny. Wyłączenie wykonywalnych specyfikacji jest szybkim i prostym rozwiązaniem tymczasowym, ale kłóci się z ideą ciągłej walidacji. Gdy dysponujesz już specyfikacjami poddawanymi ciągłej walidacji, w każdej chwili możesz stwierdzić, co robi system, przynajmniej jeśli chodzi o funkcje, które są pokryte wykonywalnymi specyfikacjami. Wówczas specyfikacje stają się elementem systemu żyjącej dokumentacji, która wyjaśnia działanie poszczególnych funkcji. W kolejnym rozdziale omówię kilka przydatnych wskazówek ułatwiających uzyskanie jak największych korzyści z zestawu wykonywalnych specyfikacji, które przekształcają się w system dokumentacji.
Pamiętaj Walidację wykonywalnych specyfikacji powinieneś wykonywać często, aby utrzymać ich wiarygodność. Inaczej niż w przypadku ciągłej integracji przy użyciu testów jednostkowych, dwa największe wyzwania stojące przed ciągłą walidacją dotyczą szybkiego feedbacku i stabilności. Stwórz odizolowane środowisko ciągłej walidacji i wykorzystaj pełną automatyzację konfiguracji, aby uczynić walidację bardziej wiarygodną. Szukaj sposobów jak najszybszego uzyskania informacji zwrotnej. Podziel testy na szybsze i wolniejsze, grupę aktualnej iteracji oddziel od pozostałych, a nawet podziel testy dłuższe na mniejsze zestawy. Nie wyłączaj testów nieudanych — albo rozwiąż problemy, albo przenieś testy do monitorowanego pakietu gromadzącego wyłącznie testy dotyczące mniej istotnych problemów regresji.
218
Specyfikacja na przykładach
11
Tworzenie systemu dokumentacji
W
rozdziale 3. przedstawiłem koncepcję żyjącej dokumentacji, wyjaśniając, dlaczego moim zdaniem jest ona taka ważna. Na razie nie zajmowałem się jednak szczegółami dotyczącymi tego, jak powinna być tworzona. W tym rozdziale omówię działania podejmowane przez zespoły, którym udało się wdrożyć moją koncepcję w życie. Żyjąca dokumentacja to coś więcej niż tylko katalog pełen wykonywalnych specyfikacji. Aby wykorzystać zalety żyjącej dokumentacji, musimy tak zorganizować nasze specyfikacje, by wspólnie tworzyły coś, co ma znaczenie, dodając do nich odpowiednie informacje kontekstowe, które pozwolą nam zrozumieć sens poszczególnych części. W najlepszym przypadku system żyjącej dokumentacji powinien pomóc nam zrozumieć działanie systemu, a to oznacza, że zgromadzone w nim informacje muszą być: Łatwe do zrozumienia. Spójne. Zorganizowane tak, aby dostęp do nich był łatwy. W tym rozdziale przedstawię techniki wykorzystywane przez ankietowane przeze mnie zespoły do zrealizowania wyszczególnionych celów.
Żyjąca dokumentacja powinna być łatwa do zrozumienia Przez rygorystyczne doprecyzowywanie specyfikacji tak, jak opisano w rozdziale 8., tworzymy wykonywalne specyfikacje, które są „ostre” i oczywiste, a ponadto opisane językiem domeny projektu. W miarę jak system dokumentacji rozrasta się, poszerzamy zakres gromadzonych danych, scalając lub dzieląc specyfikacje. Na następnych stronach znajdziesz kilka interesujących pomysłów na to, jak zagwarantować, żeby rozrastająca się żyjąca dokumentacja pozostała łatwo dostępna.
220
Specyfikacja na przykładach
Nie twórz długich specyfikacji Dokumentacja rośnie w konsekwencji dodawania nowych funkcji do systemu bazowego. Efekt jest taki, że tworzysz nowe specyfikacje i rozbudowujesz istniejące. Uważaj na specyfikacje, które za bardzo się rozrastają.
Specyfikacje, które stają się zbyt długie, często są sygnałem świadczącym o istnieniu jakiegoś problemu. Im dłuższa specyfikacja, tym trudniej będzie ją zrozumieć.
Oto kilka przykładów konsekwencji tworzenia przydługich specyfikacji: Pojęcia opisane w specyfikacjach nie są wyjaśniane na odpowiednim poziomie abstrakcji. Zadaj sobie pytanie: „Czego tu brakuje?”. Spróbuj zidentyfikować brakujące pojęcia, które pozwolą Ci poznać prawdziwe znaczenie testu. Identyfikacja brakujących pojęć może prowadzić do przełomów w zakresie projektu produktu. Zapoznaj się z częścią „Szukaj ukrytych koncepcji” w rozdziale 7. Specyfikacja opisuje kilka podobnych do siebie funkcji, zamiast skupiać się na jednej. Podziel specyfikację na kilka osobnych. Patrz „Specyfikacje powinny być ostre” w rozdziale 8., gdzie znajdziesz więcej szczegółów. Opisujesz funkcję przy użyciu skryptu, a nie specyfikacji. Przeprowadź restrukturyzację informacji i skup się na tym, co system ma robić, a nie jak to robi. Zobacz „Skrypty to nie specyfikacje” w rozdziale 8., gdzie znajdziesz więcej informacji. Specyfikacja zawiera zbyt wiele niepotrzebnych informacji kontekstowych. Oczyść ją, skupiając się na najważniejszych atrybutach, które ilustrują cel konkretnego testu.
Nie używaj wielu specyfikacji do opisania jednej funkcji W miarę ewolucji systemu zmienia się także nasze rozumienie domeny. Koncepcje, które pierwotnie wyglądają na różne, w miarę upływu czasu zaczynają wyglądać podobnie — odkrywamy, że są to dwie strony tego samego medalu. Podobnie możemy dzielić złożone pojęcia na mniejsze elementy, które nagle zaczynają wyglądać podobnie do istniejących koncepcji. W takich przypadkach wiele specyfikacji w systemie żyjącej dokumentacji, które opisują tę samą funkcję, powinno zostać połączonych. Zespół Rakesha Patela w Sky Network Services poszedł jednak w rozkładaniu specyfikacji o kilka kroków za daleko. Pojedyncza specyfikacja nie opisywała całej funkcji. Patel mówi:
Rozdział 11. Tworzenie systemu dokumentacji
221
Jeśli w jednym pliku masz za dużo przykładów, wówczas praca z nim okazuje się trudniejsza, ponieważ masz do przyswojenia dużo podobnego kodu. A przecież zawsze możesz patrzeć akurat na niewłaściwą część pliku. Kiedyś wolałem wiele różnych plików z różnymi przykładami. Jednak w takiej sytuacji masz do czynienia z rozproszeniem informacji, a jej śledzenie staje się trudniejsze.
Jeśli ktoś musi przeczytać dziesięć różnych specyfikacji, żeby zrozumieć, jak działa określona funkcja, najwyższy czas zreorganizować dokumentację.
Szukaj koncepcji wyższego poziomu Podczas dodawania funkcji do systemu często okazuje się, że uzyskujemy podobne specyfikacje, które różnią się tylko niewielkimi szczegółami.
Zrób krok wstecz i spójrz na specyfikacje z dalszej perspektywy. Odpowiedz sobie na pytanie: „Co opisują specyfikacje, jeśli spojrzymy na nie na wyższym poziomie abstrakcji?”.
Gdy zidentyfikujesz koncepcję wyższego poziomu, zazwyczaj uda Ci się stwierdzić, że grupa specyfikacji może zostać zastąpiona jedną, skoncentrowaną wyłącznie na tych atrybutach, które są różne dla całej grupy. Dzięki temu otrzymana specyfikacja będzie łatwiejsza do zrozumienia, wyszukiwania i udostępnienia. Identyfikacja brakujących pojęć może również doprowadzić do przełomów w projektowaniu systemu, podobnie jak w przypadku procesu opisanego w rozdziale 7. w części „Szukaj ukrytych koncepcji”.
Unikaj stosowania w testach technicznych pojęć automatyki Kiedy: Interesariusze nie mają wystarczającej wiedzy technicznej
Niektóre zespoły, tworząc swoje wykonywalne specyfikacje, koncentrują się na testach regresji funkcjonalnej i tworzą testy akceptacyjne mające charakter bardzo techniczny, zamiast skupić się na stworzeniu narzędzia komunikacji. Dzięki temu deweloperzy mogą szybciej pisać testy, ale często te testy trudniej odczytać, a zrozumienie ich przez kogoś, kto nie ma wiedzy dewelopera, zwykle bywa niemożliwe. Johannes Link zebrał właśnie takie doświadczenia podczas swojego pierwszego projektu z wykorzystaniem FIT1: Skończyło się tak, że mieliśmy mnóstwo testów, które zawierały liczne duplikaty. Deweloperzy mogli zrozumieć testy, ale stanowiły one tajemnicę dla każdego przedstawiciela strony biznesowej. W porównaniu z testami JUnit wykonanie i utrzymanie tych testów wymagało więcej czasu. Niektóre z nich trzeba było wyrzucić i stworzyć nowe w JUnit.
1
FIT to pierwsze narzędzie automatyzacji wykonywalnych specyfikacji.
222
Specyfikacja na przykładach Specyfikacje opisane w języku technicznym są nieefektywne w roli narzędzia komunikacji. Jeśli użytkownicy biznesowi interesują się wykonywalnymi specyfikacjami, to znaczy, że powinny być one opisywane w zrozumiałym dla nich języku. Jeśli specyfikacje w ogóle nie obchodzą użytkowników biznesowych, powinny zostać zdefiniowane w języku narzędzia technicznego.
System żyjącej dokumentacji, który zawiera techniczne koncepcje dotyczące automatyzacji, takie jak polecenia oczekiwania na zakończenie procesu, jest dla zespołu sygnałem mówiącym o konieczności przeprojektowania bazowego systemu oprogramowania. Konieczność zastosowania pojęć technicznych w dokumentacji często wskazuje na problemy z projektem systemu, takie jak niezawodność procesów asynchronicznych (patrz „Słuchaj swojej żyjącej dokumentacji” na końcu tego rozdziału). Używanie języka technicznego jest dopuszczalne tylko wtedy, gdy interesariusze mają wystarczającą wiedzę techniczną oraz potrafią zrozumieć, co dzieje się w kodzie zdefiniowanym w języku programowania (np. z zapytaniami SQL, identyfikatorami DOM i tak dalej). Zwróć uwagę, że nawet jeśli interesariusze mają wystarczającą wiedzę techniczną, użycie języka technicznego pozwala opisać raczej to, jak coś jest testowane, a nie samą funkcję systemu. Mimo że takie testy na początku pisze się szybciej, w dłuższej perspektywie może się okazać, że powodują one spore problemy w zakresie utrzymania. Zapoznaj się z częścią rozdziału 8. zatytułowaną „Skrypty to nie specyfikacje”, gdzie znajdziesz więcej informacji na ten temat. Do opisania testów akceptacyjnych w projekcie, w którym interesariusze dysponowali sporą wiedzą techniczną wystarczającą im do zrozumienia skryptów, Mike Vogel używał DbFit, rozszerzenia skryptów testowych bazy danych napisanych przeze mnie na potrzeby FitNesse. Teraz, z perspektywy czasu, uważa, że to był błąd: Na początku [interesariusze] byli zadowoleni, ponieważ mogli szybko zacząć używać Dbfit i nie musieli pisać własnych fikstur, więc od pierwszego dnia dysponowali zautomatyzowanymi testami. Później, gdy złożoność rozwiązania rosła, brakowało czasu, żeby wykonać kilka kroków wstecz i stworzyć fikstury testowe, które uprościłyby testy i były przy okazji bardziej zrozumiałe, zwiększając podatność systemu na testy. Skończyło się tak, że nasze testy były zbyt niepewne i zbyt skomplikowane.
Żyjąca dokumentacja powinna być spójna Żyjąca dokumentacja jest artefaktem projektu wyróżniającym się prawdopodobnie najdłuższym czasem życia. Technologie przychodzą i odchodzą, kod zostanie zastąpiony innym kodem, ale system żyjącej dokumentacji stale opisuje zasady dotyczące przedsięwzięcia, na potrzeby którego przygotowywany jest projekt. Przez kilka miesięcy albo nawet lat dodajemy do systemu różne treści — wszystko po to, żebyśmy później mogli go lepiej zrozumieć. Jednym z największych wyzwań stojących przed wieloma zespołami było utrzymanie spójności struktury i języka żyjącej dokumentacji. Stuart Taylor trafnie zauważa:
Rozdział 11. Tworzenie systemu dokumentacji
223
Istnieje niebezpieczeństwo, że gdy zaczynasz pisać bardzo jasne testy BDD [wykonywalne specyfikacje], będziesz mieć pięćdziesiąt siedem ścieżek nawigacji prowadzących cię do jednej strony, bo za każdym razem można zrobić to inaczej. Dlatego tak istotna jest refaktoryzacja języka i dojście do takiego momentu, w którym język nie będzie na tyle abstrakcyjny, żeby stał się niepraktyczny, a jednocześnie nie będzie tak szczegółowy, by nie można go było użyć w BDD. Spójny język pozwala także na bardziej efektywne zautomatyzowanie wykonywalnych specyfikacji. Dla Gaspara Nagya jest to jedna z głównych wytycznych procesu wytwarzania oprogramowania: Bardzo ważne jest używanie spójnej terminologii i koherentnego języka kryteriów akceptacji. Dzięki temu deweloperzy dostrzegają takie same konstrukcje, co ułatwia także automatyzację. Aby zachować spójność żyjącej dokumentacji, musimy stale ją udoskonalać i synchronizować z bieżącym modelem, spójnym z modelem zastosowanym w działającym systemie. W miarę ewoluowania koncepcji oprogramowania zmiana musi również znajdować swoje odzwierciedlenie w systemie żyjącej dokumentacji. Takie utrzymywanie dokumentacji oznacza konieczność poniesienia kosztów, ale bez spełnienia tych warunków nie można mówić o żyjącej dokumentacji.
Ewoluujący język Prawie wszystkim ankietowanym przeze mnie zespołom udało się opracować uniwersalny słownik języka specyfikacji, zestaw wzorców wielokrotnego użytku. W przypadku niektórych ów język ewoluował na przestrzeni kilku miesięcy, a zmiany często były wywołane przez bieżące problemy z utrzymaniem. Andrew Jackman wyjaśnia, że zespół Sierra w BNP Paribas rozpoczął rozwijanie słownika języka, gdy zauważył, jak zmienia się warstwa automatyzacji: Mamy tak dużo kodu fikstury, że staje się on źródłem problemów z utrzymaniem. Mieliśmy wiele bardzo specyficznych fikstur, w których były wykorzystywane bardzo dosłowne opisy sprawdzające się tylko w przypadku konkretnego testu, ale postaraliśmy się przeformułować je na język ogólny. Opracowaliśmy specjalny minisłownik, specyficzny dla domeny FIT, nadający się do zastosowania w testach internetowych. W ten sposób znacznie zredukowaliśmy kod fikstury. Niektórym zespołom szybko udało się opracować podstawy takiego języka. Dobrym przykładem może być zespół Roba Parka pracujący dla dużego amerykańskiego ubezpieczyciela: Język powstał bardzo szybko. Pierwsze trzy lub cztery fikstury klas [automatyzacji] miały charakter unikalny. Robiliśmy wszystko, żeby po prostu działały
224
Specyfikacja na przykładach
bez zarzutu, skupiając się na zagadnieniu komunikacyjności. Od razu zauważyliśmy powielanie plików kroków [klas automatyzacji] i zaczęliśmy świadomie temu przeciwdziałać. Dla każdej historyjki mieliśmy jeden plik w formacie Gherkin [wykonywalnej specyfikacji], ale dla tej samej funkcji mieliśmy też pięć czy sześć kart historyjki. W większości przypadków te kroki były bardzo do siebie podobne, więc stwierdziliśmy, że posiadanie jednego pliku dla wszystkich historyjek należących do danego elementu funkcjonalności biznesowej wychodzi produktowi na dobre. W przeciwnym razie, mimo że pliki te były naprawdę niezbyt rozbudowane, musielibyśmy radzić sobie z mnóstwem duplikatów.
Rozbudowa słownika języka pomaga zmniejszyć koszt utrzymania warstwy automatyzacji, ponieważ ponowne wykorzystanie istniejących wyrażeń do opisania nowych specyfikacji pozwala zachować spójność.
Fakt, że system żyjącej dokumentacji jest zautomatyzowany i powiązany bezpośrednio z oprogramowaniem, gwarantuje, że model oprogramowania pasuje do modelu biznesowego. W związku z tym dbanie o ewolucję języka systemu żyjącej dokumentacji jest doskonałym sposobem, aby stworzyć i utrzymać język wszechobecny (o którym mówiliśmy w rozdziale 8.).
Tworząc język specyfikacji, bazuj na personach Kiedy: W projektach internetowych
Niektóre zespoły opisują historyjki użytkownika, tworząc w tym celu specjalne profile wymyślonych użytkowników — tak zwane persony — zwłaszcza gdy projekt dotyczy tworzenia stron internetowych. W tych przypadkach język specyfikacji może odzwierciedlać aktywności podejmowane przez różne persony.
Persona może uprościć wykonywalne specyfikacje i sprawić, że staną się one łatwiejsze w utrzymaniu.
Zespół Iowa Student Loan uwzględnił w słowniku języka używanego do definiowania specyfikacji istnienie wymyślonych profili. Tim Andersen wyjaśnia: Zamiast o użytkownikach będących jakimiś amorficznymi polami w bazie danych, rozmawialiśmy o różnych osobach i ich motywacjach, sposobach korzystania z systemu i o tym, czego od niego oczekują. Nadaliśmy tym ludziom imiona. Boris był kredytobiorcą. Carrie to żyrant.
Rozdział 11. Tworzenie systemu dokumentacji
225
Persony okazały się pomocne, bo dzięki nim myśleliśmy o tym, jak system powinien zachowywać się z perspektywy użytkownika. Wykorzystanie person wiąże się z kilkoma pozytywnymi efektami ubocznymi, których wcześniej nie przewidzieliśmy. Na przykład: persony pomogły nam w testach [komponentach automatyzacji] dzięki wchodzeniu w interakcje z naszym systemem w bardziej odpowiednim punkcie wejściowym. Tworzenie takich zmyślonych profili nie ma wiele sensu w przypadku projektów, w których interakcja użytkowników jest niewielka. Bazując na sukcesie wykorzystania tego rodzaju wymyślonych profili użytkowników we wcześniejszym projekcie, Andersen próbował zastosować tę samą koncepcję do technicznego układu przetwarzania danych. W końcu jednak poddał się i zmienił język tak, żeby lepiej odpowiadał procesowi przepływu. Dane pochodzą z wielu źródeł i trafiają do systemu telefonicznego, aby użytkownicy mogli wykonywać połączenia. Dane telefonu są aktualizowane, a my odsyłamy je z powrotem do podmiotów, od których je otrzymaliśmy. To proces wsadowy. Nikt tak naprawdę go nie »używa«. Po prostu jest uruchamiany. W tym kontekście wymyślone profile użytkowników do niczego by się nie przydały. Próbowaliśmy zdefiniować testy z ich wykorzystaniem, ale reakcja klientów była bardzo chłodna — widzieliśmy tylko ich puste spojrzenia. Dlatego ostatecznie usunąłem cały związany z tą funkcją kod i zmieniliśmy go tak, żeby wykorzystać słowa kluczowe procesu Zakładając/Jeżeli/Wtedy. Kod stał się bardziej przejrzysty i bardziej zrozumiały dla wszystkich interesariuszy. Kształtowanie wszechobecnego języka na podstawie działań podejmowanych przez przykładowych użytkowników pozwala nam upewnić się, że nasze zrozumienie tego, czego oczekują od systemu prawdziwi użytkownicy, jest zgodne z tym, jak będą z niego korzystać. To definiuje strukturę i język używany w specyfikacji i pomaga nam zadbać o spójność systemu dokumentacji.
Promuj współpracę w celu zdefiniowania słownika języka Kiedy: Rezygnujesz z warsztatów specyfikacji
Jeśli nie zdecydujesz się na zorganizowanie dużych warsztatów specyfikacji i zamiast nich wybierzesz jakieś rozwiązanie alternatywne, upewnij się, że wszyscy współpracujecie w celu zdefiniowania wspólnego słownika języka.
Christian Hassa mówi, że współpraca dotycząca języka była jednym z największych wyzwań dla jego zespołu: Budowanie języka domeny, który byłby spójny i rozwijałby się we właściwym kierunku, bez żadnych podpowiedzi, byłoby zupełnie niemożliwe. Testerzy pisali coś, co deweloperzy musieli przeformułowywać. Czasami wynikało to z faktu,
226
Specyfikacja na przykładach
że testerzy tworzyli dokumenty niejasne lub niełatwe do powiązania [zautomatyzowania]. Gdy tester już się napracował, przeformułowanie wymagało zaangażowania znacznych zasobów. Kiedy próbowaliśmy wtedy natychmiast związać [zautomatyzować] pierwszy przykład, przekonywaliśmy się, że nie było to łatwe zadanie. Cała sytuacja przywodzi na myśl różnicę między programowaniem w parach a wykonywaniem sprawdzenia kodu po fakcie. Jeśli programujecie w parze, twój partner od razu zwróci ci uwagę, że jego zdaniem robisz coś źle. Jeśli robisz przegląd gotowego kodu, możesz co najwyżej powiedzieć: »Tak, następnym razem zrobię to inaczej, ale teraz zostawmy to tak, jak jest«. Christian Hassa sugeruje, żeby zamiast wyłapywać problemy z niespójnością po fakcie, po czym wracać do zidentyfikowanych błędów i je naprawiać, deweloperzy i testerzy łączyli się w pary już podczas pisania specyfikacji. Dzięki temu możliwe będzie unikanie problemów — nie będzie trzeba poprawiać błędów po fakcie. W podobny sposób współpracują ze sobą pilot i drugi pilot dla wyeliminowania problemów w kabinie samolotu. Ryzyko stworzenia nieodpowiedniej specyfikacji zostaje znacznie zmniejszone, ponieważ druga osoba sprawdza specyfikację na bieżąco i od razu wyłapuje problemy. Zespół Sierra w BNP Paribas dysponuje stosunkowo stabilnym słownikiem języka, który ewoluował przez wiele lat. Sami analitycy biznesowi zespołu używają go podczas definiowania nowych specyfikacji. Aby uniknąć niespójności języka lub trudności z automatyzacją, proszą deweloperów o sprawdzenie każdego komponentu, który ma strukturę znacznie różniącą się od istniejących specyfikacji. Podczas pracy nad Norwegian Dairy Herd Recording System zespół Bekk Consulting korzystał z podobnego procesu. Użytkownicy biznesowi zespołu piszą specyfikację z przykładami, ale deweloperzy dokonują przeglądu pracy i doradzają, jak zapewnić ich większą zgodność z resztą systemu żyjącej dokumentacji.
Gromadź dokumentację swoich bloków konstrukcyjnych
Dokumentowanie bloków konstrukcyjnych jest niewątpliwie dobrą praktyką. Podpowiada ludziom, jak mogą ponownie skorzystać z tych samych komponentów i zachować spójność użytego języka.
Niektóre zespoły przygotowują specjalny obszar dokumentacji, przeznaczony na potrzeby bloków konstrukcyjnych. W Iowa Student Loan zespół korzysta ze strony przedstawiającej wszystkie persony. W obszarze tym nie przechowuje się żadnych autorytarnych twierdzeń, lecz pokazuje, jakie bloki konstrukcyjne specyfikacji są już dostępne. Strona zespołu powstaje na bazie podstawowego kodu automatyzacji, tworząc żywy słownik żyjącej dokumentacji. Istnieje jednak jeszcze łatwiejszy sposób kompletowania dobrej dokumentacji dotyczącej języka projektu. Prawie wszyscy uczestnicy moich badań zapytani o to, jakich rad udzieliliby nowemu członkowi zespołu, który chciałby napisać dobrą specyfikację, sugerowali wykorzystanie przykładów z istniejących specyfikacji. Dobrym sposobem dokumen-
Rozdział 11. Tworzenie systemu dokumentacji
227
towania bloków konstrukcyjnych specyfikacji jest wyodrębnienie poprawnych, reprezentatywnych przykładów z istniejącego zestawu specyfikacji. Ponieważ specyfikacje te są już wykonywalne, dokumentacja składająca się z bloków konstrukcyjnych gwarantuje dokładność i spójność. Ponieważ żyjąca dokumentacja pomaga zespołowi na przestrzeni całego projektu, istnieje niebezpieczeństwo, że pewne jej elementy będą opisane w żargonie, który nie jest już używany. Jedna część może być napisana z użyciem zwrotów języka, którego zespół na przykład nie używa już trzy lata. W innej może znaleźć się terminologia sprzed dwóch lat i tak dalej, w zależności od tego, gdzie specyfikacja była pierwotnie napisana. W takim przypadku nie da się właściwie mówić o systemie dokumentacji, ponieważ musielibyśmy powierzyć komuś tłumaczenie starszych części na nowy język. Utrzymanie spójności dokumentacji w miarę ewoluowania języka naprawdę nie wymaga wielkiego wysiłku, a w dłuższej perspektywie spójna dokumentacja oznacza dla zespołu większe korzyści.
Żyjąca dokumentacja powinna być zorganizowana zgodnie z regułami ułatwiającymi dostęp Żyjąca dokumentacja szybko się rozrasta. W miarę ewoluowania projektu zespół implementacyjny będzie często dodawać do niej nowe dane. Po kilku miesiącach system dokumentacji może składać się z setek specyfikacji. Nie ma w tym niczego niezwykłego. Rozmawiałem z kilkoma zespołami, których systemy żyjącej dokumentacji składały się z ponad 50 000 testów nagromadzonych na przestrzeni kilku lat. Jeśli żyjąca dokumentacja ma być przydatna, użytkownicy muszą mieć możliwość łatwego odszukania opisu wybranej funkcji, co oznacza, że cały zestaw dokumentacji musi być dobrze zorganizowany, a poszczególne specyfikacje muszą być łatwo dostępne. Phil Cowans stwierdza, że dla niego jedną z najważniejszych lekcji wyniesionych z doświadczeń z żyjącymi dokumentacjami jest uświadomienie sobie faktu, iż tworzące je zespoły powinny od razu myśleć o strukturze wysokiego poziomu: Nie myśleliśmy o strukturze wysokiego poziomu testów. Po prostu dodawaliśmy nowe, gdy pojawiła się taka potrzeba. W rezultacie trudno było nam określić, których funkcji dotyczą poszczególne testy. Pomogłoby zdefiniowanie opisu zestawu funkcji witryny i zorganizowanie zestawu testów na tej podstawie (a nie tylko według ostatniego elementu, który został wdrożony). Myślę, że jest to przydatny element procesu wytwarzania oprogramowania i utrzymywania bazy kodu, która jest stosunkowo łatwa do zrozumienia. Jeśli za każdym razem, gdy chcemy zrozumieć, jak coś działa, musimy spędzać długie godziny, próbując stworzyć z setek pozornie niepowiązanych plików jakiś większy obraz, równie
228
Specyfikacja na przykładach
dobrze moglibyśmy zająć się lekturą kodu języka programowania. Aby w pełni wykorzystać zalety żyjącej dokumentacji, musimy sprawić, by poszukiwana informacja była łatwa do odnalezienia. Oto kilka wskazówek, jak osiągnąć taki cel.
Organizuj bieżącą pracę, segregując ją według historyjek Wiele narzędzi do automatyzacji wykonywalnych specyfikacji pozwala grupować je w hierarchie albo jako części strony internetowej, albo katalogów i podkatalogów plików.
Jeśli pracujesz z narzędziem służącym do automatyzacji wykonywalnych specyfikacji, generalnie dobrze jest grupować specyfikacje wspólnie, bazując na zakresie pracy, która akurat jest wykonywana.
Grupowanie specyfikacji w hierarchiach pozwala szybko wykonać wszystkie te specyfikacje w ramach jednej paczki testów, jak zasugerowałem w części zatytułowanej „Stwórz pakiet aktualnej iteracji” w rozdziale 10. Historyjka użytkownika zazwyczaj wymaga od nas zmiany kilku obszarów funkcjonalnych. Na przykład historyjka dotycząca ulepszenia procesu rejestracji może wpłynąć na raport o użytkowniku w systemie back-office i na to, jak system wykonuje weryfikację wieku użytkownika. Może również wymagać od nas wdrożenia nowych integracji z PayPal i Gmail. Wszystkie te funkcje powinny być opisane w osobnych i skoncentrowanych tylko na nich wykonywalnych specyfikacjach. Chcemy również stworzyć jasną definicję tego, kiedy każda historyjka jest ukończona. Wszystko, co jest związane z historyjką, powinno być zebrane w jednym miejscu, co ułatwi wykonanie wszystkich powiązanych z nią testów. Zapoznaj się z przykładem przedstawionym na rysunku 11.1 w gałęzi „Bieżąca iteracja”.
Zorganizuj historyjki na podstawie obszarów funkcjonalnych Historyjki użytkownika świetnie sprawdzają się w funkcji narzędzi planowania, ale nie nadają się za bardzo do organizowania istniejącego systemu funkcjonalności. Sześć miesięcy po integracji z systemem PayPal fakt, że funkcja ta pojawiła się w systemie jako element historyjki o numerze 128., jest właściwie bez znaczenia (chyba że jakieś regulacje wymagają od Ciebie zapewnienia możliwości śledzenia funkcji). Jeśli ktoś chciałby zrozumieć, jak działa integracja PayPal, musiałby znać numer historyjki, w której można tę funkcję znaleźć.
Większość zespołów reorganizuje swoje wykonywalne specyfikacje, umieszczając je w hierarchii na podstawie obszarów funkcjonalnych zaraz po wdrożeniu. Wyszukiwanie wyjaśnienia funkcji w hierarchii na bazie funkcji biznesowej staje się wówczas o wiele łatwiejsze.
Na rysunku 11.1 przedstawia tę zależność fragment gałęzi znajdujący się poniżej gałęzi „Zestawy funkcji”. Po implementacji historyjki o numerze 128. powinniśmy przejść do specyfikacji opisującej integrację z systemem płatności PayPal, zmiany raportów back-office do zarządzania użytkownikami i tak dalej. Takie zorganizowanie systemu żyjącej dokumentacji
Rozdział 11. Tworzenie systemu dokumentacji
229
pozwala szybko wyszukać wszystkie istniejące przykłady dotyczące płatności kartami MasterCard, gdy chcemy omówić zmianę żądania w ramach tej funkcji. Jeśli nadal chcesz wiedzieć, jak jakaś funkcja wkomponowuje się w konkretną historyjkę, istnieją narzędzia, które pozwolą Ci wyszukać tę samą specyfikację kompleksowo w różnych hierarchiach.
Rysunek 11.1. Hierarchia systemu żyjącej dokumentacji zorganizowana według obszarów funkcjonalnych (takich jak Płatności lub Zarządzanie kontem klienta). Specyfikacje bieżącej iteracji zostały pogrupowane według historyjek i funkcji. Znane niepełne zagadnienia, w przypadku których czekamy na więcej danych, mają zarezerwowane miejsce w drzewie hierarchii
Pogrupuj specyfikacje według dróg nawigacji w interfejsie użytkownika Kiedy: Dokumentujesz interfejsy użytkownika
W systemie żyjącej dokumentacji skopiuj strukturę nawigacji interfejsu użytkownika.
Zespół Iana Coopera w Beazley zastosował innowacyjny pomysł dotyczący organizacji systemu żyjącej dokumentacji. Zamiast katalogować specyfikacje według obszaru funkcjonalnego, zespół skopiował strukturę nawigacji interfejsu użytkownika i dopasował do niej system żyjącej dokumentacji. Ian Cooper wyjaśnia: Dzięki testom FitNesse mogliśmy wybrać historyjkę i po chwili wiedzieliśmy już, z czym się wiąże. Tyle że nawigowanie w tej formie było bardzo utrudnione. Skąd miałeś wiedzieć, gdzie znaleźć historyjkę, która miała być reprezentowana przez część oprogramowania?
230
Specyfikacja na przykładach
Przeprowadziliśmy optymalizację i teraz strona FitNesse wygląda jak strona pomocy. Mam test FitNesse, z którego dowiem się wszystkiego, czego chcę. Na jednej i tej samej stronie. A jeśli kliknę link znajdujący się obok okna dialogowego, system przeniesie mnie na inną stronę, która wyjaśnia zawartość okna. W ten sposób o wiele łatwiej jest sprawdzić, gdzie należy się udać, aby zdobyć wiedzę na temat działania określonego elementu. Takie podejście ma charakter intuicyjny i sprawdza się w systemach z jasno określonymi drogami nawigacji, takich jak aplikacje typu back-office. Jednak jeśli drogi komunikacji w interfejsie użytkownika często ulegają zmianom, rozwiązanie to może wiązać się z ewentualnymi problemami na etapie utrzymania.
Zorganizuj specyfikacje według procesów biznesowych Kiedy: Wymagana jest identyfikowalność przypadków użycia typu end-to-end
Stworzenie systemu żyjącej dokumentacji na bazie procesów biznesowych ułatwia śledzenie funkcjonalności systemu dla przypadków zastosowania typu end-to-end.
Mike Vogel pracował nad systemem, który miał wspierać badania farmaceutyczne. Zespół zorganizował żyjącą dokumentację według kategorii procesów biznesowych. Mike Vogel wyjaśnia, na czym polegało to rozwiązanie: Zorganizowaliśmy nasze testy [FitNesse] tak, żeby pasowały do przypadków użycia. Nasze przypadki użycia zostały pogrupowane w układzie hierarchicznym, w którym przypadek najwyższego stopnia decydował o nazwie celu systemu. Każdy przypadek użycia najwyższego poziomu był również definicją procesów biznesowych typu end-to-end dla tego celu. Przypadek użycia wskazywał przypadki użycia niższego poziomu, które były podprocesami. Spis treści dokumentu zawierającego wymagania jest identyczny ze spisem treści naszych testów. W ten sposób można było łatwiej zrozumieć, w jaki sposób testy pokrywają się z procesami biznesowymi. Rozwiązanie to zapewniało również bezpośrednią identyfikowalność na bazie wymagań biznesowych do testów, która jest kluczowym warunkiem spełnienia wymogów regulacyjnych w naszej domenie. Przedstawione przeze mnie metody to nie wszystkie sposoby organizacji żyjącej dokumentacji. Innym dobrym rozwiązaniem jest pogrupowanie informacji według rozdziałów systemu pomocy lub instrukcji użytkownika. Potraktuj zaproponowane rozwiązania jako inspirację, aby znaleźć najbardziej optymalny sposób ustalenia hierarchii, która najlepiej sprawdzi się w Twoim zespole.
Rozdział 11. Tworzenie systemu dokumentacji
231
Używaj znaczników zamiast adresów URL, odnosząc się do specyfikacji wykonywalnych Kiedy: Potrzebujesz identyfikowalności specyfikacji
Wiele narzędzi do tworzenia i zarządzania żywą dokumentacją obsługuje funkcję znaczników — tekstowych atrybutów o dowolnej formie, które możemy przypisać dowolnej stronie lub plikowi. Tego rodzaju metadane zazwyczaj sprawdzają się lepiej niż dążenie do utrzymania identyfikowalności specyfikacji w hierarchii historyjek użytkownika lub przypadków użycia. Kiedy zmienia się model domeny, najlepiej byłoby, gdyby żyjąca dokumentacja podążała za tymi zmianami. Bywa, że zmieniają się miejsca przechowywania specyfikacji, ich podziału i modyfikacji. Bazowanie na ścisłej statycznej hierarchii w zakresie śledzenia specyfikacji jest niemożliwe, ale zadanie to staje się łatwiejsze, jeśli historyjka lub przypadek użycia otrzymuje przypisany mu znacznik. Znaczniki przydają się również wtedy, gdy chcesz odwołać się do strony żyjącej dokumentacji z innego narzędzia, na przykład z systemu śledzenia zgłoszonych problemów lub aplikacji planowania harmonogramu. Użycie adresu URL na podstawie bieżącej lokalizacji strony uniemożliwiałoby ewentualne przeniesienie takiego dokumentu, ponieważ łącze będzie wskazywać niewłaściwą lokalizację.
Przypisanie znacznika i ustanowienie łącza do wyników wyszukiwania znacznika sprawia, że system będzie o wiele lepiej przygotowany na ewentualne zmiany.
Nawet jeśli nie korzystasz z narzędzi sieciowych i zachowujesz specyfikacje w katalogu projektu, dzięki zastosowaniu prostego skryptu nadal będziesz mógł używać znaczników. Takie rozwiązanie wykorzystał zespół pracujący dla Bekk Consulting przy tworzeniu systemu Norwegian Dairy Herd Recording. Børge Lotre wyjaśnia, na czym ono polega: Aby udostępnić testy Cucumbera klientom, używamy Confluence i wiążemy testy bezpośrednio z Subversion do Confluence. W tej sytuacji restrukturyzacja hierarchii plików testów Cucumbera nie odbywa się zupełnie bezboleśnie, ale znaczniki stanowią pomoc, która może równoważyć wady. Obecnie korzystamy ze znaczników w celu zaznaczania, które wymagania zostały objęte przez które testy Cucumbera. W systemie żyjącej specyfikacji unikaj bezpośredniego odwoływania się do poszczególnych specyfikacji, ponieważ w ten sposób uniemożliwiasz sobie później jakąkolwiek reorganizację. Znacznie lepiej sprawdzają się zewnętrzne łącza — metadane, znaczniki lub słowa kluczowe, które można wyszukać dynamicznie. System żyjącej dokumentacji to nie tylko stos wykonywalnych specyfikacji. Zagrzebana głęboko wewnątrz takiego niedającego się uporządkować stosu testów informacja staje się bezużyteczna jako dokumentacja. Aby skorzystać z długoterminowych korzyści specyfikacji przez przykłady, musimy upewnić się, że dokumentacja jest zorganizowana w sposób, który sprawia, że każdy może szybko znaleźć specyfikację dotyczącą danej funkcji i łatwo ją przetestować.
232
Specyfikacja na przykładach
Przedstawiłem najpopularniejsze metody organizowania specyfikacji, ale Ty wcale nie musisz spocząć na laurach. Znajdź swój własny sposób strukturyzacji dokumentów, który przez Twoich użytkowników biznesowych, testerów i deweloperów będzie uznany za intuicyjny i pozwoli im szybko znajdować to, czego szukają.
Słuchaj swojej żyjącej dokumentacji Wiele zespołów znajdujących się na początku swojej drogi ku przygodzie ze specyfikacją przez przykłady nie rozumiało, że żyjąca dokumentacja precyzyjnie odzwierciedla model domeny systemu, który opisuje. Jeżeli konstrukcja systemu bazuje na wykonywalnych specyfikacjach, ten sam wszechobecny język i modele domeny będą wykorzystywane zarówno w specyfikacjach, jak i w oprogramowaniu. Stwierdzenie przypadkowej złożoności wykonywalnych specyfikacji jest znakiem, że można uprościć system i ułatwić jego obsługę oraz utrzymanie sprawności. Channing Walton nazywa to podejście „słuchaniem swoich testów”. Walton pracował nad systemem zarządzania zleceniami dla UBS, w którym wykorzystywano złożone kryteria akceptacji dla przepływów pracy: Jeśli test jest zbyt skomplikowany, to jego układ mówi coś o tym, jak wygląda cały system. Badanie przepływu pracy było bardzo nieprzyjemnym doświadczeniem. Działo się za dużo, a testy były bardzo skomplikowane. Deweloperzy zaczęli pytać »dlaczego?«. Okazało się, że niepotrzebnie skomplikowaliśmy przepływy pracy w każdym dziale, nie bardzo orientując się w kwestii tego, co robią inni pracownicy. Testy okazały się pomocne, ponieważ to właśnie w nich trzeba było zebrać całą wiedzę na temat przepływów, więc ludzie mogli zobaczyć, że inny wydział również wykonuje walidację i obsługuje błędy. Całość udało się zmodyfikować i znacznie uprościć. Automatyzacja wykonywalnych specyfikacji zmusza deweloperów do doświadczania, jak to jest używać własnego systemu, ponieważ muszą oni korzystać z interfejsów przeznaczonych dla klientów. Jeśli wykonywalne specyfikacje są trudne do zautomatyzowania, oznacza to, że API klienta nie są łatwe w użyciu. A to z kolei znaczy, że nadszedł czas, aby je uprościć. Uświadomienie sobie tego faktu było jedną z najważniejszych lekcji dla Pascala Mestdacha: To, w jaki sposób piszesz swoje testy, przekłada się bezpośrednio na to, jak piszesz i projektujesz swój kod. Jeśli potrzebujesz zebrania i przechowywania danych pacjenta w części testu, to trzeba wykonać szereg działań: zebrać dane, umieścić je w czterech tabelach, wywołać dużą metodę, aby je przechować, oraz wywołać pewne metody konfiguracji dla tej klasy. To sprawia, że bardzo trudno dojść w końcu do tej części, w której faktycznie sprawdzasz swój scenariusz. Jeśli ta konfiguracja jest skomplikowana, jej przetestowanie będzie równie skomplikowane. A w końcu niełatwe okaże się także utrzymanie danych pacjenta w prawdziwym kodzie.
Rozdział 11. Tworzenie systemu dokumentacji
233
Markus Gärtner zwraca uwagę, że skomplikowana konfiguracja jest symptomem mówiącym o kiepskim projekcie API: Gdy zauważysz, że konfiguracja się wydłuża, pomyśl o użytkowniku twojego API i produkcie, który tworzysz. Ktoś będzie musiał później poradzić sobie jakoś ze skomplikowanym API. Czy na pewno tego chcesz? Problemy z utrzymaniem żyjącej dokumentacji mogą również stanowić wskazówkę, że architektura twojego systemu nie jest optymalna. Ian Cooper powiedział, że drobne zmiany kodu domeny — na wzór „chirurgii śrutówką” — często prowadziły do awarii wielu testów w systemie żyjącej dokumentacji. To sprawiło, że zaczynał zastanawiać się, jak poprawić projekt systemu: To znak, że coś jest nie tak z architekturą. Najpierw się opierasz, a potem zaczynasz zdawać sobie sprawę, że problem nie tkwi w FitNesse, ale w sposobie interakcji z aplikacją. Cooper zaproponował, aby traktować żyjącą dokumentację jako alternatywny interfejs użytkownika systemu. Jeśli pojawiają się kłopoty z napisaniem lub utrzymaniem tego „wirtualnego”, prawdziwy interfejs również będzie trudno napisać i utrzymać. Jeżeli pojęcie definiuje się poprzez złożone interakcje w ramach żyjącej dokumentacji, to prawdopodobnie oznacza, że te same skomplikowane interakcje pojawiają się w kodzie języka programowania. Jeśli dwa pojęcia w żyjącej dokumentacji są podobnie opisane, prawdopodobnie w modelu domeny również znajdzie się takie powielenie. Zamiast ignorować złożone specyfikacje, możemy uznać je za ostrzeżenie, że model domeny powinien zostać zmieniony lub że podstawowe oprogramowanie powinno zostać oczyszczone.
Pamiętaj Aby w pełni wykorzystać zalety systemu żyjącej dokumentacji, zadbaj o jego spójność i upewnij się, że poszczególne specyfikacje są zrozumiałe i łatwo dostępne — dla każdego, to znaczy także dla użytkowników biznesowych. Rozwijaj wszechobecny język i używaj go konsekwentnie. Podczas ewolucji systemu zwracaj uwagę na przydługie specyfikacje lub te z małych specyfikacji, które tylko nieznacznie różnią się od siebie. Postaraj się definiować koncepcje na wyższym poziomie abstrakcji, dzięki czemu pewne zagadnienia staną się łatwiejsze do wyjaśnienia. Zorganizuj system żyjącej dokumentacji w układzie hierarchicznym, który umożliwia łatwe wyszukiwanie wszystkich specyfikacji bieżącej iteracji i wszelkich funkcji zaimplementowanych wcześniej.
234
Specyfikacja na przykładach
CZĘŚĆ III
Studia przypadków
12
u
uSwitch
Switch.com to jedna ze stron internetowych najczęściej odwiedzanych przez internautów brytyjskich. Portal ten porównuje ceny produktów i usług różnych firm, analizując oferty dostawców energii, wydawców kart kredytowych oraz ubezpieczycieli. Skomplikowany system oprogramowania uSwitch bazuje na skalowalności oraz złożonych integracjach z dużą liczbą partnerów zewnętrznych. Projekt uSwitch jest interesującym studium przypadku, ponieważ służy za wzorcowy przykład tego, jak firma korzystająca z procesu kaskadowego z oddzielnymi zespołami ds. rozwoju oprogramowania i testowania, działającymi w trudnym środowisku, może przejść na znacznie lepszą metodykę dostarczania wysokiej jakości oprogramowania. uSwitch w ciągu trzech lat całkowicie zmodyfikowała proces wytwarzania oprogramowania. Moimi rozmówcami reprezentującymi zespół uSwitch byli: Stephen Lloyd, Tony To, Damon Morgan, Jon Neale i Hemal Kuntawala. Gdy pytałem, jak wygląda w ich zespole proces wytwarzania oprogramowania, wszyscy odpowiadali mniej więcej tak samo: „Rano ktoś wpada na jakiś pomysł, by po chwili rozwiązanie zostało zaimplementowane i trafiło do sieci”. Na początku mojej kariery zawodowej pracowałem dla pewnej firmy, której proces mógłby zostać opisany niemal tymi samymi słowami. Konsekwencją takiego schematu pracy prawie codziennie były prawdziwe fajerwerki nieporadności w systemach produkcyjnych. A mimo to jakość produktu i szybkość dostarczania nowych rozwiązań przez uSwitch trzeba uznać za wprost zadziwiającą! Chociaż w uSwitch nie podjęto świadomej decyzji o wdrożeniu specyfikacji przez przykłady, obecnie używany przez zespół firmy proces wytwarzania oprogramowania wykorzystuje najważniejsze wzorce opisane w tej książce, w tym także ustalanie zakresu na podstawie celów, współpracę w kwestii definiowania specyfikacji i automatyzację wykonywalnych specyfikacji. Aby usprawnić proces wytwarzania oprogramowania, zespół skoncentrował się na poprawie jakości produktów poprzez stałe wyszukiwanie i identyfikację problemów oraz usuwanie przeszkód stojących na drodze do uzyskania jak najlepszej jakości. Szukając synergii rozwoju i testowania, zespół zautomatyzował testy w formie czytelnej dla człowieka. Później członkowie zespołu odkryli, że testy mogą stać się specyfikacjami.
238
Specyfikacja na przykładach
Przejście na wykonywalne specyfikacje pozwoliło im zoptymalizować proces współpracy. W ramach doskonalenia procesu trzeba było znaleźć jakiś sposób, aby ciągła walidacja stała się bardziej wiarygodna, co doprowadziło zespół do poprawy metody udoskonalania specyfikacji. Szukając lepszych metod uzyskania zaangażowania użytkowników biznesowych, zespół zaczął definiować zakres prac na podstawie rozpoznanych celów.
Rozpoczęcie zmiany procesu W 2007 roku zespół uSwitch wykorzystywał metodę kaskadową, przygotowując długie projekty ze złożonymi, kompletnymi wymaganiami projektowymi definiowanymi przed rozpoczęciem procesu. W 2008 roku nowy CTO pchnął zespół w kierunku metodyki agile, wprowadzając trzytygodniowe iteracje Scruma. W październiku 2008 roku średni czas wprowadzania na rynek nowej funkcji w uSwitch wynosił sześć do dziewięciu tygodni. Mimo że był to w porównaniu z procesem kaskadowym ogromny postęp, w każdym sprincie wykonywano około 40% prac wcześniej zupełnie nieplanowanych. Scrum sprawdza się najlepiej w przypadku zespołów interdyscyplinarnych, ale ze względu na sposób zorganizowania prac w uSwitch nigdy nie udało się osiągnąć tego etapu. Zespół QA pracował niezależnie od zespołu deweloperskiego. Ponieważ testerzy korzystali z QTP — niedostępnego dla deweloperów — testerzy zajmowali się testowaniem, a deweloperzy rozwojem. Nie można było liczyć na efektywną komunikację między tymi grupami. W konsekwencji deweloperzy nie mieli pewności, kiedy tak naprawdę udało im się ukończyć prace nad produktem. Ponieważ kryteria akceptacji uwolnienia zakładały pozytywne zakończenie fazy testów QTP, testowanie często stawało się wąskim gardłem całego procesu. Proces konfiguracji kończący sprint trwał średnio trzy dni. Najczęściej na długość tego okresu miał wpływ czas poświęcony na testy, a zespół nadal miał sporo problemów z jakością. Gdy zespół przeszedł na krótkie iteracje, testy QTP zaczęły wymagać dłuższego czasu konserwacji. Według Hemala Kuntawali: „Nikt nie wiedział, co robiły te testy, i to była kompletna strata czasu”. Wreszcie cała firma zrozumiała konieczność podjęcia działań na rzecz poprawy jakości. Każdy pracownik został poproszony o to, żeby starał się myśleć przede wszystkim o jakości produktu. Firma zrozumiała, że zrzucanie przez deweloperów odpowiedzialności za prace na testerów bez jakichkolwiek wyjaśnień jest poważnym problemem, i dlatego postanowiono scalić zespoły deweloperów i testerów. Przestano używać różnych terminów dla określenia stanowiska pracy — testerzy stali się „deweloperami” ze szczególnymi specjalizacjami. W ten sposób zadania wymagające specjalistycznej wiedzy dotyczącej bazy danych mogły zostać przekazane bardziej doświadczonemu deweloperowi baz danych, a testerzy brali się za zadania, które wymagały specjalistycznej wiedzy z zakresu testowania. Jednak nie byli już odpowiedzialni wyłącznie za testowanie. Programiści zaczęli szukać lepszych sposobów napisania testów jednostkowych i funkcjonalnych. Zespół postanowił zrezygnować z QTP i zastąpić to narzędzie nowym — Selenium — czyniąc testy lżejszymi i łatwiej dostępnymi dla każdego zainteresowanego. Dzięki temu deweloperzy i testerzy mogli lepiej zorganizować swoją współpracę, ale jako że Selenium jest narzędziem bardzo technicznym, zmiana ta nie poprawiła komunikacji z użytkownikami biznesowymi.
Rozdział 12. uSwitch
239
Ponieważ firma uSwitch nie gromadziła żadnych godnych zaufania dokumentów dotyczących systemu, który rozwijano już od 10 lat, często zdarzało się, że starsze reguły biznesowe prowadziły do nieporozumień. Hemal Kuntawala mówi: Pewnego dnia dowiedziałem się o istnieniu reguły biznesowej w [podsystemie] Energia, o której wcześniej nie miałem zielonego pojęcia. To było frustrujące przeżycie. Chciałem znać reguły biznesowe i rozumieć działanie aplikacji bez zagłębiania się w kod i zapoznawania się z testami jednostkowymi. Właściwie to przecież nawet nie wszystkie elementy były poddawane testowaniu jednostkowemu. Szukając rozwiązania, stwierdziliśmy, że Cucumber może wypełnić lukę między testami i przedstawianiem tego, co chcieliśmy osiągnąć — czyli celem funkcji. Moglibyśmy napisać, czego chcemy, używając prostego języka, i pasowało to do podejścia outside-in forsowanego przez deweloperów. W ramach zaznajamiania wszystkich pracowników z nowym narzędziem zespół zaczął konwertować testy Selenium na testy Cucumbera. Wszyscy wciąż korzystali z automatyzacji — szukania problemów po fakcie — ale w konsekwencji działania te przygotowały grunt pod przejście na koncepcję „najpierw testy” wykonywalnych specyfikacji. Jon Neale wyjaśnia: Format wyrażenia Zakładając/Jeżeli/Wtedy testów Cucumbera zmusił nas do napisania na nowo wszystkich historyjek i skupienia się na konkretach dotyczących tego, co tworzymy. To uświadomiło nam, że o wielu rzeczach zapomnieliśmy. Zespół zajął się przeprowadzaniem interesariuszy biznesowych przez różne scenariusze Cucumbera, co miało na celu nie tylko zweryfikowanie przypadków brzegowych, ale również określenie wagi poszczególnych scenariuszy, co z kolei doprowadziło do zmniejszenia zakresu i ograniczenia kodu pisanego na wszelki wypadek. Gdy wszystkie testy Selenium znalazły swoje odpowiedniki w Cucumberze i gdy udało się je wszystkie przeanalizować wspólnie z użytkownikami biznesowymi, zespół zdał sobie sprawę, że testowanie na koniec iteracji nie ma sensu. Neale wyjaśniał: Zrozumieliśmy, że możemy wiele zyskać, jeśli usiądziemy razem i zorganizujemy warsztaty specyfikacji, rozrysowując, co dokładnie chcemy osiągnąć i jak to zamierzamy zrealizować. Wówczas zespół uzupełnił swój proces wytwarzania oprogramowania o warsztaty specyfikacji, będące metodą współpracy z użytkownikami biznesowymi na potrzeby zdefiniowania kryteriów akceptacji dla przyszłych wymagań. To znacząco poprawiło komunikację wewnątrz grupy. Deweloperzy (w tym momencie testerów również nazywano deweloperami) zdobywali wiedzę na temat domeny. Użytkownicy biznesowi poznawali przypadki brzegowe i dowiadywali się o istnieniu nietypowych ścieżek działań, ponieważ deweloperzy zadawali pytania dotyczące tego tematu.
240
Specyfikacja na przykładach
Wprowadzona zmiana miała także wpływ na podział pracy. Wcześniej pracę dzielono najczęściej według klucza technicznego. Przy takiej organizacji trudno było wypracować konkretne kryteria przyjęcia dla każdego zadania. Zespół przeniósł swoją uwagę z zadań wdrożeniowych na zagadnienia związane z wartością, którą miała zapewniać dana funkcja. Historyjki były teraz opisywane z perspektywy użytkownika, dzięki czemu łatwiej można było określić i omówić kryteria akceptacji dla poszczególnych fragmentów pracy. Ta nowa organizacja pozwoliła zespołowi także częściej oddawać gotowe do pracy oprogramowanie. Ponieważ zadania techniczne były od siebie zależne, deweloperzy niechętnie uznawali zadanie za ukończone, dopóki nie zakończono prac nad wszystkimi elementami większego bloku. Dzięki skoncentrowaniu się na historyjkach użytkowników deweloperzy pracowali odtąd na niezależnych, mniejszych komponentach, które mogły być częściej uznawane za ukończone i uwolnione.
Optymalizacja procesu W miarę jak rosła liczba wykonywalnych specyfikacji, zespół zaczął zauważać, że wyniki badań nie są w stu procentach wiarygodne. Problemy ze środowiskiem testowym często powodowały, że testy kończyły się niepowodzeniem, nawet jeśli implementacja funkcji była całkiem poprawna. Zespół nie dysponował stabilnym środowiskiem, w którym można by było uruchamiać testy. Istniało środowisko projektowe produktu, środowisko testowania oraz środowisko przejściowe, ale żadne z nich nie nadawało się do częstego uruchamiania wykonywalnych specyfikacji. Ponieważ deweloperzy korzystali ze swojego środowiska programistycznego dość dowolnie podczas wypróbowywania różnych funkcji, konfiguracja ulegała częstym modyfikacjom. Środowisko testerów wykorzystywano do testów ręcznych i przystosowywano je na potrzeby konkretnych rozwiązań. Ponieważ dwie różne konfiguracje mogły diametralnie różnić się ustawieniami, trudno było określić, z czego wynika niepowodzenie testu. W tym środowisku testy przeprowadzali również użytkownicy biznesowi, co mogło mieć negatywny wpływ na wyniki testów automatycznych Cucumbera. Środowisko przejściowe było zwierciadlanym odbiciem konfiguracji produkcyjnej i wykorzystywano je do testowania ostatnich kompilacji przed wdrożeniem. W uSwitch stworzono jeszcze jedno środowisko, które miało być wykorzystywane wyłącznie na potrzeby ciągłej walidacji. Chodziło o rozwiązanie problemów ze stabilnością. Było to dedykowane środowisko, które może być wykorzystywane do testów bez potrzeby przerywania innych prac, tworzone automatycznie przez system ciągłych kompilacji. Dzięki niemu informacje zwrotne z wykonywalnych specyfikacji otrzymywano szybko, a zebrane dane były znacznie bardziej wiarygodne. Po wyeliminowaniu problemów ze środowiskiem, będącym źródłem braku stabilności, zespół mógł się przekonać o tym, które testy lub części oprogramowania są niestabilne z powodu nieodpowiedniego projektu. Ponieważ wszystkie testy wykonywano przez interfejs użytkownika, wzrost liczby wykonywalnych specyfikacji prowadzących testy spowodował powstanie wąskiego gardła procesu. Niektóre testy trwały dłużej, a inne nie budziły
Rozdział 12. uSwitch
241
zaufania. Zespół zajął się najpierw eliminowaniem tych drugich, szukając jednocześnie przyczyn niestabilności. Testy były pisane na poziomie technicznym, co powodowało problemy z ich utrzymaniem. Zespół zaczął poprawiać testy, dzielić je na mniejsze części i zwiększać poziom abstrakcji. Hemal Kuntawala twierdzi, że to był ważny krok dla zespołu: Gdy zaczynaliśmy pisać testy, bazowały one na elementach typowych dla przeglądarek internetowych, na przykład takich jak identyfikatory DOM strony, które ulegały zmianom. Gdy przyzwyczailiśmy się do składni i potęgi Cucumbera, zaczęliśmy pisać testy w prawdziwym języku biznesu. Wcześniej na przykład napisalibyśmy: »Użytkownik wprowadza wartość 100 do pola box_id«. A teraz piszemy: »Użytkownik wprowadza poprawną wartość«. Poprawna wartość jest definiowana w osobnym teście. Gdy masz już definicję w jednym teście, nie trzeba powtarzać tego samego w każdym innym. Test dla poprawnych wartości będzie przewidywać wprowadzenie także liczb ujemnych, liter i tak dalej, ale najważniejsze jest to, że odeszliśmy od powtarzania tych danych w każdym teście. To był duży krok naprzód. Z myślą o zmniejszeniu długoterminowych kosztów utrzymania zespół uSwitch zaczął także udoskonalać specyfikacje, budować spójny słownik dla języka specyfikacji i zwracać uwagę na brakujące koncepcje w celu podniesienia poziomu abstrakcji. Przy stosunkowo dobrym pokryciu funkcjonalnym wykonywalnych specyfikacji i stabilnym środowisku ciągłej walidacji zespół uSwitch mógł bardziej zaufać swojemu kodowi. Jednak wykonywanie pakietu testów strasznie się ślimaczyło, a testowanie nie gwarantowało tak szybkiego feedbacku, na jaki liczyli członkowie zespołu. Zespół uznał, że nie wszystkie testy muszą być uwzględnione w zautomatyzowanym sprawdzianie regresji. Niektóre testy pomagały w rozwijaniu produktu, ale nie miały żadnego wpływu na funkcję, która przekładała się na realne zyski dla przedsiębiorcy. Jednym z przykładów takich funkcji było opóźnione wysyłanie korespondencji elektronicznej. Zespół uruchamiał automatycznie wykonywalne specyfikacje w trakcie prac nad implementacją funkcji, ale wyłączył test z pakietu po ostatecznym skonfigurowaniu i wdrożeniu funkcji. Tego typu testy niskiego ryzyka nie miały być uruchamiane w ramach procesu ciągłej walidacji. Dzięki temu zespół szybciej uzyskiwał potrzebne informacje zwrotne i zmniejszył także koszt utrzymania testów. Gdyby ktoś wznowił prace rozwojowe nad funkcjami z tej części systemu, test można byłoby ponownie włączyć i w razie potrzeby wprowadzić poprawki. Wykonywanie testów i sprawdzanie, czy system jest gotowy do pracy, przestało już być wąskim gardłem. Obecnie najtrudniejszą częścią procesu stało się wdrożenie do produkcji. Deweloperzy łączyli się w pary z inżynierami operacji, żeby znaleźć odpowiedź na pytanie, co spowalnia zespół. Okazało się, że przyczyną opóźnienia jest wykonywanie testów przedwdrożeniowych. Niektóre testy prowadziły do przekroczenia czasu oczekiwania w środowisku przejściowym, co wymagało od inżynierów operacji ponownego uruchomienia całego pakietu. Dzięki zidentyfikowaniu różnic w środowisku i przeformułowaniu testów tak, aby
242
Specyfikacja na przykładach
były bardziej odporne na błędy, deweloperzy skrócili czas wykonania całego pakietu testów z dwóch godzin do około 15 minut. Parowanie sprawiło, że inżynierowie operacji bardziej zaangażowali się w proces. Poprzednio zgłaszali tylko fakt, że wykonanie pakietu testów się nie powiodło, ale w ich raportach brakowało szczegółów. Teraz gdy inżynierowie wreszcie zrozumieli, jak interpretować wyniki testów, jeśli coś poszło nie tak, mogli przekazać deweloperom nieco więcej istotnych szczegółów. Kolejna zmiana dotyczyła większego zaangażowania użytkowników biznesowych w proces wytwarzania oprogramowania. Chociaż zespół do tej pory korzystał z planowania z historyjkami użytkownika, to historyjki te powstawały w zamkniętym gronie członków zespołu. Teraz użytkownicy biznesowi zaczęli pisać historyjki we współpracy z deweloperami, biorąc na siebie większą odpowiedzialność za własność specyfikacji. Użytkownicy częściej odnosili się do korzyści („aby…”), dzięki czemu deweloperzy mogli skoncentrować się na określeniu rozwiązania („chcę…”). Użytkownicy biznesowi stali się również odpowiedzialni za prowadzenie warsztatów specyfikacji. Te zmiany przyniosły poprawę komunikacji w zespole. Damon Morgan wyjaśnia: Dawniej [użytkownicy biznesowi] byli wyłączeni z procesu. Pytali: »Czy możemy to mieć?«, a my zapisywaliśmy to w jakimś dziwnym języku, którego wcale nie musieli rozumieć. Widzieli, jak zapis zmieniał pozycję w procesie, ale tak naprawdę to nic dla nich nie znaczyło. Gdy zaczęliśmy organizować warsztaty [specyfikacji] i mogliśmy wyjaśnić im, co właściwie powinno być dostarczone, a także zdefiniować kryteria wykonania dla historyjek, przy których tworzeniu pracowaliśmy wspólnie z nimi, użytkownicy biznesowi o wiele bardziej zaangażowali się w nasze prace na rzecz stworzenia produktu. Wówczas nie zdarzało się już, że historyjka wracała do nas z opisem typu: »Nie zrobiliście tego tak, jak chcieliśmy«. Częściej pojawiały się raczej komentarze w rodzaju: »Jako zespół w ogóle nie pomyśleliśmy o takim scenariuszu«. Większe zaangażowanie ze strony użytkowników biznesowych pozwoliło zespołowi uSwitch poprawić poziom wzajemnego zaufania członków grupy oraz ich pewność siebie. Oznaczało to, że nie było potrzeby ustalania długoterminowych priorytetów i definiowania dużych porcji pracy. Jednocześnie użytkownicy biznesowi stali się bardziej otwarci na propozycje deweloperów. Dzięki bliższej współpracy i wzrostowi poziomu zaufania użytkownicy biznesowi byli gotowi inaczej spojrzeć na kwestię zakresu rozwoju produktu. W kolejnym kroku zespół zaczął dzielić wymaganą funkcjonalność na minimalne funkcje, które nadawały się do uwalniania do produkcji, a jednocześnie wciąż zapewniały przedsiębiorcom istotną wartość. Jednym z przykładów takiego działania może być proces modyfikowania katalogu „Energia” — czteropoziomowej strony hierarchii zawierającej spis dostawców i planów dostaw energii. Zamiast czekać z uwolnieniem wszystkich gałęzi naraz, zespół zajął się przepisywaniem i modyfikowaniem po jednej stronie. Gotową stronę łączono następnie z siatką pozostałych usług i w tej formie uwalniano produkt. Chociaż takie podejście oznaczało
Rozdział 12. uSwitch
243
zwiększenie kosztów integracji — bo nowe strony musiały zostać jakoś umiejętnie połączone ze starszymi — zespół czerpał wiele korzyści z wcześniejszego uwolnienia produktu. Jednym z argumentów przemawiających za reorganizacją katalogu było zoptymalizowanie hierarchii pod kątem skuteczności wyszukiwania: Uwalnianie po jednej stronie oznaczało, że wyszukiwarka Google mogła indeksować je wcześniej. Ponadto zespół stwierdził, że mniejsze wersje zmniejszają ryzyko pomyłek. Jeżeli pojawi się jakiś błąd, będzie go można od razu przypisać do znanej wersji produktu. Dzięki podzieleniu pracy na mniejsze fragmenty łatwiej było określić przyczynę błędów. Gdy zespół zaczął przygotowywać potencjalnie gotowe do przekazania klientowi wersje produktu częściej niż w jednej iteracji, wąskim gardłem stało się uzyskanie akceptacji wersji wraz z końcem iteracji. Zamiast podczas jednej dużej demonstracji w końcu iteracji zespół zaczął prezentować użytkownikom biznesowym (i uzyskiwać ich akceptację) nowe możliwości produktu, gdy tylko uwolniony został fragment szerszej funkcjonalności. Zespół zauważył, że nie było już potrzeby organizowania formalnych warsztatów specyfikacji. Zostały one zastąpione nieformalnymi spotkaniami. Mniejsze zadania i szybki feedback pozwoliły zespołowi zabierać się za realizację projektu, gdy tylko stwierdził, że ma wystarczająco dużo informacji, aby rozpocząć prace, nawet jeśli nie zawsze dysponował kompletnymi danymi, umożliwiającymi wykonanie całego zadania. Według Damona Morgana: Na początku te spotkania [warsztaty specyfikacji] trwały o wiele dłużej i uczestniczyło w nich o wiele więcej osób. Staraliśmy się również przygotować wówczas bardziej rozbudowane specyfikacje. Tymczasem obecnie wszystko sprowadza się właściwie do stwierdzenia: »Zamierzamy rozpocząć prace nad implementacją tej funkcji« i tyle… Konkretna funkcja jest stosunkowo niewielkim wycinkiem produktu, dlatego wystarczy nam, że będziemy rozmawiać bezpośrednio z zainteresowanymi stronami. Cały zespół zbiera się na swoistym warsztacie minispecyfikacji, ale tak naprawdę spotkanie ma charakter nieformalny. Bez zadęcia. W tym czasie po prostu ze sobą rozmawiamy. Nie musimy nawet rezerwować specjalnie sali konferencyjnej. Definiujesz kryteria, tworzysz produkt i pokazujesz go o wiele szybciej. Zwykle funkcja powstaje i jest dostarczana w przeciągu dwóch dni, a potem od razu przechodzimy do następnej. W ten sposób jesteśmy znacznie bardziej iteracyjni w swojej pracy. Ponieważ dzięki nowemu kształtowi procesu deweloperzy mogli dowiedzieć się o wiele więcej na temat domeny biznesowej, ludzie nie mieli tylu problemów, ile dawniej, spowodowanych niezrozumieniem wymagań biznesowych. Można było od razu wykonać poprawnie wszystkie zadania mimo mniejszej ilości informacji otrzymywanych z góry. Stephen Lloyd wyjaśnia: Jesteśmy znacznie lepiej zintegrowani jako zespół i o wiele lepiej rozumiemy oczekiwania przedsiębiorców. A zatem cel specyfikowania dokładnie tego, co jest potrzebne, staje się mniej ważny, ponieważ znacznie lepiej niż rok temu rozumiemy domenę, w której działamy.
244
Specyfikacja na przykładach
Ostatecznie zespół uSwitch przeszedł na proces wdrażania na żądanie i całkowicie zrezygnował z iteracji. Aby zoptymalizować ten proces, członkowie zespołu zaczęli regularnie monitorować swoje systemy produkcji, śledząc wskaźniki błędów i wykorzystanie nowych funkcji. Ta dodatkowa transparentność pracy stała się siatką bezpieczeństwa, chroniącą zespół przed niezauważonymi wcześniej problemami wdrożeniowymi.
Obecny kształt procesu Po tych wszystkich zmianach proces wytwarzania oprogramowania w uSwitch stał się znacznie prostszy. Jest wyjątkowo lekki i bazuje na przepływach, a nie na iteracji. Nowe pomysły trafiają do rejestru produktu, gdy tylko ktoś podsunie je podczas codziennych spotkań scrumowych. Każdy ma prawo przedstawić swój pomysł — również użytkownicy biznesowi i deweloperzy. Nowa koncepcja zostaje przeanalizowana podczas krótkiego spotkania „na stojąco” — w ramach dyskusji przeprowadzonej w nielicznym gronie — a następnie poddana priorytetyzacji. Osoba, która wyszła z propozycją, może przed spotkaniem stworzyć szkice wyjaśniające, a także przygotować opis przypadku biznesowego w celu lepszego przedstawienia całego zagadnienia. Poza tym, o ile zawczasu nie trzeba definiować treści umów z partnerami zewnętrznymi, nie jest konieczne jakieś specjalne wstępne przygotowywanie projektu. Gdy historyjka staje się jednym z elementów o najwyższym priorytecie, zespół zastanawia się, jakie kroki doprowadzą projekt funkcji do szczęśliwego końca. Wówczas spotykają się wszyscy interesariusze tej historyjki, by krótko omówić to, czego potrzebuje zespół, i zdefiniować kryteria akceptacji. W przeszłości zespół tworzył podczas takich spotkań testy Cucumbera, ale po jakimś czasie stwierdzono, że składnia narzędzia stała się przeszkodą: na takich spotkaniach testy musiałaby tworzyć jedna osoba, podczas gdy inni tylko by się przyglądali, co zakłócałoby swobodny przepływ idei w czasie dyskusji. Grupa deweloperów i zespoły ds. marketingu i poczty siedzą tuż obok siebie, dzięki czemu mogą od razu przejść do ustalenia konkretów. Deweloperzy rozpoczynają prace nad historyjkami i często wymieniają komentarze z użytkownikami biznesowymi, prosząc o więcej informacji lub ponowne zdefiniowanie kryteriów akceptacji. Kryteria akceptacji zostają przekonwertowane na testy Cucumbera i zautomatyzowane w trakcie prac rozwojowych. Deweloperzy wykorzystują testowanie eksploracyjne, żeby przed wprowadzeniem zmian zdobyć więcej informacji na temat elementów systemu. Czasem korzystają z zapisu sesji klienta, aby poznać przebieg prawdziwej interakcji użytkowników z konkretną funkcją serwisu. Na tej podstawie tworzą testy Cucumbera i rejestrują ścieżki nawigacji użytkownika, które powinni uwzględnić przy pracy. Zwykle używają w tym celu zestawów narzędzi do automatyzacji testów przeglądarki poprzez interfejs użytkownika. Nie korzystają już z ręcznej obsługi skryptów, ale wykonują wiele testów eksploracyjnych, w tym także takich prowadzących do identyfikowania różnych nietypowych ścieżek nawigacji przez system, a także podejmują próby doprowadzenia do błędnego działania systemu. Gdy wszystkie scenariusze Cucumbera kończą się wynikami pozytywnymi, zmiana zostaje wdrożona w środowisku uwalniania, a następnie tego samego dnia przekazana do produkcji.
Rozdział 12. uSwitch
245
Na ogół zespół nie monitoruje wielu technicznych wskaźników projektu. Zamiast tego skupia się głównie na czasie realizacji i przepustowości. Dużo więcej uwagi poświęca się wynikom wydajnościowym systemu działającego w środowisku użytkownika i wartości dodanej przez funkcję. W tym celu zespół śledzi metryki doświadczeń użytkowników, takie jak m.in. wskaźnik CR (ang. conversion rate) czy częstotliwość korzystania z funkcji na stronie internetowej. W czasie gdy zbierałem materiały do tej książki, zespół uSwitch zdecydował się zrezygnować z szacunków. Szacunki przydają się, gdy użytkownicy biznesowi nie mają zaufania do zespołu deweloperskiego lub gdy chcą zainwestować w zlecenie większych projektów, a żaden z tych scenariuszy nie dotyczy uSwitch. Użytkownicy biznesowi mają lepszy obraz rozwoju i darzą deweloperów większym niż wcześniej zaufaniem. Także oni pracują na ogół na małych iteracjach. Oszacowanie długości pracy nad wdrożeniem jakiejś funkcji w tym przypadku nie jest konieczne.
Efekt końcowy Średni czas wytworzenia funkcji w przypadku uSwitch — od momentu akceptacji, przez etap rozwoju, aż po gotowy produkt oddawany do użytku — wynosi obecnie cztery dni. Kiedy rozmawiałem z członkami zespołu, nikt nie był w stanie przypomnieć sobie żadnego poważnego problemu w produkcji w czasie ostatnich sześciu miesięcy. Bumerangi zdarzają się rzadko — raz na kilka miesięcy. Podczas prezentacji Hemala Kuntawali w grupie użytkowników Agile Testing UK1 w 2009 roku jeden z menedżerów ds. rozwoju uSwitch powiedział, że „jakość znacznie wzrosła, podobnie jak współczynnik konwersji”. Cały proces wytwarzania oprogramowania w uSwitch bazuje obecnie na oczekiwanych wartościach biznesowych funkcji. Zamiast tworzyć wielkie plany i równie wielkie kompilacje, zespół pracuje nad regularnym dostarczaniem małych przyrostów i sprawdza, czy nowy element przekłada się na wzrost biznesowej wartości dodanej. Ponieważ model biznesowy zespołu zależy bezpośrednio od wskaźnika CR strony internetowej, tego rodzaju szacunki są łatwo dostępne. Z kilkoma interesującymi wskaźnikami oraz opisem ewolucji procesu można zapoznać się, oglądając slajdy przygotowane przez Marka Durranda i Damona Morgana do prezentacji na konferencji Spa20102.
Najważniejsze lekcje Moim zdaniem jednym z najważniejszych przekazów tej historii jest fakt, że zespół uSwitch postanowił skupić się na poprawie jakości produktu, a nie koncentrował się na wdrożeniu konkretnego procesu (więcej na ten temat w części „Skup się na poprawie jakości” w rozdziale 4.). Zamiast szukać działań efektownych, zespół nieustannie zmierzał do wdrożenia rozwiązań efektywnych, identyfikując elementy, które można było poprawić, i to właśnie 1
Patrz https://skillsmatter.com/skillscasts/910-how-we-build-quality-software-at-uswitch-com oraz http://gojko. net/2009/10/29/upgrading-agile-development-at-uswitch-com-from-concept-to-production-in-four-days/. 2 www.slideshare.net/markdurrand/spa2010-uswitch.
246
Specyfikacja na przykładach
od nich zaczynał swoją pracę. Gdy ludzie przyzwyczaili się do zmiany będącej konsekwencją nowego podejścia, wystarczyło tylko ponownie przeanalizować cały proces i zająć się kolejnym zagadnieniem. Uświadomienie sobie, że etap testowania jest wąskim gardłem procesu, a testy QTP są zbyt kosztowne i niewygodne dla deweloperów, doprowadziło zespół do przyjęcia specyfikacji przez przykłady wdrożonej za pośrednictwem automatyzacji testów funkcjonalnych, podejścia, które zaproponowałem w części zatytułowanej „Zacznij od automatyzacji testów funkcjonalnych” w rozdziale 4. W uSwitch najpierw wypróbowano Cucumbera, wykorzystując to narzędzie do automatyzacji testów funkcjonalnych, ale wkrótce uświadomiono sobie, że można osiągnąć jeszcze większe korzyści, ponieważ Cucumber umożliwia automatyzację testów przy zachowaniu ich formy czytelnej dla człowieka. W tym momencie proces tworzenia specyfikacji zmienił się diametralnie. Inną ważną lekcją z historii modyfikacji procesu wytwarzania oprogramowania w uSwitch jest uświadomienie sobie, że zmiany, choć początkowo są jedynie konsekwencją zastosowania takiego, a nie innego narzędzia, mają głównie charakter kulturowy. W zespole uSwitch najpierw zmieniono podział na grupy testerów i deweloperów, a następnie zupełnie zrezygnowano z przydzielania funkcji testera, dzięki czemu wszyscy członkowie zespołu zrozumieli, że problem niezadowalającej jakości jest problemem wszystkich osób zaangażowanych w prace nad produktem. Ludzie zaczęli się koncentrować na dostarczaniu wartości biznesowej, a nie na realizacji zadań technicznych, co pozwoliło im zwiększyć zaangażowanie użytkowników biznesowych, odtąd bardziej udzielających się w procesie rozwoju. Bez takiej ścisłej współpracy z użytkownikami biznesowymi w tak krótkim czasie realizacji niemożliwe byłoby zdecydowanie o tym, co powinno zostać wytworzone, uzyskanie powszechnej akceptacji i wdrożenie, a potem przeprowadzenie testów. Większe zaangażowanie użytkowników biznesowych sprawiło, że i oni zaczęli lepiej rozumieć, na czym polega praca zespołu, i byli gotowi zaufać deweloperom w stopniu o wiele większym niż wcześniej. Również deweloperzy zdobyli większą wiedzę o domenie biznesowej. Formalne warsztaty specyfikacji były ważnym krokiem na drodze do zebrania tej wiedzy. Po zoptymalizowaniu komunikacji, gdy deweloperzy zyskali lepsze rozumienie domeny, formalne warsztaty specyfikacji stały się zbędne. Losy zespołu uSwitch są przykładem, jak dzięki zebraniu przez zespół wystarczającej wiedzy można usprawnić proces wytwarzania oprogramowania. Moim zdaniem najbardziej kontrowersyjną decyzją uSwitch było wyłączenie niektórych mniej ważnych testów po wdrożeniu pewnego zakresu funkcji. Miałem okazję zapoznać się z innymi koncepcjami różnych zespołów, ale tylko uSwitch nie uruchamia regularnie wszystkich testów systemu żyjącej dokumentacji. Wykonywalne specyfikacje są dla nich naprawdę opcjonalne — to znaczy można je wykonać, ale nie ma takiego obowiązku. Zespół stwierdził, że wykonywanie tych testów podczas prac nad funkcją przynosi mu wiele korzyści, ale wolniejszy feedback będący wynikiem stale rozrastającego się zestawu testów w dłuższej perspektywie kosztuje więcej niż zabezpieczenie przed regresją funkcjonalną w obszarach mniej ryzykownych. Być może wynika to z tego, że zespół uSwitch korzysta z innych środków ochrony przed problemami w produkcji, ze szczególnym uwzględnieniem ciągłego monitorowania doświadczeń użytkowników.
13
RainStor
R
ainStor jest firmą brytyjską, która zajmuje się tworzeniem systemów dużej pojemności do zarządzania danymi i ich archiwizacji. Losy RainStor są interesującym studium przypadku, ponieważ zespół działa na obszarze bardzo technicznej domeny, której złożoność wynika z dużych ilości danych i wymagań wysokiej wydajności, połączonych z zaawansowanymi algorytmami kompresji danych i zarządzania nimi. Firma zatrudnia mniej niż trzydziestu pracowników, przy czym około połowa z nich pracuje w dziale badań i rozwoju, dlatego ludzie ci muszą być naprawdę skuteczni w wytwarzaniu i utrzymaniu swojego oprogramowania. Wszyscy deweloperzy i testerzy pracują w ramach tego samego zespołu scrumowego, chociaż szefowie firmy zastanawiają się obecnie nad podzieleniem go na dwie części. Przygoda zespołu ze specyfikacją przez przykłady miała formę bliską organicznej, bez wielkich planów i używania słów wytrychów. Motorem napędowym zmian byli głównie testerzy. Gdy rozmawiałem z Adamem Knightem, starszym testerem i liderem zespołu wsparcia w RainStor, usłyszałem, że „Nikt inny w firmie nie wie, co oznacza termin ATDD”. Mimo że proces zastosowany przez RainStor ma prawie wszystkie kluczowe cechy specyfikacji przez przykłady, członkowie zespołu traktują go tak, jakby ta koncepcja wytwarzania oprogramowania zrodziła się w głowach członków zespołu. Ilustrują wymagania przykładami, zautomatyzowali wykonywalne specyfikacje i przeprowadzają częstą walidację w celu skompletowania systemu żyjącej dokumentacji. Wprowadzone przez zespół modyfikacje procesu wytwarzania oprogramowania sprawiły, że w ciągu trzech lat liczebność zespołu deweloperskiego zwiększyła się trzykrotnie przy jednoczesnej wydatnej poprawie efektywności pracy zatrudnionych ludzi.
Zmiana procesu Trzy lata temu nowy CEO zdecydował o wdrożeniu Scruma i rozbudował zespół czterech deweloperów, zatrudniając dwóch testerów i menedżera testowania. Mimo że zespół pracował w iteracjach i codziennie organizował scrumowe spotkania stojące, według Knighta tak naprawdę ciągle pracowano w systemie, który można było nazwać minikaskadowym:
248
Specyfikacja na przykładach
Mieliśmy wymagania zdefiniowane w wielostronicowej dokumentacji wprowadzanej na początku sprintu. Miał to być zarówno dokument wymagań, jak i specyfikacji technicznych. Jednak plik zawierał o wiele za dużo szczegółów technicznych. Przypominał dekalog wykuty w kamieniu na początku iteracji. Deweloperzy pracowali na jego podstawie. Również testy tworzono w oparciu o treść tego dokumentu. Nie był on jednak modyfikowany tak, żeby odzwierciedlać decyzje podejmowane w procesie rozwoju, więc ostatecznie nasze przypadki testowe różniły się od realizacji. Oprócz problemów związanych z koordynowaniem rozwoju i testowania oprogramowania zespół miał problem ze sposobem wykonywania testów. Mimo że dysponował kilkoma zautomatyzowanymi testami, większą część walidacji testerzy wykonywali ręcznie. W miarę rozrastania się produktu stało się jasne, że ręczne testy nie mogą być w żaden sposób skalowalne. Nawet gdyby uzupełniono zespół nowymi pracownikami wykonującymi ręczne sprawdziany, oprogramowanie, nad którym pracuje zespół, przetwarza bardzo duże ilości danych i ręczne wykonywanie kwerend zwracających dziesiątki tysięcy rekordów było po prostu niemożliwe. Knight objął stanowisko menedżera działu testowania pod koniec 2007 roku. Chciał zwiększyć efektywność testów i zapewnić odpowiednie wsparcie zespołowi rozwoju, rezygnując stopniowo, w miarę doskonalenia produktu, z testów ręcznych. Zespół wdrożył prostą siatkę testów automatycznych, które pozwoliły przesunąć część testowania na wcześniejszy etap procesu. Dzięki temu możliwe było pisanie testów, gdy trwały jeszcze prace nad rozwojem funkcji. Udało się zsynchronizować prace programistów i testerów. Automatyzacja testów funkcjonalnych przyniosła natychmiastowe korzyści, ponieważ odtąd pod koniec iteracji nie piętrzyły się już stosy zaległych testów. Co więcej, deweloperzy szybciej otrzymywali informacje zwrotne i wiedzieli, czy określona część pracy jest naprawdę ukończona, czy nie. W ten sposób usunięto przeszkody zakłócające przepływ pracy spowodowane przez przenoszenie testów na następne iteracje. Gdy zespołowi udało się zsynchronizować testowanie i prace deweloperów, zaczęto zauważać problemy z zakresem i definicją ukończenia. Często zdarzało się, że po rozpoczęciu prac trzeba było przepisywać na nowo wymagania projektowe. Z poprzednich iteracji wracały bumerangi o treści zaczynającej się od „Skończyć…”. Latem 2008 roku Adam Knight sprowadził do firmy Davida Evansa, powierzając mu rolę konsultanta, który miał pomóc zespołowi w wyeliminowaniu problemów. W rezultacie zespół zaczął opisywać zakres przy użyciu historyjek użytkowników, które zastąpiły obszerne, szczegółowe wymagania techniczne kompletowane przed rozpoczęciem prac. To pozwoliło mu zacząć myśleć o kryteriach akceptacji z perspektywy biznesu i na tej podstawie przygotowywać testy, a nie przyjmować wymogi formułowane w kategoriach funkcji do wdrożenia. Adam Knight stwierdza, że to pozwoliło zespołowi lepiej zrozumieć zakres i uzyskać jasny obraz sytuacji. Odtąd każdy dobrze wiedział, kiedy jakaś funkcja została ukończona. Kolejnym krokiem było podzielenie historyjek na mniejsze elementy, które miały cechę potencjalnie gotowych do przekazania klientowi komponentów. Dzięki temu zespół zaczął
Rozdział 13. RainStor
249
lepiej orientować się w kwestii własnych możliwości w ramach ograniczeń czasowych iteracji. W efekcie można było lepiej zarządzać oczekiwaniami użytkowników biznesowych. Następnie zespół zaczął używać przykładów ilustrujących warunki satysfakcji, nawet dla wymagań takich jak wydajność produktu. Knight wyjaśnia: Wykorzystaliśmy dobrze zdefiniowane kryteria akceptacji dla pomiaru wydajności. Ustaliliśmy na przykład, że system musi importować pewną liczbę rejestrów w ciągu 10 minut na określonych procesorach. Albo deweloperzy uzyskiwali dostęp do dedykowanego sprzętu testowego, albo testerzy uruchamiali testy i zapewniali informację zwrotną. Skupienie się na historyjkach użytkowników pozwoliło skuteczniej zaangażować użytkowników biznesowych w określanie oczekiwań dotyczących najbliższego zakresu prac, a ilustrowanie tych oczekiwań przykładami pozwoliło zespołowi obiektywnie zmierzyć, czy zdefiniowany cel został osiągnięty. W miarę zwiększania się rozmiarów bazy klientów zespół zbierał coraz więcej unikalnych scenariuszy klientów, które trzeba było wdrożyć. Pod koniec 2008 roku zespół postanowił umożliwić docieranie bezpośrednio do klientów końcowych i zaangażowanie zainteresowanych stron w proces wspólnej pracy nad specyfikacjami. Knight dodaje: Generalnie wyglądało to tak, że klienci opisywali funkcję, którą chętnie widzieliby w systemie. Oni mówili o wymaganiach, a my pracowaliśmy z nimi w celu uzyskania realistycznych zestawów danych i oczekiwanych celów. Umieszczaliśmy te dane w zestawie testów i wykorzystywaliśmy do stymulowania procesu pracy zespołu deweloperskiego. Umieszczanie w systemie konkretnych scenariuszy klientów z przykładowymi danymi w funkcji testów akceptacyjnych stanowiło gwarancję, że zespół osiągnie postawione przed nim cele. Oznaczało to również, że zespół nie musiał tracić czasu na wymyślanie oddzielnego zestawu kryteriów akceptacji i nie marnował go na przeróbki spowodowane przez potencjalne nieporozumienia. Zastosowanie takiego procesu przynosiło najlepsze efekty, gdy zespół mógł zaangażować w prace prawdziwych klientów z realistycznymi wymaganiami. RainStor współpracuje głównie z pośrednikami w procesie sprzedaży, którzy czasami żądają implementacji jakiejś funkcji, nie podpierając swojego żądania żadnym konkretnym przypadkiem biznesowym. Knight stwierdza, że „to jest najtrudniejszy rodzaj wymagań”. W takich przypadkach konieczne jest drążenie tematu i proszenie o zdefiniowanie przykładów. Czasami przydaje się organizowanie warsztatów z klientami, aby prześledzić przykłady na stosunkowo wysokim poziomie. Zespół używa później tego typu przykładów wysokiego poziomu do sterowania zakresem. Praca z papierowymi prototypami pomaga mu także najpierw poznać efekty pracy systemu i zastanowić się nad nimi, co naturalnie prowadzi do przyjęcia perspektywy projektu typu outside-in.
250
Specyfikacja na przykładach
Obecny kształt procesu Obecnie zespół ds. badań i rozwoju produktu w RainStor pracuje w pięciotygodniowych iteracjach. Sprinty rozpoczynają się w każdy wtorek „spotkaniem inauguracyjnym”, podczas którego pracownicy zespołu krótko omawiają wszystkie historyjki planowane do wykonania w danej iteracji. Przez resztę dnia dopracowują szczegóły historyjek. Deweloperzy, testerzy, autorzy specyfikacji technicznych oraz menedżer produktu ściśle ze sobą współpracują, żeby zidentyfikować wszystkie wymagania i zdefiniować podstawowe kryteria akceptacji dla każdej historyjki. Testerzy definiują kryteria akceptacji na podstawie notatek sporządzonych podczas spotkania, udostępnionych wszystkim członkom zespołu. Gdy warunki satysfakcji dla historyjki zostają ujawnione, deweloperzy i testerzy pracują równolegle. Deweloperzy są odpowiedzialni za pozytywny wynik uruchomienia istniejących specyfikacji z przykładami, a testerzy pracują nad stworzeniem bardziej szczegółowych przypadków testowych. Zdarza się, że dla niektórych historyjek zespół pierwotnie nie dysponuje żadnymi przykładami zautomatyzowanymi. Wówczas deweloperzy pracują przede wszystkim nad dostarczeniem podstawowych funkcji, a testerzy automatyzują prostsze przykłady. Następnie testerzy przechodzą do opracowywania dalszych testów, a deweloperzy przejmują odpowiedzialność za funkcje i pozytywne wyniki testów. Trzy najważniejsze momenty olśnienia Poprosiłem Adama Knighta o wskazanie trzech najważniejszych wniosków, do jakich doszedł na podstawie swoich doświadczeń z wdrożeniem specyfikacji przez przykłady. Oto jego odpowiedzi: Gdy opracowałeś zestaw zautomatyzowanych testów, może on — jeśli tylko zdefiniujesz testy właściwie, tak aby ukazywały cel — stać się twoją dokumentacją testową. Metadane sprawiają, że testy stają się znacznie bardziej czytelne. My generowaliśmy raporty HTML, które zawierały zebrane informacje dotyczące uruchamianych testów oraz ich przeznaczenia. Dochodzenie do źródeł pojawiających się problemów stawało się wówczas o wiele łatwiejsze. Znacznie łatwiej można było także radzić sobie z konfliktami, bo każdy szybko orientował się w kwestii celu, bez konieczności odwoływania się do dokumentacji. Kryteria akceptacji i specyfikacje z przykładami powstające podczas tworzenia, przetwarzania i analizy historyjki stały się wymaganiami. Możesz mieć jakąś lekką, nierobiącą wielkiego wrażenia historyjkę, od której zaczniesz. Gdy masz już testy, które zakończą się powodzeniem, będziesz wiedział, że wymogi zostały spełnione. Nie musisz się nigdzie odwoływać, żeby zapoznać się z wymaganiami. Dzięki temu wiedzieliśmy, czy przyszłe wymagania nie będą sprzeczne i na co wpływają ewentualne zmiany. Mogliśmy w związku z tym w sposób ciągły utrzymywać wymagania. Zawsze byliśmy w stanie określić, w jaki sposób produkt przekłada się na wymagania, które zaimplementowaliśmy. Jeśli test zaczyna zwracać błędy, wiemy, które wymagania nie zostały spełnione. Test i wyniki testu były częścią produktu. Trzeba je przechowywać w systemie kontroli wersji razem z produktem. Dla różnych gałęzi i wersji wykonujemy różne — odpowiadające im — testy.
Rozdział 13. RainStor
251
Po implementacji funkcji testerzy przeprowadzają testy eksploracyjne i zaczynają uruchamiać zautomatyzowane testy nowej wersji systemu. Kiedy zaimplementowana zostanie pełna funkcjonalność dla danej historyjki, testerzy upewniają się, czy wszystkie testy kończą się bez błędów, aby potem włączyć je do systemu ciągłej walidacji. Niektóre testy dotyczą bardzo dużych zbiorów danych lub mają na celu sprawdzenie wydajności, więc zespół dzieli ciągłą walidację na trzy etapy: testy regularne, nocne i weekendowe. Testy regularne trwają mniej niż godzinę. Wolniejsze pakiety uruchamia się w nocy. A testy bardzo dużych zbiorów danych, często takie dotyczące scenariuszy klientów, są uruchamiane w weekendy. Z powodu takiego powolnego feedbacku do pakietów nocnych lub weekendowych dodawane są tylko te testy, które mają status stabilnych. Gdy deweloperzy przekazują część funkcji, jeśli to możliwe, testują je najpierw na swoich komputerach. Testerzy przeprowadzają testowanie wówczas, gdy testy wymagają specjalistycznego sprzętu, a potem informują o wynikach deweloperów. W ostatnim tygodniu iteracji zespół zamyka wszystkie niedokończone zadania. Upewnia się, że wszystkie testy pracują w odpowiedniej automatycznej paczce; zwraca się do interesariuszy w sprawie niezamkniętych jeszcze tematów i stara się dopiąć wszystko na ostatni guzik. W ostatni poniedziałek iteracji uruchamiane są końcowe testy regresji i jest organizowana retrospektywa. Ponieważ RainStor to firma stosunkowo mała, wiceprezes ds. inżynierii produktu jest odpowiedzialny m.in. za analizy. Nie zawsze jest łatwo dostępny, tak żeby mógł brać udział w dowolnej liczbie warsztatów specyfikacji, dlatego czasami pomagają mu testerzy, którzy przejmują część jego zadań analitycznych. Są odpowiedzialni za kompletowanie listy pytań i uzyskiwanie wyjaśnień przed rozpoczęciem tworzenia specyfikacji z przykładami.
Najważniejsze lekcje Chociaż liczba pracowników zespołu ds. badań i rozwoju w ciągu ostatnich trzech lat wzrosła niemal trzykrotnie, można powiedzieć, że zespół RainStor wciąż jest stosunkowo niewielki. Te same osoby opracowują produkt, obsługują dotychczasowych klientów i pomagają rozwijać bazę klientów. W tak niewielkim gronie muszą działać niezwykle skutecznie. Oto co i jak udało im się osiągnąć: Implementacja wykonywalnych specyfikacji pozwoliła im wyeliminować konieczność utrzymania dwóch zestawów dokumentów. To umożliwiło lepszą synchronizację badań i rozwoju i uniknięcie straty czasu związanej z koniecznością dokonywania przeróbek. Przejście na historyjki użytkowników pomogło im wciągnąć użytkowników biznesowych do procesu wytwarzania oprogramowania. Definiowanie zakresu prac na podstawie celów biznesowych z przykładami wysokiego poziomu dało gwarancję tego, że zespół buduje właściwy produkt i nie traci czasu na rozwijanie zbędnych funkcji.
252
Specyfikacja na przykładach
Zaangażowanie klientów we współpracę przy definiowaniu specyfikacji pomogło uczynić proces jeszcze bardziej skutecznym, ponieważ dzięki temu zespół od samego początku dysponuje kryteriami akceptacji, co stanowi gwarancję osiągnięcia postawionych przed nim celów. Na przestrzeni ostatnich trzech lat zespół stopniowo radził sobie coraz lepiej. Poprawa dokonała się bez wielkich planów i narzucania konkretnego procesu. Podobnie jak inne zespoły, także RainStor zawsze po prostu skupiał się na kolejnym elemencie procesu wymagającym optymalizacji, szukając w grupie pomysłów, które mogą się sprawdzić. Potem skupiano się na wdrożeniu metody sprawdzającej się w konkretnym kontekście. To prowadziło do przyjęcia kilku unikalnych rozwiązań, takich jak wykonywanie testów ręcznie dopóty, dopóki te nie staną się stabilne, i tworzenie żyjącej dokumentacji z metadanych za pomocą niestandardowego, spersonalizowanego narzędzia. Szczególny kontekst biznesowy obszaru działania zespołu RainStor sprawia, że możliwości wykorzystania któregoś z popularnych narzędzi do uzyskania pożądanego efektu były w tym przypadku mocno ograniczone. Dlatego zespół stworzył własne narzędzie, które pomaga mu sprawnie radzić sobie ze stawianymi przed nim wyzwaniami. Zespół wyszedł od procesu i stworzył narzędzie do jego obsługi. Moim zdaniem przykład zespołu RainStor pokazuje przede wszystkim, jak ważna jest umiejętność koncentrowania się na poprawie najważniejszych zasad i wykorzystania popularnych praktyk społeczności wyłącznie w roli inspiracji.
14
Iowa Student Loan
I
owa Student Loan to firma z sektora usług finansowych, której udało się wykorzystać wszystkie najlepsze cechy metodyki specyfikacji przez przykłady. Stanowi interesujące studium przypadku, ponieważ jej system żyjącej dokumentacji jest elementem, który decyduje o przewadze konkurencyjnej Iowa Student Loan w swojej branży. Dzięki temu systemowi możliwe było skuteczne poradzenie sobie z poważnymi problemami związanymi ze zmianą modelu biznesowego. Zespół deweloperów Iowa Student Loan tworzy i obsługuje skomplikowany system połączony z ogólnodostępną stroną internetową, za pośrednictwem której składane są wnioski o pożyczki, a także z podsystemami typu back-office, które są odpowiedzialne za proces analizy i akceptacji wniosków. Poza tym główną przyczyną złożoności systemu jest fakt, iż bazuje on na domenie, w której istotnym elementem decydującym o sukcesie przedsięwzięcia jest sprawne przetwarzanie danych. Zbierając materiały do książki, miałem okazję porozmawiać z Timem Andersenem, Suzanne Kidwell, Cindy Bartz i Justinem Davisem. Moi rozmówcy pracowali nad kilkoma różnymi projektami w czasie, gdy firma była w trakcie działań zmierzających do optymalizacji procesów biznesowych. Prześledzenie etapów przeniesienia korzyści mających swoje źródło w praktykach w mniejszej skali, prowadzących ostatecznie do zmiany całej platformy procesu wytwarzania oprogramowania może doprowadzić nas do bardzo ciekawych spostrzeżeń.
Zmiana procesu W 2004 roku zespół deweloperów Iowa Student Loan wzorcowo wdrożył reguły programowania ekstremalnego w celu poprawienia jakości wytwarzanego oprogramowania. Kiedy następny projekt znalazł się na etapie produkcji, ludzie przygotowali się na radzenie sobie z błędami tak, jak czynili to w przeszłości. Na przestrzeni kolejnych 12 miesięcy w nowym systemie zidentyfikowano jedynie pół tuzina błędów. To stało się dla zarządu dowodem, że
254
Specyfikacja na przykładach
zwinna metoda wytwarzania oprogramowania — a zwłaszcza model typu „najpierw testy” — sprawdziła się i dzięki niej znacznie poprawiła się jakość produktów. Testy miały jednak wyjątkowo techniczny charakter. Zespół korzystał z HTTPUnit (narzędzia do wykonywania testów jednostkowych stron internetowych). Programiści tłumaczyli przypadki użycia na testy HTTPUnit, które nie były wystarczająco czytelne. Gdy system został uruchomiony, zespół zauważył, że brakuje mu dokumentacji. Zatrudnił konsultanta, J.B. Rainsbergera, który miał pomóc mu w zidentyfikowaniu niewłaściwych praktyk i podsunąć kilka pomysłów na poprawienie narzędzi i działań. Jednym z wprowadzonych przez konsultanta narzędzi było FitNesse. Pierwszy projekt realizowany w lipcu i sierpniu 2006 roku, w którym wykorzystano FitNesse, miał być sposobem na spokojne wdrożenie nowej metodyki. Dzięki niemu zespół miał okazję nauczyć się, jak najlepiej wykorzystać nowe narzędzie. W tym samym czasie mógł przeanalizować sposób korzystania z wykonywalnych specyfikacji. Analitycy firmy mieli wystarczającą wiedzę specjalistyczną, więc specyfikacje tworzone przy współpracy z deweloperami okazały się bardzo techniczne. Użytkownicy biznesowi nie potrafili ich zrozumieć. Justin Davis wyjaśnia, w czym tkwił problem: Wystarczyło mi spojrzeć na testy i wiedziałem, jak je odczytać. Nic dziwnego! Jestem przecież analitykiem biznesowym, a to my ciągle je tworzymy. Jednak te testy były zupełnie niezrozumiałe dla pozostałych członków zespołu, którymi byli użytkownicy biznesowi. Taki był początek modyfikacji całej platformy i przyczyna dążenia do zautomatyzowania większej części tego, co wcześniej było wykonywane ręcznie na papierze. Następny, planowany na 3 lata projekt przewidywał zaangażowanie do pracy sześciu deweloperów, dwóch testerów, analityka biznesowego i użytkowników biznesowych. Zespół powierzył jednej osobie rolę konsultanta, który miał pomagać w usprawnieniu komunikacji z użytkownikami biznesowymi. Tim Andersen mówi: David Hussman powiedział, że powinniśmy pracować ciężej podczas opracowywania testów, które mają być sformułowane tak, by nasi klienci, biznesmeni, mogli je przeczytać i zrozumieć, bez potrzeby zapewnienia im dodatkowych wyjaśnień. To było dość trudne zadanie. Trzeba było zmienić podejście. Musieliśmy umieć spojrzeć na projekt z perspektywy przedsiębiorców. Wymagało to od nas zrozumienia ich punktu widzenia i długich rozmów na temat oczekiwanego działania systemu, a nie sztucznego definiowania wymogów technicznych. Członkowie zespołu zaczęli opisywać system z wykorzystaniem profili wymyślonych użytkowników, dzięki czemu mogli lepiej przyjrzeć się sposobowi interakcji grup użytkowników z systemem. Zamiast opierać się na przykładach aktywności zwykłych użytkowników, członkowie zespołu zaczęli więcej myśleć o tym, dlaczego różni ludzie korzystają z systemu, co chcą osiągnąć i jak chcieliby go używać. Dzięki temu interesariusze mogli pełniej zaangażować
Rozdział 14. Iowa Student Loan
255
się w proces wytwarzania systemu i dostarczać zespołowi bardziej istotnych informacji. Kilka ciekawych przykładów person można znaleźć w prezentacji Tima Andersena przygotowanej na konferencję Code Freeze w 2010 roku1.
Optymalizacja procesu Ponieważ wykonywalne specyfikacje przygotowywane wcześniej przez zespół miały bardzo techniczny charakter, warstwa automatyzacji okazała się skomplikowana i trudna do utrzymania. Testy opisywały elementy techniczne jako części większych przepływów, więc trzeba je było automatyzować poprzez imitowanie części przepływu pracy użytkownika. Tim Andersen mówi, że wyniki testów również nie były wiarygodne: Udało się nam pokazać działające testy, ale nie byliśmy w stanie zademonstrować poprawnie działającego oprogramowania. Nasze testy kłamały (fałszywy zielony pasek). Na przykład kredytobiorca mógł pożyczyć pieniądze, jeśli nie miał więcej niż 18 lat. Mieliśmy test, który sprawdzał, czy użytkownik ma w dniu wystąpienia o pożyczkę mniej niż 18 lat. Wówczas system informował: »Nie możesz uzyskać pożyczki bez zgody uprawnionej osoby«. Po zmianie daty urodzenia pojawiał się komunikat: »W porządku. Możesz wystąpić o pożyczkę bez żyranta«. Nasz test pokazywał, że wszystko jest w porządku, ale gdy ktoś naprawdę otworzył okno przeglądarki i wypróbował nasze narzędzie, okazywało się, że system nie działał. Chociaż zakodowaliśmy reguły sprawdzania poprawności wieku, nie zostały one powiązane z resztą oprogramowania we właściwym miejscu. Nasz system umożliwiał udzielenie kredytu w »stanie fantazji«. Użytkownicy biznesowi nie ufali wynikom testów wykonywalnych specyfikacji, więc zaczęli myśleć, że nie są ważne, co doprowadziło do pojawienia się kolejnej bariery utrudniającej zaangażowanie ich w proces wytwarzania oprogramowania. Tim Andersen mówi: Obie strony były mocno sfrustrowane. Pytaliśmy: »Jak to możliwe, że nie przeglądają testów? Dlaczego nie cenią naszych testów?«. W tym samym czasie ludzie biznesu pytali: »Jak to się stało, że deweloperzy mają test, który nie pokazuje błędów, a system nie działa tak, jak powinien?«. Przestali wierzyć w poprawność testów. Zespół zmodyfikował warstwę automatyzacji dla wykonywalnych specyfikacji, nie próbując stworzyć nieprawdziwych warunków dla wspomnianego „stanu fantazji”. Nowy sposób automatyzacji specyfikacji dobrze wpasował się w metody opisywania systemu z perspektywy person. Tim Andersen wyjaśnia:
1
http://timandersen.net/presentations/Persona_Driven_Development.pdf.
256
Specyfikacja na przykładach
»Stan fantazji« był terminem, którego używałem, informując deweloperów, że nie ufam testowi niewykorzystującemu danych z prawidłowego punktu wejścia. Innymi objawami świadczącymi o znalezieniu się w stanie fantazji były »grube fikstury«. Fikstury nie mogą zawierać zbyt wielkich fragmentów logiki systemu. Powinny być »lekkie«. Wykorzystanie person pozwoliło zidentyfikować odpowiedni poziom abstrakcji, aby wybrać odpowiedni punkt wejścia w aplikacji. Wcześniej często podejmowaliśmy złe decyzje, co doprowadziło nas do konfigurowania grubych fikstur, które były narażone na błędy stanu fantazji. Zespół zaprojektował automatyzację, bazując na działaniach, które będą mogły wykonać persony. Każda taka persona została zaimplementowana jako fikstura w warstwie automatyzacji i komunikowała się z serwerem za pośrednictwem odwołań HTTP, w istocie poruszając się tak, jak wyglądałaby nawigacja prawdziwego użytkownika w przeglądarce, a jednak uruchomienie przeglądarki nie było konieczne. To pozwoliło znacznie uprościć warstwę automatyzacji, ale jednocześnie sprawiło, że wyniki testów stały się odtąd bardziej wiarygodne. Po tej zmianie niektóre testy kończyły się niepowodzeniem, a zespół zaczął identyfikować błędy, które wcześniej nie zostały zauważone. Mniej więcej w maju 2007 roku wyniki testów stały się o wiele bardziej wiarygodne i warstwa automatyzacji stała się łatwiejsza w utrzymaniu. Tim Andersen wyjaśnia: Zmiana kodu naszych testów w celu wykorzystania aplikacji do zdefiniowania stanu pożyczki spowodowała także zidentyfikowanie błędów, które mogliśmy usunąć. Zniknęło fałszywe zielone światło testów kończących się bezbłędnie. Miało to również wpływ na radykalne obniżenie kosztów utrzymania testów. Gdy wykonywalne specyfikacje mówiły o funkcjonalności biznesowej na poziomie zrozumiałym dla użytkowników biznesowych, warstwa automatyzacji została znacznie uproszczona — nawiązywała do kodu domeny biznesowej. Również specyfikacje zawierały odtąd o wiele więcej istotnych treści, ponieważ nie otrzymywano już mylących fałszywych alarmów testów, które sprawdzały tylko część strumienia. W miarę wzrostu liczby testów informacje zwrotne spływały coraz wątlejszym strumieniem. Wiele wolnych testów technicznych było wykonywanych za pośrednictwem przeglądarki. Tim Andersen stwierdził, że spojrzenie na system z perspektywy person pomogło zespołowi w pozbyciu się tych problemów: Używaliśmy FitNesse jako narzędzia służącego do uczynienia konfigurowalną WatiJ [biblioteka automatyzacji UI]. Wcześniej, gdy nie korzystaliśmy z profili wymyślonych użytkowników, odwoływaliśmy się do przeglądarki jako ostatniej deski ratunku, ponieważ mówiliśmy sobie: »Musimy to jakoś sprawdzić, żeby mieć pewność, czy naprawdę działa«. Te testy przeglądarki mnożyły się jak króliki. Zespół przepisał testy przeglądarki tak, żeby można było wykorzystać persony, co znacznie poprawiło czas uzyskania informacji zwrotnej. Zamiast za każdym razem uruchamiać
Rozdział 14. Iowa Student Loan
257
przeglądarkę, nowa warstwa automatyzacji wysyłała żądania HTTP bezpośrednio. Zespół zastanawiał się również nad wykonywaniem testów na podstawie baz danych tworzonych i przechowywanych w pamięci (bez SQL Server), ale zdecydował, że przede wszystkim należy poprawić wydajność prawdziwej bazy danych SQL przy użyciu indeksów. Zespół podzielił proces ciągłej walidacji na kilka modułów, aby łatwiej i szybciej dowiadywać się o tym, co spowalnia testy. Zamiast ciągle tworzyć nowe specyfikacje, członkowie zespołu zaczęli myśleć o integracji żądań dotyczących zmian w istniejących specyfikacjach. To ograniczyło liczbę testów i pomogło uniknąć niepotrzebnych zadań konfiguracyjnych. Tim Andersen wyjaśnia: Zaczęliśmy myśleć o scenariuszach. Nowa funkcja może sama w sobie nie być wcale czystą funkcją — może na przykład być zmianą zestawu scenariuszy. Zamiast pisać nowy test dla każdego wymogu, myśleliśmy o nim w kontekście naszego obecnego systemu i tego, jakie testy musimy zmienić, porównując tę wiedzę z informacją o tym, jakie testy musimy napisać. Dzięki temu mogliśmy utrzymać stały czas kompilacji. To doprowadziło do rozpoczęcia procesu reorganizacji specyfikacji w celu zmniejszenia liczby testów. Zespół szukał niewielkich specyfikacji będących częścią większej całości i konsolidował je. Większe specyfikacje dzielono na mniejsze, bardziej skoncentrowane. „W gruncie rzeczy chodzi o refaktoryzację testów i kodu testowego tak, jakbyś refaktoryzował stary kod” — mówi Tim Andersen. Firma wcześnie zdecydowała się na przyjęcie zasad metodyki specyfikacji przez przykłady, więc zespół musiał jakoś radzić sobie z niedojrzałymi narzędziami, które kilka razy wręcz utrudniały współpracę wewnątrz grupy. Ponieważ zespół używał narzędzi typu open source, programiści mogli modyfikować kod, dopasowując aplikacje do swojego procesu. Gdy zaczęto umieszczać wykonywalne specyfikacje w systemie kontroli wersji, analitycy firmy nie mogli już zmieniać ich na własną rękę bez dostępu do narzędzi programistycznych. Deweloperzy opracowali wtyczkę do FitNesse, która obsługiwała integrację systemu kontroli wersji, umożliwiając im korzystanie z witryny wiki, gdzie analitycy biznesowi mogli dokonywać zmian w specyfikacjach. Gdy pakiet testów zaczął niebezpiecznie pęcznieć, pojawiły się problemy z regresją funkcjonalną. Identyfikowano błędy, które powinny były zostać wyłapane na etapie testowania. Działo się tak dlatego, że niektóre testy zostały wcześniej wyłączone, ponieważ deweloperzy nie byli pewni, jak współgrają z nowymi funkcjami. Z innych testów rezygnowano, gdy zespół czekał na decyzję interesariuszy. Później zapominano o ich ponownym włączeniu lub rezygnowano z rozmów na temat źródeł konfliktów. Deweloperzy zespołu Iowa Student Loan stworzyli zautomatyzowany mechanizm sprawdzający wyłączone testy (patrz część zatytułowana „Sprawdzaj automatycznie, które testy są wyłączone” w rozdziale 10.), który na koniec każdej iteracji przypominał im, że konieczne jest podjecie działania w określonych obszarach pokrywanych przez wyłączone testy. Zarządzanie wymaganiami realizowano przez JIRA, a FitNesse wykorzystywano do zarządzania wykonywalnymi specyfikacjami, więc modyfikacja stron FitNesse prowadziła
258
Specyfikacja na przykładach
do zerwania linków w JIRA. W konsekwencji programiści zajęli się rozbudową FitNesse tak, żeby móc bazować na słowach kluczowych i wykorzystać je w roli łączników pomiędzy wykonywalnymi specyfikacjami i stronami internetowymi JIRA. Przy okazji prac nad innym projektem zespół wybrał inne podejście i stworzył rozwiązanie biznesowe bazujące na zestawach stron FitNesse, zaprojektowanych tak, żeby stały się stabilnymi punktami wejściowymi dla dokumentacji, które następnie były uzupełniane o wewnętrzne linki do testów. To był początek dobrze sprawdzającego się systemu żyjącej dokumentacji. Justin Davis wyjaśnia: Jednym z celów nowego rozwiązania biznesowego było utworzenie panelu FitNesse, z którego mogłyby korzystać zespoły biznesowe i który jednocześnie pozwoliłby deweloperom zrozumieć zasady rządzące kolejnością elementów w obecnym systemie. W efekcie nowe rozwiązanie pozwoliło na stworzenie mapy zachowań systemu. Jeśli masz kontekst, wówczas wiedząc, jak działa system, możesz przejść do naszego rozwiązania, aby znaleźć to, czego potrzebujesz. Znajdziesz tam przepływ systemu i możesz wybrać, dla jakich kroków chcesz zobaczyć wymagania i testy. Wprowadzenie wspomnianego rozwiązania biznesowego i gwarancja, że wykonywalne specyfikacje będą naprawdę mogły zostać poddane częstej walidacji i zachowają swoją istotność, pozwoliły zespołowi stworzyć użyteczny system żyjącej dokumentacji. Dzięki temu wszyscy dysponowali relewantnym źródłem informacji o tym, co robi system.
Żyjąca dokumentacja jako przewaga konkurencyjna Dzięki sprawdzającemu się systemowi żyjącej dokumentacji zespół był w stanie skutecznie reagować na duże zmiany otoczenia biznesowego. Trzy miesiące przed końcem projektu nagle okazało się, że konieczna jest poważna zmiana modelu biznesowego firmy. Wcześniej organizacja najczęściej finansowała pożyczki zyskami ze sprzedaży obligacji. Z powodu kryzysu kredytowego z 2008 roku sprzedaż obligacji stawała się niemożliwa. Firma bazowała na nowoczesnych technologiach, więc zmiana modelu biznesowego musiała znaleźć swoje odzwierciedlenie w oprogramowaniu. Tim Andersen przyznał, że system żyjącej dokumentacji pomógł im zrozumieć, jakie są niezbędne warunki wsparcia zmiany modelu w związku ze zmianą otoczenia biznesowego: Zazwyczaj do finansowania prywatnych pożyczek studenckich używaliśmy wpływów z obligacji. Jednak w międzyczasie zmieniliśmy nasz model biznesowy i trzeba było dokonać ponownej konfiguracji części finansowania systemu, aby uwzględnić udział kredytodawców, zapewniających środki dla udzielania kredytów studenckich. Nowy model wymagał ogromnych zmian w rdzeniu systemu. Wcześniej w systemie nie było nawet definicji pożyczkodawcy, ponieważ dotąd zawsze to Iowa Student Loan pełnił rolę pożyczkodawcy.
Rozdział 14. Iowa Student Loan
259
Udało się nam wykorzystać dotychczasowe testy akceptacyjne. Zmodyfikowaliśmy je tak, żeby móc powiedzieć: »OK, to jest nasz wymóg finansowania«. Omówiliśmy wpływ zmiany źródła finansowania dla wszystkich testów, jakimi dysponowaliśmy. I one nadal działały. Mieliśmy kilka ciekawych wymian zdań, gdy okazało się, że w kilku scenariuszach nie ma dostępnych funduszy albo fundusze są dostępne, ale nie dla tej szkoły lub nie tego kredytodawcy. Dlatego konieczne okazało się zdefiniowanie kilku przypadków brzegowych takich wymagań, jednak w tych warunkach tak naprawdę chodziło o sprawienie, by model finansowania stał się bardziej elastyczny i konfigurowalny. Gdy zespół zrozumiał wpływ nowego modelu biznesowego na oprogramowanie, udało się wdrożyć najlepsze rozwiązanie. Tim Andersen twierdzi, że bez żyjącej dokumentacji takie zmiany byłyby niemożliwe do szybkiego wprowadzenia: Ponieważ dysponowaliśmy dobrymi testami akceptacyjnymi, mogliśmy wdrożyć to rozwiązanie w ciągu miesiąca. Każdy inny system, w którym nie byłoby tych testów, zablokowałby proces i konieczne byłoby stworzenie wielu komponentów od zera. I to właśnie w tym momencie opłaciła się inwestycja w system żyjącej dokumentacji. System ułatwił analizy, wdrażanie nowego modelu biznesowego i testowanie konsekwencji, umożliwiając równocześnie szybkie sprawdzenie, czy reszta oprogramowania nie ulegnie zmianom.
Najważniejsze lekcje Przygoda zespołu ze specyfikacją przez przykłady zaczęła się od skupienia się na narzędziu i szybkiego uświadomienia sobie, że nie pomoże ono firmie w osiągnięciu celu, jakim było zachęcenie użytkowników biznesowych do udziału w procesie. Dlatego trzeba było zmienić perspektywę i spojrzeć na specyfikacje z punktu widzenia użytkownika. Dzięki tej zmianie podejścia można było lepiej komunikować się z użytkownikami biznesowymi i zmniejszyć koszty utrzymania testów. Narzędzie nie pozwalało zespołowi skutecznie współpracować, więc trzeba było je zmodyfikować i dopasować. To kolejny argument przemawiający za korzystaniem z narzędzi typu open source. Implementacja specyfikacji przez przykłady w zespole Iowa Student Loan wynikała nie tyle z potrzeby poprawy jakości i automatyzacji testów, ile z konieczności stworzenia odpowiedniego systemu dokumentacji, którego wykorzystanie przyczyni się do poprawy skuteczności angażowania użytkowników biznesowych. Zespół dużo zainwestował w budowę dobrego systemu żyjącej dokumentacji, ale można powiedzieć, że ta inwestycja się opłaciła. Dzięki niej możliwe było przeprowadzenie bardzo złożonej modyfikacji modelu biznesowego.
260
Specyfikacja na przykładach
15
Sabre Airline Solutions
F
irma Sabre Airline Solutions (SAS) oferuje oprogramowanie i usługi, które wspomagają linie lotnicze w planowaniu, obsłudze i realizowaniu sprzedaży oferty. SAS jest jedną z pierwszych firm, która wdrożyła zasady programowania ekstremalnego i specyfikacji przez przykłady. Stanowi ciekawe studium przypadku z uwagi na zastosowanie wspomnianych metod na skalę masową przy wyjątkowo dużym projekcie w zespołach o stosunkowo sporym rozproszeniu członków. Mowa o projekcie, którego celem było stworzenie oprogramowania o nazwie Sabre AirCentre Movement Manager. Zadaniem tego oprogramowania miało być śledzenie operacji prowadzonych w przestrzeni powietrznej i alarmowanie odpowiednich służb o zaistnieniu przeszkód, które mogłyby je zakłócić, co miało umożliwić dostosowanie rozkładów lotów w celu zminimalizowania niekorzystnego wpływu wykrytych problemów na klientów i linie lotnicze. Według Wesa Williamsa, zwinnego trenera w SAS, dwa wcześniejsze projekty podobnych systemów zakończyły się niepowodzeniem z powodu wysokiej złożoności domeny oraz problemów z utrzymaniem jakości produktu. Za trzecim razem, dzięki wdrożeniu metod specyfikacji przez przykłady, wreszcie udało się odnieść sukces.
Zmiana procesu Ze względu na złożoność domeny wkrótce po wdrożeniu reguł programowania ekstremalnego zespoły robocze SAS szukały metody umożliwiającej wspólne zdefiniowanie i zautomatyzowanie testów akceptacyjnych. Wes Williams powiedział, że początkowo firma starała się osiągnąć ten cel z wykorzystaniem technicznego narzędzia do testów jednostkowych. Takie rozwiązanie nie pomogło pracownikom w kwestii współpracy i nie nadawało się do regularnego używania, więc te praktyki trzeba było zarzucić. SAS zaczęła szukać narzędzia, które wspierałoby współpracę zespołów. W 2003 roku Wes Williams dowiedział się o istnieniu FIT, pierwszego powszechnie dostępnego narzędzia do automatyzacji wykonywalnych specyfikacji. Jego zespół był pierwszym, który zaczął
262
Specyfikacja na przykładach
tworzyć testy akceptacyjne z wykorzystaniem FIT, ale wówczas wszyscy koncentrowali się jeszcze na narzędziu, a nie na praktykach. Wes Williams twierdzi, że zastosowanie FIT nie przyniosło poprawy współpracy, na którą liczyli: Podobał nam się pomysł, że klient może definiować test i decydować o wartości, którą miała dostarczać aplikacja. W rzeczywistości klient nigdy nie pisał ani jednego testu FIT w formacie HTML. Zwykle testy tworzyli deweloperzy. Mocno się staraliśmy, żeby przekonać klientów. Testerzy natomiast używali QTP. Taki układ nigdy nie premiował współpracy. Deweloperzy nigdy nie uruchamiali testów QTP i nie mieli nic wspólnego z ich pisaniem. Tylko deweloperzy tworzyli wykonywalne specyfikacje. Firma rozumiała, że taki mechanizm nie przynosi korzyści, jakich oczekiwała. Aby poprawić komunikację i współpracę, konieczne było zaangażowanie wszystkich osób pracujących nad produktem. Jedna grupa nie była w stanie dokonać tego na własną rękę. Wiceprezes ds. rozwoju produktu pod wpływem argumentów deweloperów zdecydował o zatrudnieniu konsultantów z ObjectMentor, którzy mieli zająć się przeszkoleniem wszystkich pracowników. Dzięki konsultantom ludzie stali się bardziej świadomi celów zastosowania specyfikacji przez przykłady i korzyści, jakie może nieść wykorzystanie tej metodyki. Mimo że nie udało się od razu przekonać wszystkich, szkolenia pomogły zmienić nastawienie wielu pracowników, którzy odtąd podchodzili do tego tematu z większym entuzjazmem. Wes Williams mówi: Nie wszyscy się przekonali. Ale powstał pewien trzon — grupa ludzi, którzy wierzyli w metodę i wiele się nauczyli. Ci ludzie przestali bronić się przed zmianami. Ta grupa wyszła od stosunkowo prostego projektu internetowego — wewnętrznego systemu agregacji informacji z kompilacji oprogramowania. Ludzie chcieli wypróbować praktyki nowej metody i zdobyć podstawową wiedzę na temat narzędzi, które w 2004 roku pozostawiały jeszcze wiele do życzenia. Zespół wybrał FitNesse do wspólnego zarządzania wykonywalnymi specyfikacjami. Wykonywalne specyfikacje powstawały albo tuż przed rozpoczęciem procesu rozwoju, albo mniej więcej w tym samym czasie. Interesariuszem biznesowym na potrzeby tego projektu był menedżer firmy, który zajął się weryfikowaniem testów. Zespół początkowo traktował warstwę automatyzacji jak drugiej klasy kod testowy i nie martwił się za bardzo, czy kod będzie schludny, co w konsekwencji spowodowało liczne problemy z jego utrzymaniem. Efektem ubocznym była także spora liczba powtórzeń w specyfikacjach testowych. Wes Williams wyjaśnia: Dowiedzieliśmy się, że powinniśmy starać się utrzymać fikstury tak proste, jak to tylko możliwe, i że duplikaty są złe. Ona [warstwa automatyzacji] jest kodem, tak jak każdy inny kod.
Rozdział 15. Sabre Airline Solutions
263
Deweloperzy nie przejmowali się potrzebą uczynienia warstwy automatyzacji lub wykonywalnych specyfikacji możliwie najłatwiejszymi do utrzymania, ponieważ po prostu kojarzyli te elementy z testami. Pod koniec projektu spostrzegli, że takie podejście prowadzi do ogromnych problemów z konserwacją. Podobnie jak w przypadku zespołu Iowa Student Loan, pierwszy projekt pozwolił SAS zebrać pierwsze wnioski z wykorzystania narzędzi oraz ocenić możliwości i ograniczenia metody automatyzacji wykonywalnych specyfikacji. Dzięki temu zebrano doświadczenia, dzięki którym ludzie szybko wychodzili z kolejnymi pomysłami na to, jak poprawić następny projekt. Gdy mniejszy zespół pionierów lepiej zrozumiał ograniczenia narzędzi i udowodnił, że warto zainwestować więcej w tworzenie dających się łatwo utrzymać specyfikacji z przykładami, firma zaczęła wykorzystywać doświadczenia zdobyte w procesie w większym i bardziej ryzykownym przedsięwzięciu. Kolejny projekt zakładał przepisanie starego systemu napisanego w C++ na Javę z dużą liczbą wersji rozwojowych. Projekt bazował na danych i musiał wspierać globalną dystrybucję. Ostatecznie dostarczenie gotowego produktu końcowego zajęło trzydziestu osobom dwa lata. Nad systemem pracowały trzy zespoły przebywające na dwóch różnych kontynentach. Ze względu na wysokie ryzyko wiążące się z projektem zespół chciał znacznie poprawić pokrycie testami i częstotliwość ich wykonywania. Z myślą o spełnieniu tych założeń zaczęto korzystać z praktyk wdrażanych podczas realizacji mniejszego projektu. Wes Williams mówi: Poprawnie wykonane ręczne testowanie tak złożonej aplikacji zajęłoby nam całe miesiące. Chcieliśmy uzyskać produkt wolny od wad i nie marnować wielu miesięcy na testowanie. Zaczęliśmy ciągłe testowanie. W przypadku tak dużych aplikacji niemożliwe jest nawet dzienne ręczne testowanie typu sanity testing. Ponieważ zespół dysponował już doświadczeniami z pierwszej ręki w zakresie korzystania z FitNesse, osoby pracujące przy poprzednim projekcie zaczęły automatyzowanie testów funkcjonalnych. Użytkowników biznesowych zaangażowano w definiowanie testów, spodziewając się, że takie działanie zagwarantuje spełnienie celów.
Poprawa współpracy Grupa została podzielona na trzy zespoły. Pierwszy zajmował się podstawowymi funkcjami, drugi był odpowiedzialny za interfejs użytkownika, a trzeci za integrację z systemami zewnętrznymi. Zanim pojawiła się pierwsza wersja interfejsu użytkownika, minęły mniej więcej cztery miesiące. Gdy użytkownicy biznesowi zapoznali się z jego wyglądem i działaniem, zespół zauważył, że w oprogramowaniu brakowało wielu elementów, których oczekiwali klienci. Wes Williams wyjaśnia: Okazało się, że na podstawie interfejsu użytkownika klient zupełnie inaczej wyobrażał sobie całą aplikację. Gdy zaczęliśmy pisać testy akceptacyjne dla UI, dotyczyły one o wiele większego obszaru niż te napisane dla domeny. Więc kod
264
Specyfikacja na przykładach
domeny trzeba było zmienić, ale klient zakładał, że ta część została wykonana. Istniały testy FitNesse, wykonywano je i na podstawie pozytywnych wyników zakładano, że etap został ukończony. Ludzie z zewnątrz przyjmowali, że backend będzie obsługiwał wszystkie funkcje, które widzieli na szablonach interfejsu użytkownika. Czasami backend nie obsługiwał kwerend albo wyszukiwania danych w formie, która nadawała się do wykorzystania w części frontend. Wszyscy członkowie grupy zdali sobie sprawę, że problem tkwił w podziale pracy między zespołami. Klienci, którzy zobaczyli wygląd interfejsu, naturalnie myśleli o systemie na poziomie zawierającym więcej szczegółów, więc nie mogli zaangażować się odpowiednio w definiowanie specyfikacji na potrzeby zespołów niedostarczających żadnych interfejsów. Mniej więcej sześć miesięcy po rozpoczęciu projektu grupa postanowiła zreorganizować pracę tak, żeby zespoły mogły dostarczać funkcje w sposób kompleksowy od końca do końca. Dzięki temu użytkownicy biznesowi mogli wreszcie współpracować ze wszystkimi zespołami. Wes Williams dodaje: Gdy podzieliliśmy funkcje na grupy, znajdowaliśmy się już na poziomie tak dojrzałych historyjek użytkownika i tak zaawansowanego rdzenia aplikacji, że nie doszło do żadnych nieoczekiwanych wybuchów historyjek. Pojawiające się niespodzianki nie niosły ze sobą tak wielkiego zagrożenia [dla losów projektu]. Gdy każdy zespół pracował nad dostarczeniem kompletnej funkcji od końca do końca, włączenie użytkowników biznesowych do współpracy z zespołem stało się o wiele łatwiejsze. Wspólnie określano warunki satysfakcji i ilustrowano je przykładami. Po reorganizacji pracy grupy zespoły zdały sobie sprawę, że potrzebują szybszego feedbacku dotyczącego realizowanych historyjek, dlatego skróciły iteracje o połowę (odtąd sprint trwał zalewie tydzień). Chociaż testy akceptacyjne pisano przed implementacją, nadal uważano je za testy, a nie specyfikacje. Zadanie pisania testów akceptacyjnych powierzono testerom, którzy jednak nie umieli zmieścić się w tak krótkich iteracjach. W celu usunięcia tego wąskiego gardła grupa, która realizowała poprzedni projekt z wykorzystaniem FitNesse, zasugerowała, aby deweloperzy pomogli w tworzeniu testów akceptacyjnych. Wes Williams mówi, że testerzy początkowo byli nastawieni do tego pomysłu niechętnie: Na początku myśl, że deweloper równie dobrze może pisać testy, była źródłem konfliktów, ponieważ testerom wydawało się, że lepiej radzą sobie z testowaniem. Myślę, że te dyskusje wynikały z zupełnie innego spojrzenia na projekt. Później przekonałem się, że gdy deweloper i tester wymieniają swoje opinie na temat testów, efekt końcowy jest znacznie lepszy, niż gdyby za testy odpowiadał tylko jeden z nich i wykonywał je na własną rękę. Wes Williams zdał sobie sprawę, że jeśli ma dojść do jakiejś zmiany, musi ona dotyczyć kultury pracy. Jako trener starał się ułatwiać współdziałanie ludzi i identyfikowanie proble-
Rozdział 15. Sabre Airline Solutions
265
mów. Gdy tester zaczynał mieć zaległości z testami, mógł poprosić dewelopera o pomoc. Kiedy testerzy narzekali, że deweloperzy nie wiedzą, jak pisać testy, Wes Williams zasugerował parowanie i pisanie testów w grupie. Spróbowali. Gdy wrócili do mnie, nie mogli się nadziwić: »Łał! To, co pisałem na własną rękę, w ogóle nie przypomina tego, co wyszło nam dzięki pracy zespołowej«. Musisz zadbać o to, żeby każdy mógł sam dojść do podobnych wniosków. Williams był zaskoczony tym, jak wielkie zaufanie można było zbudować między testerami i deweloperami w konsekwencji wdrożenia prostego mechanizmu: To zaufanie było niesamowite. Zdali sobie sprawę, że razem zrobią to lepiej, że jedni i drudzy pracują dla wspólnego dobra, a ten »drugi« nie działa na szkodę »pierwszego«. Ostatecznie udało się stworzyć środowisko premiujące współpracę. Sprawienie, że ludzie zaczęli ze sobą współpracować, pomogło nie tylko w usunięciu wąskich gardeł przebiegu procesu, ale spowodowało również tworzenie lepszych specyfikacji, ponieważ różne osoby potrafiły spojrzeć na ten sam problem z różnych pespektyw. Współpraca ułatwiła obu grupom dzielenie się wiedzą i stopniowe budowanie wzajemnego zaufania, co w perspektywie długoterminowej poprawiło efektywność realizacji procesu.
Efekt końcowy Poprzednie dwie próby modyfikacji starszego systemu zakończyły się niepowodzeniem z powodu trudności z jakością, a nowe oprogramowanie trafiło do bardzo dużego klienta, który prosił tylko o niewielką liczbę poprawek. Klient znalazł tylko jeden poważny błąd, który dotyczył obszaru pracy po awarii. Wes Williams przyznaje, że specyfikacja przez przykłady była „jednym z kluczowych elementów”, które umożliwiły końcowy sukces.
Najważniejsze lekcje Deweloperzy naciskali na przyjęcie specyfikacji przez przykłady, widząc w niej metodę dotarcia do testerów i użytkowników biznesowych. Jednak szybko okazało się, że skoncentrowanie się na narzędziu używanym w zamkniętej grupie nie jest właściwą drogą. Ta świadomość była kluczowa, aby uzyskać zaangażowanie innych. Chociaż szkolenie z metody pracy nie stało się bodźcem, który przekonałby do zmian wszystkich wątpiących, okazało się dobrym fundamentem. Na tej bazie mogła działać grupa ludzi, którzy byli szczerze zainteresowani wypróbowaniem nowych pomysłów. Najpierw wykorzystano mniejszy i niezbyt ryzykowny projekt, aby przetestować działanie narzędzi i odkryć najlepsze sposoby pisania i utrzymywania specyfikacji oraz warstwy automatyzacji. Niezbyt liczna grupa osób biorących udział w tym projekcie pełniła potem rolę katalizatora dla liczniejszej grupy pracującej przy większym projekcie.
266
Specyfikacja na przykładach
Najważniejsze wskazówki dotyczące projektów opartych na danych Wes Williams podzielił się swoimi doświadczeniami, wskazując pięć istotnych reguł, których przestrzeganie decyduje o jakości specyfikacji w środowisku bazującym na danych: Ukryj dane przypadkowe. Usuń powielenia. Szukaj duplikatów, gdy pracujesz nad produktem, wykorzystując metodykę przyrostową — poszukaj starych podobnych testów i oczyść je. Dokonaj refaktoryzacji testów podobnej do refaktoryzacji kodu. Odizoluj swoją grupę, uniezależnij się od wpływu osób trzecich i wyizoluj obszary, w których nie możesz mieć kontroli nad danymi. W świecie oprogramowania dla linii lotniczych twój system na pewno będzie kontaktować się z jakimś systemem gospodarza. Oni też mogą mieć system testów, ale nie jesteś w stanie kontrolować obcych danych. Musisz mieć testy, które będą sprawdzać to połączenie. Tylko że w tym przypadku chodzi o zupełnie inne testowanie! W trakcie automatycznych testów akceptacyjnych musisz imitować relacje między systemami.
Gdy zespoły zajęły się dostarczaniem komponentów systemu, użytkownicy biznesowi nie byli w stanie właściwie skoncentrować się na pracy zespołów przygotowujących drugoplanowe komponenty. Efektem tego stanu rzeczy było mnóstwo przeróbek i frustracja, będąca wynikiem świadomości niespełniania oczekiwań. Po restrukturyzacji grup pracowników w zespoły funkcyjne problemy tego typu przestały się pojawiać. Doprowadzenie do współpracy testerów i deweloperów przy pisaniu testów akceptacyjnych przyniosło owoce — lepsze specyfikacje i wzrost zaufania między tymi dwiema grupami. Specyfikacja przez przykłady pomogła firmie w zdobyciu bogatej wiedzy na temat skomplikowanej domeny poprzez zapewnienie jasnego celu rozwoju i ciągłej walidacji.
16
ePlan Services
F
irma ePlan Services z siedzibą w Denver w stanie Kolorado jest organizacją oferującą plany emerytalne 401(k)1. Przedsiębiorstwo działa w oparciu o najnowsze technologie, bazując w dużym stopniu na skutecznym procesie dostarczania oprogramowania. Według Lisy Crispin, zwinnej testerki pracującej dla ePlan Services, firma dzięki systemowi żyjącej dokumentacji radzi sobie z problemami, jakie może sprawiać złożone środowisko domeny, oraz optymalizacją transferu wiedzy dotyczącej operacji biznesowych i rozwojowych. Model biznesowy firmy zakłada oferowanie usług małym pracodawcom, którzy zyskują na niższych kosztach działalności dających im znaczną przewagę konkurencyjną. Kluczowe znaczenie ma dla firmy automatyzacja procesów biznesowych. W 2003 roku szefowie firmy uświadomili sobie, że jeśli ePlan Services ma przynosić zyski, konieczna będzie modyfikacja procesu dostarczania oprogramowania. „Pojawił się problem z dostarczaniem oprogramowania klientom — mieliśmy zbyt wiele kłopotów związanych z jakością” — wyjaśnia Lisa Crispin. Konieczność dostarczania tańszych usług i automatyzacja procesów biznesowych poprowadziła ePlan Services na ścieżkę poprawy procesu wytwarzania oprogramowania, w trakcie którego zespół wdrożył większość koncepcji specyfikacji przez przykłady.
Zmiana procesu Firma przekonała Mike’a Cohna do przejęcia zespołu deweloperów, a ten pomógł im wdrożyć Scruma. Na początku na wykonywanie ręcznych testów zespół poświęcał dwa dni pod koniec każdej iteracji. Skrypty testowe uruchamiali wszyscy członkowie zespołu — testerzy, deweloperzy i administratorzy baz danych. Tym samym jedna piąta iteracji poświęcona była na testowanie. W związku z tym firma zdecydowała o wdrożeniu automatyzacji testów. Lisa Crispin mówi, że na pierwszy ogień poszły testy jednostkowe: 1
Najpopularniejszy amerykański plan emerytalny, odpowiednik polskiego 3. filara; swoją nietypową nazwę wziął od numeru podsekcji Kodeksu skarbowego prawa podatkowego, w którym unormowano podstawowe założenia planu — przyp. tłum.
268
Specyfikacja na przykładach
Większość błędów, które wcześniej znajdowali testerzy, identyfikowana była na poziomie jednostkowym. Cały dostępny czas przeznaczałeś na te testy i nie miałeś czasu na nic innego. Podczas gdy deweloperzy przyzwyczajali się do wykonywania testów jednostkowych, testerzy zabierali się do automatyzacji testów funkcjonalnych. Bez pomocy ze strony deweloperów testerzy mogli zautomatyzować testy tylko przy użyciu interfejsu użytkownika. Osiem miesięcy później zespół dysponował setkami testów jednostkowych i wystarczającą liczbą automatycznych testów funkcjonalnych typu smoke test, żeby móc wyeliminować konieczność ręcznego sprawdzania błędów regresji na poziomie jednostkowym. Lisa Crispin mówi, że dzięki temu możliwe było spojrzenie na projekt z szerszej perspektywy: Bardzo szybko przekonaliśmy się, że gdy deweloperzy opanowali TDD, znane nam wcześniej błędy przestały się pojawiać. Mieliśmy więcej czasu na badania eksploracyjne. Wszystko, co zgłaszano jako błąd, było tylko nieporozumieniem związanym z tym, że deweloper nie rozumiał jakiegoś wymogu. Błędy w produkcji były często czymś, czego nie potrafiliśmy pojąć. Podobnie jak w wielu innych przypadkach, bez efektywnej automatyzacji testów zespół miał mało czasu, aby zająć się czymkolwiek innym. Gdy techniczne błędy na poziomie jednostkowym przestały być źródłem problemów, zaczęto dostrzegać inne. Mimo że zespół dysponował kilkoma zautomatyzowanymi testami funkcjonalnymi, to nie wystarczyło, aby uniknąć problemów. Testy z tej grupy były bardzo powolne, dlatego uruchamiano je na noc (i to tylko te sprawdzone scenariusze). Zespół zaczął szukać alternatywnych sposobów automatyzacji testów funkcjonalnych, aby szybciej uruchamiać kolejne testy. Odpowiedzią okazało się FitNesse, ale użycie tego narzędzia wymagało od deweloperów pomocy w automatyzacji. Lisa Crispin mówi, że przekonanie deweloperów do zaangażowania się w prace było prawdziwym wyzwaniem: Programiści są przyzwyczajeni do tego, że nagradza się ich za gotowy kod produkcji. Po sugestii Mike’a Cohna wybrałam jedną historyjkę i udałam się do dewelopera, który nad nią pracował. Zapytałam, czy możemy popracować w parze, pisząc testy FitNesse. W kolejnym sprincie wybrałam inną historyjkę i inną osobę. Zaraz na początku znaleźliśmy błąd, który wynikał z tego, że deweloper tak naprawdę nie zrozumiał wymogu. Tak więc deweloperzy od razu dostrzegli wartość parowania. Współpraca przy tworzeniu testów była dla testerów i deweloperów okazją do bezpośredniej wymiany opinii i omówienia wymagań, co miało się przełożyć na pisanie lepszych testów. Lisa Crispin mówi, że ta współpraca wyeliminowała większość poważniejszych problemów: Rok po wdrożeniu zwinnej metodyki mieliśmy pewność, że żadne brzydkie błędy nie trafiają do produkcji.
Rozdział 16. ePlan Services
269
Wszyscy zdali sobie sprawę z wielkiego znaczenia współpracy. Lisa Crispin mówi: Najważniejszą korzyścią był fakt, że mogliśmy usiąść i porozmawiać ze sobą tak, żeby mieć pewność, że wszyscy tak samo rozumiemy wymagania. To ważniejsze niż automatyzacja testów. Gdy dostrzegliśmy korzyści ze współpracy, właściciel produktu patrzył w przyszłość z entuzjazmem i zaczął interesować się ATDD. Efektywna automatyzacja testów funkcjonalnych wymagała od deweloperów zaangażowania, co przyniosło o wiele ściślejszą współpracę pomiędzy deweloperami i testerami. Zespół dostrzegł konkretne korzyści, które pomogły budować uzasadnienie biznesowe dla dalszych udoskonaleń. Dotychczasowe sukcesy zainspirowały członków zespołu do tego, by pójść o krok dalej i dzięki zautomatyzowanym testom zająć się zapobieganiem, zamiast później wyłapywać niedostrzeżone błędy. Celując w jeszcze lepsze zoptymalizowanie procesu, zespół zaczął korzystać ze wspólnie definiowanych testów akceptacyjnych w funkcji specyfikacji. Lisa Crispin pracowała z właścicielem produktu, żeby zawczasu przygotować przykłady. Na początku udało się osiągnąć kilka sukcesów, ale nadal traktowano przykłady jak testy funkcjonalne. Gdy zespół pracował nad automatyzacją testów zgodności, jednym z najbardziej skomplikowanych elementów systemu, poziom szczegółowości testów okazał się za wysoki i trzeba było zastanowić się nad celem, jaki miał zostać osiągnięty dzięki temu podejściu. Lisa Crispin wyjaśniła: Usiedliśmy z właścicielem produktu, żeby napisać wszystkie te testy FitNesse do algorytmów testowych. Permutacji było tak dużo, że stworzyliśmy bardzo wiele skomplikowanych testów na kilka sprintów do przodu. Kiedy deweloperzy zaczęli kodowanie, patrzyli na testy i byli zdezorientowani. Nie umieli dostrzec lasu spomiędzy drzew. Okazało się, że deweloperzy nie są w stanie przerobić tak wielkich porcji informacji otrzymywanych z góry. Po kilku eksperymentach zespół zdecydował, że z wyprzedzeniem będzie pisać tylko testy wysokiego poziomu, by umożliwić deweloperom spojrzenie na projekt z szerszej perspektywy. Gdy deweloper wybrał historyjkę, tworzył parę z testerem w celu przygotowania testu wg ścieżki szczęśliwego scenariusza, a potem jego zautomatyzowania. Następnie tester mógł rozszerzyć specyfikację, dodając do niej więcej przykładów. Testerzy wykorzystywali te zautomatyzowane ramy do eksplorowania systemu. Gdy znaleźli coś, co powodowało, że test kończył się błędem, trzeba było wrócić do dewelopera, który miał wprowadzać poprawki. Zdaniem Lisy Crispin odtąd przestano patrzeć na testy akceptacyjne jak na specyfikacje: Na początku mieliśmy tylko mgliste pojęcie o tym, jak z wyprzedzeniem pisać testy akceptacyjne, tak aby mogły stać się wymaganiami. Z czasem zmieniło się to, ile szczegółów musimy uwzględnić w testach tworzonych zawczasu, jak wiele przypadków testowych jest liczbą wystarczającą. Jestem testerką. Mogłabym testować coś wiecznie i wciąż myśleć o tym, co by tu jeszcze sprawdzić…
270
Specyfikacja na przykładach
ale my mamy tylko dwa tygodnie. Więc musieliśmy dojść do tego, jak dokonać internalizacji analizy ryzyka, żeby móc powiedzieć: »Oto są testy, których naprawdę potrzebujemy, oto najważniejsze elementy historyjki, które muszą działać jak należy«. Gdy zespół przestawił się z myślenia o zautomatyzowanych testach na myślenie o automatycznych specyfikacjach, stało się jasne, że struktura tego, co jest specyfikowane i automatyzowane, jest przede wszystkim narzędziem komunikacji, a nie sprawdzianem regresji. Zespół uprościł i dopracował testy tak, aby deweloperzy dysponowali odpowiednią dawką specyfikacji dokładnie wtedy, gdy ich potrzebują. Dobry projekt testu Lisa Crispin jest znaną zwinną testerką i współautorem książki pod tytułem Agile Testing. Zapytałem ją o to, jakie jej zdaniem są podstawowe warunki stworzenia dobrego projektu testu akceptacyjnego. Oto jak brzmiała jej odpowiedź: Dobry projekt testu ma kluczowe znaczenie w pespektywie długoterminowej. Ludzie zaczynają testowanie i kompletują duży pakiet testów. Szybko okazuje się, że wysiłek poświęcony na utrzymanie testów jest wart więcej niż same testy. Każdy test musi jednoznacznie opisywać istotę badania. Usuń wszystkie duplikaty, gdy tylko stwierdzisz ich istnienie. W projektowaniu testów muszą pomagać programiści lub ktoś, kto ma bogatą wiedzę programistyczną. Gdy dysponujesz szablonem, jego wypełnienie staje się łatwiejszym zadaniem.
Żyjąca dokumentacja Traktując przykłady tak, jakby bardziej przypominały specyfikacje niż testy, zespół Lisy Crispin przekonał się, jak wielkie mają one znaczenie w roli dokumentacji. Lisa Crispin mówi, że dzięki dysponowaniu systemem żyjącej dokumentacji zespół ePlan Services oszczędził dużo czasu, który w innych warunkach trzeba byłoby przeznaczyć na analizowanie przyczyn błędów: Ktoś daje znać: »W kwestii tych płatności kredytu… kwota oprocentowania nie jest prawidłowa. Sądzimy, że oprogramowanie może zawierać błąd«. Mogę sprawdzić testy FitNesse i wprowadzić do nich określone wartości. Może wymagania były złe? Od razu wiem, co robi kod. W ten sposób oszczędzam mnóstwo czasu. Po jakimś czasie jeden z menedżerów, starszy programista, postanowił przenieść się do Indii i okazało się, że nie będzie dostępny przez kilka miesięcy. Lisa Crispin mówi, że to zdarzenie sprawiło, iż zespół zaczął szukać sposobów zastosowania specyfikacji przez przykłady do zgromadzenia unikalnej wiedzy o systemie:
Rozdział 16. ePlan Services
271
Kiedy pojawił się jakiś nietypowy problem, on zawsze wiedział, jak sobie z nim poradzić. Dlatego naprawdę musieliśmy zdobyć wiedzę na temat starego systemu, którą miał nasz były pracownik. Wtedy zdecydowaliśmy, że podczas każdego sprintu jedna osoba będzie poświęcać część swojego czasu na prześledzenie wybranych procesów biznesowych oraz ich udokumentowanie. Ta decyzja doprowadziła do rozpoczęcia prac dokumentowania starszych części systemu. Chociaż zespół tworzył testy dotyczące części znajdujących się w trakcie rozbudowy, inne części dotychczas używanego systemu nie miały odpowiadającej im automatyzacji testów, a to czasami powodowało problemy. Tworzenie automatycznej żyjącej dokumentacji dla tych obszarów pomogło odkryć nieścisłości w procesach biznesowych. Lisa Crispin wyjaśnia: Wówczas pracowałam w tej firmie już od czterech lat, ale do tamtej pory nie rozumiałam, jak w systemie przebiega księgowanie pieniędzy. Dowiedziałam się, że mamy pięć różnych kont bankowych znajdujących się poza zautomatyzowaną aplikacją. Pieniądze z tych rachunków przemieszczają się. Wystarczy dyspozycja przelewu poprzez e-mail lub rozmowę telefoniczną, ale saldo rachunków musi się zgadzać. Gdy tak się nie dzieje, księgowa musi znaleźć przyczynę tego stanu rzeczy. Gdy księgowa wyjaśniła nam ten proces, udokumentowaliśmy go na przyszłość na naszej stronie wiki. Odtąd mogliśmy generować raporty zawierające przydatne informacje na temat przepływu pieniędzy wewnątrz i na zewnątrz systemu. Teraz gdy salda się nie bilansują, księgowa może zajrzeć do raportów i poznać przyczynę. Kompletowanie systemu żyjącej dokumentacji będącego dla nas źródłem wiedzy, z którego mogą czerpać wszyscy członkowie zespołu, pomogło deweloperom w zrozumieniu procesów biznesowych. Użytkownicy biznesowi w końcu mieli wiedzę na temat tego, co robią deweloperzy. Rejestrowanie i archiwizowanie procesów ujawnia niespójności i braki. W tym konkretnym przypadku wdrożenie reguł metody sprawiło, że ludzie częściej zastanawiali się nad swoimi działaniami z perspektywy biznesowej.
Obecny proces Wszystkie wspomniane zmiany w ePlan Services zostały wprowadzone już jakiś czas temu. Obecnie, po wdrożeniu systemu żyjącej dokumentacji, zespół korzysta ze stosunkowo stabilnego procesu. Zespół ePlan Services składa się aktualnie z czterech programistów, dwóch testerów, mistrza młyna, dwóch administratorów systemu, administratora bazy danych i menedżera i pracuje w dwutygodniowych sprintach. Dwa dni przed rozpoczęciem sprintu zespół spotyka się z właścicielem produktu i interesariuszami. Właściciel produktu omawia wszystkie historyjki planowane na następny sprint, a następnie wszyscy definiują testy wysokiego poziomu, zapisując je na tablicy. Dzięki temu zespół może wymieniać się opiniami na temat planu i każdy ma możliwość zadawania pytań dotyczących historyjek jeszcze przed rzeczywistym rozpoczęciem sesji planowania sprintu.
272
Specyfikacja na przykładach
Przy tak złożonej działalności biznesowej i przy tak małym zespole wąskim gardłem procesu jest obecnie właściciel produktu. Aby zaangażować go we wstępne prace z użytkownikami biznesowymi, testerzy przejmują część obowiązków dotyczących analizy. Właściciel produktu często tworzy zawczasu „listę kontrolną historyjki”, zawierającą informacje na temat jej celu oraz szkicowe warunki satysfakcji. Dla historyjek, które dotyczą interfejsów użytkownika, właściciel produktu dodaje do listy kontrolnej makietę UI. Historyjki, które uwzględniają skomplikowane algorytmy, uzupełnia o arkusz z przykładami. Ostatecznie właściciel produktu zabrał się również za prace niezwiązane z oprogramowaniem, więc często nie ma dość czasu na przygotowanie się do spotkania. Aby poradzić sobie z tym problemem, testerzy uzyskują jego zgodę na bezpośrednie, przygotowawcze kontakty z interesariuszami i pracują z nimi nad specyfikacjami. Iteracja rozpoczyna się od spotkania planowania, podczas którego członkowie zespołu omawiają wszystkie historyjki, a właściciel produktu odpowiada na pytania otwarte. Następnie tworzone są makiety zawartości ekranu, a na podstawie przykładów przedstawiane są wymagania. Testerzy łączą te informacje z listą kontrolną historyjki (jeśli jest dostępna), a później poprawiają specyfikacje i umieszczają je na stronie wiki. Czwartego dnia sprintu dwójka testerów spotyka się z właścicielem produktu i razem wykonują szczegółowy kompletny przegląd specyfikacji i testów, aby upewnić się, że wszyscy tak samo rozumieją to, co się w nich znajduje. Dzięki temu właściciel produktu może zająć się zanalizowaniem specyfikacji i tego, co zespół ma wykonać w ramach najbliższej iteracji. Od razu gdy specyfikacje trafiają na stronę wiki, deweloperzy zaczynają implementowanie historyjek, a potem, kiedy są gotowe, pokazują efekty swojej pracy użytkownikom biznesowym. Momenty olśnienia Poprosiłem Lisę Crispin, by opowiedziała o chwilach w procesie wdrażania specyfikacji przez przykłady, gdy doznała prawdziwego olśnienia. Oto jej odpowiedzi: Jakość nie jest moją własnością. Moim zadaniem jest niesienie pomocy klientowi w zakresie zrozumienia koncepcji jakości, ułatwienie zespołowi stworzenia definicji jakości i zadbanie o to, aby efekt pracy wyróżniał się wysoką jakością. Deweloperzy muszą zaangażować się w prace. Proces wymaga cierpliwości. Trzeba robić malutkie kroczki, a nie nastawiać się na to, żeby zrobić wszystko naraz. Narzędzie takie jak FitNesse może naprawdę wesprzeć współpracę. Myślisz o nim jak o narzędziu technicznym, które ma umożliwić automatyzację, ale FitNesse zmienia kulturę zespołu i usprawnia komunikację. Prawdziwa wartość procesu wynika z interpersonalnej interakcji.
Rozdział 16. ePlan Services
273
Najważniejsze lekcje Ze względu na biznesową strategię działania firma ePlan Services bazuje głównie na automatyzacji procesów i efektywnym dostarczaniu oprogramowania. Myśląc o poprawie jakości produktów oraz przyspieszeniu ich dostarczania, ePlan Services musiała odejść od ręcznego testowania oprogramowania. Początkowo koncentrowała się na automatyzacji testów funkcjonalnych, ale po jakimś czasie okazało się, że sytuacja, w której wszyscy zaangażowani w prace mają takie samo pojęcie na temat produktu wynikające ze współpracy, pozwala tworzyć znacznie lepsze oprogramowanie. Początkowo członkowie zespołu myśleli o współpracy z perspektywy testowania i przesadzili z uszczegółowieniem testów, w efekcie utrudniając deweloperom wykorzystanie dokumentacji w roli celu rozwoju. Zamiast przewidywać wszystkie możliwe kombinacje wartości, ludzie zaczęli określać kluczowe przykłady, dzięki czemu cały proces stał się bardziej efektywny i zapewnił deweloperom dobrej jakości specyfikacje, dokładnie wtedy, gdy były potrzebne. Kiedy zespół dysponował już kompleksowym pakietem wykonywalnych specyfikacji dla części systemu, ludzie uświadomili sobie wielką wagę żyjącej dokumentacji, zwłaszcza w roli mechanizmu wychwytywania unikalnej wiedzy. Gdy rozpoczęto dokumentowanie innych części systemu, spójny system żyjącej dokumentacji ujawnił nieścisłości i błędy w istniejących procesach biznesowych. System żyjącej dokumentacji sprawił, że proces wytwarzania oprogramowania stał się znacznie sprawniejszy, i pozwolił zespołowi odkryć nieścisłości procesów biznesowych.
274
Specyfikacja na przykładach
17
Songkick
S
ongkick to brytyjski start-up odpowiedzialny za stworzenie i utrzymanie Songkick.com, witryny internetowej oferującej dostęp do muzyki przesyłanej na żywo. Songkick jest niezwykle interesującym studium przypadku, i to z dwóch powodów… Po pierwsze, w przeciwieństwie do wszystkich innych opisanych w tej książce zespołów, Songkick wdrożył metodykę specyfikacji przez przykłady jeszcze na etapie rozruchu, więc nie musiał dopasowywać jej do jakiegoś istniejącego systemu, odziedziczonego po innych zespołach w spadku. Po drugie, również inaczej niż w przypadku większości projektów omówionych w tej książce, jedną z najważniejszych cech produktu zespołu Songkick jest interakcja z użytkownikiem. Wszystkie nowe funkcje produktu zespołu są opracowywane z naciskiem na doznania użytkownika, na podstawie obserwacji sposobów jego interakcji z witryną. Na złożony system składają się w ogromnej większości liczne subtelne wrażenia użytkowników i szereg funkcji, które opracowuje zespół, aby zapewnić użytkownikom jak najbogatsze doświadczenia. Songkick dokonał implementacji specyfikacji przez przykłady, aby skupić się przede wszystkim na dostarczaniu istotnego z punktu widzenia użytkowników oprogramowania i móc budować doświadczenie deweloperów. „Nowa firma na rynku nie może pozwolić sobie na niedostarczanie wartości przez cały czas” — mówi CTO Songkick, Phil Cowans, który wskazuje takie oto największe zalety specyfikacji przez przykłady: Osiągnięcie szybciej tego, co rzeczywiście miało zostać stworzone, dzięki zastosowaniu tego samego języka w testach i w procesie poznawania oczekiwań naszych klientów. Takie rozwiązanie pomaga zredukować problemy z komunikacją. Dążymy do tego, aby nigdy nie doprowadzić do sytuacji, w której nasi deweloperzy stwierdziliby: »To, co stworzyliśmy, działa. Tyle tylko, że nie poprosiliście o to, czego naprawdę potrzebowaliście«.
276
Specyfikacja na przykładach
Efektywne dostarczanie oprogramowania, które daje prawdziwą wartość, jest o wiele ważniejsze dla firm startujących na rynku niż dla tych bardziej dojrzałych. Praktyki specyfikacji przez przykłady pomagają zespołowi Songkick w uzyskiwaniu większej wartości przy takich samych inwestycjach w proces wytwarzania oprogramowania.
Zmiana procesu Projekt rozpoczęto dwa i pół roku temu. Po pierwszym roku zespół zaczął się rozrastać, zmieniając się tak, że — słowami Phila Cowansa — „nie dało się już usiąść przy jednym stole i zająć się wspólnie opracowywaniem kodu”. Aby poradzić sobie z dużą bazą kodu, który stawał się coraz bardziej skomplikowany, oraz z coraz liczniejszym zespołem, firma postanowiła wdrożyć metodę wytwarzania oprogramowania w oparciu o testy. Phil Cowans mówi: Przed przejściem na TDD ufaliśmy, że wszystko, co opracowaliśmy wcześniej, po wydaniu nowego kodu ciągle będzie działać poprawnie. Jednak bardzo szybko okazało się, że potrzebujemy większej pewności. Musieliśmy mieć gwarancję, że gdy skończymy prace nad jakimś komponentem, będzie on działać dokładnie tak, jak się spodziewamy, i nie wywoła kłopotów z regresją. Wydawało się dość oczywiste, że jeśli nie znajdziemy jakiegoś sposobu, aby uniknąć ciągłego potykania się o czyjeś nogi, zaczniemy zwalniać. Potrzebowaliśmy lepszego sposobu komunikowania wymagań i niedopuszczania do regresji. Po trzech miesiącach zespół poczuł, że praca w TDD przychodzi mu naturalnie. W tym samym czasie z coraz większym zainteresowaniem spoglądano w stronę Kanbana i koncepcji pracy na bazie historyjek użytkowników, co doprowadziło do zastosowania zasad TDD w kontekście funkcjonalności biznesowej i skutecznego rozpoczęcia wdrażania specyfikacji przez przykłady. Zespół Songkick lubił eksperymentować z różnymi sposobami pracy, więc po prostu wypróbowywał nowe rozwiązania bez wprowadzania większego zamieszania. Phil Cowans wyjaśnia: Byliśmy w kontakcie z facetem — który obecnie jest pełnoetatowym pracownikiem, ale wówczas pełnił funkcję doradcy — posiadającym doświadczenie z Kanbanem. Na tej podstawie mogliśmy sądzić, że da się pracować skutecznie z historyjkami użytkownika. To wydawało się mieć sens. Decyzja dotycząca wprowadzenia nowej metody jako części naszego procesu to naprawdę była wyłącznie kwestia stwierdzenia: »Są tacy, którzy tak robią i wykorzystują tę technologię. Spróbujmy i zobaczmy, co z tego wyjdzie«. Było to bardzo naturalne. Zespół zaczął od określania zakresu na podstawie celu na potrzeby zdefiniowania historyjek użytkowników, bazując na wartości biznesowej. W projektach wykorzystywano Cucumbera do tworzenia wykonywalnych specyfikacji. Phil Cowans mówi, że w miarę jak zespół
Rozdział 17. Songkick
277
zdobywał nowe doświadczenia z Cucumberem, cel procesu zmieniał się — tj. coraz większy nacisk kładziono nie tyle na testy jednostkowe, ile na specyfikacje biznesowe: Początkowo zdecydowaliśmy się na użycie mieszanki testów Rails i Cucumbera. Tego drugiego używaliśmy do kontrolowania historyjek użytkowników wysokiego poziomu i testów jednostkowych sprawdzających szczególne zachowania. Z biegiem czasu zaczęliśmy coraz częściej korzystać z Cucumbera. Sami szukaliśmy sposobów, żeby coraz więcej specyfikować w Cucumberze. Nowa metoda specyfikowania pomogła zespołowi skupić się na oprogramowaniu, które było naprawdę ważne. Phil Cowans mówi: [Nowa metoda] pomaga ludziom skoncentrować się na kwestii tego, dlaczego coś robimy, i zrozumieniu wartości tego, co robimy. Pomaga uniknąć marnowania czasu na tworzenie czegoś, czego nie potrzebujesz. Każdy patrzy na zagadnienie z tej samej perspektywy, co gwarantuje, że zespół deweloperów i reszta firmy myśli o problemie w ten sam sposób. Podobnie jak w przypadku zespołu ePlan Services, w Songkick także najpierw wdrożono (część) TDD, a następnie rozszerzono model o funkcje biznesowe. W Songkick nie pojawiły się problemy z utrzymaniem jakości produktów, które sprowokowałyby zmianę procesu, ale zdecydowano się na działania proaktywne w celu poprawy wydajności. Phil Cowans twierdzi, że największym wyzwaniem dla jego zespołu podczas wdrażania specyfikacji przez przykłady było określenie tego, co powinno być testowane, i znalezienie sposobu, by wykonywalne specyfikacje nie były tak delikatne oraz by przyspieszyć ciągłą walidację. Gdy zespół poczuł się pewniej, korzystając z narzędzi, za bardzo skoncentrował się na funkcjonalności interfejsu użytkownika, dlatego że ten komponent łatwiej było rozbudowywać. Phil Cowans wyjaśnia: Spędzaliśmy za dużo czasu, testując jakieś trywialne elementy interfejsu użytkownika, ponieważ to było łatwe. Nie poświęcaliśmy dość czasu na szukanie przypadków brzegowych i alternatywnych ścieżek prowadzących przez aplikację. Zespół zautomatyzował także wykonywalne specyfikacje w sposób, który był ściśle związany z interfejsem użytkownika, więc wyniki testów nie były zbyt pewne. Phil Cowans mówił, że w pewnych sytuacjach to zmuszało do testowania po fazie rozwoju zamiast stosowania testów jako specyfikacji: Ktoś zmienia znaki interpunkcyjne na stronie internetowej i test kończy się niepowodzeniem. To frustrujące, bo sprawia, że trudno przewidzieć skutki zmian. Trudno jest wcześnie zaktualizować cały zestaw testów. W rezultacie w pewnych przypadkach ludzie woleli najpierw stworzyć kod, a potem przechodzili do testów.
278
Specyfikacja na przykładach
Aby rozwiązać te problemy, zespół zaczął tworzyć testy o bardziej semantycznym charakterze i przeniósł translację koncepcji języka domeny i interfejsu użytkownika do warstwy automatyzacji. Phil Cowans wyjaśnia: Zaczynasz rozumieć proces i dostrzegasz, gdzie zależność od interfejsu użytkownika może powodować problemy w perspektywie długoterminowej. Rozwijanie krokowych definicji skoncentrowanych na domenie [w warstwie automatyzacji] pomogło nam z poradzeniem sobie z tym problemem, dając okazję pracy ze znacznikami wyższego poziomu. Wprowadzane zmiany były tak naprawdę początkiem udoskonalania specyfikacji i szukania sposobów ich wyrażania w języku biznesu, a nie w języku interfejsu użytkownika. Według Phila Cowansa przyzwyczajanie się do procesu i narzędzi wykorzystywanych przy specyfikacji przez przykłady trwało około sześciu miesięcy: Prawdopodobnie dopiero w ciągu ostatnich sześciu, dziewięciu miesięcy poczuliśmy, że to jest część tego, co robimy. W tym czasie nikt już nie kwestionował tego, jak przygotowujemy specyfikacje pracy. Metoda stanowi tło. Zespół zdał sobie sprawę z tego, jak wielkie znaczenie mają wykonywalne specyfikacje, gdy stanął przed koniecznością odtworzenia części systemu dotyczącego kanałów aktywności użytkowników. Istniejący zestaw zautomatyzowanych specyfikacji skoncentrowanych na celach biznesowych dał jego członkom pewność, że modyfikując kanały, nie wprowadzają nowych błędów lub ograniczeń funkcjonalności. Phil Cowans mówi: W tym momencie wszyscy zrozumieli, że dzięki temu zaoszczędzimy sporo czasu. Moim zdaniem dzięki testom udało się nam oszczędzić na refaktoryzacji 50% czasu. W przypadku nowej firmy nie można gardzić oszczędnością rzędu 50% czasu pracy. Zestaw wykonywalnych specyfikacji skutecznie chroni system przed problemami z regresją. Według Phila Cowansa liczba błędów wykrywanych w produkcji jest tak niska, że zespół w ogóle nie potrzebuje systemu śledzenia błędów. Dzięki temu można skoncentrować się na dostarczaniu nowych funkcji zamiast na serwisowaniu systemu.
Obecny kształt procesu Obecnie proces wytwarzania oprogramowania zespołu Songkick opiera się na przepływach Kanban. Firma dysponuje zespołem produktowym, odpowiedzialnym za osiąganie kolejnych etapów pracy z mapy drogowej, oraz zespołem ds. rozwoju z deweloperami odpowiedzialnymi za implementację. Zespół ds. produktu składa się z szefa rozwoju produktu, dyrektora kreatywnego i projektanta interakcji. Zespół ds. rozwoju to dziewięciu deweloperów i dwóch testerów. Dwie osoby koncentrują się bardziej na stronie klienta i interfejsach użytkownika,
Rozdział 17. Songkick
279
Jeszcze bez żyjącej dokumentacji W czasie gdy rozmawiałem z Philem Cowansem, liczba wykonywalnych specyfikacji zespołu wzrosła na tyle, żeby można było zacząć myśleć o reorganizacji specyfikacji, czyli o stworzeniu systemu żyjącej dokumentacji. Oto co powiedział na ten temat mój rozmówca: Podczas projektowania nie myśleliśmy specjalnie o strukturze wysokiego poziomu tych testów. W miarę ewoluowania aplikacji dodawaliśmy tylko nowe testy, odpowiadając w ten sposób na bieżące zapotrzebowanie. W rezultacie, gdy zachodzi konieczność modyfikacji istniejącego kodu, trudno zorientować się, które testy pokrywają jaką funkcję. Lepiej było zdecydować się na opis wysokiego poziomu zestawu funkcji witryny i zorganizować zestaw testów na tej podstawie, a nie dodawać po prostu co rusz to jakieś nowe testy dla każdej opracowanej nowej funkcji. Myślę, że takie rozwiązanie sprawdziłoby się lepiej, również jeśli chodzi o rozwój produktu i utrzymanie bazy kodu, który jest stosunkowo łatwy do zrozumienia. Efekt byłby taki, że ostatecznie mielibyśmy do dyspozycji wspólny język opisywania tego, jak nowe elementy pasują do tych, które zostały wdrożone wcześniej.
a reszta zespołu skupia się przede wszystkim na middleware i systemach zaplecza. Phil Cowans, pełniący funkcję CTO, jest również częścią zespołu deweloperskiego. Jego zdaniem firma stara się maksymalnie premiować współpracę zespołów, więc granice między nimi są dość niewyraźne. Gdy funkcja ma na tyle wysoki priorytet, że rośnie prawdopodobieństwo jej implementacji, zespół produktu organizuje spotkanie, by poznać doświadczenia użytkowników i zastanowić się nad technologią niezbędną do wykonania zadania. Efektem takiego spotkania są szkieletowe szablony, notatki o szczególnych przypadkach oraz pierwsze szkicowe formy historyjek użytkownika dla funkcji. Gdy zespół ds. rozwoju ma wystarczającą zdolność do rozpoczęcia realizacji funkcji, organizuje pierwsze spotkanie z zespołem ds. produktu oraz wszystkimi deweloperami i testerami, którzy prawdopodobnie będą pracować nad wdrożeniem funkcji. Na tym spotkaniu dzieli się funkcję na historyjki użytkowników i członkowie zespołu wspólnie przeprowadzają sesję burzy mózgów, definiując kryteria akceptacji dla każdej historyjki. Kryteria akceptacji to zbiór elementów, które należy sprawdzić, zawierający szczegółowe przykłady do uzupełnienia w późniejszym czasie. Testerzy są właścicielami wymagań, w tym także historyjek użytkownika oraz powiązanej listy kryteriów akceptacji. Są odpowiedzialni za obsługę i uzupełnianie tych źródeł, w miarę jak w czasie prac pojawiają się dodatkowe informacje. Ze względu na znaczenie użyteczności i interakcji z użytkownikiem testerzy ręcznie sprawdzają podstawowe elementy każdej funkcji trafiającej do nich od deweloperów, a jednocześnie uruchamiają wszystkie wykonywalne specyfikacje. Tym samym testerzy zaczynają myśleć o planie testów już po pierwszym spotkaniu.
280
Specyfikacja na przykładach
Deweloperzy piszą specyfikację z przykładami, a testerzy analizują otrzymany materiał, podsuwając swoje propozycje tego, co jeszcze powinno się w nim znaleźć. Następnie deweloperzy przechodzą do zautomatyzowania specyfikacji, implementacji wymaganej funkcji z wykorzystaniem TDD, by w końcu udostępnić gałąź kodu dla testerów. Wtedy testerzy uruchomiają ręczne testy, zaczynają testy eksploracyjne i przekazują zebrane wyniki z powrotem do deweloperów. Gdy testerzy i deweloperzy zgadzają się, że funkcja jest gotowa, ta trafia do kolejki integracji. Funkcje z kolejki zostają zintegrowane z gałęzią główną. Wówczas uruchamiany jest cały zestaw testów ciągłej walidacji, kod zostaje wdrożony w środowisku próbnym, a testerzy uruchamiają końcowe manualne testy podstawowych funkcji. Następnie kod zostaje uznany za ukończony i przekazuje się go do środowiska produkcyjnego. Momenty olśnienia Poprosiłem Phila Cowansa o zastanowienie się nad swoimi doświadczeniami z wdrożenia specyfikacji przez przykłady i wskazanie kluczowych momentów olśnienia. Oto jego lista: Stosunkowo łatwe jest testowanie tego, co widzisz, ale w końcu i tak trzeba posiąść ogromną wiedzę całościową dotyczącą mechanizmów systemu — tego, co robi, a nie tego, jak wygląda interfejs użytkownika aplikacji. Myślenie w kategoriach historyjek użytkownika i ścieżek prowadzących przez aplikację naprawdę bardzo się przydaje. Traktuj swój pakiet testów jak bardzo ważnych gości. Potrzebuje on starannej konserwacji tak samo jak kod aplikacji. Testy to kanoniczny opis tego, co robi aplikacja. Ostatecznie sukces będzie udziałem tych, którzy potrafią stworzyć właściwe oprogramowanie zgodnie z właściwymi regułami. Jeśli testy są twoim opisem tego, co robi kod, nie są tylko ważną częścią procesu rozwoju, ale stają się ważną częścią ogólnego procesu tworzenia produktu. Mogą ci pomóc w zrozumieniu tego, co właśnie stworzyłeś, i jednocześnie zapewniają pełną kontrolę nad złożonością produktu. Ważna jest umiejętność podtrzymania zaangażowania wszystkich osób pracujących na rzecz procesu. To nie jest coś, za co odpowiadają tylko deweloperzy. Ostatecznie [specyfikacja przez przykłady] daje ci testy napisane przez deweloperów, które są czytelne dla właściciela produktu. Powinieneś to wykorzystać.
Najważniejsze lekcje Podstawową lekcją wyniesioną z doświadczeń zespołu Songkick było dla mnie stwierdzenie, że jeśli nie musisz zapewniać prawidłowego działania skomplikowanego systemu odziedziczonego „w spadku” po poprzednikach, wówczas możliwe jest szybkie przejście z modelu TDD do specyfikacji przez przykłady. W Songkick potraktowano model specyfikacji przez przykłady jak naturalne rozszerzenie procesu TDD w celu pokrycia funkcjonalności biznesowej.
Rozdział 17. Songkick
281
Zespół Songkick tworzy i serwisuje system internetowy, więc początkowo automatyzacja testów była zbyt blisko związana z interfejsem użytkownika. To spowodowało wiele problemów z obsługą systemu i doprowadziło do rozpoczęcia procesu poprawiania specyfikacji i automatyzacji testów interfejsu użytkownika na wyższym poziomie abstrakcji. Po roku zespół zaczął doceniać znaczenie żyjącej dokumentacji, dostrzegając jej wielką przydatność, gdyby pojawiła się potrzeba przepisania lub odtworzenia elementów systemu. Jako start-up Songkick mógł czerpać korzyści z faktu skoncentrowania się na dostarczaniu funkcji, które były naprawdę wysoko oceniane przez użytkowników. Zapewnienie wspólnego zrozumienia będącego konsekwencją współpracy przy tworzeniu specyfikacji pozwala mieć pewność, że wszyscy skupiają się na dostarczeniu właściwego produktu. Drugim najważniejszym dobrodziejstwem było posiadanie wykonywalnych specyfikacji, ponieważ dzięki nim Songkick mógł szybko identyfikować trudności i skupić się na ukończeniu opracowywania nowych funkcji, nie tracąc czasu na rozwiązywanie problemów i usuwanie błędów.
282
Specyfikacja na przykładach
18
Podsumowanie
M
oje badania pierwotnie miały pomóc mi w uzyskaniu zewnętrznego potwierdzenia wcześniej sformułowanych już przeze mnie wniosków. Chciałem zdobyć dowody świadczące o tym, że w świecie inżynierii oprogramowania istnieje wiele zespołów, które przygotowują właściwe oprogramowanie przy użyciu zwinnych technik. Miałem nadzieję, że zespoły te korzystają z BDD, zwinnego modelu testów akceptacyjnych lub z metodyki, którą zacząłem nazywać specyfikacją przez przykłady. Myślałem, że wiem, jak wyglądają te procesy, i zdawało mi się, że znajdę osoby korzystające z nich i bazujące na znanym mi modelu. Jednak im więcej zbierałem materiałów, tym bardziej zaskakujących rzeczy się dowiadywałem. Okazało się, że wiele zespołów pracujących w różnych kontekstach stosuje różne praktyki i techniki, aby osiągnąć identyczne efekty. Stwierdziłem, że w tym przypadku trudno mówić o czymś takim jak „najlepsze praktyki”. Proces wytwarzania oprogramowania jest w ogromnym stopniu uzależniony od kontekstu i to, co jednemu zespołowi może się wydawać dobrym pomysłem, w innym może się zupełnie nie sprawdzić. Gdy patrzę wstecz na swoje badania, dziwi mnie, jak wielu nowych rzeczy dowiedziałem się o skutecznym dostarczaniu produktów wysokiej jakości. Niektóre z nich stanowiły dla mnie kompletną nowość. Inne były wnioskiem z analizy elementów, na które wcześniej patrzyłem z innej, szerszej perspektywy, ale które, dzięki bardziej drobiazgowej analizie, dały mi o wiele głębsze zrozumienie rzeczywistych sił stojących za interesującymi mnie praktykami. Na zakończenie tej książki chciałbym przedstawić pięć najważniejszych wniosków, które sformułowałem na podstawie wyników moich badań.
Współpraca przy definiowaniu wymagań buduje wzajemne zaufanie interesariuszy i członków zespołu W Bridging the Communication Gap utrzymywałem, że warsztaty specyfikacji przynoszą dwa słodkie owoce. Jeden jest jak najbardziej namacalny: to przykłady lub specyfikacje. Drugi ma charakter niematerialny: wspólne zrozumienie tego, co należy zrobić, będące efektem wymiany poglądów. Przewidywałem, że to wspólne zrozumienie może być nawet ważniejsze
284
Specyfikacja na przykładach
niż same przykłady. Jednak okazuje się, że sytuacja jest znacznie bardziej skomplikowana! Istnieje jeszcze jedna niematerialna wartość wynikająca z warsztatów specyfikacji, odkryta przeze mnie podczas zbierania materiałów do tej książki. Przykłady zespołów takich jak uSwitch, SAS, Beazley i Weyerhaeuser pokazują, że współpraca przy tworzeniu specyfikacji staje się iskrą, która prowadzi do eksplozji — przemiany kultury pracy zespołów. W rezultacie procesy rozwoju, analizy i testowania zaczynają lepiej do siebie pasować, a zespoły integrują się. Cytując Wesa Williamsa, „to zaufanie było niesamowite”. Wiele firm, z którymi pracowałem, korzysta z modelu rozwoju oprogramowania bazującego na braku zaufania. Użytkownicy biznesowi mówią analitykom, czego potrzebują, jednak nie ufają im na tyle, by powierzać im odpowiedzialność za prawidłowe wykonanie zadania. Wymagają podpisów pod specyfikacjami. Analitycy mówią deweloperom, czego potrzebują, ale nie wierzą, że ci dostarczą produkt. W końcu testerzy muszą znaleźć jakiś sposób, aby niezależnie sprawdzić, czy deweloperzy są uczciwi. Ponieważ deweloperzy nie ufają testerom (bo przecież „oni nie tworzą kodu!”), gdy testerzy zgłaszają problem, opatrują go uwagą o błędzie „niemożliwym do odtworzenia” lub dopiskiem w stylu: „Na moim sprzęcie wszystko działa”. Testerzy są szkoleni, aby nie ufać nikomu. Zachowują się niemal jak doskonale zakonspirowani szpiedzy. Model oparty na braku zaufania prowadzi do konfrontacji i stworzenia nieprzyjaznych warunków pracy, a ponadto wymaga sporej liczby działań czysto biurokratycznych. Z założenia dokumentacja z wymaganiami musi przejść etap uzyskiwania akceptacji i podpisów, bo użytkownicy chcą mieć pewność, że to, co robią analitycy, zostanie wykonane poprawnie. Tymczasem prawda jest taka, że formalna akceptacja jest wymagana, ponieważ analitycy nie chcą być później obwiniani za ewentualne luki funkcjonalne. Jako że wszyscy muszą wiedzieć, co dzieje się z projektem, specyfikacje przechodzą proces zarządzania zmianą. W rzeczywistości chodzi o zapewnienie, by nikt nie był obwiniany za to, że nie przekazał informacji o zmianie. Mówi się, że kod zostaje zamrożony na potrzeby testowania, by zapewnić bardziej stabilne otoczenie. Takie rozwiązanie stanowi także gwarancję tego, że deweloperzy nie będą oskarżani o oszukiwanie, gdy system przechodzi etap testowania. Teoretycznie wszystkie te mechanizmy są po to, aby mieć pewność, że produkt końcowy będzie charakteryzował się wysoką jakością. Tymczasem w rzeczywistości stają się one tylko generatorami alibi. Wszystkie te generatory to czyste marnotrawstwo! Poprzez budowanie wzajemnego zaufania użytkowników biznesowych, analityków, deweloperów i testerów możemy eliminować generatory alibi i biurokrację, która jest wynikiem zastosowania wspomnianych mechanizmów formalnej akceptacji. Współpraca przy tworzeniu specyfikacji jest świetnym sposobem rozpoczęcia budowania tego zaufania.
Współpraca wymaga przygotowania Mimo że wcześniej sugerowałem, iż dobrym sposobem wdrożenia metody w iteracji jest zorganizowanie spotkania wstępnego planowania, w Bridging the Communication Gap nie rozwijałem tego tematu. Zaproponowałem przygotowanie etapu wstępnego planowania, ponieważ z moich doświadczeń wynikało, że spędzamy za dużo czasu na początku każdego
Rozdział 18. Podsumowanie
285
warsztatu, próbując zidentyfikować ważne atrybuty zestawu przykładów, a tymczasem prawdziwa dyskusja rozpoczyna się dopiero wtedy, gdy mamy już jakieś konkrety, nad którymi można popracować. Teraz widzę, że spotkanie wstępnego planowania jest częścią znacznie bardziej złożonej praktyki. Po zapoznaniu się z doświadczeniami zespołów, które w różny sposób sformalizowały fazę wstępnego przygotowania, zrozumiałem, że współpraca przy definiowaniu przykładów jest procesem dwuetapowym. W pierwszym kroku ktoś przygotowuje podstawowe przykłady. W drugim przykłady te są omawiane na spotkaniu z zespołem, a następnie rozbudowywane. Celem fazy przygotowawczej jest znalezienie odpowiedzi na kilka podstawowych pytań i zdefiniowanie formatu przykładów, gdy zespół zaczyna je omawiać. Wszystko to może wykonać jedna osoba (lub para), dzięki czemu warsztat z udziałem większej grupy stanie się znacznie bardziej efektywny. Zespoły, które pracowały nad projektami z niejasnymi wymaganiami, gdy konieczne były wstępne analizy, tak organizowały sobie prace, aby etap przygotowawczy rozpoczynał się dwa tygodnie przed wspólnymi warsztatami. Dzięki temu analitycy mieli dość czasu, by porozmawiać z użytkownikami biznesowymi, zebrać przykłady i zacząć je udoskonalać. Zespoły, które dysponowały bardziej stabilnymi wymaganiami, zaczynały pracować na przykładach kilka dni wcześniej, zbierając oczywiste otwarte pytania i odpowiedzi. Wszystkie te metody pomagają lepiej wykorzystać zalety warsztatów, w których uczestniczy większe grono ludzi.
Współpraca może przybierać wiele różnych form W Bridging the Communication Gap zasugerowałem, że duże warsztaty, w których uczestniczy cały zespół, są najlepszą metodą wykorzystania zalet współpracy przy tworzeniu specyfikacji. I w tym przypadku, dzięki zebraniu różnych opinii na temat procesów zespołów pracujących w różnych kontekstach, wiem już, że w rzeczywistości to zagadnienie jest dużo bardziej skomplikowane. Wiele zespołów przekonało się, że formalne warsztaty specyfikacji przydają się do przekazywania wiedzy na temat domeny i dostosowania oczekiwań deweloperów, testerów i analityków biznesowych oraz interesariuszy. Jednak większość zbadanych przeze mnie zespołów po jakimś czasie w ogóle rezygnowała z tak dużych warsztatów, ponieważ stwierdzała, że są one trudne do skoordynowania i wymagają dużego zaangażowania czasowego wszystkich obecnych. Gdy udaje się wdrożyć podstawowe mechanizmy modelu, poprawia się wzajemne zaufanie osób uczestniczących w pracach, a programiści i testerzy zdobywają wiedzę na temat domeny, dzięki czemu do stworzenia poprawnych specyfikacji wystarczają warsztaty organizowane w mniejszym gronie lub mniej formalne spotkania. Wiele zespołów przeszło z metody zapraszania na warsztaty „każdego, kto ma jakiś związek z historyjką”, do spotkań w obecności tylko tych ludzi, którzy czynnie pracują nad zadaniem. Gdy jedni muszą wprowadzać zmiany, innym wystarczy, że dowiedzą się z systemu żyjącej dokumentacji, jakie funkcje ma oprogramowanie.
286
Specyfikacja na przykładach
Przydaje się umiejętność spojrzenia na cel końcowy jak na dokumentowanie procesów biznesowych Jeśli myślimy o dokumentacji procesów biznesowych jako o celu końcowym specyfikacji przez przykłady, wiele typowych problemów z automatyzacją i utrzymaniem systemu po prostu traci rację bytu. Na przykład oczywisty staje się wówczas błąd opracowywania nadmiernie złożonych skryptów, które naśladują sposób tworzenia oprogramowania. Skrypty zawsze w końcu stają się zbyt trudne do utrzymania, a wartość komunikacji na ich podstawie jest niewielka. Nasza społeczność dostrzegła ten fakt już kilka lat temu, a wielu praktyków zaczęło odradzać zespołom pisanie testów akceptacyjnych w formie przepływu pracy. Mimo że taką radę można uznać za dobrą w większości przypadków, to nie będzie ona przydatna, jeśli domena ma charakter przepływowy — tak jak to wygląda na przykład w przetwarzaniu płatności. David Peterson stworzył Concordion, które miało być odpowiedzią na wszystkie nadużycia przepływów pracy w FIT. Autor trafił w sedno, radząc ludziom tworzenie specyfikacji, a nie skryptów. I w tym przypadku można powiedzieć, że taka wskazówka jest dobrą zasadą ogólną, ale trudno przekonać do niej ludzi, którzy zajmują się projektowaniem stron internetowych. Problem polega na niedopasowaniu modeli w testach akceptacyjnych lub specyfikacjach do modeli biznesowych1. Jedna mała zmiana w domenie biznesowej i mamy do czynienia z poważnymi konsekwencjami w obszarze testów, które stają się trudniejsze do utrzymania. Jeśli skupimy się na dokumentowaniu procesów biznesowych, model w specyfikacjach zostanie dostosowany do modelu biznesowego, a wszelkie wprowadzone zmiany będą miały charakter symetryczny. Mała zmiana w modelu domeny spowoduje niewielką zmianę w specyfikacji i w testach. Możemy dokumentować procesy biznesowe o wiele wcześniej, jeszcze przed rozpoczęciem pisania oprogramowania, i pozostaną one takie same, nawet gdy zmienimy technologie. Specyfikacje, które mówią o procesach biznesowych, w dłuższej perspektywie czasowej tylko zyskują na wartości. Użytkownicy biznesowi mogą uczestniczyć w dokumentowaniu procesów biznesowych i zapewniają znacznie lepszy feedback, niż gdyby przyszło im komentować testy akceptacyjne, które odnoszą się do oprogramowania. Dzięki skupieniu się na dokumentowaniu procesów biznesowych wiemy też, co powinniśmy automatyzować i jak to robić. Łatwo jest wychwycić wady w zmieniających się specyfikacjach, uwzględniając wymyślone koncepcje testowania lub dopasowując działania do interakcji użytkownika z interfejsem. Jeśli specyfikacje dokumentują procesy biznesowe, warstwa automatyzacji przenosi te procesy na oprogramowanie. To jest obszar, w którym pojawiają się techniczne przepływy pracy, skrypty i symulacje interakcji użytkownika. Sama automatyzacja nie jest celem. To tylko narzędzie do realizacji procesów biznesowych. Aby myśleć o zebraniu rzetelnej dokumentacji, musimy wypracować mechanizm częstej walidacji. Automatyzacja jest stosunkowo niedrogim sposobem realizacji tego zadania, ale na pewno nie jedynym. Niektóre cechy, na przykład takie jak użyteczność systemu, nigdy nie będą właściwie zautomatyzowane, co nie znaczy, że nie możemy próbować częstej 1
Patrz http://dannorth.net/2011/01/31/whose-domain-is-it-anyway.
Rozdział 18. Podsumowanie
287
walidacji choćby części specyfikacji. To rozwiązuje problem specyfikowania elementów, które są trudniejsze do zautomatyzowania. Problem, którego wiele zespołów próbuje nie dostrzegać.
W dłuższej perspektywie prawdziwą wartością dla zespołu jest system żyjącej dokumentacji Prawie wszystkie ankietowane przeze mnie zespoły doświadczyły krótkoterminowych korzyści z szybszego dostarczania nowych wersji produktów i ich lepszej jakości. A jednak zespoły, które „oczyściły swoje testy”, osiągnęły również fantastyczne korzyści w perspektywie długoterminowej. Pomagałem wielu z nich jako konsultant, przekonując ludzi do wdrożenia praktyk specyfikacji przez przykłady, ale ponieważ zazwyczaj nie towarzyszę zespołom zbyt długo, informacja o skutkach zmian w dalszej perspektywie zwykle mi umykała. Na szczęście beneficjentami korzyści były firmy, które wdrożyły wspomniane praktyki już jakiś czas temu i działają na rynku od sześciu lub siedmiu lat. Zespół Iowa Student Loan mógł szybko zmodyfikować model biznesowy, ponieważ dysponował wiarygodną dokumentacją. Zespół ePlan Services przetrwał odejście kluczowego członka zespołu. Zespół pracujący nad projektem Sierra używa „testów” w funkcji uzupełniającej dokumentacji, gdy trzeba odnieść się do próśb o pomoc w serwisowaniu systemu. Moim zdaniem w tym kontekście użycie terminu „testy” jest w ogóle niewłaściwe, gdyż zespół wcale nie wykorzystuje tych materiałów do testowania oprogramowania: to dokumentacja, którą zebrano po to, aby stworzyć wiarygodne i relewantne źródło wiedzy. Większość wymienionych zespołów wdrożyła system żyjącej dokumentacji metodą prób i błędów, w ramach procesu poszukiwania sposobów zoptymalizowania kosztów utrzymania testów. Testy zostały poddane restrukturyzacji tak, żeby stały się bardziej stabilne. Umożliwiono dopasowanie modelów w testach do modelu biznesowego. Zespoły zrestrukturyzowały katalogi zawierające testy tak, aby łatwiej można było znaleźć dane istotne dla konkretnej zmiany, rozwijając system dokumentacji, który odzwierciedla podejście do funkcji systemu użytkowników biznesowych. Na tym etapie mogę pokusić się o zdefiniowanie odważnego wniosku, że nowe zespoły mogą sięgnąć po wspomniane wcześniej korzyści szybciej, jeśli stworzą system żyjącej dokumentacji świadomie i celowo, a nie zmarnują czasu na lata prób i błędów. Mając to na uwadze, zachęcam Ciebie i Twój zespół do podjęcia odważnych prób. Jeśli zbierzesz własne doświadczenia, proszę, podziel się nimi ze mną. Możesz napisać do mnie na adres: [email protected].
288
Specyfikacja na przykładach
Dodatek A Źródła Książki Gojko Adžić, Bridging the Communication Gap: Specification by Example and Agile Acceptance Testing, Neuri, 2009. Gojko Adžić, Test Driven .NET Development with FitNesse, Neuri, 2008. David Anderson, Kanban: Successful Evolutionary Change for Your Technology Business, Blue Hole Press, 2010. Mijo Balic, Ingrid Ottersten, Peter Corrigan, Effect Managing IT, Copenhagen Business School Press, 2007. Mike Cohn, Agile Estimating and Planning, Robert C. Martin Series, Prentice Hall, 2005. Lisa Crispin, Janet Gregory, Agile Testing: A Practical Guide for Testers and Agile Teams, Addison-Wesley Professional, 2009. Kev Darling, F-16 Fighting Falcon (Combat Legend), The Crowood Press, 2005. Mark Denne, Jane Cleland-Huang, Software by Numbers: Low-Risk, High-Return Development, Prentice Hall, 2003. Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, Addison-Wesley Professional, 2003. Steve Freeman, Nat Pryce, Growing Object-Oriented Software, Guided by Tests, Addison-Wesley Professional, 2009. Donald C. Gause, Gerald M. Weinberg, Exploring Requirements: Quality Before Design, Dorset House Publishing Company, 1989. Capers Jones, Estimating Software Costs: Bringing Realism to Estimating, wydanie 2, McGraw-Hill Osborne, 2007. Craig Larman, Bas Vodde, Practices for Scaling Lean & Agile Development: Large, Multisite, and Offshore Product Development with Large-Scale Scrum, Pearson Education, 2010. Richard Monson-Haefel, 97 Things Every Software Architect Should Know: Collective Wisdom from the Experts, O’Reilly Media, 2009. Rick Mugridge, Ward Cunningham, Fit for Developing Software: Framework for Integrated Tests, Prentice Hall, 2005.
290
Specyfikacja na przykładach
Mary Poppendieck,Tom Poppendieck, Lean Software Development: An Agile Toolkit, Addison-Wesley Professional, 2003. James Shore, Shane Warden, The Art of Agile Development, O’Reilly Media, 2007. Gerald Weinberg, Quality Software Management: Vol. 1, Systems Thinking, Dorset House Publishing, 1992.
Źródła internetowe W tej części znajdują się adresy wszystkich zasobów pojawiających się w książce. Wszystkie wymienione łącza (i wiele więcej) znajdziesz także na stronie internetowej książki: http:// www.specificationbyexample.com.
Narzędzia Concordion: http://www.concordion.org. Cucumber: http://cukes.info. FitNesse: http://fitnesse.org. GreenPepper: http://www.greenpeppersoftware.com. JBehave: http://jbehave.org. Robot Framework: http://www.robotframework.org. SpecFlow: http://www.specflow.org. TextTest: http://www.texttest.org. Twist: http://studios.thoughtworks.com/twist-agile-test-automation.
Materiały wideo Gojko Adžić, Challenging Requirements, http://gojko.net/2009/12/10/challenging-requirements/. Dan North, How to Sell BDD to the Business, https://skillsmatter.com/skillscasts/923-how-to-sell-bdd-tothe-business. Hemal Kuntawala, How we build quality software at USwitch.com, https://skillsmatter.com/skillscasts/910-how-we-build-quality-software-at-uswitch-com. Björn Regnell, Supporting Roadmapping of Quality Requirements, http://oredev.org/videos/supportingroadmapping-of-quality-requirements.
Prezentacje Tim Andersen, Persona Driven Development, http://www.umsec.umn.edu/events/Code-Freeze-2010/PDD, http://timandersen.net/presentations/Persona_ Driven_Development.pdf. Mark Durrand, Damon Morgan, Creating a Lean business from the inside out: Technical innovation at uSwitch.com to reduce waste, http://www.slideshare.net/markdurrand/spa2010-uswitch.
Dodatek A Źródła
291
Artykuły Gojko Adžić, Agile in a Start-up Games Development Studio, http://gojko.net/2010/05/19/agile-in-astart-up-games-development-studio/. Gojko Adžić, Are tools necessary for acceptance testing, or are they just evil?, http://gojko.net/2010/03/01/are-tools-necessary-for-acceptance-testing-or-are-they-just-evil. Gojko Adžić, Examples make it easy to spot inconsistencies, http://gojko.net/2009/05/12/examples-makeit-easy-to-spot-inconsistencies/. Gojko Adžić, How to implement UI testing without shooting yourself in the foot, http://gojko.net/2010/04/13/how-to-implement-ui-testing-without-shooting-yourself-in-the-foot-2/. Gojko Adžić, Improving testing practices at Google, http://gojko.net/2009/12/07/improving-testingpractices-at-google/. Gojko Adžić, QUPER model for better requirements, http://gojko.net/2009/11/04/quper-model-for-betterrequirements/. Gojko Adžić, Shock therapy agile adoption at 7Digital, http://gojko.net/2009/12/08/shock-therapy-agileadoption-at-7digital/. Michael Bolton, Acceptance Tests: Let’s Change the Title, Too, http://www.developsense.com/blog/2010/08/ acceptance-tests-lets-change-the-title-too/. Michael Bolton, Testing vs. Checking, http://www.developsense.com/blog/2009/08/testing-vs-checking/. Alistair Cockburn, Sacrifice One Person, http://alistair.cockburn.us/Sacrifice+one+person+strategy. Craig Larman, Bas Vodde, Acceptance Test-Driven Development with Robot Framework, http://code. google.com/p/robotframework/wiki/ATDDWithRobotFrameworkArticle. Craig Larman, Bas Vodde, Feature Teams Primer, http://www.featureteams.org/feature_team_primer.pdf. Dan North, Whose domain is it anyway?, http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/. Björn Regnell, Richard Berntsson Svensson, Thomas Olsson, Supporting Roadmapping of Quality Requirements, „IEEE Software” 25, nr 2 (marzec/kwiecień 2008), s. 43 – 47. James Shore, Alternatives to Acceptance Testing, http://jamesshore.com/Blog/Alternatives-to-AcceptanceTesting.html. James Shore, The Problems with Acceptance Testing, http://jamesshore.com/Blog/The-Problems-WithAcceptance-Testing.html. Lance Walton, Writing Maintainable Acceptance Tests, http://www.casualmiracles.com/blog/2010/03/04/ writing-maintainable-acceptance-tests/.
Komiksy Chris Matts, Real Options at Agile 2009, http://www.lulu.com/product/filedownload/real-options-at-agile2009/5949486.
292
Specyfikacja na przykładach
Kursy i szkolenia Gojko Adžić: http://neuri.co.uk/training. Object Mentor: http://objectmentor.com/omTraining/omi_training_index.html. Lisa Crispin i Janet Gregory: http://janetgregory.ca/service-type/training/. Elisabeth Hendrickson: http://www.qualitytree.com/workshops/. Pyxis Technologies: http://pyxis-tech.com/en/training. TechTalk: http://www.techtalk.at/training.aspx. Rick Mugridge: http://www.rimuresearch.com/Coaching.html.
Skorowidz
A
D
analitycy, 121 analiza kaskadowa, 78 wstępna, 123 aplikacje typu back-office, 102, 230 ATDD, Acceptance Test-Driven Development, 11, 55, 116 automatyzacja elementów systemu, 68 interfejsu użytkownika, 183 scenariuszy, 79 testów, 20, 66, 74 walidacji specyfikacji, 169, 172, 194 wykonywalnych specyfikacji, 69, 72, 177, 232 zmiany zegara, 208
dane referencyjne, 192, 193 testowe, 191 DDE, 80 dedykowane środowisko testowe, 200 definicje kroków, step definitions, 170 definiowanie historyjek, 100 wymagań, 283 zakresu, 19, 93, 95
B BDD, Behavior-Driven Development, 11, 18, 55 biblioteki automatyzacji interfejsu użytkownika, 184 automatyzacyjne przeglądarki, 184 bumerang, 88
C cel biznesowy, 50, 94 zakres prac, 45 chirurgia śrutówką, 90 CI, continuous integration, 195 ciągła integracja, CI, 195, 213 walidacja, 199 CRUD, Create, Read, Update, Delete, 96 czas reakcji, 141
mapowanie efektu, 105 mapowanie historyjki użytkownika, 105 wstrzykiwanie funkcjonalności, 19, 105
demo produktu, 79 dokumentacja, 29, 49, 56, 219 dokumentowanie procesów biznesowych, 286 dzielenie testów, 211
E EDT, Example-Driven Development, 11 efektywne dostarczanie oprogramowania, 276 eksperci, 121
F feature injection, 19, 105 feedback, 77, 78 fikstury, fixtures, 170 fikstury testowe, 181 formułowanie celów, 99 formy współpracy, 285 funkcjonalność biznesowa, 154 interfejsu użytkownika, 186, 188
G
gromadzenie wiedzy, 147 grupowanie nieudanych testów, 215 specyfikacji, 229
H hierarchia systemu żyjącej dokumentacji, 229 historyjki, 78–81, 95, 101, 228
I identyfikowalność wymagań, 83 ilustrowanie wymagań niefunkcjonalnych, 140 informacja zwrotna, 207 inicjowanie zmian, 63 integracja zespołów multidyscyplinarnych, 78 interfejs użytkownika, 141, 157 automatyzacja, 184 funkcjonalność, 186, 188 poziomy automatyzacji, 190 test, 185, 188 iteracje, 80, 81
J język specyfikacji, 223, 224 wszechobecny, Ubiquitous Language, 165
K kamienie milowe, 84 Kanban, 30 klasy równoważności, 132 kod automatyzacji, 178 komunikacja w zespole, 242 koncepcje wyższego poziomu, 221 konsultant, 173 kontekst w bazie danych, 189 kontrola jakościowa, QA, 114 wersji, 83 koszt automatyzacji, 171 utrzymania wykonywalnych specyfikacji, 170 kryteria akceptacji, 250
294
Skorowidz
L
organizacja warsztatów specyfikacji, 111
lista kontrolna, 143, 144 logika biznesowa, 180, 182
M mapowanie efektu, 105 historyjki użytkownika, 105 menedżer produktu, 136 metadane, 250 metaprogramowanie, 119 metodyka scrumowa, 81 metodyki zwinne, 65 migracja, 75 minimalne zbywalne właściwości, 99 model ATDD, 55 BDD, 55 QUPER, 142 tradycyjny, 28 Zakładając/Jeżeli/Wtedy, 163, 168 zorientowany na dokumentację, 60 modele współpracy, 109, 124 modyfikacja przykładów, 138
N narzędzia, 290 do automatyzacji, 84, 172
specyfikacji, 170 testów, 182
monitorujące, 77 open source, 259 narzędzie Balsamiq Mockups, 142 Cucumber, 84 FIT, 171, 261 FitNesse, 262, 272 niedopasowanie organizacyjne, 88
O odchudzone wytwarzanie oprogramowania, 95 opis, 154 procesów walidacji, 179, 180 testów akceptacyjnych, 154 optymalizacja praktyk testowania, 87 procesu, 240
P PBR, Product Backlog Refinement, 111 planowanie automatyzacji, 173 podział historyjek, 104 poprawa jakości, 65 powielanie logiki biznesowej, 180 poziom przepływu pracy użytkownika, 190 reguł biznesowych, 190 techniczny aktywności, 190 priorytetyzacja, 98, 244 priorytetyzacja historyjek, 118 proces asynchroniczny, 206 konfiguracji, 238 RUP, 86 wytwarzania oprogramowania, 245 programiści, 121 programowanie ekstremalne, XP, 30, 195 w parach, 113 projekt typu brownfield, 34 typu greenfield, 34, 199 projektowanie testów, 270 projekty oparte na danych, 266 przepływ procesu, 183 przetwarzanie asynchroniczne, 204 przykłady funkcjonalne, 142 kompletne, 133 podstawowe, 161 przypadków brzegowych, 138 realistyczne, 134, 136 referencyjne, 144, 145 reprezentatywne, 159 wymagań funkcjonalnych, 140 zrozumiałe, 137 przypadki brzegowe, 239 użycia, use cases, 85, 86
Q QA, 114 QUPER, 142
R realizacje przypadków użycia, 86 refaktoryzacja, 186 refaktoryzacja specyfikacji, 87 reguły biznesowe, 87 reorganizacja pracy, 104 warstwy automatyki, 187 restrukturyzacja skryptów, 154 rola Batmana, 76 rozwiązania alternatywne, 103 RUP, Rational Unified Process, 86 rzucanie wyzwania wymaganiom, 96
S SBE, Specification by Example, 65 Scrum, 30 SKIT, 79 skrypt, 152 skrypty testów ręcznych, 175 słownik języka specyfikacji, 225 specyfikacja, 45, 107, 147–168 dobra, 149 domyślne wartości, 164 funkcjonalność biznesowa, 154 implementacja oprogramowania, 155 integralność referencyjna, 163 interfejs użytkownika, 157 jedna reguła biznesowa, 161 język domeny, 165 oczekiwane wyniki, 158 reprezentatywne przykłady, 159 trudności techniczne, 156 udoskonalanie, 20, 147–168 utrzymywanie, 61 wartości wejściowe, 158 wdrażanie, 147 zła, 150 specyfikacja przez przykłady, 11, 20, 28–30, 54, 61, 75, 78 dostosowanie aktywności, 39 identyfikowalność, 82 jakość produktu, 32 wdrażanie, 74 wprowadzanie zmian, 30 zatwierdzenia, 82 znajdowanie błędów, 36 specyfikacje grupowane, 229 rozbudowane, 220 wykonywalne, 20, 48, 53, 58
Skorowidz spike, 172 spotkanie ATDD, 116 przygotowawcze, 117 trzech amigos, 112 z interesariuszami, 119 spójność żyjącej dokumentacji, 223 sprawdzanie logiki biznesowej, 182 testu, 87 funkcjonalności, 133 stabilność automatycznych testów, 198 studia przypadków, 235 system kontroli wersji, 84 systemy zewnętrzne, 202 szacowanie historyjek, 99
Ś śledzenie bumerangów, 88 procesu przepływu, 182 przebiegu zatwierdzeń wymagań, 82
T tablica Kanban, 78 TDD, 70 test, 50 akceptacyjny, 50, 100, 196 automatyczny, 57 Cucumbera, 239, 244 first, 19 FitNesse, 269 funkcjonalny, 66, 74 integracyjny, 206, 207 jednostkowy, 196 niefunkcjonujący, 69 nieudany, 215, 216 niskiego poziomu, 104 regresji, 215 równoległy, 183, 212 sanity testing, 263 szybki, 210 techniczny, 155 typu end-to-end, 207 wolny, 210 wyższego poziomu, 104 testerzy, 120, 279 testowanie baz danych, 209 danych referencyjnych, 204
interfejsu użytkownika, 176, 185, 188 przez historyjki użytkownika, 11 regresyjne, 50 specyfikacji wykonywalnej, 157 w chmurze, 213 w transakcjach, 203 timing, 44 transakcje, 203 tworzenie baz danych, 191 dokumentacji, 49, 55–62, 219
strony internetowe, 60 testy automatyczne, 57 wykonywalna specyfikacja, 58 dublera systemu, 201 procesu przepływu, 82 przykładów, 127 specyfikacji, 46, 107, 147–168
przykłady ilustrujące, 130
295
wsparcie kierownictwa, 72 wspomaganie definiowania zakresu, 105 współpraca, 109, 116, 263, 283–285 wstrzykiwanie funkcjonalności, feature injection, 19, 105 wybór modelu współpracy, 124 zakresu automatyzacji, 185 wydajność, 140 wymagania interesariuszy, 136 niefunkcjonalne, 140, 141 przekrojowe, 144 wydajnościowe, 140 wzorce kluczowych procesów, 43, 44 procesu specyfikacji, 54
X XP, Extreme Programming, 30
U
Z
UAT, User Acceptance Testing, 35 udoskonalanie specyfikacji, 20, 147–168 utrzymywanie specyfikacji, 61 użyteczność, 141, 144 użytkownik biznesowy, 99 używanie znaczników, 231
zaangażowanie interesariuszy, 118, 119 zakres automatyzacji, 185 implementacji, 45 projektu, 93 zamknięte odpowiedzi, 131 zarządzanie danymi testowymi, 191 testami, 197, 214 warstwą automatyzacji, 178 wymaganiami, 257 zastępowanie specyfikacji, 221 zatwierdzanie, 82 zatwierdzenie przypadków użycia, 85 zaufanie, 283 zespół Knighta, 136 Andrew Jackmana, 114 Bekk Consulting, 163 Clare McLennan, 198 ePlan Services, 267–273 Global Talent Management, 77, 83 Google, 87 Iana Coopera, 154, 202
W walidacja, 20, 47, 49, 195 procesów asynchronicznych, 204 specyfikacji, 169, 172 typu end-to-end, 206 wielostopniowa, 202 warstwa automatyzacji, 163, 178, 179 interfejsu użytkownika, 183 warsztaty PBR, 111 specyfikacji, 110, 116, 239 wartość, 98 wdrażanie specyfikacji, 147 zasady współpracy, 77 wersje oprogramowania, 73 właściciel produktu, 118
296
Skorowidz
zespół Iowa Student Loan, 216, 253–259 Jodie Parker, 123 Marty Gonzalez Ferrero, 128 Pierre’a Veragena, 189 QA, 238 RainStor, 211, 247–252 Rakesha Patela, 220 Roba Parka, 201 Sabre Airline Solutions, 261–266 Sierra, 80, 120, 226 SNS, 81, 83
Songkick, 275–281 Steera, 86 Stuarta Taylora, 113 TechTalk, 131 uSwitch, 100, 173, 214, 237–246 zestawy testów, 208 zmiana procesu, 64 zmniejszanie zawodności, 197 znaczniki, 231 zwiększanie niezawodności systemu, 198 zwinne testowanie akceptacyjne, 11, 18
Ź źródła wartości, 98
Ż żyjąca dokumentacja, 30, 53–62, 270, 287 hierarchia, 229 jako przewaga konkurencyjna, 258 łatwy dostęp, 219, 227 spójny język, 223 utrzymywanie, 233