
TDD – czy same testy to wymagania?
Na niedawno zakończonej konferencji beIT organizowanej na Politechnice Gdańskiej przez Wydział Elektrotechniki, Telekomunikacji i Informatyki, wygłosiłem referat zatytułowany Filozofia czyli Aplikacja jako element biznesowej rzeczywistości (a nie gra komputerowa). Przesłanie tej prezentacji to:
Oprogramowanie bardzo często zastępuje konstrukcje rzeczywiste takie jak zegarek, kartoteka, biblioteka, księgi handlowe, programator pralki i wiele innych rzeczy. Dlatego analiza powinna polegać na zrozumieniu i udokumentowaniu mechanizmu działania „tego czegoś” a nie jedynie na spisaniu zewnętrznych oznak tego działania i zarządzanie tym spisem.
Referat miał lekkie podłoże filozoficzne :).
Ten artykuł nie będzie jednak powtórzeniem referatu (wyżej link do pobrania). Do jego napisania skłoniło mnie jedno z pytań z sali:
„Stosujemy TDD, czy to nie wystarczy? Po co więc robić to o czym Pan mówi?”
Otóż odpowiedź brzmiała: TDD nie zastępuje opisu mechanizmu działania. Innymi słowy: sam zestaw testów bardzo często nie stanowi żadnej informacji o tym co ma powstać.
Niedawno pisałem:
Mechanizm jednak to nie zawsze tylko same reguły, bardzo często (praktycznie zawsze dla nietrywialnych systemów) powinien powstać diagram pokazujący wewnętrzną budowę (architekturę) systemu, zestaw komponentów odpowiedzialnych za logikę realizowania tych reguł (a jedną z nich jest np. ?treść dokumentów musi być zapamiętywana z możliwością przywołania jej w dowolnym momencie?). Taki diagram nazywa się Model dziedziny. Jak go tworzyć pisałem nap. w artykule Model dziedziny jako wymaganie. (Źródło: Model To Mechanizm | | Jarosław Żeliński IT-Consulting)
A teraz jako przykład przytoczę dość złożony komponent wielu systemów (pogrubienie moje):
Jak działa scoring w Banku. Klient zainteresowany uzyskaniem kredytu wypełnia wniosek kredytowy dla wybranego produktu kredytowego. Dane z wniosku rejestrowane są w systemie informatycznym, który wspomaga proces obsługi wniosków kredytowych w Banku. Podczas przetwarzania wniosku następuje weryfikacja danych oraz zapytanie o automatyczną rekomendację kredytową kierowaną do silnika decyzyjnego. Silnik decyzyjny wykonuje zdefiniowany w postaci reguł przetwarzania algorytm scoringowy: gromadzi dodatkowe informacje z dostępnych źródeł (np. Biuro Informacji Kredytowej SA, bazy niesolidnych klientów oraz dowodów zastrzeżonych ? MIG BR, MIG DZ), wyznacza wskaźniki, określa przydział do klas ryzyka oraz wylicza ocenę punktową w oparciu o karty scoringowe. (Źródło: Scoring – metoda oceny wiarygodności kredytowej – ERP-view.pl – ERP, CRM, MRP, Business Intelligence, MRP)
Odpowiadając na pytanie o TDD powiem tak: nie da się „jednoznacznie zamówić” Systemu scoringowego, podając jedynie partię danych wejściowych i spodziewanych danych wyjściowych. Testy można opracować znając mechanizm działania tego systemu, tworzymy wtedy reprezentatywny zestaw testów „pokrywający cały kod”, o ile znamy strukturę tego kodu (projekt). Sam kod nie musi istnieć w momencie projektowania tych testów, ale opracowany mechanizm tak, bo jak już pisałem „model dziedziny to struktura kodu realizującego logikę biznesową wraz z metodami”.
Można tu powiedzieć, że nie każdy system to złożoność systemu scoringowego. To prawda, ale to co nazywamy biznesem to reguły biznesowe, mechanizm działania organizacji, a ten nigdy nie jest trywialny. Reguły udzielania upustów, reguły przydzielania kredytów kupieckich, reguły nagradzania w systemach lojalnościowych, reguły rozliczania kosztów i wiele, wiele innych w prawie każdej firmie, organizacji czy instytucji publicznej.
Prawdopodobieństwo tego, że powstanie „poprawne” oprogramowanie tylko na podstawie zapisu szeregu „zewnętrznych obserwacji” (bo czym są wymagania jako zapis burz mózgów, ankiet, wywiadów, itp.?) jest tym bardziej bliskie zeru im bardziej organizacja ma złożony mechanizm działania (czyli większość).
Zjawisko to jest znane już od dziesiątków lat:
Problemy, w których rozwiązaniu mają pomóc budowane złożone systemy są zwykle ?problemami złośliwymi? (Rittel i Webber, 1973). ?Problem złośliwy? to taki skomplikowany problem, w którym jest tak wiele powiązanych ze sobą bytów, że nie istnieje jego ostateczna specyfikacja. Prawdziwy charakter problemu objawia się dopiero w miarę opracowywania rozwiązania.
Dlatego rozwiązanie nietrywialnego problemu nie polega na specyfikowaniu tego co znamy, a na podjęciu próby zaprojektowania rozwiązania. Tym projektem nie jest jednak „opis reakcji systsemu na bodźce” (czarna skrzynka). Projektem jest opisany (jednoznacznie udokumentowany) mechanizm działania rozwiązania (biała skrzynka).
Dlatego wymagania specyfikujemy skutecznie poprzez projekt produktu a nie poprzez listę cech produktu. Zamówienie dla developera powinno zawierać projekt a nie wizualizację efektu końcowego, dokładnie tak jak w branży budowlanej, elektronicznej czy nawet mechanicznej (nawet wykonawca wału korbowego dostaje rysunki techniczne a nie rozwlekłą prośbę o fajny wał do samochodu).
Zilustrować to można tak:
- Wymagania biznesowe zgłasza biznes, są one formą opisu i konsekwencją problemu biznesowego, wymagania wobec rozwiązania to ustalony zakres projektu.
- Jeżeli jest to projekt z obszaru inżynierii oprogramowania, ma powstać oprogramowanie opisane z użyciem Przypadków użycia i Modelu dziedziny.
- Jak przejść od wymagań biznesowych do Przypadków użycia i modelu dziedziny i kto ma tego dokonać?
Kto ma opracować to ostatnie? Programista? A na jakiej podstawie, skoro „nie zna tego biznesu” (to programista a nie analityk biznesowy)? Czy same przypadki użycia opisują reguły (mechanizm działania) działania systsemu scoringowego czy systemu upustów w promocji (to jedna liczba, wartość upustu, na fakturze)? Nie. Czy da się na bazie partii testów (czyli skończonej, ale z reguły niezupełnej liście bodziec-odpowiedź) stworzyć cokolwiek? Mało kiedy. Oznacza to, że wymagania zebrane tylko jako przypadki użycia „mało kiedy” dają szansę na powstanie oprogramowania „za pierwszym razem”, tu prototypów nie jest nigdy przewidywalna. To dlatego metody zwane zwinnymi, bazujące wyłącznie na user story i prototypach, nadają się do problemów prostych. Kompletnie nie sprawdzają się w przypadkach złożonych systemów, rozumianych jako złożone mechanizmy. Te ostatnie trzeba nie raz „od zera” odkryć i opisać.
Paradygmat i metody obiektowe
Kluczem metod obiektowych (i paradygmatu obiektowego) jest hermetyzacja. Oznacza to, że złożoność obiektu „z zewnątrz” nie jest znana nigdy, nie ma znaczenia wielkość obiektu (mała klasa czy mega-komponent), na zewnątrz postrzegany jest wyłącznie jako interfejs. Rozważania na początku pokazały, że odpowiedzi na bodźce to oczekiwane (wymagane) cechy rozwiązania, które jednak nie determinują jego mechanizmu.
Oprogramowanie pomagające w nauce tabliczki mnożenia do 100, może zawierać statyczną tablicę znaną z ostatnich stron starych zeszytów, a może to być mechanizm będący implementacją algorytmu mnożenia. Po pierwsze zestaw testów, jak widać, nie determinuje żadnej z tych metod implementacji. Po drugie specyfikacja w pierwszym wypadku będzie „duża” (kosztowna), w drugim bardzo prosta. Po trzecie rozwijanie (tabliczka mnożenia do 1000) oprogramowania w wersji z tablicą statyczną będzie znacznie droższe niż pierwotne wytworzenie wersji z mnożeniem do 100. W drugim przypadku będzie polegało wyłącznie na zdjęciu blokady mnożenia liczb większych niż 10.
Tak więc co z tym TDD? Popatrzmy na to jak jest definiowane:
Co to jest Test Driven Development
Test Driven Development, czyli TDD, to technika tworzenia oprogramowania sterowana przez testy. Tworzenie kodu składa się z wielokrotnie wykonywanych trzech głównych kroków:
- Stworzenie testu jednostkowego, który powinien być możliwie najprostszy, aby uniknąć możliwości popełnienia błędu w samym teście. Test ma sprawdzać funkcjonalność, która będzie implementowana w kroku 2.
- Implementacja funkcjonalności ? tworzymy funkcjonalność, którą chcemy zaimplementować. Funkcjonalność ta powinna spełniać założenia testu jednostkowego, a wykonanie testu jednostkowego powinno kończyć się sukcesem.
- Refaktoryzacja, czyli porządki w stworzonej funkcjonalności. Ma to na celu uporządkowanie kodu, tak aby spełnione były standardy. Czynności wykonywane w tym kroku nie mogą zmienić wyniku testów.
Źródło: Test Driven Development
Pod pojęciem funkcjonalność tu rozumiany jest „oczekiwany efekt”, bo test nie jest niczym innym. Czy testy to są (zastępują) projekt wewnętrznej logiki? W przypadkach trywialnych pewnie tak, tam gdzie logika jest prosta lub nie występuje (przypadki użycia typu CRUD), albo tam gdzie „logika” jest „powszechnie znana” zna ją także programista (np. sposób działania zegara).
Jednak system o nietrywialnej logice działania, nie da się wyspecyfikować w postaci skończonej (lub rozsądnie krótkiej) listy bodziec-efekt (np. przykładowych partii gry w szachy). W jednej ze swoich książek Martin Fowler napisał, że żadna ilość godzin filmu znad stołu bilardowego, jako wymaganie, nie da w efekcie nawet namiastki dobrej gry w bilarda. Ale schemat stołu, wymiary kul, kija oraz prawa fizyki rządzące ruchem kul, pozwolą na napisanie wręcz doskonałej symulacyjnej gry. Taki opis to właśnie model dziedziny gry w szachy, dokładny opis mechanizmu tego co dzieje się na stole bilardowym.
Ostatnie pytanie brzmiało: Jak przejść od wymagań biznesowych do Przypadków użycia i modelu dziedziny i kto ma tego dokonać?
Odpowiedź na to pytanie zawiera pewien artykuł, napisany w 2014 roku na nieco inny temat:
…rolą analityka biznesowego nie jest spisanie przebiegu dziesiątek wywiadów i setek indywidualnych wymagań. Nie mają większego sensu dokumenty na dwa, trzy tysiące stron (nikt ich nie czyta!). Rolą analityka biznesowego jest przeanalizowanie dostępnych dokumentów, informacji, i stworzenie opisu mechanizmu działania organizacji oraz opisu rozwiązania, narzędzia mogącego usprawnić działanie organizacji. Opisu zawierającego reguły biznesowe, przetwarzane informacje (wzory dokumentów) oraz listą usług jakie ma świadczyć planowana do wdrożenia aplikacja wraz z opisem tego, jak te usługi mają być realizowane (umiejętności, które można zautomatyzować). Sens mają więc zwięzłe opisy i modele mechanizmów działania organizacji oraz opisy tego jakie informacje i jak mają być przetwarzane z uwzględnieniem tego, że część tych prac nadal będą wykonywali ludzie. Takie jak reguły gry w szachy: ważne są dwie strony opisu reguł gry a nie setki stron opisów przykładowych partii. (Źródło: Warsztaty Analityczne ? Czyli Malowanie Trawy | | Jarosław Żeliński IT-Consulting)
Tak więc robimy to tak, jak w innych dziedzinach inżynierii: analizujemy, projektujemy i zlecamy wykonanie (implementację).
Na zakończenie
Kim jest, członkiem którego zespołu jest (powinien być) projektant? Przewrotnie odpowiem, że praktyka pokazuje, że – z powodu ryzyka projektowego – wykonawca nie powinien sam sobie stawiać wymagań. To dlatego złożone i ryzykowne projekty mają wydzieloną rolę analityka projektanta, nie jest to członek zespołu biznesu ani developera bo obie te strony mają sprzeczne interesy (zakres i koszt). W branży budowlanej jest to Biuro Projektowe (tu architekt), trzeci niezależna rola, poza inwestorem i wykonawcą (z uwagi na ryzyko, prawo budowlane zabrania łączenia jakiejkolwiek z tych trzech ról). W metodykach takich jak SCRUM, jest to Product Owner, i z powyższego powodu nie jest dobrze gdy jest to „człowiek developera”.

BIO: Od roku 1991 roku, nieprzerwanie, realizuję projekty z zakresu analiz i projektowania systemów, dla urzędów, firm i organizacji. Od 1998 roku prowadzę także samodzielne studia i prace badawcze z obszaru analizy systemowej i modelowania (modele jako przedmiot badań: ORCID). Od 2005 roku, jako nieetatowy wykładowca akademicki, prowadzę wykłady i laboratoria (ontologie i modelowanie systemów informacyjnych, aktualnie w Wyższej Szkole Informatyki Stosowanej i Zarządzania pod auspicjami Polskiej Akademii Nauk w Warszawie. Oświadczenia: moje badania i publikacje nie mają finansowania z zewnątrz, jako ich autor deklaruję brak konfliktu interesów.