Zastrzyk zależności: jak go sprzedać [zamknięte]

95

Poinformuj mnie, że jestem wielkim fanem wstrzykiwania zależności (DI) i testów automatycznych. Mógłbym o tym rozmawiać cały dzień.

tło

Niedawno nasz zespół właśnie dostał ten duży projekt, który ma powstać od podstaw. Jest to strategiczna aplikacja o złożonych wymaganiach biznesowych. Oczywiście chciałem, żeby był ładny i czysty, co dla mnie oznaczało: łatwość konserwacji i testowania. Więc chciałem użyć DI.

Odporność

Problem był w naszym zespole, DI to tabu. Zostało to poruszone kilka razy, ale bogowie nie pochwalają. Ale to mnie nie zniechęciło.

Mój ruch

Może to zabrzmieć dziwnie, ale biblioteki innych firm zwykle nie są zatwierdzane przez nasz zespół architektów (pomyśl: „nie powinieneś mówić o Unity , Ninject , NHibernate , Moq lub NUnit , aby nie skaleczyć ci palca”). Zamiast więc używać sprawdzonego kontenera DI, napisałem niezwykle prosty kontener. Zasadniczo połączył wszystkie zależności podczas uruchamiania, wstrzykuje wszelkie zależności (konstruktor / właściwość) i usuwa wszelkie obiekty jednorazowe na końcu żądania WWW. Był bardzo lekki i po prostu zrobił to, czego potrzebowaliśmy. A potem poprosiłem ich o przejrzenie.

Odpowiedź

Krótko mówiąc. Spotkałem się z dużym oporem. Głównym argumentem było: „Nie musimy dodawać tej warstwy złożoności do już złożonego projektu”. Ponadto „To nie tak, że będziemy podłączać różne implementacje komponentów”. I „Chcemy, aby było to proste, jeśli to możliwe, po prostu umieść wszystko w jednym zestawie. DI to niepotrzebna złożoność bez korzyści”.

Wreszcie moje pytanie

Jak poradziłbyś sobie z moją sytuacją? Nie jestem dobry w prezentowaniu moich pomysłów i chciałbym wiedzieć, jak ludzie przedstawiliby swoje argumenty.

Oczywiście zakładam, że tak jak ja, wolisz używać DI. Jeśli się nie zgadzasz, powiedz dlaczego, abym mógł zobaczyć drugą stronę monety. Byłoby naprawdę interesujące zobaczyć punkt widzenia kogoś, kto się nie zgadza.

Aktualizacja

Dziękuję za odpowiedzi wszystkich. To naprawdę przedstawia rzeczy z perspektywy. Miło jest mieć inny zestaw oczu, aby przekazać ci opinię, piętnaście jest naprawdę niesamowite! To są naprawdę świetne odpowiedzi i pomogły mi dostrzec problem z różnych stron, ale mogę wybrać tylko jedną odpowiedź, więc wybiorę tę, która uzyskała najwyższy głos. Dziękujemy wszystkim za poświęcenie czasu na odpowiedź.

Zdecydowałem, że prawdopodobnie nie jest to najlepszy czas na wdrożenie DI i nie jesteśmy na to gotowi. Zamiast tego skoncentruję swoje wysiłki na przetestowaniu projektu i spróbuję przedstawić zautomatyzowane testy jednostkowe. Zdaję sobie sprawę, że pisanie testów jest dodatkowym kosztem i jeśli kiedykolwiek zostanie postanowione, że dodatkowy koszt nie jest tego wart, osobiście nadal postrzegałbym to jako sytuację wygraną, ponieważ projekt jest nadal testowalny. A jeśli kiedykolwiek testy lub DI będą wyborem w przyszłości, projekt z łatwością sobie z tym poradzi.

Mel
źródło
64
Wygląda na
24
Używanie DI jest (przynajmniej w Javie, C #, ...) prawie naturalną konsekwencją użycia testów jednostkowych. Czy Twoja firma stosuje testy jednostkowe?
sebastiangeiger
27
Lub po prostu nie skupiać się na DI. DI różni się od „konserwowalnego i testowalnego”. Kiedy są różne opinie na temat projektu, musisz skomponować, a czasem zaakceptować, że nie decydujesz. Widzę na przykład katastrofy spotęgowane przez inwersję kontroli, DI i wielu warstw frameworków, co sprawia, że ​​złożone rzeczy powinny być proste (w twoim przypadku nie mogę się kłócić).
Denys Séguret
34
„... mógłbym o tym rozmawiać cały dzień.” Wygląda na to, że musisz przestać mieć obsesję na punkcie czegoś, co jest nadużywane częściej niż nie z powodu dogmatycznego przestrzegania pewnego dnia.
21
Z brzmienia tego, twoi współpracownicy mają obiektywne argumenty przemawiające przeciwko stosowaniu pojemników DI: „nie musimy dodawać tej warstwy złożoności do już złożonego projektu” - czy może mają rację? Czy w rzeczywistości korzystasz z dodatkowej złożoności? Jeśli tak, to powinno być możliwe argumentowanie. Twierdzą, że „DI jest niepotrzebną złożonością bez korzyści”. Jeśli możesz wykazać obiektywną korzyść, powinieneś wygrać to dość łatwo, nie? Testowanie jest wspomniane dość często w innych komentarzach; ale testowanie zasadniczo nie wymaga DI, chyba że potrzebujesz makiety (co nie jest dane).
Konrad Rudolph

Odpowiedzi:

62

Biorąc kilka kontrargumentów:

„Chcemy, aby było to proste, jeśli to możliwe, po prostu umieść wszystko w jednym zestawie. DI to niepotrzebna złożoność bez korzyści”.

„to nie tak, że będziemy podłączać różne implementacje komponentów”.

Chcesz, aby system był testowalny. Być łatwo sprawdzalne trzeba patrzeć na wyśmianie różnych warstw projektu (bazy danych, komunikacji itd.), W tym przypadku będzie można podłączyć w różnych implementacjach komponentów.

Sprzedawaj DI na korzyściach testowania, jakie daje. Jeśli projekt jest złożony, będziesz potrzebować dobrych, solidnych testów jednostkowych.

Kolejną korzyścią jest to, że podczas kodowania interfejsów, jeśli masz lepszą implementację (szybszą, mniej wymagającą pamięci, cokolwiek) jednego ze swoich komponentów, użycie DI znacznie ułatwia wymianę starej implementacji na Nowy.

Mówię tu o tym, że musisz zająć się korzyściami, które przynosi DI, zamiast argumentować za DI ze względu na DI. Skłaniając ludzi do zaakceptowania oświadczenia:

„Potrzebujemy X, Y i Z”

Następnie przesuń problem. Musisz upewnić się, że DI jest odpowiedzią na to stwierdzenie. W ten sposób współpracownicy będą właścicielami rozwiązania, a nie poczują, że zostało im narzucone.

ChrisF
źródło
+1. Krótko i na temat. Niestety, z argumentów wysuniętych przez współpracowników Mela trudno będzie przekonać ich, że warto nawet po prostu spróbować - jak powiedział Spoike w swojej odpowiedzi, bardziej problem natury niż problem techniczny.
Patryk Ćwiek
1
@ Trustme-I'maDoctor - Och, zgadzam się, że to problem ludzi, ale dzięki takiemu podejściu pokazujesz korzyści, a nie argumentujesz za DI dla samego siebie.
ChrisF
To prawda i życzę mu powodzenia, jego życie jako programisty będzie łatwiejsze przy odpowiedniej testowalności itp. :)
Patryk Ćwiek
4
+1 Myślę, że twój ostatni akapit powinien być pierwszy. To jest kluczowe dla problemu. Gdyby można było przeprowadzić test jednostkowy i zasugerowano przekształcenie całego systemu w model DI, powiedziałbym mu również „nie”.
Andrew T Finnell,
+1 bardzo pomocne. Nie powiedziałbym, że DI jest absolutną koniecznością do testowania jednostkowego, ale sprawia, że ​​wszystko jest o wiele łatwiejsze.
Mel
56

Z tego, co piszesz, nie sama DI jest tabu, ale użycie kontenerów DI, co jest inną rzeczą. Sądzę, że nie napotkasz żadnych problemów ze swoim zespołem, kiedy po prostu napiszesz niezależne komponenty, które otrzymują inne komponenty, których potrzebują, na przykład przez konstruktora. Tylko nie nazywaj tego „DI”.

Możesz pomyśleć, że takie komponenty nie używają kontenera DI są uciążliwe i masz rację, ale daj swojemu zespołowi czas, aby się o tym przekonał.

Doktor Brown
źródło
10
+1 pragmatyczne obejście impasu politycznego / dogmatycznego
k3b
32
W każdym razie warto rozważyć ręczne podłączenie wszystkich obiektów i wprowadzenie pojemnika DI tylko wtedy, gdy zacznie się owłosić. Jeśli to zrobisz, nie zobaczą kontenerów DI jako dodatkowej złożoności - zobaczą to jako zwiększenie prostoty.
Phil
2
Jedynym problemem jest to, że wzorem przekazywania luźno powiązanych zależności do osób zależnych jest DI. IoC, czyli użycie „kontenera” do rozwiązania luźno powiązanych zależności, jest automatycznym DI.
KeithS
51

Odkąd zapytałeś, stanę po twojej stronie przeciwko DI.

Sprawa przeciwko wstrzyknięciu zależności

Istnieje reguła, którą nazywam „Zachowaniem złożoności”, która jest analogiczna do reguły w fizyce zwanej „Zachowaniem energii”. Stwierdza, że ​​żadna ilość inżynierii nie może zmniejszyć całkowitej złożoności optymalnego rozwiązania problemu, wszystko, co może zrobić, to przesunąć tę złożoność. Produkty Apple nie są mniej złożone niż produkty Microsoftu, po prostu przenoszą złożoność z przestrzeni użytkownika do przestrzeni inżynierskiej. (Jest to jednak błędna analogia. Chociaż nie możesz wytwarzać energii, inżynierowie mają nieprzyjemny zwyczaj tworzenia złożoności na każdym kroku. W rzeczywistości wielu programistów wydaje się lubić zwiększanie złożoności i używanie magii, co jest z definicji złożonością, której programista nie do końca rozumie. Ta nadmierna złożoność może zostać zmniejszona.) Zwykle to, co wygląda na zmniejszenie złożoności, polega na przeniesieniu złożoności gdzie indziej, zwykle do biblioteki.

Podobnie DI nie zmniejsza złożoności łączenia obiektów klienckich z obiektami serwera. To, co robi, to wyjmuje go z Javy i przenosi do XML. To dobrze, ponieważ centralizuje wszystko w jednym (lub kilku) plikach XML, w których łatwo jest zobaczyć wszystko, co się dzieje i gdzie można to zmienić bez ponownej kompilacji kodu. Z drugiej strony jest to złe, ponieważ pliki XML nie są Java i dlatego nie są dostępne dla narzędzi Java. Nie można ich debugować w debuggerze, nie można używać analizy statycznej do śledzenia ich hierarchii połączeń itd. W szczególności błędy w środowisku DI stają się niezwykle trudne do wykrycia, zidentyfikowania i naprawy.

Dlatego o wiele trudniej jest udowodnić, że program działa poprawnie przy użyciu DI. Wiele osób twierdzi, że programy korzystające z DI są łatwiejsze do testowania , ale testowanie programów nigdy nie może udowodnić braku błędów . (Należy zauważyć, że powiązany dokument ma około 40 lat, a więc zawiera pewne tajemnicze odniesienia i przytacza niektóre nieaktualne praktyki, ale wiele podstawowych stwierdzeń nadal jest prawdą. W szczególności P <= p ^ n, gdzie P to prawdopodobieństwo, że system jest wolny od błędów, p to prawdopodobieństwo, że składnik systemu jest wolny od błędów, a n to liczba składników. Oczywiście to równanie jest nadmiernie uproszczone, ale wskazuje na ważną prawdę.) Awaria NASDAQ podczas IPO na Facebooku jest ostatnim przykładem, gdzietwierdzili, że spędzili 1000 godzin na testowaniu kodu i nadal nie odkryli błędów, które spowodowały awarię. 1000 godzin to pół osoby rocznie, więc to nie tak, że skakali podczas testów.

To prawda, że ​​prawie nikt nigdy nie podejmuje (nie mówiąc już o zakończeniu) zadania formalnego udowodnienia, że ​​dowolny kod jest poprawny, ale nawet słabe próby udowodnienia pokonały większość reżimów testowania w poszukiwaniu błędów. Silne próby udowodnienia, na przykład weryfikacja L4. , Niezmiennie odkrywają dużą liczbę błędów, których nie wykryły testy i prawdopodobnie nigdy ich nie wykryją, chyba że tester już znał dokładną naturę błędu. Wszystko, co sprawia, że ​​kod jest trudniejszy do zweryfikowania przez inspekcję, może być postrzegane jako zmniejszające prawdopodobieństwo wykrycia błędów , nawet jeśli zwiększy to możliwość testowania.

Ponadto DI nie jest wymagany do testowania . Rzadko używam go do tego celu, ponieważ wolę testować system pod kątem prawdziwego oprogramowania w systemie, niż jakąś alternatywną wersję testową. Wszystko, co zmieniam w teście, jest (lub może równie dobrze) być przechowywane w plikach właściwości, które kierują program do zasobów w środowisku testowym, a nie do produkcji. Wolę spędzać czas na konfigurowaniu testowego serwera bazy danych z kopią produkcyjnej bazy danych, niż spędzać czas na kodowaniu próbnej bazy danych, ponieważ w ten sposób będę w stanie śledzić problemy z danymi produkcyjnymi (problemy z kodowaniem znaków to tylko jeden przykład ) i błędy integracji systemu, a także błędy w pozostałej części kodu.

Wstrzykiwanie zależności nie jest również wymagane w przypadku odwrócenia zależności . Możesz łatwo użyć statycznych metod fabrycznych, aby zaimplementować odwrócenie zależności. Tak właśnie było w latach 90.

W rzeczywistości, chociaż używam DI od dekady, jedyne zalety, które zapewnia, przekonuję, to możliwość skonfigurowania bibliotek stron trzecich do korzystania z bibliotek stron trzecich (np. Skonfigurowanie Springa do używania Hibernacji i obu do korzystania z Log4J ) oraz włączanie IoC za pośrednictwem serwerów proxy. Jeśli nie korzystasz z bibliotek stron trzecich i nie korzystasz z IoC, to nie ma to większego sensu i rzeczywiście dodaje nieuzasadnionej złożoności.

Old Pro
źródło
1
Nie zgadzam się, można zmniejszyć złożoność. Wiem, bo to zrobiłem. Oczywiście niektóre problemy / wymagania wymuszają złożoność, ale ponad to większość można z trudem usunąć.
Ricky Clarkson
10
@ Ricky, to subtelne rozróżnienie. Tak jak powiedziałem, inżynierowie mogą zwiększyć złożoność, a złożoność ta może zostać usunięta, więc możesz zmniejszyć złożoność implementacji, ale z definicji nie możesz zmniejszyć złożoności optymalnego rozwiązania problemu. Najczęściej to, co wygląda na zmniejszenie złożoności, polega jedynie na przeniesieniu go w inne miejsce (zwykle do biblioteki). W każdym razie jest to drugorzędne w stosunku do mojej głównej kwestii, że DI nie zmniejsza złożoności.
Old Pro
2
@Lee, konfigurowanie DI w kodzie jest jeszcze mniej przydatne. Jedną z najczęściej akceptowanych zalet DI jest możliwość zmiany implementacji usługi bez ponownej kompilacji kodu, a jeśli skonfigurujesz DI w kodzie, stracisz to.
Old Pro
7
@OldPro - Konfiguracja w kodzie ma tę zaletę, że zapewnia bezpieczeństwo typu, a większość zależności ma charakter statyczny i nie ma żadnych korzyści z definicji zewnętrznej.
Lee
3
@Lee Jeśli zależności są statyczne, to dlaczego nie są one zakodowane na stałe, bez objazdu przez DI?
Konrad Rudolph
25

Z przykrością stwierdzam, że problem, który masz, biorąc pod uwagę to, co powiedzieli twoi współpracownicy w twoim pytaniu, ma raczej charakter polityczny niż techniczny. Należy pamiętać o dwóch mantrach:

  • „To zawsze jest problem ludzi”
  • Zmiana jest przerażająca”

Oczywiście, możesz przywołać wiele kontrargumentów z solidnymi przyczynami technicznymi i korzyściami, ale to postawi cię w złej sytuacji z resztą firmy. Mają już postawę, że tego nie chcą (ponieważ czują się swobodnie z tym, jak teraz wszystko działa). Może to nawet zaszkodzić twoim relacjom z kolegami z pracy, jeśli będziesz wytrwałość w tej sprawie. Zaufaj mi w tej sprawie, ponieważ stało się to ze mną i ostatecznie wyrzucono mnie kilka lat temu (młody i naiwny, że byłem); jest to sytuacja, w której nie chcesz się wciągać.

Chodzi o to, że musisz osiągnąć pewien poziom zaufania, zanim ludzie posuną się tak daleko, aby zmienić swój obecny sposób pracy. O ile nie masz zaufania i nie możesz decydować o takich rzeczach, takich jak pełnienie roli architekta lub kierownika technicznego, niewiele możesz zrobić, aby odwrócić kolegów. Przekonanie i wysiłek (podobnie jak podejmowanie drobnych kroków usprawniających) zajmie dużo czasu, aby zdobyć zaufanie w celu zmiany kultury firmy. Mówimy o okresie wielu miesięcy lub lat.

Jeśli okaże się, że obecna kultura firmy nie współpracuje z tobą, to przynajmniej wiesz jeszcze jedną rzecz, o którą należy zapytać podczas następnej rozmowy kwalifikacyjnej. ;-)

Spoike
źródło
23

Nie używaj DI. Zapomnij o tym.

Utwórz implementację wzorca fabrycznego GoF, który „tworzy” lub „znajduje” określone zależności i przekazuje je do obiektu i pozostawia go przy tym, ale nie nazywaj go DI i nie twórz złożonej uogólnionej struktury. Zachowaj prostotę i aktualność. Upewnij się, że zależności i twoje klasy są takie, że możliwe jest przejście na DI; ale fabryka powinna pozostać mistrzem i mieć bardzo ograniczony zakres.

Z czasem możesz mieć nadzieję, że wzrośnie, a nawet pewnego dnia przejdzie na DI. Niech potencjalni klienci dojdą do wniosku we własnym czasie i nie naciskaj. Nawet jeśli nigdy się do tego nie dostaniesz, przynajmniej twój kod ma pewne zalety DI, na przykład kod testowany jednostkowo.

Jasonk
źródło
3
+1 za rozwój wraz z projektem i „nie nazywaj go DI”
Kevin McCormick
5
Zgadzam się, ale ostatecznie to DI. Po prostu nie używa kontenera DI; przekazuje ciężar dzwoniącemu, zamiast scentralizować go w jednym miejscu. Mądrze byłoby jednak nazwać to „uzewnętrznianiem zależności” zamiast DI.
Juan Mendes
5
Często przychodziło mi do głowy, że tak naprawdę grok na koncepcji wieży z kości słoniowej, takiej jak DI, musiałeś przejść przez ten sam proces, co ewangeliści, aby zdać sobie sprawę z tego, że jest problem do rozwiązania. Autorzy często o tym zapominają. Trzymaj się języka wzorcowego niskiego poziomu, a w konsekwencji może pojawić się potrzeba pojemnika (lub nie).
Tom W
@JuanMendes z ich odpowiedzi Myślę, że eksternalizacja zależności jest tym, czemu są przeciwni, ponieważ nie lubią bibliotek stron trzecich i chcą wszystkiego w jednym zestawie (monolit?). Jeśli to prawda, nazwanie go „uzewnętrznieniem zależności” nie jest lepsze niż wywołanie DI z punktu widzenia.
Jonathan Neufeld,
22

Widziałem projekty, które doprowadziły DI do skrajności, aby przeprowadzać testy jednostkowe i kpić z obiektów. Tak bardzo, że konfiguracja DI stała się językiem programowania sama w sobie z taką ilością konfiguracji potrzebną do uruchomienia systemu, jak rzeczywisty kod.

Czy system cierpi teraz z powodu braku odpowiednich wewnętrznych interfejsów API, których nie można przetestować? Czy masz nadzieję, że przejście systemu na model DI pozwoli lepiej przeprowadzić test jednostkowy? Nie potrzebujesz kontenera, aby przetestować kod w jednostce. Użycie modelu DI pozwoliłoby na łatwiejsze testowanie jednostkowe na obiektach próbnych, ale nie jest to wymagane.

Nie musisz jednocześnie przełączać całego systemu, aby był kompatybilny z DI. Nie powinieneś też arbitralnie pisać testów jednostkowych. Zmień kod, gdy znajdziesz go w swojej funkcji i zgłoszeń błędów. Następnie upewnij się, że dotknięty kod jest łatwy do przetestowania.

Pomyśl o CodeRot jako o chorobie. Nie chcesz zacząć arbitralnie hakować rzeczy. Masz pacjenta, widzisz obolałe miejsce, więc zaczynasz naprawiać to miejsce i otaczające go rzeczy. Po oczyszczeniu tego obszaru przejdź do następnego. Wcześniej czy później dotkniesz większości kodu i nie wymagało to tej „ogromnej” zmiany architektonicznej.

Nie podoba mi się, że testy DI i Mock wzajemnie się wykluczają. A po obejrzeniu projektu, który z braku lepszego słowa zwariował przy użyciu DI, byłbym zmęczony, nie widząc korzyści.

Istnieje kilka miejsc, w których warto korzystać z DI:

  • Warstwa dostępu do danych umożliwiająca zamianę strategii dotyczących tworzenia opowieści
  • Warstwa uwierzytelniania i autoryzacji.
  • Motywy interfejsu użytkownika
  • Usługi
  • Punkty rozszerzeń wtyczek, z których może korzystać własny system lub firma zewnętrzna.

Wymaganie od każdego programisty, aby wiedział, gdzie jest plik konfiguracyjny DI (zdaję sobie sprawę, że kontenery mogą być tworzone za pomocą kodu, ale dlaczego miałbyś to zrobić). Gdy chcą przeprowadzić RegEx, jest frustrujące. Och, widzę, że jest IRegExCompiler, DefaultRegExCompiler i SuperAwesomeRegExCompiler. Jednak w żadnym miejscu w kodzie nie mogę przeprowadzić analizy, aby zobaczyć, gdzie używana jest opcja Domyślna i używana jest funkcja SuperAwesome.

Moja osobowość zareagowałaby lepiej, gdyby ktoś pokazał mi coś lepszego, a następnie próbował mnie przekonać swoimi słowami. Jest coś do powiedzenia na temat kogoś, kto poświęciłby czas i wysiłek, aby ulepszyć system. Nie uważam, że wielu programistów dba o to, aby produkt był naprawdę lepszy. Jeśli możesz udać się do nich z prawdziwymi zmianami w systemie i pokazać im, w jaki sposób uczyniło to dla ciebie lepszym i łatwiejszym, jest to warte więcej niż jakiekolwiek badania online.

Podsumowując, najlepszym sposobem na zmianę w systemie jest powolne ulepszanie kodu, którego aktualnie dotykasz, z każdym przejściem. Wcześniej czy później będziesz w stanie przekształcić system w coś lepszego.

Andrew Finnell
źródło
„Testy DI i próbne wykluczają się wzajemnie” To nieprawda, nie wykluczają się również wzajemnie. Po prostu dobrze ze sobą współpracują. Wymieniasz także miejsca, w których DI jest dobry, warstwę usług, dao i interfejs użytkownika - to prawie wszędzie, prawda?
NimChimpsky
@Arewrew ważne punkty. Oczywiście nie chciałbym, żeby zaszło za daleko. Najbardziej chciałem zautomatyzowanego testowania klas biznesowych, ponieważ musimy wdrażać bardzo złożone reguły biznesowe. I zdaję sobie sprawę, że nadal mogę je testować bez pojemnika, ale osobiście sensowne jest użycie pojemnika. Zrobiłem małą próbkę, która pokazała tę koncepcję. Ale nawet na to nie spojrzano. Myślę, że mój błąd polegał na tym, że nie stworzyłem testu, który pokazałby, jak łatwe jest testowanie / wyśmiewanie.
Mel
Tyle umowy! Naprawdę nienawidzę plików konfiguracyjnych DI i ich wpływu na przebieg programu śledzenia. Całość zamienia się w „upiorną akcję na odległość” bez widocznych powiązań między elementami. Kiedy łatwiej jest odczytać kod w debuggerze niż w plikach źródłowych, coś jest naprawdę nie tak.
Zan Lynx
19

DI nie wymaga inwazyjnej inwersji kontenerów kontrolnych ani ramek próbnych. Możesz oddzielić kod i zezwolić na DI za pomocą prostej konstrukcji. Testy jednostkowe można przeprowadzać za pomocą wbudowanych funkcji programu Visual Studio.

Szczerze mówiąc, twoi współpracownicy mają rację. Niewłaściwe korzystanie z tych bibliotek (a ponieważ nie są z nimi zaznajomione, wystąpią problemy z nauką) spowoduje problemy. Ostatecznie kod ma znaczenie. Nie psuj swojego produktu do testów.

Pamiętaj tylko, że w tych scenariuszach niezbędny jest kompromis.

Telastyn
źródło
2
Zgadzam się, że DI nie wymaga kontenerów IoC. chociaż nie nazwałbym tego inwazyjnym (przynajmniej ta implementacja), ponieważ kod został zaprojektowany w taki sposób, aby był niezależny od kontenerów (głównie iniekcje konstruktora) i wszystkie elementy DI mają miejsce w jednym miejscu. Tak więc nadal wszystko działa bez kontenera DI - wprowadzam konstruktory bez parametrów, które „wstrzykują” konkretne implementacje do drugiego konstruktora z zależnościami. W ten sposób nadal mogę łatwo z niego kpić. Tak, zgadzam się, DI faktycznie osiąga się poprzez projekt.
Mel
+1 Za kompromis. Jeśli nikt nie chce iść na kompromis, wszyscy cierpią.
Tjaart
14

Nie sądzę, abyś mógł już sprzedawać DI, ponieważ jest to decyzja dogmatyczna (lub, jak @Spoike nazwał to grzeczniej, politycznie ).

W tej sytuacji sprzeczanie się z powszechnie uznanymi najlepszymi praktykami, takimi jak zasady projektowania SOLID, nie jest już możliwe.

Ktoś, kto ma większą władzę polityczną niż ty, podjął (być może złą) decyzję, aby nie używać DI.

Po drugiej stronie sprzeciwiłeś się tej decyzji, wdrażając własny kontener, ponieważ używanie ustalonego kontenera było zabronione. Ta polityka faktów dokonanych , którą próbowałeś, mogła pogorszyć sytuację.

Analiza

Moim zdaniem, DI bez testdriven development (TDD) i testowanie jednostkowe nie ma znaczących korzyści, które przewyższają początkowe dodatkowe koszty.

Czy to naprawdę problem?

  • nie chcemy DI ?

czy o to bardziej chodzi

  • tdd / unittesting to marnowanie zasobów ?

[Aktualizacja]

Jeśli widzisz swój projekt na podstawie klasycznych błędów w widoku zarządzania projektem , widzisz

#12: Politics placed over substance.
#21: Inadequate design. 
#22: Shortchanged quality assurance.
#27: Code-like-hell programming.

podczas gdy inni widzą

#3: Uncontrolled problem employees. 
#30: Developer gold-plating. 
#32: Research-oriented development. 
#34: Overestimated savings from new tools or methods. 
k3b
źródło
obecnie nie przeprowadzamy żadnych testów jednostkowych w naszym zespole. Podejrzewam, że twoje ostatnie oświadczenie jest na miejscu. Podnosiłem testy jednostkowe kilka razy, ale nikt nie wykazywał żadnego rzeczywistego zainteresowania i zawsze były powody, dla których nie mogliśmy go przyjąć.
Mel
10

Jeśli okaże się, że musisz „sprzedać” zasadę swojemu zespołowi, prawdopodobnie jesteś już kilka kilometrów na niewłaściwej ścieżce.

Nikt nie chce wykonywać dodatkowej pracy, więc jeśli to, co próbujesz sprzedać, wygląda dla nich jak dodatkowa praca, to nie przekonasz ich poprzez Powtarzane Wywołanie Przełożonego. Muszą wiedzieć, że pokazujesz im sposób na zmniejszenie obciążenia pracą, a nie jej zwiększenie.

DI jest często postrzegane jako dodatkowa złożoność z obietnicą potencjalnej zmniejszonej złożoności później , która ma wartość, ale nie tyle dla kogoś, kto próbuje zmniejszyć swoje wstępne obciążenie. W wielu przypadkach DI jest tylko kolejną warstwą YAGNI . Koszt tej złożoności nie jest równy zero, w rzeczywistości jest dość wysoki dla zespołu, który nie jest przyzwyczajony do tego typu wzorców. I to są prawdziwe dolary, które są wrzucane do wiadra, które może nigdy nie przynieść żadnych korzyści.

Połóż to na swoim miejscu
Najlepszym rozwiązaniem jest użycie DI tam, gdzie jest rażąco użyteczne, a nie tylko tam, gdzie jest to powszechne. Na przykład wiele aplikacji używa DI do wybierania i konfigurowania baz danych. A jeśli twoja aplikacja jest dostarczana z warstwą bazy danych, to kuszące miejsce na jej umieszczenie. Ale jeśli aplikacja jest dostarczana z wbudowaną niewidoczną dla użytkownika bazą danych, która w przeciwnym razie jest ściśle zintegrowana z kodem, wówczas szanse na konieczność zastąpienia bazy danych w czasie wykonywania zbliżają się do zera. A sprzedaż DI, mówiąc: „słuchaj, możemy łatwo zrobić coś, czego nigdy, nigdy, nigdy nie będziemy chcieli robić”, prawdopodobnie sprawi, że znajdziesz się na liście „ten facet ma złe pomysły” z szefem.

Ale powiedz zamiast tego, że masz wyjście debugowania, które normalnie dostaje IFDEF w wydaniu. I za każdym razem, gdy użytkownik ma problem, zespół pomocy technicznej musi wysłać mu kompilację debugowania, aby mógł uzyskać dane wyjściowe dziennika. Możesz użyć DI tutaj, aby pozwolić klientowi przełączać się między sterownikami dziennika - LogConsoledla programistów, LogNullklientów i LogNetworkklientów z problemami. Jedna zunifikowana kompilacja, konfigurowalna w czasie wykonywania.

Wtedy nie musisz nawet nazywać go DI, zamiast tego po prostu nazywa się to „naprawdę dobry pomysł Mela” i jesteś teraz na liście dobrych pomysłów zamiast złego. Ludzie zobaczą, jak dobrze działa wzór i zaczną go używać tam, gdzie ma to sens w kodzie.

Kiedy właściwie sprzedasz pomysł, ludzie nie będą wiedzieli, że ich przekonałeś.

tylerl
źródło
8

Oczywiście Inversion of control (IoC) ma wiele zalet: upraszcza kod, dodaje magii, która wykonuje typowe zadania itp.

Jednak:

  1. Dodaje wiele zależności. Prosta aplikacja hello world napisana przy użyciu Springa może ważyć kilkanaście MB, a widziałem, że Spring dodał tylko, aby uniknąć kilku linii konstruktora i seterów.

  2. Dodaje wyżej wspomnianą magię , która jest trudna do zrozumienia dla osób postronnych (na przykład deweloperów GUI, którzy muszą wprowadzić pewne zmiany w warstwie biznesowej). Zobacz świetny artykuł Innowacyjne umysły nie myślą podobnie - New York Times , w którym opisano, w jaki sposób eksperci nie doceniają tego efektu .

  3. Utrudnia śledzenie użycia klas. IDE, takie jak Eclipse, ma ogromne możliwości śledzenia wykorzystania danych wywołań klas lub metod. Ale ten ślad ginie, gdy wywoływany jest zastrzyk zależności i odbicie.

  4. Wykorzystanie IoC zwykle nie kończy się na wstrzykiwaniu zależności, kończy się niezliczonymi serwerami proxy, a otrzymujesz ślad stosu liczący setki linii, z których 90% to proxy i wywoływane przez odbicie. To znacznie komplikuje analizę śladu stosu.

Tak więc, będąc wielkim fanem Spring i IoC, ostatnio musiałem przemyśleć powyższe pytania. Niektóre z moich współpracowników to programiści internetowi zaczerpnięci ze świata Java ze świata rządzonego przez Pythona i PHP, a rzeczy oczywiste dla javaistów są dla nich czymś oczywistym. Niektóre z moich innych kolegów robią sztuczki (oczywiście nieudokumentowane), co bardzo utrudnia znalezienie błędu. Oczywiście niewłaściwe użycie IoC sprawia, że ​​są dla nich lżejsze;)

Moja rada, jeśli narzucisz użycie IoC w swojej pracy, będziesz odpowiedzialny za wszelkie nadużycia, które popełni ktoś;)

Łukasz Lech
źródło
+1 jak w przypadku każdego potężnego narzędzia, łatwo można go niewłaściwie wykorzystać i MUSISZ zrozumieć, kiedy NIE należy go używać.
Phil
4

Myślę, że ChrisF ma coś dobrego. Nie sprzedawaj DI jako takiego. Ale sprzedaj pomysł testowania kodu przez jednostkę.

Jednym z podejść do umieszczenia kontenera DI w architekturze może być powolne pozwalanie testom na wprowadzenie implementacji w coś, co dobrze pasuje do tej architektury. Np. Powiedzmy, że pracujesz na kontrolerze w aplikacji ASP.NET MVC. Powiedz, że piszesz klasę w ten sposób:

public class UserController {
    public UserController() : this (new UserRepository()) {}

    public UserController(IUserRepository userRepository) {
        ...
    }

    ...
}

To pozwala pisać testy jednostkowe niezwiązane z faktyczną implementacją repozytorium użytkowników. Ale klasa nadal działa bez kontenera DI, aby go utworzyć. Konstruktor bez parametrów utworzy go z domyślnym repozytorium.

Jeśli współpracownicy zauważą, że prowadzi to do znacznie czystszych testów, być może zdadzą sobie sprawę, że jest to lepszy sposób. Może uda ci się je nakłonić do takiego kodowania.

Kiedy zdadzą sobie sprawę, że jest to lepszy projekt niż UserController, który wie o konkretnej implementacji UserRepository, możesz zrobić następny ruch i pokazać im, że możesz mieć komponent, kontener DI, który może automatycznie zapewnić wymagane wystąpienia.

Pete
źródło
Wspaniały! Obecnie robię to, ponieważ naprawdę chcę zautomatyzowane testowanie jednostek, nawet jeśli nie mogę dostać DI. Zapomniałem wspomnieć, że testy jednostkowe również nie są wykonywane w naszym zespole :( więc jeśli będę pierwszy.
Mel
2
W takim razie powiedziałbym, że to prawdziwy problem. Znajdź źródło odporności na testy jednostkowe i zaatakuj to. Niech DI na razie kłamie. Testowanie jest ważniejsze IMHO.
Christian Horsdal
@ChristianHorsdal Zgadzam się, chciałem, żeby był luźno sprzężony, aby umożliwić łatwe kpowanie / testowanie.
Mel
Ten pomysł jest naprawdę fajny ... Świetna sprzedaż do testowania
bunglestink
2

Być może najlepiej jest cofnąć się i zadać sobie pytanie, dlaczego chcesz wprowadzić pojemniki DI? Jeśli ma to poprawić testowalność, Twoim pierwszym zadaniem jest skłonienie zespołu do kupienia testów jednostkowych. Osobiście bardziej martwi mnie brak testów jednostkowych niż brak pojemnika DI.

Uzbrojony w kompleksowy pakiet lub zestawy testów jednostkowych, możesz śmiało rozpocząć ewolucję swojego projektu w miarę upływu czasu. Bez nich zmagasz się z coraz bardziej wymagającą walką, aby projekt był dostosowany do zmieniających się wymagań, która ostatecznie przegrywa wiele zespołów.

Tak więc moja rada to najpierw przetestowanie i refaktoryzacja jednostek mistrzowskich, a następnie wprowadzenie pojemników DI i wreszcie pojemników DI.

kimj100
źródło
2

Słyszę tutaj kilka dużych głosów nr z twojego zespołu:

  • „Brak bibliotek innych firm” - AKA „Not Invented Here” lub „NIH”. Istnieje obawa, że ​​wdrażając bibliotekę strony trzeciej, a tym samym uzależniając bazę kodów od niej, jeśli w bibliotece znajdzie się błąd lub luka w zabezpieczeniach, a nawet ograniczenie, które trzeba pokonać, uzależnia się od tej trzeciej strony, aby naprawić swoją bibliotekę, aby Twój kod działał. W międzyczasie, ponieważ jego „twój” program, który zawiódł spektakularnie, został zhakowany lub nie robi tego, o co prosili, nadal ponosisz odpowiedzialność (a twórcy stron trzecich powiedzą, że ich narzędzie jest „takie, jakie jest” ", używaj na własne ryzyko).

    Kontrargumentem jest to, że kod rozwiązujący problem już istnieje w bibliotece innej firmy. Czy budujesz komputery od podstaw? Czy napisałeś Visual Studio? Czy unikasz wbudowanych bibliotek w .NET? Nie. Masz zaufanie do Intel / AMD i Microsoft, a oni cały czas znajdują błędy (i nie zawsze je szybko naprawiają). Dodanie biblioteki innej firmy pozwala szybko uzyskać funkcjonalną bazę kodu, bez konieczności ponownego wymyślania koła. A armia prawników Microsoftu będzie się śmiać z twojej twarzy, gdy powiesz im, że błąd w bibliotekach kryptograficznych .NET powoduje, że są oni odpowiedzialni za incydent włamania się do twojego klienta podczas korzystania z programu .NET. Podczas gdy Microsoft z pewnością skoczy do naprawy luk w zabezpieczeniach „zerowej godziny” w dowolnym ze swoich produktów,

  • „Chcemy upchnąć wszystko w jednym zestawie” - w rzeczywistości nie. Przynajmniej w .NET, jeśli zmienisz jeden wiersz kodu, cały zestaw zawierający ten wiersz kodu musi zostać odbudowany. Dobry projekt kodu opiera się na wielu zestawach, które można odbudować tak niezależnie, jak to możliwe (lub przynajmniej odbudować zależności, a nie zależności). Jeśli NAPRAWDĘ chcą wydać plik EXE, który jest tylko plikiem EXE (który w niektórych okolicznościach ma wartość), jest na to odpowiednia aplikacja; ILMerge.

  • „DI to tabu” - WTF? DI jest przyjętą najlepszą praktyką w dowolnym języku O / O z konstrukcją kodu „interfejs”. W jaki sposób Twój zespół przestrzega metodologii projektowania GRASP lub SOLID, jeśli nie luźno łączą zależności między obiektami? Jeśli nie zawracają sobie głowy, to utrwalają fabrykę spaghetti, która sprawia, że ​​jest to skomplikowane bagno. Teraz DI zwiększa złożoność, zwiększając liczbę obiektów, i chociaż ułatwia podstawienie innej implementacji, utrudnia zmianę samego interfejsu (przez dodanie dodatkowej warstwy obiektu kodu, który musi się zmienić).

  • „Nie musimy dodawać tej warstwy złożoności do już złożonego projektu” - mogą mieć rację. Kluczową rzeczą do rozważenia przy opracowywaniu kodu jest YAGNI; „Nie będziesz go potrzebować”. Projekt, który jest SOLIDNIE konstruowany od samego początku, jest projektem SOLIDNYM „na wiarę”; nie wiesz, czy będziesz potrzebować łatwości zmiany, jaką zapewniają projekty SOLID, ale masz przeczucie. Chociaż możesz mieć rację, możesz również bardzo się mylić; bardzo SOLIDNY ​​projekt może być postrzegany jako „kod lasagna” lub „kod ravioli”, mający tak wiele warstw lub kawałków wielkości kęsa, że ​​dokonywanie pozornie błahych zmian staje się trudne, ponieważ musisz przekopać się przez tak wiele warstw i / lub prześledzić taki zawiły stos wywołań.

    Popieram zasadę trzech ostrzeżeń: spraw, by działała, czyściła, uczyniła SOLIDNYM. Kiedy po raz pierwszy piszesz wiersz kodu, musi on po prostu działać i nie dostajesz punktów za projekty wieży z kości słoniowej. Załóżmy, że jest to jednorazowe i rób to, co musisz zrobić. Za drugim razem, gdy spojrzysz na ten kod, prawdopodobnie chcesz go rozwinąć lub ponownie użyć i nie jest to jednorazowy pomysł. W tym momencie uczyń go bardziej eleganckim i zrozumiałym, zmieniając go; uprościć skomplikowaną logikę, wyodrębnić powtarzający się kod do pętli i / lub wywołań metod, dodać kilka komentarzy tu i tam dla każdego kludge, który musisz zostawić na miejscu itp. Za trzecim razem, gdy spojrzysz na ten kod, jest to prawdopodobnie wielka sprawa. Teraz powinieneś przestrzegać reguł SOLID; wstrzykiwać zależności zamiast je konstruować, wyodrębniać klasy, aby przechowywać metody, które są mniej spójne z „mięsem” kodu,

  • „To nie tak, że będziemy podłączać różne implementacje” - Pan, proszę pana, ma zespół, który nie wierzy w testy jednostkowe na waszych rękach. Uważam, że nie jest możliwe napisanie testu jednostkowego, który działa w izolacji i nie ma żadnych skutków ubocznych, bez możliwości „kpienia” z obiektów, które mają te skutki uboczne. Każdy nietrywialny program ma skutki uboczne; jeśli twój program odczytuje lub zapisuje do bazy danych, otwiera lub zapisuje pliki, komunikuje się przez gniazdo sieciowe lub peryferyjne, uruchamia inny program, rysuje okna, wyświetla dane wyjściowe na konsoli lub w inny sposób wykorzystuje pamięć lub zasoby poza „piaskownicą” swojego procesu, ma efekt uboczny. Jeśli nie robi żadnej z tych rzeczy, co robi i dlaczego powinienem to kupić?

    Szczerze mówiąc, testy jednostkowe nie są jedynym sposobem na udowodnienie, że program działa; możesz pisać testy integracji, kod do algorytmów sprawdzonych matematycznie itp. Jednak testy jednostkowe bardzo szybko pokazują, że przy danych wejściowych A, B i C ten fragment kodu generuje oczekiwany X (lub nie), a tym samym, że kod działa poprawnie (lub nie działa) w danym przypadku. Zestawy testów jednostkowych mogą wykazać z dużym stopniem pewności, że kod działa we wszystkich przypadkach zgodnie z oczekiwaniami, a także zapewniają coś, czego nie jest w stanie udowodnić matematycznie; demonstracja, że ​​program STILL działa tak, jak powinien. Matematyczny dowód algorytmu nie dowodzi, że został on poprawnie zaimplementowany, ani nie dowodzi, że wprowadzone zmiany zostały poprawnie zaimplementowane i go nie złamały.

Krótko mówiąc, jeśli ten zespół nie widzi żadnej wartości w tym, co zrobiłby DI, to nie będzie go wspierać, a wszyscy (przynajmniej wszyscy starsi faceci) muszą coś kupić, aby dokonać prawdziwej zmiany wydarzyć się. Kładą duży nacisk na YAGNI. Kładziesz duży nacisk na SOLID i automatyczne testy. Gdzieś pośrodku leży prawda.

KeithS
źródło
1

Zachowaj ostrożność, dodając dodatkowe funkcje (takie jak DI) do projektu, gdy nie zostaną zatwierdzone. Jeśli masz plan projektu z ograniczeniami czasowymi, możesz wpaść w pułapkę braku czasu na ukończenie zatwierdzonych funkcji.

Nawet jeśli nie korzystasz teraz z DI, weź udział w testach, abyś dokładnie wiedział, jakie są oczekiwania na testy w Twojej firmie. Będzie inny projekt i będziesz mógł porównać problemy z testowaniem bieżącego projektu w porównaniu z DI.

Jeśli nie używasz DI, możesz stać się kreatywny i sprawić, że kod DI będzie „gotowy”. Użyj konstruktora bez parametrów, aby wywołać inne konstruktory:

MyClassConstructor()
{
    MyClassConstructor(new Dependency)
    Property = New Dependent Property
}

MyClassConstructor(Dependency)
{
    _Dependency = Dependency
}
JLH
źródło
0

Myślę, że jedna z ich największych obaw jest wręcz przeciwna: DI nie komplikuje projektu. W większości przypadków zmniejsza to złożoność.

Pomyśl tylko bez DI, co uzyskasz zależny obiekt / komponent, którego potrzebujesz? Zwykle odbywa się to przez wyszukiwanie w repozytorium, uzyskanie singletona lub utworzenie instancji.

Pierwsze 2 zawiera dodatkowy kod w zlokalizowaniu zależnego komponentu, w świecie DI nie zrobiłeś nic, aby wykonać wyszukiwanie. Złożoność komponentów jest w rzeczywistości zmniejszona.

Jeśli tworzysz się w niektórych przypadkach, co jest nieodpowiednie, powoduje to nawet większą złożoność. Musisz wiedzieć, jak poprawnie utworzyć obiekt, musisz wiedzieć, jakie wartości zainicjować obiekt do stanu, w którym można go uruchomić, wszystkie te powodują dodatkową złożoność kodu.

Zatem DI nie sprawia, że ​​projekt jest skomplikowany, ale upraszcza go, upraszczając komponenty.

Innym ważnym argumentem jest to, że nie zamierzasz podłączać różnych implementacji. Tak, to prawda, że ​​w kodzie produkcyjnym często nie ma wielu różnych implementacji w prawdziwym kodzie produkcyjnym. Jest jednak jedno ważne miejsce, które wymaga innej implementacji: Mock / Stub / Test Doubles in Tests Unit. Aby DI działało, w większości przypadków opiera się na modelu programistycznym opartym na interfejsie, z kolei umożliwia kpienie / kasowanie w testach jednostkowych. Oprócz zastąpienia implementacji „projektowanie zorientowane na interfejs” zapewnia również czystsze i lepsze projektowanie. Oczywiście nadal możesz projektować z interfejsem bez DI. Jednak testy jednostkowe i DI zmuszają cię do przyjęcia takich praktyk.

O ile twoi „bogowie” w towarzystwie nie uważają, że: „prostszy kod”, „testy jednostkowe”, „modularyzacja”, „pojedyncza odpowiedzialność” itp. Są czymś przeciwko czemu, nie powinno być powodu, aby odrzucali używanie DI.

Adrian Shum
źródło
To ładnie w teorii, ale w praktyce dodanie kontenera DI JEST dodatkową złożonością. Druga część twojego argumentu pokazuje, dlaczego warto pracować, ale nadal działa.
schlingel
W rzeczywistości z moich wcześniejszych doświadczeń, DI to REDUKCJA zamiast dodawania złożoności. Tak, ma kilka dodatkowych elementów dodanych do systemu, co przyczynia się do złożoności. Jednak w przypadku DI złożoność innych komponentów w systemie jest znacznie zmniejszona. Na koniec złożoność jest w rzeczywistości zmniejszona. W drugiej części, chyba że nie przeprowadzają żadnych testów jednostkowych, NIE jest to dodatkowa praca. Bez DI ich testy jednostkowe będą głównie trudne do napisania i utrzymania. Dzięki DI wysiłek jest znacznie zmniejszony. Tak więc jest to REDUKCJA pracy (chyba, że ​​nie są i nie ufają testom jednostkowym)
Adrian Shum
Powinienem podkreślić jedno: DI w mojej odpowiedzi nie oznacza żadnego istniejącego frameworku DI. To tylko metodologia projektowania / opracowywania komponentów w Twojej aplikacji. Możesz dużo skorzystać, jeśli kod jest oparty na interfejsie, komponenty oczekują wstrzyknięcia zależności zamiast wyszukiwania / tworzenia. Dzięki takiemu projektowi nawet piszesz jakieś „moduły ładujące” specyficzne dla aplikacji, które wykonują okablowanie komponentów (bez ogólnego przeznaczenia DI fw), nadal czerpiesz korzyści z tego, o czym wspomniałem: zmniejszenie złożoności i zmniejszenie pracy w testach jednostkowych
Adrian Shum
0

„Chcemy, aby było to proste, jeśli to możliwe, po prostu umieść wszystko w jednym zestawie. DI to niepotrzebna złożoność bez korzyści”.

Korzyścią jest to, że promuje projektowanie interfejsów i umożliwia łatwe kpiny. Co w konsekwencji ułatwia testowanie jednostkowe. Testy jednostkowe zapewniają niezawodny, modułowy i łatwy w utrzymaniu kod. Jeśli twój szef nadal utrzymuje zły pomysł, cóż, nic nie możesz zrobić - zaakceptowana najlepsza praktyka branżowa, przeciwko której się kłócą.

Poproś, aby spróbowali napisać test jednostkowy w środowisku DI i kpiącą bibliotekę, a wkrótce nauczą się go kochać.

Nim Chimpsky
źródło
Dosłownie podwojenie lub potrojenie liczby klas w twoim systemie jest teraz dla mnie przydatne. Jest to podobne do debaty o próbie uzyskania 100% pokrycia testu jednostkowego przez napisanie pojedynczego testu dla każdej metody lub napisanie znaczących testów jednostkowych.
Andrew T Finnell,
Nie rozumiem, uważasz, że testowanie jednostkowe to dobry pomysł? Jeśli to zrobisz, wyśmiewasz także przedmioty? Jest to łatwiejsze dzięki interfejsom i DI. Ale wydaje się, że właśnie o to walczysz.
NimChimpsky
To naprawdę problem z kurczakiem i jajami. Testy interfejsów / DI i jednostek są tak ściśle ze sobą powiązane, że ciężko jest zrobić jedno bez drugiego. Uważam jednak, że testy jednostkowe to lepszy i łatwiejszy sposób na rozpoczęcie od istniejącej bazy kodu. Stopniowo przekształcamy stary, kludgy kod w spójne komponenty. Następnie można argumentować, że tworzenie obiektów powinno odbywać się za pomocą frameworka DI zamiast newwszędzie i pisania klas fabrycznych, ponieważ wszystkie te komponenty są na swoim miejscu.
Spoike
0

Czy pracujesz z tymi ludźmi przy jakichkolwiek mniejszych projektach, czy tylko jednym dużym? Łatwiej jest przekonać ludzi do wypróbowania czegoś nowego w projekcie drugorzędnym / wyższym niż zespół / firmy z chleba i masła. Głównymi powodami są to, że jeśli się nie powiedzie, koszt usunięcia / wymiany jest znacznie mniejszy i jest o wiele mniej pracy, aby uzyskać go wszędzie w małym projekcie. W dużym istniejącym masz albo duży początkowy koszt wprowadzenia zmiany wszędzie na raz, albo dłuższy okres, w którym kod jest mieszanką starego / nowego podejścia zwiększającego tarcie, ponieważ musisz pamiętać, w jaki sposób każda klasa jest zaprojektowana pracować.

Dan Neely
źródło
0

Chociaż jedną z rzeczy, które promują DI, są testy jednostkowe, ale uważam, że w niektórych przypadkach dodaje ono złożoności.

  • Lepiej mieć samochód trudny w testowaniu, ale łatwy w naprawie niż samochód łatwy w testowaniu i trudny w naprawie.

  • Wydaje mi się również, że grupa działająca na rzecz DI przedstawia swoje pomysły tylko poprzez wpływanie na to, że niektóre istniejące podejścia projektowe są złe.

  • jeśli mamy metodę wykonującą 5 różnych funkcji

    DI-People mówi:

    • brak rozdzielenia obaw. [na czym polega problem? starają się, aby wyglądało to źle, co w logice i programowaniu znacznie lepiej jest wiedzieć, co robią się nawzajem, aby lepiej unikać konfliktów i złych oczekiwań oraz łatwo dostrzegać wpływ zmiany kodu, ponieważ nie możemy zrobić wszystkiego obiekty niezwiązane ze sobą w 100% lub przynajmniej nie możemy tego zagwarantować {chyba że test regresji jest ważny?}]
    • Złożona [Chcą zmniejszyć złożoność, tworząc dodatkowe pięć dodatkowych klas do obsługi jednej funkcji i dodatkowej klasy (kontenera), aby utworzyć klasę dla potrzebnej funkcji w oparciu o ustawienia (XML lub Słownik) oprócz filozofii „mieć domyślne / albo nie "dyskusje, ...] następnie przenieśli złożoność do kontenera i struktury, [dla mnie wygląda na przeniesienie złożoności z jednego miejsca do dwóch miejsc ze wszystkimi złożonościami specyficznymi dla języka, aby sobie z tym poradzić. ]

Uważam, że lepiej jest stworzyć nasz własny wzór projektowy, który bardziej odpowiada potrzebom biznesowym, niż być pod wpływem DI.

na korzyść DI, może to pomóc w niektórych sytuacjach, na przykład, jeśli masz setki implementacji dla tego samego interfejsu zależy od selektora, a implementacje te różnią się znacznie logiką, w tym przypadku wybrałbym DI lub DI podobne techniki. ale jeśli mamy kilka implementacji dla tego samego interfejsu, nie potrzebujemy DI.

użytkownik114367
źródło