Dependency Injection to bardzo potężny i przydatny wzorzec projektowy. Pozwala zaprowadzić w kodzie porządek, jawnie zadeklarować powiązania między klasami i uprościć proces utrzymania kodu. Powstała cała masa narzędzi wspomagających nas w tym światłym dziele. I po co?
[blogvember2016 no=”17″]
Kontenery
Kontenery Dependency Injection powstały, aby uprościć proces tworzenia obiektów w systemie. Mówimy im, jakie klasy wchodzą w skład systemu, a one sobie wszystkie klocki układają. Zależności między strukturami wykrywają. Drzewa zasadzają, grafy modelują. By na koniec: tworzyć instancje.
Co bardziej zaawansowane kontenery potrafią o wiele więcej. A to Aspect-Oriented Programming nam udostępnią, a to dekoratory w prosty sposób pozwolą dorzucić, a to Dispose() wywołają kiedy trzeba, a to to, a to tamto. Więcej można poczytać w poście Profesjonalne kontenery i DI: kontener.
Lata temu ludzie rzucili się na tę rodzinę narzędzi. Powstawały coraz to nowe, bardziej skomplikowane. Później, jak to często bywa, nastąpił odwrót i tendencja upraszczania całego procesu zarządzania zależnościami. Aż dotarliśmy do stanu równowagi: equilibrium. Wszyscy byli szczęśliwi.
A potem: z dev-Olimpu poleciały gromy.
Alternatywa
Po co nam dodatkowe narzędzia? Możemy to naklepać ręcznie! W każdym projekcie z osobna! Bo kontenery są trudne! I powinniśmy minimalizować liczbę zależności w projekcie!
Takie oto głosy zaczęły dobiegać z programistycznych niebiesiech. Okazało się, że na przykład Mark Seemann (autor książki “Dependency Injection in .NET”) i Greg Young (kto nie zna, ten niech pozna we własnym zakresie) wiele mają kontenerom do zarzucenia. Że to UNIKALNE (IUnikable) zło. Że niepotrzebne. Że skomplikowane.
Polecam chociażby te linki:
- Mark: “When to use a DI Container” (txt)
- Mark: “DI Friendly Framework” (txt)
- Greg: “8 Lines of Code” (vid)
- … (jest tego więcej)
Argumenty przedstawiane w tych treściach na pewno nie są bezpodstawne. Ci kolesie, jak już otwierają paszczę lub siadają do klawiatury, to wiedzą co czynią. Mam tylko jeden problem: zaprezentowane remedium… zupełnie do mnie nie przemawia.
Eksperymentalnie zrealizowałem kiedyś projekt bez wykorzystania kontenera. Wszystkie zależności rzeźbiłem ręcznie. Projekt ten miał raptem kilkadziesiąt klas na krzyż (“las krzyży” vs “las klas”?), a i tak kod budujący obiekty wyglądał bardzo… kupiaszczo. Nie chciałbym teraz do niego wrócić.
Werdykt
Kontenery nie są narzędziami banalnymi w “obsłudze”. Ich niepoprawne skonfigurowanie może nieść za sobą katastrofalne konsekwencje. Co powiedz na aplikację, która wysypuje się co 2 tygodnie, bo z powodu nieprzemyślanych rejestracji obiekty mnożą się jak wirusy i zżerają całą pamięć? Wiesz, ile czasu może zająć diagnostyka i profilowanie? Ja wiem :), więc podpowiem: DNI całe!
Ale z drugiej strony: popatrz na kod w podlinkowanych postach i prezentacjach.
Lambda na lambdzie i lambdą pogania. Poukrywane, pozagnieżdżane. Ja osobiście wolę mieć 50 linii czytelnego kodu niż 8 linii kodu, który bez problemu “załapie” maksymalnie 10% populacji.
Albo IFy, SWITCHe. Kurde… ControllerFactory o nazwie PoorMansCompositionRoot? Z mega-switchem? Ciut nie pattern-matching, tylko dla BARDZO ubogich.
Bardzo szanuję obu Panów, są półbogami programowania. Gdyby ich scalić, to powstałby dev-bóg. Ale tego… po prostu nie kupuję.
Oczywiście, każda zależność, referencja, to dodatkowy koszt. Każde narzędzie to proces nauki, obowiązki związane z utrzymaniem i aktualizacjami. Każda biblioteka to ryzyko “cudzych” błędów. Ale czy to powód, żeby wszystko pisać samemu?
NIE! A nawet: NIH! NIH Syndrome się kłania. Tak, jak bez sensu jest pisać własny kontener (co na jutubie czynię :) ), tak bez sensu jest ręcznie, samodzielnie, dbać o wszystkie rejestracje i tworzenie obiektów.
Z głową i umiarem. Świadomie, panie i panowie. Ze zrozumieniem, bez tępego copy/paste ze StackOverflow. Oto uniwersalna porada i maść na ból wszelaki.