Czy uzywajac kontenera nie powinno sie nigdzie dawac new?

Czy uzywajac kontenera nie powinno sie nigdzie dawac new?
GO
  • Rejestracja:prawie 21 lat
  • Ostatnio:prawie 5 lat
0

Czy jak w projekcie uzyty jest ninject lub autofac to nigdzie nie powinno sie uzywac new?

Trafiłem w jakimś kursie na taką linijkę (pomimo używania kontenera):

Kopiuj
var client = new HttpClient();
clien.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
5

Kontener powinien być wykorzystywany do pobierania zależności (serwisów) - wynika to stąd, że w Twoich serwisach powinieneś opierać się na interfejsach, których konkretne implementacje powinien znać / łączyć dopiero kontener (na tym polega cała idea DI).

Za pomocą new powinieneś tworzyć DTO oraz inne tego typu obiekty, których wybór / zachowanie / itd. nie różni się w runtime'ie (takie obiekty nie są formalnie w ogóle zależnościami Twojego serwisu).

Opierając się na Twoim przykładzie: najprawdopodobniej HttpClient powinieneś pobierać z kontenera, podczas gdy MediaTypeWithQualityHeaderValue zostało prawidłowo utworzone za pomocą new.


edytowany 1x, ostatnio: Patryk27
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
3

To zalezy gdzie tworzy sie nowy obiekt- kontekst jest wszystkim. Ciezko odpowiedziec bez tego. Ogolnie tam gdzie sie da najlepiej stosowac Dependency Injection i wykorzystywac kontener do tworzenia obiektow. Natomiast w tym konkretnym przypadku ktory podales z HttpClient to nie powinno sie tworzyc nowej instacji za kazdy razem kiedy chcemy wykonac request pod ten sam adres.

HttpClient is intended to be instantiated once and reused throughout the life of an application. The following conditions can result in SocketException errors:
Creating a new HttpClient instance per request.
Server under heavy load.
Creating a new HttpClient instance per request can exhaust the available sockets.

Zrodlo


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus
WeiXiao
Ogolnie tam gdzie sie da najlepiej stosowac Dependency Injection i wykorzystywac kontener do tworzenia obiektow. Natomiast w tym konkretnym przypadku ktory podales z HttpClient to nie powinno sie tworzyc nowej instacji za kazdy razem kiedy chcemy wykonac request pod ten sam adres. ale DI chyba nie implikuje tworzenia nowej instancji za każdym razem, czy źle rozumiem AddSingleton?
Aventus
@WeiXiao: Jeśli zarejestrujesz coś w kontenerze jako singleton to jak najbardziej, nowa instancja nie będzie tworzona za każdym razem. Zwróć jednak uwagę że odnosiłem się do Tworzenia HttpClient przy użyciu new, bez kontroli cyklu życia obiektu tworzącego HttpClient.
GO
  • Rejestracja:prawie 21 lat
  • Ostatnio:prawie 5 lat
0

@Aventus: czyli np wydzielic HttpClient do osobnej klasy i zrobic go jako statycznego np:

Kopiuj
public static class ClientHelper
{
  public static HttpClient Client {get; private set;}
  public static void Init()
  {
    Client = new HttpClient();
    Clien.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  }
}
leggo
Słyszałem i czytałem, że każda klasa z końcówką ~Helper, ~Manager, ~Utils to antypatterny i mogą kusić do pisania nieczystego kodu ;)
Aventus
@leggo: to prawda, z serwisami tez należy być ostrożnym. Zresztą ja serwisów prawie w ogóle nie stosuję, są lepsze metody.
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
2

Jeśli masz możliwość wstrzykiwać zależności to ja bym stworzył dedykowaną klasę (np. MyRequestService) dla konkretnego requestu. Ta klasa wiedziała by po jakim kluczu wyciągnąć potrzebny URL np. z konfiguracji. Następnie wyabstrahował bym to do interfejsu (w celu podmienienia tego w testach) i zarejestrował tą implementację wraz z interfejsem w kontenerze, jako singleton. Wtedy kontener zajmie się prawidłowym zarządzaniem "życia" tego obiektu.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 5 godzin
3

Wtrącę swoje dwa grosze, chociaż lekko dywaguję :]

Kontener powinien być wykorzystywany do pobierania zależności (serwisów) - wynika to stąd, że w Twoich serwisach powinieneś opierać się na interfejsach, których konkretne implementacje powinien znać / łączyć dopiero kontener (na tym polega cała idea DI).
Za pomocą new powinieneś tworzyć DTO oraz inne tego typu obiekty, których wybór / zachowanie / itd. nie różni się w runtime'ie (takie obiekty nie są formalnie w ogóle zależnościami Twojego serwisu).

Wstrzykiwanie zależności można łączyć z polimorfizmem, ale samo w sobie wstrzykiwanie nie ma z polimorfizmem nic wspólnego.

In software engineering, dependency injection is a technique whereby one object (or static method) supplies the dependencies of another object. A dependency is an object that can be used (a service). An injection is the passing of a dependency to a dependent object (a client) that would use it. The service is made part of the client's state.[1] Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.
The intent behind dependency injection is to decouple objects to the extent that no client code has to be changed simply because an object it depends on needs to be changed to a different one. This permits following the Open / Closed principle.

changed to a different one możne oznaczać, że np raz wstrzykujemy stringa 'kasia', a raz 'basia', albo raz wstrzykujemy HttpClienta łączącego się do klastra A, a raz do klastra B.

Robienie interfejsów z jedną produkcyjną implementacją to już w ogóle moim zdaniem bezsens (YAGNI), ale mam przeczucie, że w C# jest dość popularne.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
WeiXiao
Robienie interfejsów z jedną produkcyjną implementacją to już w ogóle moim zdaniem bezsens (YAGNI), ale mam przeczucie, że w C# jest dość popularne. Niestety.
KE
Niestety, nie tylko w c# :(
KL
Akurat tego teraz widzę sporo w Javie, którą dostałem do łapek i się zastanawiam co autora dręczyło w dzieciństwie...
leggo
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 4 lata
  • Lokalizacja:Chorzów
  • Postów:65
0

Przykład z mojego podwórka:
Stwórz sobie fabrykę abstrakcyjną Clienta Http.
I ją możesz sobie wstrzykiwać, a nie będzie Cię kłuło w oczy, że masz gdzieś 'new'

Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
0

@Wibowit:

Robienie interfejsów z jedną produkcyjną implementacją to już w ogóle moim zdaniem bezsens (YAGNI), ale mam przeczucie, że w C# jest dość popularne.

Ale to chyba nie było odniesienie do tego co pisałem?


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
Zobacz pozostałe 12 komentarzy
Aventus
Nie no rozumiem, to ma sens (odnośnie dogmatyzmu, chociaż też trzeba uważać aby nie pójść w drugą stronę skrajności). Tylko że jak już napisałem, idąc tą logiką w obu przypadkach mamy do czynienia z robieniem czegoś pod kątem testów.
Wibowit
Tak, ale wstawienie słówka virtual jest znacznie mniejszą ingerencją. Jest znacznie mniej dodatkowego kodu i nie ma problemów z nawigacją po kodzie produkcyjnym (nie trzeba się przebijać przez interfejs, by dotrzeć do implementacji). Zresztą w Javie/Scali też robiłem pewne zmiany pod testy, np zmieniałem metody z private na protected, by je nadpisać w testach (ale to akurat rzadko). Trzeba sobie rozważyć za i przeciw, przetestować swoje pomysły na rzeczywistym kodzie i wyciągnąć wnioski: czy rozwiązanie jest dobre czy nie. U mnie nadpisywanie metod w testach działa :)
Aventus
Nie zgadzam się co do tego że używanie virtual jest mniejszą ingerencją ponieważ- jak już wspomniałem- narusza pryncypia OOP, no ale ok- dogmaty. Jak sam piszesz, dla Ciebie to działa. Ja nie jestem tego zwolennikiem, i może na tym warto zakończyć dyskusję ;)
somekind
@somekind z jakiegoś powodu bardzo nie lubi nadpisywania metod bądź częściowych mocków - ja po prostu nie lubię łamania SRP (czyli mieszania logiki biznesowej z zależnościami infrastrukturalnymi) i słabego designu (wydzielenie klasy odpowiedzialnej za komunikację ułatwia jej reużycie, w przeciwnym przypadku trzeba kopiować albo dziedziczyć). Brak tworzenie mutantów w testach czy zbędnych z biznesowego punktu widzenia metod wirtualnych to tylko dodatkowy zysk mający wpływ na czystość i czytelność kodu.
neves
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Kraków
  • Postów:1114
1

Najlepiej to by było zacząć od podstaw i opowiedzieć na pytanie po co w ogóle wstrzykujemy? co chcemy przez to osiągnąć? przecież nie robimy tego bo tak :D

  • wstrzykujemy po to by móc podmienić implementację wstrzykiwanego typu bez modyfikacji klasy do której wstrzykujemy
  • a potrzebujemy podmieniać implementację przede wszystkim na potrzeby testów by móc testować daną klasę

Więc jak piszemy test dla danej klasy to od razu mamy odpowiedź czy potrzebujemy by dana zależność była wstrzykiwana czy nie.
A jak nie piszemy testu, to zastanówmy się jakbyśmy testowali daną klasę, to czy byśmy chcieli testować w izolacji od danej zależności czy nie, jeśli w izolacji to mamy kandydata na wstrzyknięcie, jeśli nie to możemy użyć "new".


WeiXiao
To fakt, że nie trzeba robić później N * new w ctorze nie jest istotną i wystarczającą zaletą? :P
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około 2 godziny
0

Robienie interfejsów z jedną produkcyjną implementacją to już w ogóle moim zdaniem bezsens (YAGNI), ale mam przeczucie, że w C# jest dość popularne.

bo to nie java i inaczej wszystko trzeba by było oznaczyć jako virtual żeby to zamockować do unit testów, albo używać narzędzi które mogą co prawda pozwalać na zmianę implementacji nawet statycznych klas, ale operują na ILCode bezpośrednio, poniżej poziomu języka i trzeba zaufać jakiejś magii co jest czasem nieintuicyjne; łatwo też gdzieś zgubić konfigurację i dopuścić faktyczną implementację do testów, potem nagle po kilku miesiącach ktoś sprawdza czemu testy się wolno wykonują i okazuje się że lecą zapytania do rzeczywistej bazy danych albo dysku

też nie po to domyślnie metody i własności nie są wirtualne żeby je spowalniać do poziomu javy, a posiadanie interfejsu ma zazwyczaj swoje korzyści w przyszłości kiedy nagle chcemy część kodu wydzielić do biblioteki i nagle potrzebujemy drugiej implementacji - poza tym to dosłownie dwa kliknięcia - extract interface -> ok; można trzymać na początku w tym samym pliku


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 1x, ostatnio: obscurity
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 5 godzin
1

Niektórzy pewnie będą smutni, że dygresja się rozwija, ale nadarzyła się świetna okazja do wojenki Java vs C# :]

łatwo też gdzieś zgubić konfigurację i dopuścić faktyczną implementację do testów, potem nagle po kilku miesiącach ktoś sprawdza czemu testy się wolno wykonują i okazuje się że lecą zapytania do rzeczywistej bazy danych

Przypadkowo zdarzyło ci się skonfigurować bazę w testach? Zainteresuj się wstrzykiwaniem zależności - nie wstrzykniesz konfiguracji, to jej nie będzie :)

też nie po to domyślnie metody i własności nie są wirtualne żeby je spowalniać do poziomu javy

Masz bardzo kiepskie pojęcie na temat JVMa i dlatego opowiedziałeś bajkę oderwaną od rzeczywistości. To w C# usuwa się virtual z metod, po to by działały tak szybko jak w Javie. Wirtualność metod w Javie ma praktycznie zerowy wpływ na wydajność dopóki tych metod nie nadpisujesz (a bez wirtualności i tak być ich nie nadpisał). Nie ma wydajnościowej różnicy między używaniem getterów i setterów (to są wirtualne metody!) w Javie a używaniem pól bezpośrednio.

Co więcej Java już w 2011 roku potrafiła jednocześnie:

  • zdewirtualizować metodę
  • wkleić ją (inlining)
  • przenieść alokację obiektu alokowanego przez new na stos
  • przeprowadzić dalsze uproszczenia (w tym np kolejne dewirtualizacje metod na obiekcie przeniesionym na stos)

Przykład: C# i .NET Dlaczego foreach jest gorsze od for (beta)

a posiadanie interfejsu ma zazwyczaj swoje korzyści

Takie jak metody wirtualne :) To, że nie ma jawnego słówka virtual w C# nie znaczy, że metoda nie jest wirtualna. Podobnie w Javie nie ma jawnego słówka virtual, ale czasem też nie ma jawnego słówka public, abstract, final czy innych. Kompilator sobie wstawia co trzeba.

Z jakiegoś niewiadomego powodu też wywoływanie wirtualnych metod w interfejsów jest w C# wolniejsze od wywoływania metod explicite oznaczonych jako virtual i to nawet na .NET Core 2.1. Moje benchmarki tutaj: C# i .NET Mockowanie - interfejs vs virtual

poza tym to dosłownie dwa kliknięcia - extract interface -> ok; można trzymać na początku w tym samym pliku

Nooo, generowanie getterów i setterów w Javie to też dwa kliknięcia - tylko po co się skazywać na przebijanie się w kółko przez ten boilerplate?


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 4x, ostatnio: Wibowit
Zobacz pozostałe 10 komentarzy
WeiXiao
W obu przypadkach instalacja przechodzi dość standardowo - windows przeklikanie, a linux dodanie keya + pobranie paczki, więc @Azarien musi swój setup ogarnąć :P Ale jeżeli chodzi o wydajność, to z mojego doświadczenia chodzi lepiej na Linuxach (web + db), lecz nie nazwałbym swoich testów rzetelnymi, ale https://robertoprevato.github.io/More-about-Linux-vs-Windows-hosted-ASP-NET-Core-applications-in-Azure-App-Service/
Wibowit
Wyższa wydajność na Linuksie może być spowodowana wyższą wydajnością Linuksowego podsystemu I/O niż Windowsowego - w sensie nierzadko widywałem benchmarki potwierdzające taką tezę. Poza tym Linux lepiej sobie radzi z egzotycznymi topologiami CPU (np AMD Threadripper), ale w typowych przypadkach są CPU od Intela, na których Windowsy dobrze działają.
SO
@WeiXiao to porównanie to można o kant d**y rozbić. To jest porównanie wydajności app service na linuxie vs na windowsie. Przecież na windowsie jako reverse proxy robi IIS. Jak to jest rozwiązane na linuxie? Dodatkowo tam jest docker więc też całkiem inna architektura.
WeiXiao
@some_ONE: Nie znalazłem nic innego. Jak będzie mi się chciało, to wystawie coś na jakimś hostingu i porównam, ale raczej wniosek będzie taki sam, że na Linuxie lepiej to chodzi niż na Windzie.
orchowskia
Na linuxie lepiej chodzi bo za darmo, a co za darmo to dobre - jak piwo. Darmowe piwo, dobre piwo. I mówię bardzo poważnie
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 5 godzin
0

Kontener jest do rozwiązywania problemów z zależnościami pomiędzy paczkami

Albo do ich przykrywania (i w efekcie powodowania dalszych problemów tego typu). Problemy z tight coupling można rozwiązać przez refaktor tak by mieć loose coupling, ale można też zaprząc do pracy kontener. Kontener radzi sobie bez problemu z najbardziej szalonymi grafami zależności między obiektami (włącznie z cyklami "rozwiązywanymi" przez proxy, setter injection, etc) i wprowadza iluzję iż dopóki kontener wstaje to nie ma problemów z zależnościami. Inaczej mówiąc: kontener sprawia iż pakowanie się w tight coupling jest, przynajmniej z początku, znacznie przyjemniejsze niż pozbywanie się go.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:4 minuty
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
1

W uzupełnieniu tekstu @Wibowit - w javie już od jakiegoś czasu część osób walczy z kupą powodowaną przez wstrzykiwanie przez kontenery. (Edit: była poprawka zdania)
Przykładowe video Tomera Gabela:

I jest tam ładne podsumowanie If You are seeing benefit from IoC your codebase is already out of control.
(IoC w znaczneiu kontener DI).


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 2x, ostatnio: jarekr000000
Zobacz pozostałe 4 komentarze
WJ
@jarekr000000: Daj jakiś artykuł o tym. W necie jest dużo archiwalnych artykułów trudno jest się przez to przebić.
Wibowit
@WywaloneJajca: najpierw pokaż kod w C# który obrazuje to co masz na myśli
jarekr000000
W javie masz różne kontenery śmieci, ale w wiodącym - Springu od wersji 4.3 wywalili konieczność dawania tych adnotacji: https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3
Wibowit
w javie już od jakiegoś czasu część osób walczy z kupą powodowaną przez kontenery i wstrzykiwanie. - powinno być raczej kupą powodowaną przez wstrzykiwanie przez kontenery, no nie?
jarekr000000
@Wibowit: tak, dokładnie, DI robione po ludzku jest spoko.
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
1

@jarekr000000:

(...)już od jakiegoś czasu część osób walczy z kupą powodowaną przez kontenery i wstrzykiwanie.

Ale konkretnie to z jaką kupą? Ok, jeśli ktoś robi sobie miszmasz zależności to faktycznie DI i kontenery mogą to zamaskować. Nie widzę tylko co w tym złego robi sama idea DI. Tak samo zacytowane przez Ciebie zdanie (domyślam się że wyrwane z kontekstu, więc może to był błąd) można by podpiąć pod setki innych zagadnień. "Jeśli widzisz zysk z X to Twój kod już jest poza kontrolą". Tak naprawdę nic merytorycznego to nie wnosi.

Jeśli mam zależność, która z kolei posiada również jakąś zależność to chyba lepiej oddelegować odpowiedzialność budowania tejże zależności gdzieś indziej zamiast zatruwać kod który ma jedynie z tego korzystać, a nie martwić się jak to zbudować. A jeśli zależność ta nie może być wykonana podczas testów (ponieważ np. wykonuje requesty HTTP) to raczej nie wykorzystam fabryki bezpośrednio tylko właśnie użyje DI.

Nie wiem, będę musiał chyba oglądnąć podany przez Ciebie filmik jak znajdę trochę czasu, bo jak na razie brzmi to jak szukanie problemów na siłę.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus
Zobacz pozostałe 7 komentarzy
mad_penguin
mad_penguin
@Michał Sikora: jakie kontenery masz na myśli, czy może coś opartego na generacji kodu? Bo w sumie myślałem o tych popularnych .netowych, ale one też są oparte na refleksji przecież :D
Michał Sikora
Michał Sikora
Myślałem o Daggerze 2. Dopiero teraz zauważyłem, że temat jest dziale C# i .NET. Możliwe, że nie ma tu takiego odpowiednika. :P
mad_penguin
mad_penguin
W .necie widzę jeszcze 1 zaletę, jak rejestrujesz to robisz Bind<IService>().To<Service>() i kompilator nie przepuści serwisu który nie implementuje interfejsu. W javie nie widziałem takiej składni, wszędzie piszą Service.class, mniemam że pierwszej wersji się nie da zrobić przez type erasure
Wibowit
Type erasure następuje po sprawdzeniu typów przez kompilator, nie przed. W np Guice też nie przejdzie jeśli bindujesz niezgodne typy: https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/binder/LinkedBindingBuilder.html#to-java.lang.Class- bind(A.class) tworzy LinkedBindingBuilder<A> a ten w metodzie to przyjmuje tylko podklasy A.
mad_penguin
mad_penguin
My bad, dzięki :)
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
2

Jeszcze dodam jedną ważną kwestię odnośnie DI przez konstruktor- pozwala to również jasno zdefiniować kontrakt danej klasy, oraz zależności bez których ta klasa nie będzie mogła poprawnie wykonać swoich odpowiedzialności. Bez zapewnienia tych zależności wiemy już na etapie budowania instancji że ma niespełnione wymagania.

Odnoszę wrażenie że podany wyżej przykłady próbują rozwiązać jakieś problemy w świecie Javy (mogę się mylić, nie mam zamiaru wdawać się w wojenki Java/C#), a próbuje się to przedstawić jako coś uniwersalnego i przenieść na inne ekosystemy gdzie takie problemy nie występują.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 5 godzin
0

Odnoszę wrażenie że podany wyżej przykłady próbują rozwiązać jakieś problemy w świecie Javy (mogę się mylić, nie mam zamiaru wdawać się w wojenki Java/C#), a próbuje się to przedstawić jako coś uniwersalnego i przenieść na inne ekosystemy gdzie takie problemy nie występują.

Jeśli są w tym wątku przykłady w Javie w filmie podanym przez @jarekr000000 . Jednak w tym filmie gość wprost powiedział, że używa Javy bo jest najbardziej przystępna dla ogółu składniowo (jego zdaniem Java jest łatwiejsza do zrozumienia przez nie-Javowców niż analogicznie w przypadku innych języków). Powiedział też, że mechanizmy, które krytykuje występują między innymi w Javie (jak przykład podał Springa czy Guice), C# (tam też są kontenery DI, ale nie siedzi w C#, więc nie podał przykładów) oraz JavaScripcie (jako przykład podał Angulara, który zawiera kontener DI).


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:4 minuty
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
1
Aventus napisał(a):

Odnoszę wrażenie że podany wyżej przykłady próbują rozwiązać jakieś problemy w świecie Javy (mogę się mylić, nie mam zamiaru wdawać się w wojenki Java/C#), a próbuje się to przedstawić jako coś uniwersalnego i przenieść na inne ekosystemy gdzie takie problemy nie występują.

Zwykłe demonizowanie wroga nieznanego. Akurat Java i C# tu się raczej nie różnią. Widzę to nawet w tym wątku - te same argumenty.

Wystarczy dodać, że w dużo bardziej (od C#) składniowo rozbudowanej Scali, powoli ludzie też odwracają sięo d wszelkich cudownych paternów DI, które były o wiele mniej magiczne niż oparte na refleksji.
Po prostu powrót do kompilatora i new. Dlaczego?

Powód fajności kontenerów DI, możesz sobie wszystko wstrzyknąc gdzie chcesz, przez ileś warstw to powód chaosu.
Mi przypomina się analogiczna walka z GOTO (lata 80-te, początek 90). Argumentem za GOTO było to, że mozesz sobie skoczyć gdzie chcesz nawet do środka procedury i przez to zaoszczedzisz dużo kodowania, rozbijania na funkcje. I to prawda, tylko zaoszczędzona ilość lini kodu jest przy dobrym programowaniu mała, a kupa w kodzie duża.
Robiąc DI ręcznie, przy pomocy new muszę stworzyć więcej klas pośrednich i rozudowując system dostajęból kawałkami i po kawałku rozwiązuje (tworząc fabryki itp.). Przez to zwykle żadna moja klasa nie ma więcej niż kilka zależności (np. 3). Jak gdzieś mi się robi 5 to już wiem, że trzeba refaktorować.

Przy kontenerze DI, nawet z konstruktorami łatwo się rozszaleć i kończymy z klasami mającymi tych zależności 10. (A przy field injection to i 20).

Przy okazji jeszcze gorsze od kontenerowego DI (i z nim powiązane) są aspekty runtime i tego w Javie (Spring/ Java EE) jest pełno. Kontener automatycznie rozpoczynający transakcje w metodach, kontener sprawdzający uprawnienia na wejściu do metody itp. To jest dopiero niezła recepta na katastrofę na produkcji, ale dziesiątki tysiący serwisów tak jest robionych :-(


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 3x, ostatnio: jarekr000000
orchowskia
Fajna analogia z GOTO. Fakt czasami tak jak z tym GOTO trzeba najpierw ogarnąć cały kod zanim zaczniesz rozumieć o co w nim chodzi.
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
1

Ja korzystam z kontenerów IoC i nie zauważyłem więcej niż jakies 2-3 zależności na jedną klase. Faktycznie Spring działa przez refleksje, ale on wybuchnie na początku urcuhamiania aplikacji jeśli coś jest nie tak więc to średnio trafiony argument, nie widziałem żeby nagle aplikacja po 2 tygodniach od uruchomienia nagle padła przez kontener IoC. Aczkolwiek AOP rzeczywiście moża wywołac spore problemy...


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
edytowany 1x, ostatnio: scibi92
orchowskia
  • Rejestracja:około 6 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Zielona Góra
  • Postów:83
0

Ja mam doświadczenie w c# - co prawda nie z ninjectem, ani autofac tylko z DI dostępnym by default w ASP .NET Core, oraz javą i springiem.

W C# założenia zespołu były takie:

  • minimalizacja "new" - chyba że to jakieś DTO
  • wstrzykiwanie tylko przez konstruktor
  • ASP.NET Core był na sterydach = większość opierała się o singletony, choć zazwyczaj używa się transientów(nowa instancja za każdym razem kiedy prosisz kontener)

Ogólnie nie działaliśmy zgodnie z założeniami Microsoftu, były problemy z Entity Framework itd. Choć nic czego nie dałoby się ogarnąć jakoś sensownie.
Aha no i ten kontener miał bardzo mało magii - nie było jakichś proxy itd - jeśli do singletonu wstrzyknięto transient, albo obiekt requestScope, to on tam po prostu zostawał. Co było upierdliwe, ale fajne. Ogólnie DI mi nie przeszkadzało i wszystko było w miarę łatwe, choć czasami ciężko było przewidzieć mi działanie kodu.

Natomiast w Springowych projektach było różnie:

  • Wstrzykiwanie przez konstruktor, ale i bardzo często do prywatnych pól.
  • Do singletonu można wstrzyknąć obiekt o requestScope i to działa - są proxy które to ogarniają automagicznie

W springu nie widzisz co skąd i dlaczego, "ify" na zależnościach to wiedza tajemna zespołu - a przynajmniej ja tak to widzę. W przeciwieństwie do ASP .NET Core gdzie definiuje się te zależności kodem

Kopiuj
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();

co jest dość przejrzyste i łatwo tym sterować w przeciwieństwie do springa, jego conditionali itd. Dotatkowo w springu używa się mnóstwa adnotacji(atrybutów) co zaśmieca kod i czyni go wg. mnie okropnym.

Co do pytania - to uważam że jeśli używasz kontenera to powinieneś go używać i minimalizować new. W każdym razie zastanowiłbym się czy faktycznie tego potrzebujesz.

A jeśli chodzi o Scale - to z tego co wiem że ludzie różnie sobie radzili i chyba wyszło im faktycznie na to że DI(takie frameworkowe) jest bez sensu. Chociaż słyszałem o jakichś lewych patternach, ale uznanych za antypatterny więc niegodne naśladowania.

EDIT: Pomimo tego uważam że Java jest fajna. a C# jest od Microsoftu i jest fajny, ale Microsoft nie jest fajny :P

edytowany 1x, ostatnio: orchowskia
Wibowit
Chociaż słyszałem o jakichś lewych patternach, ale uznanych za antypatterny więc niegodne naśladowania. - chodzi o cake pattern
orchowskia
Tak! Ciasto pattern! :)
orchowskia
Ah no i ogólnie - to DI z ASP.NET CORE jest na serio proste i upośledzone. Pewnie używając wielkich frameworków problemy będą podobne jak w spring.
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
0

@orchowskia:

ASP.NET Core był na sterydach = większość opierała się o singletony, choć zazwyczaj używa się transientów(nowa instancja za każdym razem kiedy prosisz kontener)

W Core zazwyczaj używa się scoped, chyba że są konkretne powody by tego nie robić.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
orchowskia
Fakt. Poprawię ;)
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:4 minuty
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0
WywaloneJajca napisał(a):

Problem w Javie jest taki, że po prostu macie słabe kontenery IOC, które łamią Open Closed, ponieważ trzeba rejestrować wszystkie beany ręcznie.

Nie wiem skąd te mądrości bierzesz , ale jak już czymś rzucasz to warto by doczytać.
W javie (s Wpringu) własnie nigdzie się tych beanów nie rejestruje tylko kontener sam je wyszukuje w kodzie (skanowanie klas) i to jest właśnie dramat ( BASIC).

Aventus napisał(a):

W Core zazwyczaj używa się scoped, chyba że są konkretne powody by tego nie robić.

To dziwne, bo z opisu wynika, że to odpowiednik springowych RequestScoped, SessionScoped czy JobScoped. W springu dzięki takim scope różne łazęgi przekazują cichaczem parametry między warstwami. Weź to potem refaktoruj jak parametr wygląda na niewykorzystany już w warstwie kontrolerów. A potem gdzieś w perzystencji ktoś go na nowo odkrywa :/ Fakt, że w springowcy chyba zrozumieli, że tak się nie robi i dawno mnie scope nie zaskoczył.

Edit:
Byłbym zapomniał. Żeby mieć luksus nie korzystania z kontenera IoC to trzeba mieć odpowiednią infrastrukturę. Jeśli zrobienie serwera web wymaga skanowania klas, które są potem podnoszone przy użyciu domyślnego konstruktora i jakoś zarządzane przez kontener to zima. Dawniej tak w javie było (servlety). Dopiero od kiedy można odpalić server z metody main to jest OK. Na pierwszy rzut oka taki Kestrel w .NET powinien dawać radę.


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 9x, ostatnio: jarekr000000
Zobacz pozostałe 3 komentarze
orchowskia
@jarekr000000: i tym oto sposobem dotarliśmy do tematu poruszonego wczoraj :D ASP .NET Core i kestrel odpala się z maina i wszystko można sobie podefiniować jak się chce. Masz rację. Ale nie wiem czy można sobie prosto zrezygnować z DI - chyba ciężko.
jarekr000000
@orchowskia: z tym ciężko to to IMO tylko tak się wydaje. Mam częśc projektów gdzie jest kontener i część gdzie nie ma. Nawet tam gdzie DI kontener jest ograniczam jego używanie do minimum - jakoś problemu nie widzę. Widzę problem z robieniem sensownych testów dla kawałków kodu, gdzie tego kontenera było nieco za dużo (trzeba dużo mockować).
orchowskia
Z tego co pamiętam to kontekstu w EF nie dało się za bardzo zadeklarować inaczej niż poprzez kontener - tzn ominąłem to ale trochę to zajęło. Kontrolery chyba też istniały tylko w kontrolerze. Jeśli chodzi o ograniczanie jego użycia to oczywiście się da. A zamiast EF można spróbować chociażby Dappera(takie prawie JDBC).
mad_penguin
mad_penguin
@orchowskia: EF można przekazać po prostu konfigurację przez konstruktor, gdzie tu problem?
orchowskia
Fakt można konstruktorem - były inne problemy których już dokładnie nie pamiętam. Jak wcześniej pisałem projekt miał bardzo dużo customowych rzeczy. Praktycznie cały .NET był czymś owinięty mam wrażenie
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
1

W springu dzięki takim scope różne łazęgi przekazują cichaczem parametry między warstwami

To nieźle. Ja z czymś takim się nie spotkałem, a nawet gdyby ktoś tak robił w .Net to świadczy o programiście. Nijak to się ma do DI, kontenerów czy czegokolwiek innego.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
jarekr000000
Oczywiście, że to jak napisałem - raczej tylko łazegi robią. Sęk w tym, że mając kod gdzie pojawiają się Scoped beany potencjalnie zawsze jest to możliwe. Puty siedze w kodzie mojego zespołu, to jest spoko, ale że ja lubie się pakować w różne projekty (audyty, problemy itp.) to takie kwiatki widuje.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)