W ostatnią sobotę miało miejsce pierwsze berlińskie Legacy Code Retreat (w sile 16 uczestników). Pomogłem trochę w jego organizacji, głównie jednak wziąłem w nim udział jako uczestnik. W tym poście opiszę swoje wrażenia.
Format
Format Legacy Code Retreat został zaproponowany przez J. B. Rainsbergera i jest podobny do „normalnego” Code Retreat – składa się z 6 sesji, w których pracujemy w parach i po każdej sesji kasujemy nasz kod. W przeciwieństwie jednak do normalnego Code Retreat nie zaczynamy od zera pisać „Grę w życie” a pracujemy już z dostarczonym kodem gry Trivia i naszym celem jest jego zrozumienie i bezpieczne zrefaktoryzowanie.
Nasz event poprowadzony został przez Martina Klose, który świetnie spisał się w roli facylitatora. Rozpoczęliśmy od krótkiego wprowadzenia, gdzie Martin omówił „4 rules of simple design” i algorytm refaktoryzacji legacy kodu. Z ciekawostek, event prowadzony był po angielsku, z czego bardzo się cieszę, jako że byłem jedyną osobą która nie potrafiłaby pracować po niemiecku..
Fajnym motywem podczas rozpoczęcia dnia było ćwiczenie, które wykonaliśmy by „szybko się poznać” w grupie. Martin polecił nam ustawić się w szeregu, gdzie na jednym końcu były osoby, które uważały się za wymiataczy w TDD a na drugim końcu, osoby, które dopiero rozpoczynały swoją przygodę z TDD. Następnie Martin zasugerował by osoby początkujące pracowały w ciągu dnia z osobami doświadczonymi.
- Sesja 1 – Zapoznanie z kodem
- Pierwsze starcie z kodem. W tej sesji rozpoczęliśmy pisanie testu charakteryzacyjnego i zajęło nam to praktycznie cały dostępny czas (przy czym prawie 10 minut zmarnowaliśmy na skonfigurowanie JUnita, który z jakiegoś powodu nie chciał dodać się do projektu, ech…). Dev z którym pracowałem w parze nigdy nie pisał w Javie, także trochę czasu spędziliśmy również na wytłumaczenie podstawowych rzeczy na temat Javy.
- Sesja 2
- Martin sugeruje wszystkim zastosowanie techniki Golden Master. Sprowadza się to mniej więcej do tego co robiłem w poprzedniej sesji, więc z moim nowym dev partnerem ruszamy do kodowania. Po parunastu minutach mamy już gotowy test, który porównuje wykonanie programu z naszą „złotą kopią”. Jesteśmy pewni siebie i wtedy pojawia się Martin z pytaniem „Skąd wiecie, że wasz test jest wystarczający?” „Jaką macie pewność, że pokrywa on wszystko to, co robi kod?”. Jako stary wyjadacz „testowania mutacyjnego” nie daję się zbić z tropu i przystępujemy do „testowania” naszego testu poprzez celowe wprowadzanie błędów do kodu produkcyjnego i obserwowanie czy nasz test to wykrywa. Martin miał rację.. Są pewne modyfikacje, których nasz test nie wyłapuje. Resztę sesji spędzamy na udoskonalaniu naszego testu.
- Sesja 3
- W tej sesji skupiliśmy się na refakoryzacji kodu. Konkretnie poprawialiśmy czytelność (łatwość zrozumienia) instrukcji warunkowych, np. „if (roll % 2 != 0)” na „if(canLeavePenatlyBoxAfter(roll)”
- Sesja 4
- Refaktoryzacja kodu małymi kroczkami. Reguły: Ustaw timer na 2 minuty. Pracuj z kodem i wrzucaj swoje zmiany do repozytorium kodu. Jeśli w ciągu 2 minut nie zdążysz wrzucić niczego do repo, cofnij swoje zmiany do momentu ostatniego commitu w repo i rozpocznij od nowa. Po drugim razie, gdy dopadł nasz timer, pracowaliśmy w naprawdę malutkich kroczkach i w sumie daliśmy radę! Generalnie, im częściej wrzucamy nasze zmiany do repo tym lepiej (mniej konfliktów, częstszy feedback), także myślę że ćwiczenie wykonane w tej sesji było wartościowe.
- Sesja 5
- Celem tej sesji było zidentyfikowanie fragmentów kodu, które dało się zamienić w „pure functions„. Podczas tej sesji pracowałem w Rubym (wszystkie poprzednie były w Javie) i odczułem na własnej skórze, jak wspaniałe wsparcie do refactoringu ma Java.. (Np. IDE w Javie było dużo sprytniejsze w znajdywaniu duplikacji w kodzie). Jedną z zalet „wyciąganych” przez nas funkcji było to, że można je było stosunkowo łatwo przetestować.
- Sesja 6
- W czasie tej sesji, po zidentyfikowaniu i stworzeniu kilku „pure functions” mieliśmy przyjrzeć się im bliżej i zastanowić się, gdzie można by je przenieść – jednym słowem, zaczęliśmy „wyciągać klasy”. Cały schemat refactoringu można opisać mniej więcej tak:
- Extract method
- Replace fields with parameters to the method
- Make method static
- Test the method
- Find a new home for the method, move to (and maybe create) new class
- Alternatywnym sposobem, wypróbowanym przez niektórych uczestników było zastosowanie refaktoringu „pull up” i przeciągnięcie pewnych funkcjonalności do „nowej” klasy bazowej, a następnie zastosowanie refakoryzacji „replace inheritance with delegation” – coś, co mam w najbliższym czasie przetestować.
Scala
Po trzeciej sesji mieliśmy długi lunch, w czasie którego rozmawiałem o Scali. Temat, który mnie interesował to testowanie i jak w podejściu funkcyjnym radzimy sobie z problematycznymi zależnościami kodu, takimi jak baza danych czy odwołania do innych systemów. W podejściu obiektowym, używamy w tym celu „mocków’. Z tego co zrozumiałem, w Scali ważnym pojęciem jest kompozycja funkcji, i właśnie odpowiednio korzystając z kompozycji możemy „wstrzykiwać” albo prawdziwą funkcję, która pobiera dane z bazy danych, albo funkcję „testową”, która tylko udaję bazę danych. I tak testowanie takiego systemu sprowadza się do przetestowania funkcji, z których składa się nasz system na poziomie jednostkowym, a następnie przetestowanie całego systemu (złożonej funkcji), gdzie być może niektóre funkcje zastąpione są zmienikami na potrzeby testów.
Organizacja
Jeśli chodzi o organizację tym razem kupiliśmy małe śniadanie w piekarni a na obiad poszliśmy do restauracji – wyszło to dużo taniej niż zamawianie kateringu.
Generalnie, bardzo nam się podobało i już myślimy o kolejnym evencie, może w czerwcu?
Zachęcam Cię do organizacji Legacy Code Retreat w swoim mieście!
Ps. Zdjęcia z wczoraj można zobaczyć tutaj..

