W sobotę 10 grudnia odbył się w Warszawie
Agile Development Day. Była to impreza zorganizowana przez firmy
Sages i
Pragmatis. Event polegał na wspólnym tworzeniu aplikacji, ćwiczeniu TDD, programowania w parach i innych zwinnych praktykach. Był do tego Continous Integration (build był uruchamiany co git push) i Continous Delivery (deployment co udany build).
Aby dostać się na warsztaty trzeba było się wcześniej zapisać. Z ponad 60 osób chętnych, wybrano 22 w tym mnie :) Została przygotowana startowa baza kodu i udostępniona na github’ie. Trzeba było więc wcześniej ściągnąć kod i przygotować środowisko. Technologicznie był
Spring Core, Spring MVC,
JSP,
Casandra,
Maven. Jako że nie miałem wcześniej możliwości korzystać ze Spring’a w warunkach bojowych (po za jakimiś szkoleniami / prezentacjami), to miałem z czym się bawić. Zaprzyjaźniłem się więc z książkami na ten temat i archetypami kodu, aby porozkminiać te technologie i aby było na czym bazować.
Event zaczął się o 8 rano w
Millennium Plaza. Najpierw było przywitanie i omówienie zasad, co będziemy robić w ciągu dnia. Następnie było o aplikacji jaką mamy stworzyć. Mianowicie za pomocą pisanego serwisu internetowego można się chwalić czego się nauczyliśmy, ile czasu na to poświeciliśmy i ile punktów zebraliśmy. Taki jakby twitter, tyle że piszemy co poznaliśmy, jaki był stopień trudności, system nalicza jakieś tam punkty i chwalimy się tym przed znajomymi. Plus jeszcze jakieś pierdoły do tego.
Po omówieniu wymagań aplikacji było wprowadzenie do Casandry, gdyż była to najbardziej „dziwna” i nieznana technologia z używanego technology stack. Później było szybciutko o Spring MVC i zaczęło się. Uczestnicy mieli wybrać sobie couch’a i osobę do pary (najlepiej aby ktoś znał Springa MVC). Jako że znałem Piotra (jednego z prowadzących) to się z nim dogadałem i wraz z Marcinem usiedliśmy do pierwszego user story.
Wybraliśmy sobie na tapetę formatowanie czasu, ile zajęła nam nauka danej technologii. Napisaliśmy kilka testów i zaczęła się zabawa. Postanowiliśmy dodać do projektu bibliotekę
JUnitParams do pisania sparametryzowanych testów w JUnit’cie. Swoją drogą jest to biblioteka napisana przez
Pawła Lipińskiego, który organizował, prowadził i kodował na warsztatach. Pomogło nam to pisać ładniejsze, parametryzowane testy w JUnicie, podczas pierwszej iteracji.
Wcześniej ustalono, że iteracje będą trwały po półtorej godziny i pomiędzy nimi będą zmiany par, a co kilka iteracji będzie retrospekcja. Czyli jakby jeden dzień ze sprintu został skompresowany do 1,5h a cały Sprint do 5ciu dni (czyli pięciu iteracji). Taka organizacja pracy bardzo motywowała do jak najszybszego kończenia zadań. Nie inaczej było w naszej parze, gdyż chcieliśmy jak najszybciej zobaczyć choćby częściowy efekt naszej pracy na „live”, mimo że nie wszystkie przypadki mieliśmy obsłużone. No i tu zaczęła się prawdziwa walka z technologiami.
Gdy jeszcze wczoraj Piotrek w projekcie dodał
Tiles’y zaczęła się cała aplikacja wysypywać. Doszedł on do wniosku, że Casandra z Tiles’ami nie funkcjonuje ;) i wycofał zmiany. W naszej historyjce chcieliśmy (wręcz musieliśmy) skorzystać z JSTL’owego Taga
c:forEach, ale też nie chciało działać. Był ten sam błąd co w przypadku Tiles’ów. Nasza koncepcja zamknięcia wyświetlania czasu we własny Tag JSTL’owy również nie zadziałała i trzeba było to jakoś inaczej obmyślić. To wszystko pewnie przez Casandrę ;)
Akurat nadszedł koniec pierwszej iteracji i nastąpiła rotacja par. Jako, ze pracowaliśmy na moim laptopie, to Marcin odszedł, a dołączył się Michał. Porozmawialiśmy chwilę, co zrobić z naszym problemem niemożliwości użycia JSTL’a i zaproponowałem, aby stworzyć
Data Transfer Object (DTO) i za jego pomocą wyświetlać już odpowiednio sformatowany tekst. Coś tam niby się udało, ale potem było trochę walki z merge’owaniem zmian. Niestety szybko się okazało, że user story bardzo nachodzą na siebie, wręcz się powtarzają. Powodowało to masę konfliktów i trudności z push’owaniem zmian, gdyż po pull’u, odpaleniu testów, i przy próbie ponownego push’a okazywało się, że ktoś w między czasie zdążył wypushować swoje zmiany i proces trzeba było powtarzać ponownie.
Po drugiej iteracji postanowiono zrobić retrospekcję. Mieliśmy na małych, przylepnych karteczkach wypisać, co nam się podobało, a co nie i przykleić to na ścianę. Później trzeba było w ciszy to pogrupować (silent sorting) i ponazywać grupy. Po „uroczystym” przeczytaniu tego co jest fajne i niefajne, każda para wraz ze swoim mentorem miała się zastanowić, co zrobić, aby było lepiej. Super pomysłem było wprowadzenie stand-up meeting’ów - w trakcie trwania iteracji - [chyba] co 20 minut, aby poprawić komunikację w zespole i wiedzieć, kto co robi i na kiedy będzie. Innym ciekawym pomysłem było wpisywanie podczas commit'a / push’a jako autor numer implementowanego user story i nazwiska autorów. I rzeczywiście, początkowo brakło konwencji wypychania zmian do repozytorium, aby były one jednolite i czytelne.
Następnie był obiad i kolejna iteracja. Tym razem osoby, które przez dwie iteracje robiły jedną opowieść, miały się przesiąść. Może to trochę nieoptymalne posunięcie z punktu widzenia ukończenia zadania, ale podczas eventu chodziło o wspólną naukę. Trafiłem więc do zadania wyświetlania podpowiedzi. Mianowicie gdy wpisujemy technologię, której się właśnie nauczyliśmy, ma nam podpowiadać czy było to łatwe, średnie czy trudne. Wiązało się to z koniecznością napisania kawałka JavaScript’a, ale na szczęście to akurat poszło gładko. Problemem się jednak okazało, gdy coś co było zależne od naszego zadania (mianowicie dodawanie nowych umiejętności) czy jest już skończone i czy dane lądują tam, skąd je odczytujemy. Niestety ciężko w Casandrze cokolwiek podejrzeć, co wylądowało w bazie danych, gdyż zapisują się tam dane binarne. Nad tym zadaniem pracowałem przez dwie iteracje i później na ostatnią iterację, znów trzeba było się przesiąść.
Dosiadłem się więc do Bartka i tam nawet początkowo było fajnie (nie znaczy to wcale, że wcześniej było źle). Dostałem szybkie wprowadzenie co robimy, że właśnie jest test z nową funkcjonalnością i mam ją zaimplementować. Chwila ogarniania / czytania kodu i z pomocą Bartka udało się. Problem niemożliwości skorzystania z JSTL’a rozwiązano użyciem Skryptletów. Coś tam nawet się udało wyświetlić, ale nie można było wypchać zmian, gdyż najpierw trzeba było powalczyć z kwestią, co wyświetlać, jak ktoś jest niezalogowany. Inny zespół pisał back-end do tej funkcjonalności i niestety czas warsztatów nie pozwolił już na połączenie naszych zmian.
Po piątej iteracji przejrzeliśmy backlog zapisywany na
tinypm.com. Okazało się, że niewiele funkcjonalności udało się w pełni zaimplementować. Paweł pokazał jednak na żywym środowisku, że coś tam działa. Patrząc na statystyki na Jenkinsie, było widać, że w ciągu zmian udało się wypchnąć do repozytorium kod 54 razy z czego tylko 9 się wywaliło. Uważam to za niezły wynik, biorąc pod uwagę to, że dla uczestników był to świeży projekt, bez wypracowanych konwencji i nie każdy musiał znać wszystkie wykorzystywane technologie. Poniżej przedstawiam trend tesów.
Podczas warsztatów budowały się build’y od 88 do 142. Wcześniejsze build’y pochodziły z przygotowań do warsztatów. Widać wyraźnie że od 95 build’a liczba testów zaczęła znacząco rosnąć, z każdą nową zmianą.
Na koniec nadszedł czas na podsumowanie. Poprzestawialiśmy trochę stoły i ułożyliśmy krzesła w dwa kółka. W środku było 5 krzeseł, a na zewnątrz reszta. Kto siedział w środku ten mógł mówić, pod warunkiem, że cztery wewnętrzne krzesła były zajęte. Jedno było wolne, aby kogoś mógł się dosiąść i oczywiście można było spokojnie opuścić wewnętrzny krąg. Osoby siedzące w środku mówiły o swoich odczuciach dotyczących warsztatów, co się nauczyły itd. Czyli taka runda feedback’owa dla innych uczestników i organizatorów.
Jako że ja nie miałem okazji zasiąść w środku, to swoją opinię wyrażę teraz. Ogółem event wyszedł bardzo fajnie. Organizacja w porządku: były kanapki rano, napoje i ciasteczka przez caly dzień, dobry obiad w trakcie (i nie była to pizza). Lokalizacja warsztatów bardzo dobra, mianowicie blisko centralnego – ważna kwestia dla osób przyjezdnych, a tych nie brakowało. Ja sam przyjechałem z Wrocławia, ale spotkałem również ludzi z Gdyni, Gdańska, Wrocławia, a nawet z Berlina. Organizacja pod względem technicznym również dobra – były dwa rzutniki, na jednym Jenkins, a na drugim live aplikacja. Bardzo dobrym pomysłem było przygotowanie zaczynu aplikacji i jej udostępnieniu w necie. Również Continous Integration i Delivery daje bardzo fajny efekt psychologiczny. Można było szybko zobaczyć swoje zmiany na Jenkinsie jak i na na środowisku „produkcyjnym”.
Niestety, jak to sami organizatorzy przyznali, rozpoczęcie przygotowywania tej aplikacji na tydzień przed warsztatami to było trochę za późno. Wynikały później z tego problemy z technologiami (niemożliwość użycia Tiles’ów i JSTL’a). Uważam również, że dobranie stosu technologicznego było nienajszczęśliwsze. Fajnie, że było cos egzotycznego (Casandra), ale mało kto wiedział, jak z tego odpowiednio korzystać. Do tego zastosowanie Springa MVC i JSP powodowało, że czasem trzeba było się męczyć z JavaScriptem (AJAX i jQuery). Te problemy technologiczne powodowały, ze ciężko było się skupić na czystym pisaniu kodu (nie wspominając już o TDD), a trzeba było się męczyć ze zgraniem technologii i merge’owaniem zmian.
Wcześniej wydawało mi się że w miarę ogarnąłem już Git’a, ale dopiero tutaj w warunkach bojowych zweryfikowałem swoje poglądy na ten temat. Problem scalania zmian występuje (pushowaliśmy do jednej gałęzi, aby Continous Server już dalej robił swoje), jak w każdym innym systemie kontroli wersji.
Jakub Nabrdalik mówił, że jednym z możliwych sposobów jest zrobienie miecza z dwóch zwiniętych kartek papieru i ten kto aktualnie posiada miecz może push’ować. Jak ktoś innyc chce to robić, to musi uzyskać ten miecz. Wydaje mi się, że skorzystanie z Mercuriala mogło by trochę ułatwić sprawę z łączeniem zmian w kodzie, ale nie jestem ekspertem w tym temacie.
Innym poważnym minusem co do warsztatów, było przygotowanie user story’s. Bardzo często były one do siebie podobne, zachodziły na siebie i od siebie zależały. Jednak podczas wyboru user story nie posiadaliśmy tej wiedzy. Na przyszłość trzeba lepiej przygotować historyjki do zaimplementowania, wraz z grafem, co od czego zależy, co trzeba zrobić najpierw i z lepszym opisem. Większość opowiastek dotyczyła strony głównej, przez co wzajemnie sobie modyfikowaliśmy zawartość tych samych plików, co prowadziło do problematycznych konfliktów. Na przyszłość można kilka opowiastek udostępnić np. tydzień wcześniej, aby można było w domu coś na rozgrzewkę napisać. Zachęciło by to bardziej do zajrzenia w kod i do lepszego przygotowania do warsztatów. I najlepiej aby były one możliwie jak najbardziej rozłączne.
Również wybór Casandry na bazę danych nie było chyba najlepsze, gdyż z rozmów pomiędzy ludźmi słyszałem, że niektóre zespoły sporo się z nią męczyły. Fajnie poznać przy takiej okazji coś nowego, ale wybór chyba nie był najszęśliwszy. Jak bym proponował na następny raz jakąś bazę działającą w pamięci, inną NoSQL’ową (obiektową, key-value) lub jakąś lekką SQLową, którą wszyscy znają. Jako technologię widoku proponowałbym GWT (lub coś o podobnej koncepcji), gdyż tam nie trzeba się bawić z JavaScriptem, ani z JSP, a maksymalnie z niewielkimi kawałkami HTML’a.
Nie oznacza to, ze nic nie wyniosłem z warsztatów. Miałem w końcu motywację do lepszego poznania Springa, Git’a,
JUnitParams… Zrozumiałem, że nie tylko testy jednostkowe są najważniejsze, ale obok nich musi się znajdować kilka integracyjnych i akceptacyjnych (już w początkowym stadium projektu). Przykładowo prosty test end-to-end uruchamiający przeglądarkę na stronie głównej i sprawdzający czy jakiś tam przycisk istnieje, pozwolił nam szybko wykryć, że Tagi w JSP nie chcą działać. Inna sprawa ze testy nie były podzielone na jednostokowe i inne (trwające dłużej), przez co ich uruchamianie było trochę przydługie.
Dowiedziałem się też o fajnej technice, podkreślającej współwłasność kod. Mianowicie po za wywaleniem z szablonów plików / klas i metod informacji o autorze, można dać wszystkim pracownikom z danego projektu, jedno konto i hasło do repozytorium. Dopiero wtedy powstaje wspólny kod i nikt się nie boi modyfikować nieswoich części. Poznałem również trochę bardziej w praktyce procesy zachodzące w procesie Agile'owym, jak i mogłem się dowiedzieć jak wygląda IT w innych miastach.
Zawsze z takich wydarzeń można wynieść ciekawe skróty klawiaturowe. I tak dla IDEI:
Crtl + Shift + Enter - Statement Comlete, czyli dodanie średnika na końcu linii. Z analogicznych skrotów korzystałem w NetBeans’ie, ale tam to było to
Ctrl + ; i
Ctrl + Shift + ;. Innymi interesującymi skrótami w Idei są:
Ctrl + Shift + T czyli przejście do klasy, która testuję aktualną klasę, w której jesteśmy i
Ctrl + Shift + N (odpowiednik Eclipsowego
Ctrl + Shift + R), czyli wyszukiwanie po nazwie pliku z projektu.
Ciekawe, nowopoznane skróty dla Eclipse’a to
Ctrl + Shift + M - zaimportowanie statyczne danej metody na której znajduje się aktualnie focus. Przydatne zwłaszcza jak mockujemy z Mockito i chcemy samo
when() zamiast
Mockito.when(). Ponadto
Ctrl + Shift + O czyli organizacja importów (w Idei można zrobić, aby automatycznie narzędzie przed commitem zmian, odpowiednio organizowało importy). I na koniec
syso + Ctrl + Spacja, czyli skrót od
System.out.println();. W Idei jest to
sout + Tab co jest według mojego gustu fajniejsze.
Dobra to chyba tyle z podsumowania wydarzenia. W tym roku już się żadna konferencja / warsztaty nie szykują, więc trzeba będzie z tym poczekać do przyszłego roku. Mam nadzieję na kolejną edycję Agile Development Day lub podobny tego typu event.