Jaka jest negatywna strona twojego doświadczenia TDD? Czy uważasz, że kroki dziecka (najprostszy sposób na zielony test) są denerwujące i bezużyteczne? Czy uważasz, że testy bez wartości (gdy test ma sens na początku, ale w końcowej implementacji sprawdza tę samą logikę co inne testy) utrzymanie krytyczne? itp.
Powyższe pytania dotyczą rzeczy, z którymi czuję się niekomfortowo podczas mojego doświadczenia TDD. Jestem więc zainteresowany, czy inni programiści mają podobne odczucia i co o nich myślą.
Byłbym wdzięczny za linki do artykułów opisujących negatywne strony TDD (Google jest wypełniony pozytywnymi i często fanatycznymi artykułami).
Odpowiedzi:
Podobnie jak wszystko, co znajduje się pod sztandarem „Agile”, TDD jest czymś, co brzmi dobrze w teorii, ale w praktyce nie jest tak jasne, jak dobre jest (a także jak większość „Agile”, powiedziano ci, że jeśli nie lubisz to, robisz to źle).
Definicja TDD nie jest wyryta w kamieniu: faceci tacy jak Kent Beck domagają się, aby przed pojedynczą linią kodu napisano test niekompilacyjny, a każdą pojedynczą linię kodu napisać, aby pomyślnie przejść test. Projekt z przodu jest minimalny i wszystko jest napędzaneprzez testy. To po prostu nie działa. Widziałem aplikację dla dużych przedsiębiorstw opracowaną przy użyciu tej metodologii i mam nadzieję, że jest to gorszy kod, jaki widzę w mojej karierze (nie będzie to daleko; i było tak pomimo tego, że pracują nad nią utalentowani programiści). Z tego, co widziałem, wynika ogromna liczba źle przemyślanych testów, które głównie sprawdzają poprawność wywołań funkcji, wyjątki są zgłaszane, gdy zmienne są zerowe, a środowisko próbne przechodzi dokładny trening (whoop-de-whoop); Twój kod produkcyjny jest mocno powiązany z tymi testami i nie pojawia się marzenie o ciągłym i łatwym refaktoryzowaniu - w rzeczywistości ludzie są jeszcze mniej podatni na naprawienie złego kodu z powodu wszystkich testów, które złamie.
I odwrotnie, słyszałem, jak ludzie twierdzą, że TDD oznacza zaprojektowanie testów z góry na wysokim poziomie w ramach fazy planowania - obok projektu architektonicznego. Testy te mogą ulec zmianie podczas opracowywania, gdy dostępnych jest więcej informacji, ale zostały one starannie przemyślane i stanowią dobry przewodnik na temat tego, co powinien zrobić kod. Dla mnie to ma sens.
źródło
Ten wywiad ( autor Clojure ) Rich Hickey zawiera następujące informacje. Czuję się w 100% współczujący:
Kolejne podobne oświadczenie Donalda Knutha w wywiadzie książkowym Coders at Work , skopiowane z tego miejsca :
źródło
Moje negatywne doświadczenia z TDD były moje pierwsze. TDD brzmiało dla mnie wspaniale, robiłem kontrolę jakości przez lata i nadal miałem w głowie nowe horrory. Chciałem zmiażdżyć każdy błąd, zanim przekształci się on w kompilację. Niestety użycie TDD nie gwarantuje, że napiszesz dobre testy. W rzeczywistości moją początkową predyspozycją było pisanie prostych testów, które generowały prosty kod. Naprawdę prosty kod, który zawierał kilka abstrakcji. Naprawdę proste testy, które były powiązane z wewnętrznymi elementami klasy. A kiedy masz już kilka tysięcy bitowych testów, na pewno nie czujesz, że poruszasz się szybciej, gdy musisz zmienić ich setkę, aby zmienić kod w celu wykorzystania bardzo ważnej koncepcji domeny X.
Zapaliło się dla mnie światło - TDD nie jest umiejętnością testową. To umiejętność projektowania. Może tylko prowadzić cię do dobrego, prostego, wykonalnego kodu, ćwicząc i stale zdając sobie sprawę z kierunków projektowania, w które cię poprowadzi. Jeśli piszesz testy dla pokrycia kodu, stworzysz kruche testy. Jeśli piszesz testy, które pomogą Ci zaprojektować swoje abstrakcje, jest to po prostu bardziej rygorystyczny sposób pisania odgórnego kodu. Najpierw zobaczysz kod z perspektywy dzwoniącego, który zachęca cię do ułatwienia mu życia, zamiast odzwierciedlać wewnętrzne elementy klasy na zewnątrz.
Myślę, że TDD jest przydatne, ale nie jestem do tego dogmatyczny. Jeśli te „testy bez wartości” utrudniają konserwację - usuń je! Testy traktuję tak samo jak resztę kodu. Jeśli można go zrefaktoryzować i uprościć, zrób to!
Nie widziałem tego osobiście, ale słyszałem, że niektóre miejsca śledzą zasięg kodu i testy się liczą. Więc jeśli zbieranie danych jest efektem ubocznym TDD, to mogę to również postrzegać jako negatywne. Z entuzjazmem usunę 1000 linii kodu, a jeśli to zdezaktualizuje 20 testów i porzuci mój procent pokrycia kodu, cóż.
źródło
Mam zamiar wyjść tutaj na całość i z brutalną szczerością oświadczam, że to dosłownie rytualna strata czasu. (W większości sytuacji.)
Kupiłem książkę o testowaniu jednostkowym, która również omawiała TDD i chociaż zgadzam się z korzyściami UT, po około stu godzinach próbowania TDD zrezygnowałem z niej z wielu powodów. W pewnym sensie jestem tutaj, ale TDD:
Innym problemem jest dyskutowany stopień doskonałości, do którego należy zrobić TDD, aby zrobić to z powodzeniem. Niektórzy twierdzą, że jeśli TDD nie będzie wytrwale wykonywany przez wszystkich w zespole od początku projektu, tylko cierpisz. Inni twierdzą, że nikt nigdy nie robi TDD według książki. Jeśli oba są prawdziwe, oznacza to, że praktykujący TDD cierpią, niezależnie od tego, czy zdają sobie z tego sprawę, czy nie.
Oczywiście, jeśli argumentuje się, że robiąc rzeczy w sposób podobny do TDD, dojdziesz do projektów, które mogą łatwo współpracować z TDD, cóż, istnieją znacznie szybsze sposoby na osiągnięcie tego - a mianowicie poprzez studiowanie koncepcji składalność. Istnieje wiele zasobów, nawet rygorystycznych teorii matematycznych (głównie w programowaniu funkcjonalnym, ale także w innych dziedzinach). Dlaczego nie poświęcić całego czasu na naukę TDD ?
Kulturowo, TDD wykazuje objawy bycia praktyką rytualną. Jeździ na poczuciu winy; zachęca do procedury ponad zrozumienie; zawiera mnóstwo doktryn i haseł („sfałszuj go, dopóki go nie sprawisz” jest naprawdę dość niepokojący, jeśli spojrzysz na to obiektywnie). Definicja słowa „rytuał” w Wikipedii jest dość trafna:
źródło
Aby dodać, innym problemem związanym z TDD, który zauważyłem, jest:
TDD powoduje niezamierzone przesunięcie uwagi zespołu programistów z Kodeksu Jakości na Przypadki Testowe i Pokrycie Kodu! Osobiście nie lubiłem TDD, ponieważ czyni mnie mniej kreatywnym i sprawia, że tworzenie oprogramowania jest nudnym procesem mechanicznym ! Testy jednostkowe są przydatne, gdy są rozsądnie stosowane, ale stają się ciężarem, gdy traktuje się cel rozwoju oprogramowania.
Znam faceta, który jest menedżerem i jest technicznie nudny, gdy miał obsesję na punkcie TDD. Było to dla niego tak magiczne, że wierzył, że przyniesie magiczne rozwiązania wszystkich problemów w jego słabo skonstruowanym oprogramowaniu z najmniejszym możliwym do utrzymania kodem. Nie mówiąc już o tym, co się stało z tym projektem - poniósł porażkę w jego rękach, podczas gdy wszystkie jego testy były zielone. Wydaje mi się, że TDD pomógł mu uzyskać jakieś informacje statystyczne, takie jak „99/100 moich przypadków jest zielonych” itp. To był powód jego obsesji, ponieważ nigdy nie byłby w stanie ocenić jakości ani zaproponować ulepszeń w projekcie.
źródło
Moje główne negatywne doświadczenia to próba użycia TDD do edycji kodu innego programisty, który nie ma żadnych testów lub bardzo, bardzo podstawowych testów integracyjnych. Kiedy idę dodać funkcję lub naprawić problem z tym kodem; Wolałbym najpierw napisać test (metoda TDD). Niestety kod jest ściśle powiązany i nie mogę niczego przetestować bez dużej ilości refaktoryzacji.
Refaktoryzacja i tak jest świetnym ćwiczeniem, ale jest wymagane, aby wprowadzić kod w stan testowalny. Po tym kroku nie mam czeków i sald, aby sprawdzić, czy moje zmiany coś zepsuły; po uruchomieniu aplikacji i sprawdzeniu każdego przypadku użycia.
Z drugiej strony dodawanie funkcji / naprawianie błędów do projektu TDD staje się bardzo proste. Z natury kod napisany za pomocą TDD jest zwykle dość oddzielony od małych kawałków do pracy.
W każdym razie TDD jest wytyczną. Postępuj zgodnie z nim, aż osiągniesz maksymalną skuteczność. Przyzwoity zasięg testu i oddzielony kod, dobrze napisany kod.
źródło
Doświadczyłem, że czasami polegam zbytnio na moich testach, jeśli chodzi o konstrukcję systemu. W zasadzie mam zbyt mało szczegółów na temat drobiazgowej implementacji, aby cofnąć się o krok i spojrzeć na większy obraz. Często skutkuje to niepotrzebnie złożonym projektem. Wiem, że powinienem zmienić kod, ale czasami mam wrażenie, że mogę zaoszczędzić dużo czasu, robiąc krok wstecz.
Biorąc to pod uwagę, jeśli masz ramy takie jak szyny, gdzie twoje decyzje architektoniczne są bardzo ograniczone, problemy te w zasadzie nie istnieją.
Innym problemem jest to, gdy ślepo ufasz swoim testom. Prawda jest - jak każdy inny kod - twoje testy również mogą zawierać błędy. Dlatego bądź tak krytyczny wobec swoich testów, jak i wobec implementacji.
źródło
Jako wielki fan TDD czasami dostrzegam te wady
Koszty utrzymania kodu testowego dla podobnych testów, które różnią się tylko nieznacznie (utworzone przez duplikację kodu (inaczej dziedziczenie kopiuj-wklej-wklej)). Jeśli już go masz, możesz łatwo stworzyć podobny. Ale jeśli nie przefakturujesz kodu testowego, eliminując duplikację kodu do metod pomocniczych, możesz potrzebować trochę czasu na naprawę testów, jeśli zmienią się szczegóły implementacji twojego kodu biznesowego.
Jeśli jesteś pod presją czasu, możesz ulec pokusie wyeliminowania zepsutych testów (lub ich skomentowania) zamiast ich naprawiania . W ten sposób tracisz inwestycję w testy
źródło
Jeszcze nie spotkałem się z więcej niż jednym scenariuszem jako twórca gier, w którym warto było TDD. I w tym przypadku był to fragment kodu, który miał charakter czysto matematyczny i wymagał solidnego podejścia do testowania ogromnej liczby przypadków skrajnych jednocześnie - rzadka potrzeba.
Być może coś kiedyś zmieni zdanie, ale wśród praktyk XP pomysł bezlitosnego refaktoryzowania i rozwijania własnej formy kodu jest o wiele ważniejszy i prowadzi do największej wydajności dla mnie, por. cytat z artykułu Jamesa Newkirka :
Wspomniane przeze mnie koncepcje odwagi i zacieśniania pętli informacji zwrotnej są również, moim zdaniem, kluczowe dla wydajności.
źródło
Moje negatywne doświadczenia TDD, choć mogą być ograniczone, po prostu wiem, od czego zacząć! Na przykład postaram się zrobić coś TDD i albo nie mam pojęcia, od czego zacząć testowanie trywialnych rzeczy (czy mogę nowy
Foo
obiekt, przekazać goQuux
doBaz
itp.) Testy, które niczego nie testują ) lub jeśli próbuję zaimplementować go w istniejącym projekcie, stwierdzę, że musiałbym przepisać różne klasy, aby móc z nich korzystać w TDD. Efektem końcowym jest to, że szybko porzucam całkowicie to pojęcie.Prawdopodobnie nie pomaga to tak często, że jestem jedyną osobą w całej firmie, która wie, co to jest testowanie jednostkowe (TDD lub inne) i dlaczego jest to dobra rzecz.
źródło
Foo
z Mock obiektów zamiastQuux
iBaz
bezpośrednio, można wywołać funkcję chcesz przetestować, a następnie sprawdzić, czy mocks nazywano z funkcjami można się spodziewać. Obiekty pozorne to technologia aktywująca, która pomaga rozdzielić jednostki i umożliwić ich testowanie. Dlatego singletony są złe, ponieważ często nie można ich po prostu wyśmiewać . * 8 ')Fanatycy TDD.
Dla mnie to tylko jedna z długiej linii religijnych wariatów pukających do moich drzwi, próbujących udowodnić, że mój sposób robienia rzeczy jest nieodwracalnie zepsuty, a jedyną drogą do zbawienia jest Jezus, Powrót Kenta lub Testowanie Jednostek.
IMO, ich największym kłamstwem jest to, że TDD doprowadzi cię do
zbawienialepszego projektu algorytmu. Zobacz słynny solver Soduku napisany w TDD: tutaj , tutaj , tutaj , tutaj i tutajI porównaj to solver sudoku Peter Norvig wykonany nie przy użyciu TDD, ale przy użyciu staromodnej inżynierii: http://norvig.com/sudoku.html
źródło
Jeśli użyjesz TDD z tych „fanatycznych” artykułów, błędnie poczujesz, że w twoim oprogramowaniu nie ma błędów.
źródło
TDD ma pewne zalety:
TDD dotyczy inwestycji długoterminowych. Wysiłek opłaca się, gdy przejdziesz do trybu konserwacji aplikacji, a jeśli aplikacja nie planuje osiągnąć tego punktu, możesz nigdy nie odzyskać inwestycji.
Uważam cykl TDD czerwono-zielony z krokami dziecka podobnymi do listy kontrolnej samolotu. Sprawdzanie wszystkich rzeczy w samolocie przed startem jest denerwujące i żmudne, zwłaszcza jeśli jest to banalnie proste (kroki dziecka TDD), ale stwierdzono, że zwiększa bezpieczeństwo. Oprócz sprawdzenia, czy wszystko działa, zasadniczo resetuje płaszczyznę . Innymi słowy, samolot jest restartowany przed każdym startem.
źródło
Moje negatywne doświadczenia związane z TDD są czymś, co odczuwam w przypadku wielu nowych i hiper-rzeczy. W rzeczywistości podoba mi się TDD, ponieważ zapewnia on poprawność mojego kodu, a co ważniejsze: mogę rozpoznać testy zakończone niepowodzeniem po dodaniu nowego kodu lub dowolnego rodzaju refaktoryzacji.
W TDD denerwuje mnie fakt, że istnieje wiele zasad lub wytycznych na ten temat. Ponieważ jest to wciąż dość nowe zjawisko, większość z nas ma doświadczenie jako początkujący w TDD. Więc to, co działa dobrze dla niektórych z nas, może nie działać dla innych. Chcę powiedzieć, że nie ma prawdziwego „niewłaściwego lub właściwego” sposobu wykonania TDD: Jest taki sposób, który działa dla mnie - i dla mojego zespołu, jeśli go mam.
Tak długo, jak piszesz testy - przed kodem produkcyjnym lub po nim tak naprawdę nie ma znaczenia IMHO - nie jestem pewien, czy testowanie naprawdę oznacza, że musisz przestrzegać wszystkich wytycznych, które są teraz podane, ponieważ nie zostały jeszcze udowodnione idealne rozwiązanie do codziennej pracy. Jeśli znajdziesz lepszy sposób na pisanie testów, powinieneś opublikować go na blogu, przedyskutować tutaj lub napisać o nim artykuł. Więc za około dziesięć lat moglibyśmy podzielić się wystarczającym doświadczeniem, aby móc stwierdzić, która reguła TDD może być uznana za dobrą, czy nie w określonej sytuacji.
źródło
Nieraz napisałem kod, który odrzuciłem następnego dnia, ponieważ był niezdarny. Uruchomiłem ponownie z TDD i rozwiązanie było lepsze. Więc nie miałem zbyt wiele na linii negatywnego doświadczenia TDD. Jednak powiedziawszy to, spędziłem czas zastanawiając się nad problemem i wymyślając lepsze rozwiązanie poza przestrzenią TDD.
źródło
Odkryłem, że TDD działa słabo, jeśli chodzi o systemy wschodzące. Jestem programistą gier wideo, a ostatnio wykorzystałem TDD do stworzenia systemu, który wykorzystuje wiele prostych zachowań do stworzenia realistycznie wyglądającego ruchu dla bytu.
Na przykład istnieją zachowania odpowiedzialne za odsuwanie cię od niebezpiecznych obszarów różnego rodzaju i takie, które są odpowiedzialne za przenoszenie cię w interesujące obszary różnych typów. Połączenie wyników każdego zachowania tworzy końcowy ruch.
Elementy systemu zostały zaimplementowane z łatwością, a TDD przydał się tutaj do określenia, za co powinien odpowiadać każdy podsystem.
Miałem jednak problemy, gdy chodziło o określenie interakcji między zachowaniami, a co ważniejsze, w jaki sposób zachodzą one w czasie. Często nie było właściwej odpowiedzi i chociaż moje wstępne testy zakończyły się pomyślnie, QA mogła nadal znajdować przypadki, w których system nie działał. Aby znaleźć właściwe rozwiązanie, musiałem powtarzać kilka różnych zachowań, a jeśli za każdym razem aktualizowałem testy, aby odzwierciedlić nowe zachowania, zanim sprawdziłem, czy działają w grze, być może raz po raz wyrzucałem testy. Więc usunąłem te testy.
Powinienem być może mieć silniejsze testy, które uchwyciły odkryte przypadki QA, ale kiedy masz taki system, który opiera się na wielu systemach fizyki i rozgrywki, a masz do czynienia z zachowaniami z czasem, staje się to trochę koszmar dokładnie sprecyzować, co się dzieje.
Niemal na pewno popełniłem błędy w moim podejściu i, jak powiedziałem, dla wnętrzności systemu TDD działało znakomicie, a nawet wspierało kilka optymalizujących refaktorów.
źródło