Czy używasz TDD? oraz pytania do TDD.

Czy używasz TDD? oraz pytania do TDD.
WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
2

@LukeJL:

To jest akurat założenie autora tego wątku. W pierwszym poście jest napisane: Dlaczego warto stosować TDD, i czy się opłaca biorąc pod uwagę czas poświęcony na tworzenie testów?

i czemu niby mamy kontynuować operowanie na tym założeniu jeżeli wiemy że jest niepoprawne?

Pisanie testów, to pisanie testów.

Robienie TDD, to robienie TDD.

Rozróżniajmy te rzeczy.

Ale na użycie debuggera stracisz pewnie tyle samo czasu, co na pisanie testów, a na końcu nawet nie będziesz miał artefaktu w postaci testów.

oraz @somekind

O debuggerze nie piszę jako o alternatywie do pisania testów, a jako o sposobie na przyspieszenie developmentu, bo od razu mam ten feedback o którym ty piszesz ("Potrzebujesz informacji zwrotnej na bieżąco, żeby się zorientować, czy kod się odpala i czy działa poprawnie") i nie tracę czasu na przebudowywanie appki i ponowne odpalanie appki i wprowadzenie jej w odpowiedni stan.

Po wydevelopowaniu takiego kodu w oparciu o debugger wiem że:

  • kompiluje się
  • jako tako działa

a zatem mogę teraz napisać testy.

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
2

Ale zwała v2.

Wczoraj Kent Beck opublikował ponownie swój wpis z 2007 nt. debugger driven development :D czyli tego, o czym tu piszę z @Miang na ostatnich dwóch stronach

czyżby czytał 4p?

https://tidyfirst.substack.com/p/coding-in-the-debugger

Early dynamic programming environments like LISP and Smalltalk supported programming in the debugger. Java and similar pessimistic languages refuse to even attempt to execute programs until the compiler is convinced that they are correct, making such debugger-based programming impossible. However, advances in programming environments for Java have made programming in the debugger possible, coinciding nicely with the limitations of TDD that make in-situ coding attractive.
(...)
Now use the usual TDD process: write a test and generate stub types and methods. When the test compiles, you can begin in-situ coding by running the test with debugging on. The keyboard shortcut for this is alt-shift-D, T, but you can start in-situ coding for subsequent tests in the same test class by pressing F11.

screenshot-20230929084711.webp

Next you will see the stub method you need to fill in, but with an example of the context in which the real code will execute: fields, parameters, and the call stack:

screenshot-20230929084745.webp

With this context visible, the developer can focus on coding the needed logic instead of remembering the details of the test fixture. They can try little snippets of code using real data, accelerating the feedback loop for coding. Once the code is satisfactory, they can continue execution (F8) and immediately see if the code matched the test.

LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8488
0

Nie rozumiem jak to ma działać dokładnie.

Debugger sam wymyśla fejkowe dane? Czy gdzieś się definiuje?

A na końcu testy się same generują?

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
4

@LukeJL:

Przeczytaj uważnie to.

O debuggerze nie piszę jako o alternatywie do pisania testów, a jako o sposobie na przyspieszenie developmentu, bo od razu mam ten feedback o którym ty piszesz ("Potrzebujesz informacji zwrotnej na bieżąco, żeby się zorientować, czy kod się odpala i czy działa poprawnie") i nie tracę czasu na przebudowywanie appki i ponowne odpalanie appki i wprowadzenie jej w odpowiedni stan

A jeżeli dalej nie rozumiesz, to obrazkami:

Debugger driven development służy do tworzenia kodu (nie testów)

Załóżmy że piszemy jakiś kod który ma pobrać dane i coś z nimi zrobić, zaczynamy od pustego kodu

screenshot-20230929090256.png

Odpaliliśmy appkę i podpieliśmy się debuggerem, teraz w trakcie uruchomienia aplikacji piszemy kod.

Dopisujemy nowy kod i wykonujemy kolejną linie (wywołanie metody)

screenshot-20230929090446.png

Dodatkowo możemy sobie zmienić nasze dane, bo uznaliśmy że chcemy mieć 1, 2, 4 zamiast 1, 2, 3

screenshot-20230929090518.png

Teraz, gdy już mamy dane, to dopisujemy kod który coś na nich zrobi

screenshot-20230929090546.png

screenshot-20230929090604.png

I wyprintowało się 1, 2, 4 - jest świetnie.

Ale zauważamy że w sumie w specyfikacji było napisane że trzeba printować wartość + 1, no to zmieniamy i cofamy się debuggerem do linii wyżej

screenshot-20230929090658.png

I jak sam widzisz

screenshot-20230929090713.png

Wyprintowały się nowe wartości, a stare są nadal widoczne na konsoli... bo robiliśmy wszystko w locie, bez żadnej rekompilacji i ponownego odpalania programu!

Mamy nie tylko natychmiastowy feedback w "prawdziwym środowisku", to w dodatku napisaną implementacje.

I szybciej niż w klasycznym podejściu bez zmian w locie.

I to wszystko w kontekście tego co napisałeś "Potrzebujesz informacji zwrotnej na bieżąco, żeby się zorientować, czy kod się odpala i czy działa poprawnie".

jarekr000000
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: U krasnoludów - pod górą
  • Postów: 4712
3

Dowcip z debuggerem polega na tym, że albo:

  • trzeba mieć studencki program na kilkadziesiąt linijek,
  • albo zajebiste testy. (fakt TDD tu nie ma nic do rzeczy, bo właśnie dla debuggera często pisze się testy pod bugi )

Inaczej przeklikanie się do miejsca gdzie chcemy (np. przygotowanie danych) kasuje cały zysk z korzystania z tego degugerra.
Właśnie siedziałem tydzień nad pisaniem takiego testu (dla kodu 3rd party) i w końcu tego debuggera nie podpiąłem, bo jak już odtworzyłem całą sytuację w teście - to się wyjaśniło co się dzieje...

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
0
WeiXiao napisał(a):

Załóżmy że piszemy jakiś kod który ma pobrać dane i coś z nimi zrobić, zaczynamy od pustego kodu

No i piszemy sobie sygnaturę funkcji, która przyjmuje parametry i zwraca wynik.
Potem testy do niej.
A potem implementujemy funkcję. Możemy po Twojemu, można po prostu ją napisać, bez znaczenia.

Wyprintowały się nowe wartości, a stare są nadal widoczne na konsoli... bo robiliśmy wszystko w locie, bez żadnej rekompilacji i ponownego odpalania programu!

Yay, to teraz wystarczy nie wyłączać nigdy komputera, i nasze dzieło przetrwa ludzkość!

I szybciej niż w klasycznym podejściu bez zmian w locie.

Tak, dobry debugger jest lepszy od słabego debuggera, a słaby lepszy od braku.
No i pewnie takie klepanie kodu w prawie interaktywnym środowisku jest lepsze dla początkujących.

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
4

@somekind:

Potem testy do niej.
A potem implementujemy funkcję. Możemy po Twojemu, można po prostu ją napisać, bez znaczenia.

Dokładnie, kolejność

  • Test -> Implementacja

  • Implementacja -> Test

Rzadko kiedy ma znaczenie.

W dyskusjach nt. TDD ludzie skupiają się na testach (że testowaniu czy implementacja działa) oraz jakichś kolorkach Red/Green,
a prawdziwą wartością jest to, że wychodząc od testu jest na tobie wymuszony lepszy API design dla usera (lepszy, niż gdybyś nie poużywał tego API).

I oczywiście można uznać że to w sumie "drivuje" twój development, więc jest to TDD, a zatem ok.

Aczkolwiek moim zdaniem to całe TDD odnosi sukces "przez przypadek", bo oni skupiają się tam na jakichś niezbyt istotnych rzeczach zamiast wprost napisać np. o tym API design

  • Run all tests. The new test should fail for expected reasons
    • This shows that new code is actually needed for the desired feature. It validates that the test harness is working correctly. It rules out the possibility that the new test is flawed and will always pass.
  • Write the simplest code that passes the new test
    • Inelegant or hard code is acceptable, as long as it passes the test. The code will be honed anyway in Step 5. No code should be added beyond the tested functionality.
  • All tests should now pass
    • If any fail, the new code must be revised until they pass. This ensures the new code meets the test requirements and does not break existing features.

Gdyby TDD brzmiało tak:

  • Write contracts for your code
  • Write test, so this way you can understand user's or caller's perspective better by interacting with current design
  • Apply design changes (if needed)
  • Write Implementation
  • Run tests.

To moim zdaniem byłoby to nie tylko sensowniejsze (bo bullshit został wycięty), to dodatkowo o wiele bardziej uproszczone, przez co nie byłoby setek dyskusji nt. TDD.

Miang
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1792
0
WeiXiao napisał(a):
  • Write contracts for your code

WĘŻYKIEM PODKREŚLIĆ
tego najczęściej brakuje

G8
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2000
1

@WeiXiao wyjaśnia tutaj czym jest debugger i jak działa. Ciekawe, że ludzie którzy piszą testy nie wiedzą czym jest debugger. Może debugger to już przeżytek?

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
0

@gajusz800

Prędzej bym obstawiał że ludzie programują w środowiskach gdzie debugger jest toporny lub trzeba się nagimnastykować aby go używać, a zatem się im nie chce.

Ciekawe jak to jest faktycznie

AN
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 989
2

No kwestia tego, że technologia debuggerów często nie nadążała za rozwojem i niestety ja zrezygnowałem z tego i już nie jestem przyzwyczajony. Mówię tu o np. wsparciu w IDE rozwiązań typu Docker w WSL, docker-compose itd. nie zawsze było to proste do podłączenia. Teraz na najnowszych IDE może się uda ale na 2-3 letnich nie bardzo

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
somekind napisał(a):
WeiXiao napisał(a):

Załóżmy że piszemy jakiś kod który ma pobrać dane i coś z nimi zrobić, zaczynamy od pustego kodu

No i piszemy sobie sygnaturę funkcji, która przyjmuje parametry i zwraca wynik.
Potem testy do niej.
A potem implementujemy funkcję. Możemy po Twojemu, można po prostu ją napisać, bez znaczenia.

@WeiXiao: Robi się dokładnie tak jak @somekind pisze. To że polemizujesz z tym pokazuje po prostu bardzo jasno, że nie łapiesz tego podejścia jeszcze na tyle że móc je krytykować.

PS: Ja najpierw piszę test pod nieistniejącą funkcję bez sygnatury. Wtedy jest błąd kompilacji (który ja też traktuje jako fail testów), i dopiero potem definiuję funkcję. Potem w teście dodaję parametry, co znowu powoduje błąd kompilacji, i dopiero potem definiuje argumenty. Myślę że w ten sposób można jeszcze lepiej projektować kod testami. Ale deklaracja funkcji najpierw przed napisaniem implementacji też jest spoko.

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
1

@Riddle

że nie łapiesz tego podejścia jeszcze na tyle że móc je krytykować.

To gdzie zatem jest ta wartość? bo poza API designem jej nie widzę

Escanor16
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 367
3

Nie prościej jest napisać najpierw interfejs z metodami do testowania, wstrzyknąć go do testu, zrobić assercje a potem jak człowiek zaimplementować w odpowiednim momencie w serwisie logikę do tych metod?

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
0
Escanor16 napisał(a):

Nie prościej jest napisać najpierw interfejs z metodami do testowania, wstrzyknąć go do testu, zrobić assercje a potem jak człowiek zaimplementować w odpowiednim momencie w serwisie logikę do tych metod?

Prościej, może i prościej. Ale czy lepiej?

Weź pod uwagę że sygnatura funkcji też musi być zaprojektowana, więc lepiej napisać użycie funkcji zanim jej użyjesz, tak jakbyś projektował jej interfejs podczas pisania; i potem według zasad TDD powinieneś zobaczyć czerwony pasek (w tym wypadku błąd kompilacji), i wtedy możesz dodać sygnaturę. Ktoś powiedziałby że to na to samo wychodzi, ale nie do końca - projektując sygnaturę od "drugiej strony" czyli od strony piszącego kod (użytkownika funkcji), możemy ją lepiej zaprojektować.

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
1
WeiXiao napisał(a):

Dokładnie, kolejność

  • Test -> Implementacja

  • Implementacja -> Test

Rzadko kiedy ma znaczenie.

Dla mnie ma znaczenie, bo jak jeśli testy, to mam:

  • działającą i aktualną dokumentację;
  • wiedzę o tym, co mam zaimplementować;
  • wiedzę o tym, ile mi jeszcze zostało do zakończenia pracy i czy już skończyłem.

Zaczynając od implementacji nie mam nic, i nie wiem na jakim etapie pracy jestem.

Aczkolwiek moim zdaniem to całe TDD odnosi sukces "przez przypadek", bo oni skupiają się tam na jakichś niezbyt istotnych rzeczach zamiast wprost napisać np. o tym API design

Ja nie wypowiadam się o TDD, bo go nie stosuję. Za to bawi mnie argument o tym designie API. Ktoś poza początkującymi tego potrzebuje?

WeiXiao napisał(a):

Prędzej bym obstawiał że ludzie programują w środowiskach gdzie debugger jest toporny lub trzeba się nagimnastykować aby go używać, a zatem się im nie chce.

Ciekawe jak to jest faktycznie

Dla większości ludzi debugger to po prostu debugger, używa się go w celu znalezienia błędu i naprawy go, a nie do pisania kodu od początku do końca.

jarekr000000
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: U krasnoludów - pod górą
  • Postów: 4712
3
WeiXiao napisał(a):

@gajusz800

Prędzej bym obstawiał że ludzie programują w środowiskach gdzie debugger jest toporny lub trzeba się nagimnastykować aby go używać, a zatem się im nie chce.

Ciekawe jak to jest faktycznie

Faktycznie jest tak, że przez kilkanaście lat używałem deguggera nagminnie od Basica, przez C/C++ i naprawde wypasione deguggerey w javie (zdalny debug, podmiana kodu, cofanie, pułapki na zmiany zmiennych, wyrażenia itp).
A potem przestałem i to nadal pisząc w javie. Przy czy nigdy nie był to mój cel, po prostu nagle zorientowałem się, że debugger odpalam bardzo od święta.

somekind napisał(a):

Aczkolwiek moim zdaniem to całe TDD odnosi sukces "przez przypadek", bo oni skupiają się tam na jakichś niezbyt istotnych rzeczach zamiast wprost napisać np. o tym API design

Ja nie wypowiadam się o TDD, bo go nie stosuję. Za to bawi mnie argument o tym designie API. Ktoś poza początkującymi tego potrzebuje?

Jestem wiecznym początkującym więc nie dziwie się, że potrzebuje. Zwykle od razu mam w głowie jakieś API, ale na etapie pisania testu często ten koncept całkiem się rozlatuje.
Tu chyba chodzi o to, że dość łatwo stworzyć API nietestowalne, i potem mieć problem jak tu napisać testy (i po co? skoro działa).

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
2

@somekind

Za to bawi mnie argument o tym designie API. Ktoś poza początkującymi tego potrzebuje?

To chyba mierny żart. Poprogramuj w czymś co nie jest .NETem (C, C++, co tam chcesz) to zobaczysz że chociażby dobrze zaprojektowany BCL to nie takie hop siup.

Masz całe książki na ten temat, jak robić to sensownie.

https://www.amazon.com/Framework-Design-Guidelines-Conventions-Addison-Wesley/dp/0135896460

Jeżeli "od buta", podchodząc pierwszy raz do problemu, bez świadomości jakie problemy się ujawnią podczas implementacji jesteś w stanie zadesignować API które:

  • Łatwe do odkrycia
  • Łatwe do użycia
  • Bezpieczne do użycia
  • Upraszcza na tyle, ile się da
  • Przyszłościowe

To wow.

Tutaj masz playlistę godzinnych spotkań gdzie ludzie debatują nt. (min) API design, a ty samemu takie rzeczy od buta robisz?

Za mało ci płacą

Dla większości ludzi debugger to po prostu debugger, używa się go w celu znalezienia błędu i naprawy go, a nie do pisania kodu od początku do końca.

No a czemu, jeżeli zalety są wymierne?

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
0
WeiXiao napisał(a):

Tutaj masz playlistę godzinnych spotkań gdzie ludzie debatują nt. (min) API design, a ty samemu takie rzeczy od buta robisz?

Tylko ja nie projektuję API tysięcy klas i metod, co najwyżej pojednyczych fragmentów systemu w znanej mi domenie biznesowej.

No a czemu, jeżeli zalety są wymierne?

Przyczyny pewnie są różne, wiele osób może np. czuć opór przed uruchamianiem kodu, który wie jak naprawić bez debugowania.

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
1

@somekind:

Tylko ja nie projektuję API tysięcy klas i metod, co najwyżej pojednyczych fragmentów systemu w znanej mi domenie biznesowej.

Już się retoryka zmieniła z kto poza żuniorami potrzebuje się zastanawiać na jakimś tam API do ja nic takiego nie muszem? :P

Jakby... no fajnie że większość kodu który piszesz jest w bardzo dobrze ci znanej domenie oraz tylko jakieś małe zmiany w kodzie robisz, ale nie wszystkich praca tak wygląda. Patrz bardziej z perspektywy osób tworzących biblioteki, no bo co do zasady pisanie "cora" w twojej appce powinno być bardzo podobne do pisania bibliotek.

Zresztą, nawet to co napisałeś imo nie oznacza że nie warto pchać wysiłku w design czy review designu.

Przyczyny pewnie są różne, wiele osób może np. czuć opór przed uruchamianiem kodu, który wie jak naprawić bez debugowania.

Ale jakie naprawianie jeżeli piszemy o wytworzeniu wersji nr. 1? :(

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
1
WeiXiao napisał(a):

Już się retoryka zmieniła z kto poza żuniorami potrzebuje się zastanawiać na jakimś tam API do ja nic takiego nie muszem? :P

Nie napisałeś o jakie API Ci chodzi, nagle zacząłeś rzucać całymi frameworkami. Dla mnie API to każda klasa, którą dany "moduł" wystawia publicznie, i w tym znaczeniu używam tego akronimu.

Jakby... no fajnie że większość kodu który piszesz jest w bardzo dobrze ci znanej domenie oraz tylko jakieś małe zmiany w kodzie robisz, ale nie wszystkich praca tak wygląda. Patrz bardziej z perspektywy osób tworzących biblioteki, no bo co do zasady pisanie "cora" w twojej appce powinno być bardzo podobne do pisania bibliotek.

W pracy utrzymuję jakieś 20 bibliotek na wewnętrzne potrzeby firmy.
Co konkretnie chcesz wiedzieć?

Zresztą, nawet to co napisałeś imo nie oznacza że nie warto pchać wysiłku w design czy review designu.

Czy ja gdzieś pisałem, że nie warto? o.O
Tylko najpierw się projektuje, a potem robi. Gdy odwrócisz kolejność, to w efekcie masz JS.

Ale jakie naprawianie jeżeli piszemy o wytworzeniu wersji nr. 1? :(

A to wersja nr 1 nie musi działać poprawnie?

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
1

@somekind:

Nie napisałeś o jakie API Ci chodzi, nagle zacząłeś rzucać całymi frameworkami. Dla mnie API to każda klasa, którą dany "moduł" wystawia publicznie, i w tym znaczeniu używam tego akronimu.

Jakimi całymi frameworkami? Oni tam omawiają właśnie m.in konkretne klasy tworzące framework.

API to nie tylko klaski w module, ale również to, co te klaski wystawiają.

W pracy utrzymuję jakieś 20 bibliotek na wewnętrzne potrzeby firmy.

No to jeżeli piszesz biblioteki które są używane przez kogoś, to w takich przypadkach powinieneś włożyć wysiłek w to, aby ich API było jak najwyższej jakości.

Tylko najpierw się projektuje, a potem robi. Gdy odwrócisz kolejność, to w efekcie masz JS.

Jeżeli masz pełną wiedzę na poziomie konceptualnym i technicznym jak coś zaimplementować i jakie są problemy to tak, ale w innych przypadkach nie.

Przykład: Podczas implementowania może ci wyjść że wypadałoby dodać jakąś obsługę błędu i zamiast zwracać X zwracasz Result<X>

A zatem: initial concept -> PoC/experimental implementation -> redesign (if needed) -> ...

A to wersja nr 1 nie musi działać poprawnie?

No może, a nawet wypadałoby, dlatego nie wiem czemu piszesz coś o naprawianiu.

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
1
WeiXiao napisał(a):

Jakimi całymi frameworkami? Oni tam omawiają właśnie m.in konkretne klasy tworzące framework.

Nie wiem, co oni tam konkretnie omawiają, przecież nie będę tracił czasu na oglądanie czegoś takiego. :D Zakładałem, że skoro .NET w tytule, to mowią o projektowaniu dotneta.

API to nie tylko klaski w module, ale również to, co te klaski wystawiają.

Przecież to właśnie napisałem.

No to jeżeli piszesz biblioteki które są używane przez kogoś, to w takich przypadkach powinieneś włożyć wysiłek w to, aby ich API było jak najwyższej jakości.

No i tak robię, tylko nie używam debuggera do projektowania.

A zatem: initial concept -> PoC/experimental implementation -> redesign (if needed) -> ...

No do PoCa raczej testów nie będę pisał. Tylko pisanie PoCów to jest inny temat.

No może, a nawet wypadałoby, dlatego nie wiem czemu piszesz coś o naprawianiu.

Bo czasem (1/100) zaimplementowanych funkcji się zdarzy, że test nie przechodzi tak bardzo, że trzeba odpalić pod debuggerem naprawić.

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
1

@somekind:

Przecież to właśnie napisałem.

Skądże, napisałeś:

Dla mnie API to każda klasa, którą dany "moduł" wystawia publicznie, i w tym znaczeniu używam tego akronimu.

A więc tak rząd wielkości wyżej, aczkolwiek rozumiem i to był tylko nitpick ;)

No i tak robię, tylko nie używam debuggera do projektowania.

Ja też nie. Ja używam debuggera do zaimplementowania kodu, który wymaga rozeznania, bo jest szybciej.

A implementacja może wpłynąć na design, bo jesteś świadomy problemów. Ile to razy ludzie mówią "gdybym to teraz pisał od 0, to bym poszedł do tego zupełnie inaczej"? nierzadko, dlaczego? bo teraz są świadomi m.in problemów, wyzwań czy też potencjalnych uproszczeń.

Jakbyś się skupił na tym przypadku

Jeżeli masz pełną wiedzę na poziomie konceptualnym i technicznym jak coś zaimplementować i jakie są problemy to tak, ale w innych przypadkach nie.
Przykład: Podczas implementowania może ci wyjść że wypadałoby dodać jakąś obsługę błędu i zamiast zwracać X zwracasz Result<X>
A zatem: initial concept -> PoC/experimental implementation -> redesign (if needed) -> ...

To byś chyba zrozumiał, bo cały czas piszesz z perspektywy jakbyś zawsze miał pełną wiedzę nt. danego problemu.

No do PoCa raczej testów nie będę pisał. Tylko pisanie PoCów to jest inny temat.

Czy Ty naprawdę nigdy nie piszesz kodu, co do którego najpierw musisz zrobić rozeznanie? WTF?

somekind
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
1
WeiXiao napisał(a):

A implementacja może wpłynąć na design, bo jesteś świadomy problemów. Ile to razy ludzie mówią "gdybym to teraz pisał od 0, to bym poszedł do tego zupełnie inaczej"? nierzadko, dlaczego? bo teraz są świadomi m.in problemów, wyzwań czy też potencjalnych uproszczeń.

Tak, po zdobyciu doświadczenia (albo feedbacku od użytkowników) można zmienić zdanie i można zrobić coś od nowa inaczej, wiele razy tak robiłem. Za każdym razem wychodząc od jakichś założeń i mając jakieś cele do osiągnięcia.
To nie wpływało na proces pisania kodu.

Jakbyś się skupił na tym przypadku

Jeżeli masz pełną wiedzę na poziomie konceptualnym i technicznym jak coś zaimplementować i jakie są problemy to tak, ale w innych przypadkach nie.
Przykład: Podczas implementowania może ci wyjść że wypadałoby dodać jakąś obsługę błędu i zamiast zwracać X zwracasz Result<X>
A zatem: initial concept -> PoC/experimental implementation -> redesign (if needed) -> ...

To byś chyba zrozumiał, bo cały czas piszesz z perspektywy jakbyś zawsze miał pełną wiedzę nt. danego problemu.

Ten przykład jest dla mnie mocno średni, bo to, czy mogę zwrócić Result<X> czy nie, nie zależy od mojego doświadczenia ani wiedzy, tylko od tego, czego oczekują użytkownicy danej biblioteki, a to poniekąd wynika z tego, co oferuje język.
A jeśli wiemy, że możemy informację o błedzie zwracać w ten sposób, to to robimy zawsze, z każdej metody w danej aplikacji (a przynajmniej każdej będącej częścią API), więc to nie jest coś, co wyjdzie podczas implementowania.

Czy Ty naprawdę nigdy nie piszesz kodu, co do którego najpierw musisz zrobić rozeznanie? WTF?

Piszę. Tylko przed napisaniem takiego kodu najpierw robię rozeznanie. :)
Kolejność jest taka:

  1. spike, którego wynikiem jest dokumentacja z opisem napotkanych problemów i ich rozwiązań. Tu piszę kod w dużej mierze do wyrzucenia, bez testów.
  2. solution design
  3. implementacja - tu już wiem, co i jak osiągnąć, mam zaprojektowane API, więc implementuję.

A tak w ogóle, to ja nawet sobie nie wiem jak można implementować debuggerem podczas tworzenia biblioteki, i nie mieć testów wcześniej. Przecież biblioteki samej z siebie nie ma jak uruchomić, testy są najprostszym sposobem.

LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8488
3

Nawiasem mówiąc ostatnio przeglądałem książkę Clean Code i autor radził rzucać wyjątki zamiast zwracać kod błędu.
Jest to zabawnie nieadekwatne, jeśli język oferuje lepsze abstrakcje. Nie wiem, jak działa Result w innych językach, ale w Rust jest to wartość, którą zwraca funkcja, ale ta wartość może zachować się podobnie co wyjątek, bo można to propagować dalej za pomocą operatora ?, który albo zwraca wartość czegoś, albo w przypadku błędu kończy funkcję i ten błąd się propaguje dalej
https://doc.rust-lang.org/std/result/#the-question-mark-operator-
ni pies, ni wydra, ale ogólnie lepsze moim zdaniem od obu podejść.

No ale Wujek Bob napisał, że trzeba robić wyjątki XD :P :) No ale po raz kolejny okazuje się, że porady na temat dobrych praktyk nie zawsze są uniwersalne, a często należy rozpatrywać pod kątem języka programowania, o którym pisze autor. I ograniczeń tego języka. Tak jak wzorce projektowe to często lista życzeń "jak powinien wyglądać język" i obchodzenie ograniczeń języka, tak "dobre praktyki" to często porady jak nie strzelić sobie w stopę pisząc w danym języku.

SL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1023
0
LukeJL napisał(a):

No ale Wujek Bob napisał, że trzeba robić wyjątki XD :P :) No ale po raz kolejny okazuje się, że porady na temat dobrych praktyk nie zawsze są uniwersalne, a często należy rozpatrywać pod kątem języka programowania, o którym pisze autor. I ograniczeń tego języka. Tak jak wzorce projektowe to często lista życzeń "jak powinien wyglądać język" i obchodzenie ograniczeń języka, tak "dobre praktyki" to często porady jak nie strzelić sobie w stopę pisząc w danym języku.

Wyjątki powstały, żeby nie sprawdzać błędów w każdym miejscu. Używanie wyjątków do wszystkiego to konwencjonalny sposób na obsługę błędów w takiej Javie i te 20 lat temu nikt nie myślał inaczej. Arguement, że wyjątki są do sytuacji wyjątkowych jest z d**y, bo to czy sytuacja jest wyjątkowa czy nie zależy od callera a nie od funkcji, która je rzuca.

To, że teraz popularne stały się return value nie zmienia faktu, że taka Java i jej biblioteka standardowa była projektowana pod takie podejście. Wiadomo, że to z złe podejście z wielu powodów (performance, czytelność, problem z zanieczyszczaniem sygnatury typów), ale taki już jest

KamilAdam
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Silesia/Marki
  • Postów: 5550
2

Nawiasem mówiąc ostatnio przeglądałem książkę Clean Code

spójrz w którym roku powstał CC. Grubo prze Funkcyjna Rewolucją w Javie i świadomością programistów Javy iż można używać Either<ErrorResult, OkResult> do obsługi błedów

No ale Wujek Bob napisał, że trzeba robić wyjątki XD

Nie zdziwię się jak w nowszych książkach będzie pisać żeby wyjątków nie używać
Wujek Bob nie krowa żeby zdania nie zmieniać. A jak zmienił zdanie to nawet lepiej. Nowa książkę można napisać. Szkoda tylko że nie napisze Clean Code 2.0 żeby właśnie wytłumaczyć iż rzucanie wyjątków to było dobre w 2008 a mamy już 2023 i jestesmy parę przetestowanych pomysłów dalej

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
2
KamilAdam napisał(a):

Nawiasem mówiąc ostatnio przeglądałem książkę Clean Code

spójrz w którym roku powstał CC. Grubo prze Funkcyjna Rewolucją w Javie i świadomością programistów Javy iż można używać Either<ErrorResult, OkResult> do obsługi błedów

No ale Wujek Bob napisał, że trzeba robić wyjątki XD

Nie zdziwię się jak w nowszych książkach będzie pisać żeby wyjątków nie używać
Wujek Bob nie krowa żeby zdania nie zmieniać. A jak zmienił zdanie to nawet lepiej. Nowa książkę można napisać. Szkoda tylko że nie napisze Clean Code 2.0 żeby właśnie wytłumaczyć iż rzucanie wyjątków to było dobre w 2008 a mamy już 2023 i jestesmy parę przetestowanych pomysłów dalej

No wiadomo ze książka musiała użyć przykładów z obecnie panującego stylu, ale to przecież nie jest istotą tej książki.

Istotą jest to, żeby pisać kod który jest: samoopisowy, czytelny, pokazuje intencje, nie wymaga komentarzy, prosty, nieprzekombinowany. I to jaknajbardziej jest nadal aktualne.

Języki się zmieniają, więc oczywiście że dochodzą nowe sposoby żeby uczytelnić kod; ale celem autora w "Clean Code" jest właśnie to żeby iść w stronę kodu który jest czytelny niż nie. To że przykłady użyte do obrazowania tego celu stają się out-of-date, to nie znaczy że idea za przykładami też.

Miang
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1792
0
slsy napisał(a):
LukeJL napisał(a):

No ale Wujek Bob napisał, że trzeba robić wyjątki XD :P :) No ale po raz kolejny okazuje się, że porady na temat dobrych praktyk nie zawsze są uniwersalne, a często należy rozpatrywać pod kątem języka programowania, o którym pisze autor. I ograniczeń tego języka. Tak jak wzorce projektowe to często lista życzeń "jak powinien wyglądać język" i obchodzenie ograniczeń języka, tak "dobre praktyki" to często porady jak nie strzelić sobie w stopę pisząc w danym języku.

Wyjątki powstały, żeby nie sprawdzać błędów w każdym miejscu. Używanie wyjątków do wszystkiego to konwencjonalny sposób na obsługę błędów w takiej Javie i te 20 lat temu nikt nie myślał inaczej.

obsługę błędów, nie obsługę zwracanych wartości

Arguement, że wyjątki są do sytuacji wyjątkowych jest z d**y, bo to czy sytuacja jest wyjątkowa czy nie zależy od callera a nie od funkcji, która je rzuca.

Funkcja znając swoja specyfikację wie co jest wartością zwracaną

To, że teraz popularne stały się return value nie zmienia faktu, że taka Java i jej biblioteka standardowa była projektowana pod takie podejście. Wiadomo, że to z złe podejście z wielu powodów (performance, czytelność, problem z zanieczyszczaniem sygnatury typów), ale taki już jest

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.