Test driven development: Część 1

utworzone przez | 29/10/2019 | architektura

Rysownicy szkicują. Pisarze robią konspekty. Naukowcy stawiają hipotezy. Co robią programiści? Zwykle idą na żywioł. Strach przed waterfallem poszedł tak daleko, że przestaliśmy planować cokolwiek. Tymczasem dobrze jest mieć mechanizm, który będzie co kilka minut przypominał nam, gdzie jest nasz cel. Tym właśnie jest test driven development.

Skoro to czytasz, to zapewne termin “test driven development” obił Ci się o uszy. Może nawet masz za sobą (niekoniecznie udane) pierwsze podejście. I drugie. I trzecie… Może zastanawiasz się jak robić to dobrze, albo po co w ogóle to robić. I tu wchodzi migawka.it – cała na biało.

TDD albo APAP – wybór należy do Ciebie.

TDD jest wyrazem akceptacji sposobu, w jaki działa ludzki mózg – jego mocnych i słabych stron – oraz rozumieniem, że tak jak niewłaściwe korzystanie z młotka skończy się bólem palca, tak nadwyrężanie mózgu skutkuje bólem głowy.

Spójrz na swoje aktualne zadanie. Nieważne jak jest małe. Mózg jest dygresyjny i lubi się na czymś zafiksować albo popłynąć, jeśli nic go nie pilnuje:

Miałem to już skończyć, ale od 3 godzin próbuję sprawić, żeby pętla odpalana raz do roku działała 10 milisekund szybciej… Co ja miałem…? Moment, jak ja się znalazłem w tym kodzie i dlaczego jest trzecia w nocy? O, tu można poprawić wcięcie. 

Wiem, trochę koloryzuję, ale jednak brzmi znajomo, co nie?

Kojarzysz jak Scrum rozbija Twój projekt na dwutygodniowe cykle, z których każdy ma (no dobra, w idealnych warunkach 😉) jasno określony, osiągalny cel? TDD robi dokładnie to samo, tylko w skali minut. Dzięki temu Twoja głowa co chwilę naprowadzana jest z powrotem na wyznaczony cel, a Ty możesz skupić się na pisaniu dobrego kodu, zamiast na pamiętaniu co masz do zrobienia i gdzie jest paracetamol.

A to w testach nie chodzi o błędy?

Zauważ, że nie wspomniałem ani słowem o zapobieganiu błędom. Otóż to dzieje się niejako przypadkiem i to na dwa sposoby.
Pierwszy to zapobieganie regresom. Test da nam znać, kiedy coś przestanie działać zgodnie ze specyfikacją nim wyrażoną. Ważne by pamiętać, że „przestało działać” nie zawsze znaczy “popsute”. Czasem coś przestaje działać, bo nie jest potrzebne albo zmieniły się wymagania biznesowe i to jest OK.

Drugi sposób to architektura i czytelność kodu, która wynika z programowania sterowanego testami. TDD pomaga nam skupić się na tym, jak kod będzie używany (na API i interfejsach) i w naturalny sposób prowadzi nas do SOLID, czystej architektury i programowania funkcyjnego. A czytelny, zrozumiały i pozbawiony przypadkowej złożoności kod trudniej jest popsuć.

Pisanie unit testów jest bardziej aktem projektowania niż weryfikacji

Robert C. “Uncle Bob” Martin

Lubię mówić, że dobra architektura jest tam, gdzie TDD nie wkurza. To jak kontrolka ESP w samochodzie – jeśli się zapala, to znaczy, że niekoniecznie jedziemy tam, gdzie byśmy chcieli.

Wykonywalna specyfikacja

I wreszcie TDD jest sposobem na stworzenie dokumentacji, która nie tylko opisze cały nasz projekt, z przykładami użycia każdej jego części, ale sama zadba o własną aktualność. A to wartość sama w sobie, bo od braku dokumentacji gorsza jest tylko błędna dokumentacja.

Co nas czeka?

W tej serii postaram się wytłumaczyć nie tylko jak pisać testy, ale przede wszystkim dlaczego i jakie cele powinny nam w tym przyświecać. Spróbuję usystematyzować Twoje myślenie tak, żeby TDD pomagało Ci w pracy i stało się równie naturalne jak szkicowanie dla rysownika.

Model pracy w TDD

Zaczniemy od poznania koncepcji cyklu pracy i dowiemy się po co nam on. Skonfrontujemy ze sobą różne cykle pracy na różnych poziomach projektu i odkryjemy fraktalną naturę dobrych pomysłów.

Cykl pracy: Plan, Do, Study, Act

W kontekście TDD wprowadzimy cykl PDSA i kompletnie olejemy standardowo stosowany Red → Green → Refactor. Oczywiście z uzasadnieniem 😉. Omówimy ze szczegółami co robić na każdym z jego etapów.

Praca z kodem legacy

Wejdziemy w stan wojny, obrócimy PDSA o 90 stopni i odkryjemy pętlę OODA (Observe→ Orient → Decide → Act), którą piloci myśliwców stosują do walk powietrznych. Użyjemy jej do pokonania potężnego przeciwnika – Kodu Legacy.

Testy regresyjne

Wrócimy na chwilę do koncepcji testów regresyjnych i porozmawiamy o usuwaniu testów i będziemy się cieszyć, że popsuliśmy stare testy.

Wykonywalna specyfikacja

Popatrzymy czego możemy dowiedzieć się z dobrego zestawu testów i powiemy sobie kilka słów o BDD – behavior driven development.

Czym jest unit i testowalność kodu

Spojrzymy na źródło wszelkiego zła w pierwszych podejściach do TDD – błędne rozumienie koncepcji jednostki w teście jednostkowym. Zobaczymy jak testowalność kodu łączy się z rozdzieleniem odpowiedzialności, enkapsulacją a nawet programowaniem funkcyjnym.

Architektura jako odruch bezwarunkowy

Zobaczymy jak, w całkowicie naturalny sposób, programowanie sterowane testami doprowadzi nas do tego, co czytelnicy Migawki lubią najbardziej (albo czego mają już serdecznie dość 😀), czyli Czystej Architektury.

Czy TDD nas spowalnia?

Na koniec zastanowimy się, czy to, czego nauczyliśmy się na przestrzeni całej serii przyspieszy czy spowolni naszą pracę. Odpowiedź… nie jest oczywista 😉.

Mam nadzieję, że zostaniecie ze mną do samego końca serii, polecicie znajomym i dacie jakże cenny feedback 🙂. Dalej pozostanie Wam już tylko stosować TDD w codziennej pracy i cieszyć się z pancernego kodu, zrozumiałej dokumentacji i osiąganych jeden za drugim deadline’ów 🙂.

.

O autorze

O autorze

Piotr Podgórski

Praktyk TDD, bez którego nie wyobraża sobie pracy nad czymkolwiek. Propagator metodyk lekkich i zwinnych, bywalec Zwinnej Łodzi. Nie straszna mu praca z kodem legacy, gdzie przyświeca mu odwracanie zależności i myśl Davida Wheelera: Every problem in computer science can be solved by another layer of indirection.

Czysta architektura okiem ekipy migawka.it

Jakie problemy napotkaliśmy na początku? W czym nam pomogła? Kiedy na pewno z niej nie skorzystamy?