Krolik napisał(a):
- Tylko w idealnym świecie oraz książkach interfejs jest całkowicie niezależny od implementacji. W praktyce jednak implementacja ma wpływ na interfejs, a interfejs na implementację. Myśląc tylko o samym interfejsie, możemy zaprojektować taki interfejs, że implementacja będzie 3x bardziej skomplikowana niż mogłaby być. Możemy też spowodować problemy z wydajnością - np. konieczność przekształcania formatu danych do takiego jaki zażyczył sobie projektant interfejsu, albo problemy na styku sync/async.
Możemy. Możemy też używać goto
, singletonów, oprzeć całą aplikację na statycznych klasach, a nawet zawrzeć ją w jednej wielkiej klasie. Możemy mieć setki pól przechowujących stan i bezargumentowe metody zwracające void
. Tylko co to ma do rzeczy? TDD nie wymusza pisania słabego kodu.
W efekcie pisząc testy pod interfejs zaprojektowany w oderwaniu od implementacji może się okazać, że w trakcie pisania implementacji będziemy musieli zmienić interfejs, a w efekcie przepisać testy.
Wychwytywanie błędów w architekturze to jeden z efektów pisania testów jednostkowych, i ich ogromna zaleta.
Innymi słowy - marnujemy czas na przepisywanie testów kilka razy.
No tak, bo w trakcie "normalnego programowania", nigdy niczego nie przepisujemy. Zwłaszcza, gdy jednak jakimś cudem znajdziemy błędy w implementacji. (Tzn. użytkownik na produkcji znajdzie.)
- Pisanie implementacji pod gotowy zestaw testów powoduje u niektórych programistów chęć "zaliczenia" wszytkich testów byle jak, byle tylko na końcu było zielone. W efekcie czytelność i prostota implementacji pozostawia wiele do życzenia. Np. widziałem kod ogólnie całkiego dobrego programisty, który folgując TDD, napisał implementację odzwierciedlającą po prostu po kolei każdy przypadek testowy jakimś wielkim switchem czy drabinką ifów, zamiast uogólnić wszystkie przypadki. A ponieważ w testach brakowało dwóch szczególnych przypadków, a jeden był na dodatek źle, to i kod miał analogiczne błędy.
Powiedzieć o kimś takim, że to słaby programista jest obrażaniem @maszynaz. Dobrzy programiści nie piszą słabego kodu, żeby przeszedł testy. Celem testów jest pomoc w procesie implementacji, a nie samo ich zaliczenie, gościowi się praca pomyliła z politechniką.
- Testy przed implementacją wymuszają programowanie/projektowanie stylem top-down. W efekcie można spędzić 5 dni na pisanie kodu i dalej nie mieć nic działającego, prócz kilku pięknych warstw abstrakcji. Ja tu widzę pewien paradoks, bo top-down jest bardzo, bardzo "nie-agile". Tymczasem wielu programistów, których podziwiam, i którzy piszą bardzo dobrze zaprojektowany kod, preferują bottom-up (np. Paul Graham, Peter Norvig, Ken Thompson, Linus Torvalds).
http://www.paulgraham.com/progbot.html
Napisanie klasy z pustymi metodami, potem testów, a potem implementacji metod, jest bardzo dalekie od jakiegokolwiek projektowania.
Nie znając implementacji, nie jesteś w stanie określić prawidłowo wszystkich przypadków brzegowych, bo mogą być przypadki brzegowe ukryte, wynikające z implementacji. Przypadkiem brzegowym mogą być np. dane wejściowe o wielkości dokładnie 65536 B, bo implementacja używa bufora o takiej dokładnie wielkości i pechowo tylko dla tej wartości jest off-by-one error... Pisząc testy przed implementacją nie masz szans takich rzeczy sprawdzić.
Ale czy ktoś zabrania dopisania brakującego testu w trakcie implementacji? Skoro takie zjawisko istnieje, to trzeba je uwzględnić w testach i tyle.
Testy są dodatkiem do aplikacji, a nie są metodą jej wytwarzania.
Uważasz, że TDD nie jest metodą/metodologią tworzenia kodu?
Testy to też jest kod, który trzeba wytworzyć i utrzymać. Im mniej, aby osiągnąć cel, tym lepiej.
Dlatego pisząc testy trzeba jest pisać tak, jak każdy inny kod, a nie na zasadzie kopiuj-wklej.
Testy są użytecznym narzędziem, ale są tylko jednym z wielu narzędzi zapewnienia odpowiedniej jakości projektu. Robienie z nich centralnego elementu wytwarzania oprogramowania to jakieś nieporozumienie.
Owszem, tylko to jest narzędzie, które akurat każdy programista może stosować, bo jest dość proste, tanie i efektywne.
Klienta nie obchodzą testy, klienta obchodzi działające oprogramowanie.
Na szczęście coraz więcej klientów rozumie, że testy leżące bliżej kodu pozwalają na redukcję czasu poprawiania błędów w późniejszych fazach przedsięwzięcia, co ma duży wpływ na koszty.
Może za ileś lat programiści też to zrozumieją.
Twój post wygląda tak, jakbyś sam najpierw chciał sprowadzić pisanie testów do bycia głównym elementem wytwarzania oprogramowania, a potem pokazać jakie to złe podejście i testowanie w ogóle obalić. Z kimś, kto obala własne argumenty trudno polemizować, bo ma zawsze rację. :P
To co piszesz wygląda tak, jakbyś uważał, że TDD polega na tym, że najpierw jacyś architekci projektują cała aplikację, później banda programistów siada i pisze miesiącami testy do wszystkich metod całej aplikacji, a na końcu pisze się implementację, żeby przeszła te testy. Tymczasem to w ogóle nie o to chodzi. Jest zadanie do wykonania, jeśli w toku tego zadania programista dochodzi do wniosku, że procesy, które ma zaimplementować warto przetestować, to pisze testy, a potem implementację. Traci co prawda na czasie pisania kodu testów, ale zyskuje znacznie więcej na czasie uruchamiania aplikacji i doprowadzania jej do momentu, w którym korzysta z implementowanego przez niego kodu. To jest jak najbardziej oddolny, a nie odgórny proces.