Czy da się uniknać DI?

0
Option<int> option = 1;
    
    option.Match(
        None: () => Console.WriteLine("default")
        Some: value =>
        {
            Console.WriteLine(value);
        });


//Normalna wersja

int? option = 1;

Console.WriteLine(option ?? "default");

Dalej nierozumiem czym się tak podniecacie w tym optionalu.

4

Zalet nie widać jak się nie umie z Optionali korzystać.
Tu jest przykład co się dzieje na nullu:

User user = userService.getUserFromDB(10001);
if ( user != null) {
    final Group group = user.getGroup();
    if ( group != null ) {
        final User owner = group.getGroupOwner();
        if ( owner != null ) {
            owner.sendMessage("hello there!!!");
        }
    }
}

I jak to wygląda po przejściu na Optional:

userService.getUserFromDB(10001)
.flatMap(user -> user.getGroup() )
.flatMap(group -> group.getGroupOwner() )
.ifPresent(user-> user.sendMessage("Hallo there!"));

Więcej w:
Dzisiaj mega długi tekst o M...
Monady Sronady część II W cz...

3

Odpowiadam w nowym poście, bo na komentarze musiałbym strasznie dużo nein, nein nein napisać. A tak zbiorczo:

A wyjątek też możesz po złapaniu przekazać jako obiekt w dół, lecz to już jest pewne zboczenie :-p - nohtyp 34 minuty temu

Either przekazuje problem lub obiekt. Więc w dół przekażesz albo wartość, albo dlaczego się nie udało. W przypadku wyjątku :

  • w góre dostajesz albo wartość, albo wyjątek. (gicio),
  • w dół? Możesz sobie zrobić Pair<Exception,T>... i właśnie zrobiłeś Eithera. Tylko kiepskiego.

Jeśli już pada argument o wydajności (na który czekałem) to znak, że liczba argumentów się skończyła :-) - nohtyp 24 minuty temu

Podałem to jako trzeci i dla mnie najmniej ważny argument. Niemniej, nie jest nonsensowny - dwa razy miałem do czynienia z systemami, które umarły na produkcji przez Exception Oriented Programming.
Słyszałem o wielu więcej takich przypadkach. Jest to dość częsty problem i oólnie rzutuje na dalszy rozwój JVM (np. rekursja ogonowa, a wyjątki). Dużo systemów rzuca pod spodem tonami niepotrzebnych (bo obsłużonych) exceptionów.

Ja bym tylko na rzecz monad dodał taki argument: monady dają Ci api, które naprawdę ciężko jest nadużyć i jednocześnie nie zauważyć. To fajne jeśli pracujesz z debilami. Natomiast wyjątki są i tak lepsze, ale niestety w firmach nikogo nie widziałem, kto by je mądrze projektował i używał z główą :-( - nohtyp 21 minut temu

Monad też można źle użyć i to bardzo. Szczególnie w językach imperatywnych Java, Kotlin, Scala. Typowo pierwsze użycie optionala to zwykle totalny Rak. (isPresent, get).

W sumie można powiedzieć, że wyjątki lepiej sprawdzają sie w implementowaniu bibliotek, natomiast do rzeźbienia w brązie lepiej mogą (chociaż nigdy tego nie widziałem) wypaść monady. - nohtyp 20 minut temu

Dokładnie nie. Obecne wyjątki są katastrofą przy implementacji bibliotek.
Przykład :driver SQL, który gdzieś tam ma jakieś executeQuery(String sql);
Co ta metoda ma zwracać?

Runtime exception? Ale wtedy nie wiadomo (z sygnatury) co przechwytywać, a może ktoś robi jakiegoś SQL Explorer i chce użytkownikowi pokazać co się dzieje.
A na takim poziomie zwykle checmy obsłużyć błąd.
Obecnie w javie jest w tej sytuacji użyty Checked exception, który np. zawsze zrobi nam tego stack trace... nawet jeśli mamy go (stack trace) w poważaniu.
Czasami fajnie jak Error to jakiś enum lub coś podobnego. Możemy sobie enuma wbić jako pole Exceptiona, lub zasymulować enuma hierarchią Exceptionów, ale zwykle widać od razu, że to lekka przesada jest.

Jeśli teraz na bazie tego Statement.executeQuery() robimy sobie wyższego poziomu funkcję ( typu getUserFromDB()) to wiadomo, że SQLException znaczy tyle, że
ktoś coś zrypał w kodzie, nie ma połączenia z bazą danych lub coś podobnego. Raczej nic, co obchodzi wywołującego getUserFromDB() i z czym ten ktoś mógłby sobie poradzić. Więc najlepiej zasiać panikę i rzucić RuntimeException, bo pewnie złożenie się kawałka procesu, który to wykonał to i tak najlepsza opcja.

W podejściu z Either, SQL.executeQuery powinien zwracać nam Eithera, którego albo obsługujemy od razu, bo chcemy użytkownikowi pokazać co jest problemem. (Jak np.: pisze z palca SQL)
Ewentualnie zamieniamy na RuntimeException jeśli to lży w naszym kodzie i SQL powinien być dobry (tylko coś nie wyszło :-) ). Wtedy dostaniemy Exception, z tym samym opisem błędu, ale ze stack trace zaczynającym się, nie gdzieś w czeluściach SQL drivera, tylko w metodzie, która to wywołała (i pewnie ma błąd).

Obecnie część bibliotek, żeby nie tworzyć tych sztucznych CheckedException zwraca jakieś KODY BŁEDU lub specjalne obiekty (Status, Result).

Przykład przykry: Załóżmy, że robisz jakieś indeksowanie dysku i chcesz po kolei przeczytać każdy plik ( wiadomo, że do wielu z nich nie dostaniesz dostępu...)
Files.newInputStream rzuca Ci wyjątkiem 200 razy na sekundę. Może się okazać, że przez to rzucanie wyjątkami cały ten proces trwa kilka razy dłużej nić gdyby ( jak dziadowie w C) mieć po prostu status otwarcia pliku....

0

A to nie jest przypadkiem tak że jak ktoś musi używać optionala to znaczy, że jest mało uważny :---|

HA, to ci którzy nie muszą go używać są lepsi. :-| - Wiedziałem....

4
._. napisał(a):

A to nie jest przypadkiem tak że jak ktoś musi używać optionala to znaczy, że jest mało uważny :---|

HA, to ci którzy nie muszą go używać są lepsi. :-| - Wiedziałem....

Dokładnie, masz rację.

Jeszcze tylko znajdź mi programistę co jest uważny 6 godzin dziennie 5 dni w tygodniu, przez parę miesięcy, i jak dla mnie może nawet serwisy w asmie trzaskać. Uważnemu kompilator tylko zawadza. (Btw. jak się ma tony makr w asmie to całkiem sprawnie się kod pisze, tylko trzeba uważać na rejestry i stos.. ciągle).

0
jarekr000000 napisał(a):
._. napisał(a):

A to nie jest przypadkiem tak że jak ktoś musi używać optionala to znaczy, że jest mało uważny :---|

HA, to ci którzy nie muszą go używać są lepsi. :-| - Wiedziałem....

Dokładnie, masz rację.

Jeszcze tylko znajdź mi programistę co jest uważny 6 godzin dziennie 5 dni w tygodniu, przez parę miesięcy, i jak dla mnie może nawet serwisy w asmie trzaskać. Uważnemu kompilator tylko zawadza. (Btw. jak się ma tony makr w asmie to całkiem sprawnie się kod pisze, tylko trzeba uważać na rejestry i stos.. ciągle).

Jak ktoś jest nieuważny to nawet optional mu nie pomoże, równie dobrze może zapomnieć wrzucić wartość do optionala.
No, chyba że piszemy metodą wszystko do optionala, bo poco być uważnym.

Dla mnie ten temat jest błachy, za miesiąc wszyscy zaczną używać NullObject, bo ktoś na prezentacji znowu odkryje jakiś stary wzorzec.

0

Można albo zwracać nulle i przy każdej metodzie zgadywać czy akurat null może się pojawić albo można zwracać Optionala tam gdzie wartości może nie być i mieć pewność, że jeśli sygnatura metody pokazuje coś to to dostaniemy.

0
danek napisał(a):

Można albo zwracać nulle i przy każdej metodzie zgadywać czy akurat null może się pojawić albo można zwracać Optionala tam gdzie wartości może nie być i mieć pewność, że jeśli sygnatura metody pokazuje coś to to dostaniemy.

Czy twoim zdaniem metoda GetUserFromDB(). Potrzebuje dodatkowo optionala jako extra sygnatury.?

Ewentualnie DataBaseReader.GetUser()

0

Jeśli użytkownika może nie być to tak

1

Moim zdaniem w 99% usera zawsze może nie być w bazie.
Zawsze komuś może przyjść do głowy wpisać niewłaściwy nik czy id usera.

Nie potrzebuje do tego ekstra sygnatury.

0

Mówisz o specyficznym przypadku, a mi chodzi o zasadę: jeśli zwracana wartość może być lub może być null to lepiej zwrócić Optional (ewentualnie either z wyjaśnieniem)

0
._. napisał(a):

Czy twoim zdaniem metoda GetUserFromDB(). Potrzebuje dodatkowo optionala jako extra sygnatury.?

To jest akurat przypadek z życia wzięty.

Kilka lat temu Springowe repozytoria w Javie zaczęły używac optionala. Wczesniej metoda:

T findOne(ID primaryKey);

Powodowała ciągle problemy. Część ludzi sprawdzała czy będzie null. Część oczekiwała, że jak nie ma obiektu to powinien polecieć wyjątek....
Jak ktoś był uważny to poszukał w dokumentacji i sprawdził. A jak nie był uważny, to pomyliło mu się np. z innym popularnym javowym frameworkiem, gdzie odpowiednik (load (by id)) . rzucał takim exceptionem.

Dlatego, aby uniknąć takich zagwozdek promują teraz:

<S extends T> Optional<S> findOne(Example<S> example);
0

Wracając do pierwszego postu :) Wg. mnie to kompletnie wypaczono pojęcie DI - zależności to użycie obiektu jakiejś klasy w innej, injection to sposób w jaki instancja zależności dostaje się do obiektu, który od niej zależy. Popularnie DI oznacza użycie jakiegoś kontenera, frameworku czy innego ustrojstwa odpowiedzialnego za magiczne tworzenie potrzebnych obiektów zależności. Przez lata dało się zwyczajnie inicjować obiekty przez konstruktor, settery, albo tworząc instancje zależności przez new wewnątrz klasy zależnej. Większość wzorców konstrukcyjnych (fabryki, proxy) powstała po to, żeby jakoś ułatwić / uelastycznić wstrzykiwanie zależności.

1

Tyle że settery to zło i trzeba je tępić. Jeśli mamy jakiś złożony obiekt to jak już można z buildera skorzystać...
Np. DataSource z Apache (DBCP) jest usłany setterami, a szczerze mówiąc nie wiem czemu

0

Tyle że settery to zło i trzeba je tępić. Jeśli mamy jakiś złożony obiekt to jak już można z buildera skorzystać...
Np. DataSource z Apache (DBCP) jest usłany setterami, a szczerze mówiąc nie wiem czemu

Przecież samo DDD promuje wstrzykiwanie zależności do metod ustawiających, zmieniających stan obiektu.
A ile razy ustawiasz ten seter i co się stanie, jeśli go nie ustawisz.?

1
scibi92 napisał(a):

Tyle że settery to zło i trzeba je tępić. Jeśli mamy jakiś złożony obiekt to jak już można z buildera skorzystać...
Np. DataSource z Apache (DBCP) jest usłany setterami, a szczerze mówiąc nie wiem czemu

Zależy jak na to patrzeć. Według mnie settery czasami mają jakiś tam sens (w legacy kodzie czy gdzieś, gdzie nie jesteś zmienić pewnych podejść) pod warunkiem, że klasa nie ma zdefiniowanego bezargumentowego konstruktora. Konstruktor powinien zawsze tworzyć obiekt, który jest w co najmniej minimalnym stopniu poprawny -> jestem w stanie wywołać każdą metodę na danym obiekcie i nic nie wykrzaczy się jakimś dzikim NPE czy innym błędem. Dodając jeszcze obostrzenie, że dany setter nie jest w stanie zmienić tego stanu rzeczy to jestem w stanie go akceptować.

Niestety, częściej spotykałem się z podejściem, że Builder był stosowany jako synonim bezargumentowego konstruktora zrobiony w modny sposób (tak jakby to coś zmieniało czy stworzę niepoprawny obiekt przez Builder'a czy przez bezargumentowy konstruktor) niż jako wzorzec służący do tworzenia skomplikowanych obiektów.

0
scibi92 napisał(a):

Tyle że settery to zło i trzeba je tępić. Jeśli mamy jakiś złożony obiekt to jak już można z buildera skorzystać...

To który sposób wstrzykiwania zależności wybierzesz i jakie ma on wady to już kwestia wtórna. Settery ustawiające zależności klasy to faktycznie złooooo, ale wciąż dużo lepiej niż bezargumentowy konstruktor i @Autowire na prywatnych polach.

Staram się pilnować, żeby nie dało się utworzyć kalekiego obiektu, czyli sam używam w 99% przypadków konstruktora przyjmującego wszelkie niezbędne parametry i tyle, możne na nim być nawet @Autowire, czy inne @Inject, ewentualnie prosta metoda fabrykująca też może być ok jak trzeba coś uczytelnić.
Klasycznego buildera nie używam, a już używanie go bo obiekt jest złożony uważam za szczególnie nieszczęśliwy pomysł - to jest raczej powód do uproszczenia obiektu i ograniczenia liczby zależności. Moment w którym builder się przydaje, to parametry lub zależności opcjonalne, wtedy wygląda to z zewnątrz tak:

new DependatnClass.Builder(compulsoryDependency, compulsoryProperty)
  .optionalDependency(optionalDependency)
  .optionalProperty(optionalProperty)
  .build()

Wewnątrz wywoływany jest na ogół wieloargumentowy konstruktor klasy z wartościami domyślnymi, lub ustawionymi w builderze, bo takie rozwiązanie pozwala wciąż mieć final na polach klasy. W sumie builder to efekt siermiężności Javy - w takim Kotlinie doskonale zastępują go parametry nazwane i opcjonalne, no i wrzucenie null jako wartości skończy się opierdolem od kompilatora, a nie klienta, ale to już osobna historia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1