27 listopada 2011

Łącząc przyjemności - o TDD i spacerze "nagraniowym" z Maksymem

Warto czasami przystanąć, zastanowić się i po prostu pomyśleć bez jakichkolwiek zewnętrznych "przeszkadzaczy". Doświadczyłem błogosławieństwa takich chwil niedawno dwukrotnie i nie mogłem uwierzyć, jak niewiele trzeba, aby mieć ich więcej.

Podczas konferencji JDD w Krakowie (czytaj Wrażenia pokonferencyjne - zacznijmy od JDD w Krakowie) miałem przyjemność uczestniczyć w sesji "TDD Coding Dojo" z Krzyśkiem Jelskim i Marcinem Zajączkowskim. Kiedy wracałem do domu pociągiem, a może jeszcze wcześniej, w taksówce, zacząłem zastanawiać się nad słowami Jakuba Nabrdalika, który kiedyś stanowczym tonem stwierdził, że nie da się robić TDD z już gotową aplikacją. Miałem wtedy wrażenie, że Kuba jest tak etycznie upośledzony przez TDD, że jedyną, słuszną drogą dla TDD jest zacząć od testów. Ja jednak bardzo nalegałem na możliwość dopisywania testów do gotowej aplikacji (projekt Apache OpenEJB), aby stworzyć siatkę bezpieczeństwa dla późniejszych prac przy zmianie kodu. Nie pomagał nawet mój wrodzony wdzięk. Po prostu, Kuba kończył taki pomysł stanowczym: "To nie będzie TDD" i tyle mi było z nim rozmawiać. Oj, jaki ja byłem na niego zły za takie potraktowanie. Nie żebym czuł jakąś zadrę do niego za to, ale po prostu nie mogłem zrozumieć, dlaczego to nie przejdzie.

I właśnie podczas powrotu do Warszawy, po sesji z Krzyśkiem i Marcinem, olśniło mnie! Wydaje mi się, że zrozumiałem ideę TDD. Wreszcie połączyłem teorię z praktyką i jakkolwiek nie było tego drugiego wiele, to wystarczyło, abym usnął tezę, która wydaje się zgodna z myśleniem Kuby (!) Nie zapomnę tej chwili, kiedy prawie wykrzyknąłem "Eureka!"

TDD stosujemy jako "zapalnik" zmian w aplikacji. Pojawia się test, nie przechodzi (czerwono), piszemy minimalistyczną implementację, taką, aby jedynie pozwoliła przejść testowi (pojawia się zielone), refaktoring i tak w kółko. Kiedy zastanowić się nad kolejnością zmian w aplikacji - najpierw test, później minimalnistyczna implementacja i tak, aż do znudzenia, to łatwo zrozumieć, że aplikacja ma tyle, aby jedynie/aż przeszły testy. Nic więcej. Jeśli jest więcej, to prawdopodobnie możemy liczyć się z miejscami niepokrytymi testami. Całkiem zrozumiałe, jeśli para programistów jest więcej niż początkująca w temacie programowania i TDD w ogólności.

Weźmy teraz działającą aplikację. Skoro działa, to każdy kawałek kodu, który mógłby wyglądać na potencjalny błąd...NIE jest błędem! Na pewno nie jest nim jeszcze. Gdyby już był, to pojawiłaby się poprawka i...po błędzie. I teraz pora na moje olśnienie - wręcz niemożliwym jest pisanie testów, które objęłyby wszystkie możliwe przypadki do przetestowania dla działającej aplikacji. Słyszałem o narzędziach automatyzujących, które prześwietlając kod wykrywają "zakręty" na if'ach i temu podobnych konstrukcji "rozgałęziających", ale, właśnie, to są automaty. Gdyby pisać je ręcznie, to nigdy nie wiadomo, czy jest ich wystarczająco wiele, aby powiedzieć, że jest ich wystarczająco wiele. Właśnie to odwrócenie zależności między testami a aplikacją jest problemem. Nie można mówić o odwróceniu zależności w przypadku TDD, gdzie zależnością aplikacji są testy. A może na odwrót? Tak czy inaczej, jeśli zakładamy, że dla testu sprawdzającego, czy zwrócono liczbę 5 piszemy kod, który po prostu zwraca 5, to nie ma szansy na pomyłkę. Kod może być dalej pod kątem zaawansowania funkcjonalnego, ale należałoby to odznaczyć jako...nadgorliwość. Oczekujemy 5, to nie ma potrzeby wywoływać usługi RESTowej, która zwraca 5, bo wystarczy zwrócić 5. Proste i oczywiste.

Czy moje zrozumienie TDD jest właściwe? Czy takiego myślenia oczekuje się od praktyków TDD? Chętnie poznam Twoją opinię. W komentarzach jest duuuużo miejsca na dywagacje.

Kolejnym momentem, w którym doświadczyłem momentu olśnienia był dzisiejszy spacer z Maksymem. Kolejny samotny spacer przez 1,5-2h to nie przelewki. Łazisz po utartych ścieżkach Lasu Kabackiego i tak idziesz, i idziesz, i idziesz. Można kota dostać.

Z drugiej strony, kilka dni temu odznaczyłem sobie kilka nagrań z konferencji do odsłuchania i wcale mi się nie uśmiechało odsłuchiwanie ich podczas siedzenia w domu. Każdorazowo, kiedy próbowałem usiąść nad nimi w domu, zawsze pojawiało się zniecierpliwienie i w ogóle ogólna niechęć do ślęczenia przed kompem i gapienia się w monitor z założonymi rękoma. Nuda. Nosiło mnie moje wewnętrzne ADHD. 30 minut jeszcze dam radę słuchać, ale więcej?! Nie ma mowy! No i jeszcze mógłbym nie usłyszeć Maksyma, kiedy się obudzi i daje znać o tym wszem i wobec!

I tak dzisiaj przypomniałem sobie o tych nagraniach i idąc Lasem Kabackim włączyłem Language Panel o językach programowania. Byłem ciekaw, co też tam Ci myśliciele mówią o językach. Skoro i tak miałem ponad godzinę czasu na spacer, to przecież mogłem go spędzić łącząć przyjemne z pożytecznym.

I tak ze słuchawkami na uszach (głos) i smartfonem w nogach Maksyma (wizja) zeszło mi przyjemnie 40 minut. Las gwarantował spokój, brak zewnętrznych przeszkadzaczy i wiatru, który szalejąc na osiedlu tutaj zanikł kompletnie. Przyjemna sprawa.

Początkowo planowałem godzinny spacer, ale kiedy minęło mi 40 minut, stwierdziłem, że pozwolę sobie na dłuższy spacer i...ponad godzinne nagranie Clojure and the Web. Nie polecam tego nagrania, ale dla napaleńców może być ciekawym podsumowaniem zalet Clojure (przez pierwsze 20 minut) oraz przegląd szkieletów webowych w Clojure z praktycznym przeglądem Ring w drugiej części.

Po 2,5 godzinach wróciłem do domu wyjątkowo zadowolony (!) Maksym przez całą drogę spał smacznie, ja przejrzałem 2 nagrania, co dało nam obu sporą dawkę świeżego (?) powietrza, a reszta rodzinki odetchnęła na jakiś czas od Maksyma. Już nie mogę doczekać się kolejnego spaceru! Co proponujecie do obejrzenia? Może coś w tematyce TDD? Zastanawiam się, czy pomysł odsłuchiwania na mrozie wypali. Ale w końcu i w Norwegii używają Galaxy S2, a tam ciągle zimno.

2 komentarze:

  1. Jacku, stosuję podobne sposoby na połączenie odsłuchiwania nagrań i spacerowania z dzieckiem. Zamiast lasu mam cmentarz i czasem dziwnie się ludzie patrzą, jak widzą gościa z wózkiem oglądającego coś na telefonie w takim miejscu ;)

    Co do TDD, to chyba podobnie mnie kiedyś olśniło. Zdałem sobie sprawę, że Test Driven Development to programowanie STEROWANE testami, czyli testy nadają kierunek dalszej pracy, a nie odwrotnie.
    Zwykłe pokrywanie istniejącego kodu testami to nie TDD. Często jest to zresztą niemożliwe, bo pisane testy ukazują słaby model obiektowy i zmuszają do przepisywania czegoś, czego przepisać się nie da (brak czasu, budżetu, ewentualnie po prostu odwagi).

    OdpowiedzUsuń
  2. Z tym TDD rzeczywiście jest tak jak mówisz.

    A samo pisanie testów do istniejących aplikacji... czasem jest to horror - szczególnie jeśli ma się do czynienia ze sporym kawałkiem kodu sprzed wielu lat. I ustawiczny brak czasu nawet na próbę pisania testów. Aż strach wtedy dodawać nowe funkcje do aplikacji. Nie mówiąc o usuwaniu błędów w starym kodzie :)

    OdpowiedzUsuń