poniedziałek, 24 maja 2010

Szkolenie TDD - retrospekcja

Już trochę czasu minęło od pierwszego otwartego szkolenia Test-Driven Development, które miałem przyjemność prowadzić. Było to dla mnie na tyle ważne doświadczenie, że nadal odczuwam potrzebę podsumowania go. Zatem do dzieła...

Uczenie programistów techniki TDD dało mi mnóstwo satysfakcji. Świetne było obserwowanie postępów uczestników. Widziałem też, że bardzo podobało się im podejście do programowania, w którym wiele "robi za nas" eclipse - chodzi o generowanie kodu i refaktoryzacje. TDD znakomicie promuje wykorzystanie możliwości IDE - w końcu chcemy ułatwić sobie życie i jak najwięcej robić automatycznie. No i okazuje się, że zaczynanie od testów sprawia, że powstaje więcej kodu, ale wcale nie tak dużo więcej go piszemy.

Podczas szkolenia starałem się nie zanudzać wykładami, prowadziłem natomiast dużo warsztatów. Podobało się to uczestnikom i myślę, że to właśnie praktyczne doświadczenie TDD jest najcenniejsze w tego typu szkoleniach.

Okazało się, że znakomicie zadziałało programowanie w parach. Wszyscy chętnie pracowali w ten sposób (co prawda nie jednocześnie, gdyż liczba osób była nieparzysta :) Praktyka programowania w parach doskonale uzupełnia się z TDD - cykl Red-Green-Refactor daje naturalne momenty zmiany drivera. Dodatkowo świetny jest aspekt uczenia się od siebie nawzajem oraz doświadczenia różnych stylów programowania. Było na przykład tak, że jedna para wypracowywała pewien sposób pisania testów, który podczas następnego ćwiczenia "migrował" dalej (przed każdym warsztatem następowała zmiana w parach).

Co do prowadzenia wykładów - doświadczyłem ogromnego znaczenia pilota do prezentacji. Pierwszego dnia zapomniałem go wziąć. Aby móc zmieniać slajdy, musiałem mówić stojąc blisko laptopa. Natomiast użycie tego urządzenia podczas następnych dni pozwoliło mi opowiadać dużo swobodniej - chodzić po sali, częściej utrzymywać kontakt wzrokowy ze słuchaczami. Zupełnie inna jakość.

Z rzeczy do poprawienia to na pewno warto uzupełnić prezentacje większą ilością przykładów - kodu i może trochę UMLa przy tematach z projektowania. Jeden obraz wart tysiąca słów, a kilka slajdów z kodem z pewnością równoważy wiele minut opowiadania "na sucho". Myślę tu głównie o refaktoryzacjach, zwłaszcza tych dotyczących kodu odziedziczonego. Ewentualnie zamiast kodu w prezentacjach niezłe mogłoby być też kodowanie na żywo.

No i jakoś nie wyszło mi Aha Experience Exercise. Owszem, kilka "Aha!" pojawiło się na początku, gdy wprowadzałem to ćwiczenie, ale w trakcie już nie dochodziły kolejne.

Z niecierpliwością czekam na kolejną okazję, kiedy będę mógł wykorzystać doświadczenie z tego szkolenia i poprawić swój warsztat trenera i programisty. Tak, tak, programisty też - podczas wspólnego kodowania ja też uczę się od uczestników. Dziękuję!

środa, 19 maja 2010

Javarsovia 2010

Wczoraj kapituła Javarsovii wysłała mi email, że moja prezentacja została zaakceptowana. Tak więc z przyjemnością ujawniam o czym będę mówił w tym roku:

Temat: "Clean Tests" by Uncle Paul, czyli jak pisać testy, żeby dobrze Ci służyły.
Abstrakt: Niewielu programistów ma dobry zestaw testów dla swoich aplikacji. Jeszcze mniej ma takie, które są zarówno dobrą “siatką bezpieczeństwa” przy realizacji jakichkolwiek zmian, ale również mogą służyć za zawsze aktualną dokumentację systemu. W czasie prezentacji pokażę jak pisać i refaktoryzować testy by się je łatwo czytało, nietrudno utrzymywało, oraz by dobrze dokumentowały aktualny stan systemu.

poniedziałek, 17 maja 2010

Tumbler 0.2.1

Dzięki aktywności Bartka Zdanowskiego (a dokładniej jego niedoczytaniu dokumentacji ;-)) wypuściłem wersję 0.2.1, która jasno mówi jak coś jest nie tak. Czyli jak jest JUnit <4.6 albo ktoś używa @Test zamiast @Scenario. No more NPEs ;-)

Do tego Tumbler 0.2.1 pojawi się w repo maven'a pewnie już jutro. Szczegóły będą na stronie Tumbler'a.


Aktualizacja: 
Tumbler jest już w repo mavenowym.
groupId: pl.pragmatists.tumbler
artifactId: tumbler

piątek, 14 maja 2010

Tumbler 0.2.0

Przez ostatnie dwa tygodnie znowu znalazłem trochę czasu i dorobiłem do Tumblera rzeczy, których brakowało. Dzięki temu wydałem właśnie wersję 0.2.0. W sumie powinienem chyba dobić do 1.0.0, bo w tej chwili ma on wszystkie podstawowe cechy takiego narzędzia, ale jakoś jeszcze nie jestem przekonany do takiego skoku w numerku.
Co się zmieniło?
  1. Zmieniłem moje wynalazki: Subject i Example na standardowe w BDD Story i Scenario. One może troszkę gorzej oddają o co chodzi, ale za to są spójne z zapisem Dana North'a używanym m.in. w JBehave, NBehave i jeszcze pewnie gdzieś indziej. A nuż ktoś będzie się chciał zmigrować, to będzie miał łatwiej. A i czytelnicy Dan'owych artykułów od razu zmapują sobie jego idee na Tumblerową rzeczywistość.
  2. Dodałem raporty w HTML. Jeśli to ma być narzędzie używane jakoś przez biznes, to musi być dla nich czytelne. Można używać własnych szablonów (freemarker) albo domyślnego. Zgodnie z sugestią Szczepana Fabera jest też "spis treści" dla stories, wraz ze statystykami wykonania dla całego projektu.
  3. Za namową Lasse Koskeli usunąłem @CamelCase. Jeśli ktoś nie chce pełnych zdań w eclipsie, to niech sobie ustawi zmienną -DcamelCase=true. W ten sposób nie wpływa na resztę zespołu.
W sumie więc nie ma tak dużo nowości, ale z drugiej strony myślę, że użyteczność narzędzia wzrosła znacznie.

Bardzo chciałbym się dowiedzieć co myślicie o tym narzędziu. Co można by dodać, co powinno być inaczej.

Tumbler działa tylko z nowymi wersjami JUnit'a. Wersja domyślnie będąca w eclipsie, jest dość stara (i buggy) - 4.5. Do poprawnego działania Tumbler wymaga wersji 4.8. Użycie starszej wersji JUnit'a skutkuje następującym wyjątkiem:
java.lang.NoSuchMethodError: org.junit.runner.Description.getMethodName()Ljava/lang/String;
at tumbler.internal.ScenarioListener.isItSingleScenario(ScenarioListener.java:97)
at tumbler.internal.ScenarioListener.testStarted(ScenarioListener.java:92)
at org.junit.runner.notification.RunNotifier$3.notifyListener(RunNotifier.java:83)

czwartek, 13 maja 2010

Behaviour-Driven Development

Tak sobie ostatnio pomyślałem, że wyjechałem z tym Tumblerem bez przybliżenia najpierw o co w nim chodzi. To znaczy wyjaśniłem (mam nadzieję) o co w NIM chodzi, ale nie pisałem nigdy o samej idei na której on bazuje, czyli BDD. Samo hasło pewnie większość z Was słyszała, ale ciekawy jestem jaki procent wie o co w tym chodzi (nic, i tak się nie dowiem).

No więc BDD wywodzi się od Dana North'a (kiedyś z Thoughtworks, teraz nie wiem), który doszedł do wniosku, że jest jakaś dziura między tym co zwykle programiści myślą o projekcie, który robią, a tym czego oczekuje biznes. Główny problem jest taki, że każda z tych grup mówi innym językiem - biznes zasuwa wyłącznie o pieniądzach, a programiści chcą mieć wszystko wyłożone w javie. No więc Dan wpadł na pomysł jak to połączyć.
Po pierwsze trzeba się uporać z językiem - nie ma sensu, żeby każdy nazywał rzeczy po swojemu, więc Dan doszedł do wniosku, że skoro nas klient nas Paaaannnnnn to wszędzie należy używać tej nomenklatury (tak, to to samo co Ubiquitous Language w DDD).
Po drugie biznes(meni) patrzy na system z punktu widzenia jego użycia, a programiści z punktu widzenia... frameworków? Języka? Czy czegoś podobnego. Mówiąc w skrócie biznes patrzy z zewnątrz do wewnątrz a programiści odwrotnie.
No więc Dan wpadł na pomysł, żeby zbliżyć te wizje do siebie przez zmuszenie programistów do tego, żeby myśleli po angielsku, a więc za pomocą rzeczowników i czasowników a nie instancji i metod. Konkretnie chodziło mu o to, żeby wyrażać testy jako przykłady (coding by example) wyrażane w języku naturalnym (angielskim, bo: primo - polska fleksja nie nadaje się do parsowania, secundo - Dan nie włada polszczyzną). Idealnie powinno być tak, że nieprogramiści (tak, to jednak pewnie grubo ponad 99% ludzkości) są w stanie to przeczytać i zrozumieć. Tu wchodzimy na grząski grunt DSLi, którymi nie chcę się dziś zajmować, bo jest późno, a i tak już dużo napisałem.
Wracając do tematu, Dan wymyślił dość zwięzły i krótki zapis, który jest zrozumiały dla innych (no..., że nie tylko dla nas), a przy okazji jest parsowalny i da się przerobić łatwo na coś zrozumiałego dla maszyn. Zapis Dana jest następujący (ukradłem ten tekst ze strony Dana, więc mu nie mówcie):


Title (one line describing the story)
Narrative:
As a [role]
I want [feature]
So that [benefit]
Acceptance Criteria: (presented as Scenarios)
Scenario 1: Title
Given [context]
  And [some more context]...
When  [event]
Then  [outcome]
  And [another outcome]...
Scenario 2: ...
Story to coś a'la User Story w zwinnych metodykach, czyli jakaś funcjonalność. Narrative to znów znany ze zwinnych metodyk zwrocik (oj, zdrobnienie - wyszło, żem Warszawiak) "Jako KTOŚTAM chciałbym COŚTAM żeby COŚ SIĘ STAŁO". Do tego dochodzi Scenario, czyli konkretny przykład stosowania funkcjonalności, w formie znanej z wykładów Szczepana Fabera:
Given  ...
When ...
Then ...
Czyli prosty zapis tego co dane jest na wejściu, operacji, i jej wyniku.
Takie zdania powinien być w stanie nam dostarczyć każdy analityk (no dobra, tak naprawdę, to biznes powinien siedzieć nad tym z programistą, w końcu customer on-site...) A my z tych zdań budujemy szybko sobie testy, które prowadzą (młodzież powiedziałaby drajwują, ale ja jestem stary) zarówno zakres funkcjonalny tworzonej aplikacji, jak i w pewnym stopniu design - przynajmniej API.

Podsumowując - chodzi o to, by mieć wspólny zapis dla przykładów, które prowadzą development, oraz by te przykłady były wybierane (przez biznes) na podstawie ich wartości dla systemu. Realizacja tego pomysłu powoduje, że cały development jest prowadzony de facto przez interfejsy użytkownika, bo to jest to, o czym biznes myśli i co jest sobie w stanie wyobrazić (i dobrze!)

Do tego w BDD jest cała podszewka lingwistyczno-psychologiczna (powinienem pojechać tu hipotezą Sapir'a-Whorf'a ale na to jest zdecydowanie za późno....), która mówi o tym, że programiści lepiej myślą o kodzie jeśli rozumieją i wyrażają go po ludzku.

No i na koniec wisienka na torcie: oczywiście przykłady to tak naprawdę testy. Same przykłady to już dużo, bo pozwalają myśleć o kodzie z punktu widzenia jego użycia. Ale skoro przykłady opracowuje się na początku - przed pisaniem kodu, to chyba jest jasne, że nie wyrazić ich w postaci testów było by głupotą. No więc w ten sposób przykłady zachowań z BDD stykają się z testami akceptacyjnymi, prowadząc do A-TDD (Acceptance-Test Driven Development).

No, to chyba tyle. To teraz jak to się ma do Tumbler'a?
Jak już wiemy o co chodzi, to Tumbler po prostu realizuje tę ideę i trochę ją rozszerza (cóż - jestem przekonany, że Dan nie wymyślił tego po ubarwionej zielskiem wycieczce po Camden Town, tylko faktycznie miał to na myśli). Nie tylko pozwala on przekształcać pełnotekstowe przykłady/scenariusze (o składni +/- takiej jak powyższa) na testy JUnit'owe, ale generuje również raporty (aktualnie txt oraz html) z tego co przechodzi, co nie, a co jeszcze nie zostało zaimplementowane. To już dużo. Jednak główną myślą, która mi przyświecała przy tworzeniu tego narzędzia było, że większość programistów nie ma planu co ma zrealizować, tylko pisze co im się akurat wydaje w danym momencie ważne. Tak powstają nie tylko potwory i spółka, ale również po prostu niekompletne implementacje. A gdyby tak zastanowić się chwilę nad każdą funkcjonalnością, zapisać ją w formie przykładów i dopiero potem zrealizować? Dam głowę, że tak napisany kod nie powodowałby u autora myśli "gdybym tylko mógł napisać to jeszcze raz!" - bo raz piszemy to najpierw w głowie w przykładach, a potem przelewamy na papier -  tfu, klawiaturę - w dopracowanej formie.

PS. Tumbler z troszkę zmienionym API oraz nowymi funkcjonalnościami wyjdzie w ten weekend, więc kto żyw ściągać w poniedziałek rano i stosować! ;-)