DI: profesjonalne kontenery

11

Po długiej przerwie cykl, wraz ze mną, wraca do życia. W poprzednim odcinku padło stwierdzenie, że rozwiązaniem problemu wielu skomplikowanych zależności jest kontener. I że najlepszy jest własny. O ile drugie stwierdzenie na pewno jest durne i bezsensowne, to z pierwszym też można polemizować.

A może tak bez kontenera?

Użycie kontenera jest jedną z opcji zarządzania zależnościami w projekcie… jednak nie jedyną. Pamiętacie “baobab” – analogię jaką w przebłysku geniuszu wysnułem o tutaj? Że zależności są jak matrioszka, że nie chciałbym składać swoich zależności ręcznie, i tak dalej…

Okazuje się, że to nie jest takie czarno-białe. Zapraszam do tekstu “Z kontenerem czy bez?” po więcej dywagacji.

Dlaczego nie “własny” kontener?

Na pewno nie będę produkcyjnie wykorzystywał czegoś, co sam napisałem, ponieważ jest to po prostu najgorsze z możliwych rozwiązań. Kontenery w prawdziwego zdarzenia mają tyle przewag nad moją implementacją, że długo by wymieniać… ale spójrzmy na kilka chociażby kwestii.

Po pierwsze: inny szanujący się kontener daje możliwość automatycznej rejestracji komponentów. Podaję mu dllki, które ma przeskanować, a on sam robi resztę. Mogę ten proces dodatkowo stuningować tak, żeby spełniał moje – czasem nawet dość wygórowane – wymagania, jednocześnie uciekając od konieczności każdorazowego dodawania linijki rejestrującej w kontenerze każdą nową klasę.

Po drugie: inny szanujący się kontener daje możliwość zarządzania cyklem życia tworzonych komponentów. Mój biedny pseudo-kontenerek ( https://github.com/maniserowicz/di-talk/blob/tests-for-container/src/app/PoorMansContainer.cs ) zawsze tworzył nową instancję obiektu. Jest to całkowicie poprawne DOMYŚLNE zachowanie, ale jako programista powinienem mieć możliwość powiedzenia mu: jeśli ktoś zażąda implementacji interfejsu X to w trakcie obsługi jednego webrequesta stwórz tylko jedną instancję. Albo daną “rejestrację” traktuj całkowicie jako singleton… co daje taką korzyść, że mam jedną instancję jakiejś klasy a ktoś czytający jej kod nie będzie na mnie krzyczał za to że wykorzystuję coś co często jest uznawane jako antipattern :).

Po trzecie: inny szanujący się kontener daje możliwość uzyskania całej kolekcji wszystkich implementacji danego interfejsu. Wystarczy jako zależność podać IEnumerable<IInterface>. Chociaż akurat to byłoby dość łatwo dodać i do mojego kontenerka.

Po czwarte: inny szanujący się kontener może automatycznie zarejestrować fabryki tworzące komponenty tak, abym mógł zadeklarować zależność jako Func<IInterface> i tylko w przypadku faktycznej konieczności utworzenia instancji uczynić to w mojej klasie “klienckiej”.

Po piąte: inny szanujący się kontener może pozwolić mi małym kosztem, bez wykorzystania dodatkowych narzędzi, zaimplementować AOP, czyli programowanie aspektowe! Co prawda ta koncepcja do mnie osobiście nie przemawia, ale warto zdawać sobie sprawę z takiej możliwości (o AOP będziecie mogli posłuchać przy okazji zbliżającego się eventu dotnetconf.pl, gdzie Basia będzie o tym gadać).

Po szóste: inny szanujący się kontener będzie prawdopodobnie działał szybciej niż ten mój. Ale do tego zaraz wrócimy.

Po siódme: inne kontenery oferują niekiedy bardzo ciekawe narzędzia wspomagające pracę z nimi. Zobaczcie chociażby jak wygląda debuggowanie Castle Windsor: http://docs.castleproject.org/Default.aspx?Page=Debugger-views&NS=Windsor. Jaw dropped? U mnie tak.

Po ósme: inne kontenery są pisane latami, przez dobre zespoły. Są przetestowane w setkach projektów przez tysiące programistów.

Po… i tak dalej.

Kontenery do wyboru

W świecie .NET mamy wybór naprawdę imponujący:

Ja od wielu lat na co dzień używam Autofac i z czystym sumieniem mogę go polecić.

W jednym projekcie pisanym w Nancy próbowałem używać TinyIoC i przez dość długi czas się sprawdzał, ale w końcu okazał się “zbyt tiny” i trzeba się było przemigrować na Autofaca.

Z 6 lat temu miałem romans z Unity, ale zrejterowałem. Jeśli ten projekt nie poszedł znacznie do przodu od tamtego czasu to zdecydowanie go nie polecam… ale jeśli by nie poszedł do przodu, to pewnie by już dawno zdechł. Więc pewnie poszedł. Więc nie mam opinii :).

Jak wybrać kontener?

W wielu “porównaniach” kontenerów na pierwszym miejscu badana jest ich wydajność. I jest to, powiem szczerze, jedna z najgłupszych rzeczy jaką można zrobić: porównywać kontenery pod względem wydajności i na tym opierać swój wybór. Dlaczego? Dlatego że dla mnie osobiście nie robi różnicy czy kontener jest w stanie stworzyć miliard obiektów z 5 czy 10 milisekund. Jeżeli wąskim gardłem w aplikacji jest proces tworzenia obiektów to pozostaje tylko pogratulować zespołowi, że tak znakomicie i megawydajnie ją napisał. Szapoba, buty cmokam. Ja się z taką aplikacją jeszcze nie spotkałem i wątpię, żebym się kiedykolwiek spotkał.

Na co zatem zwracać uwagę? Na możliwości kontenera oraz na proponowaną przez jego twórców składnię. Byłem niezmiernie zaskoczony gdy zaobserwowałem na jak wiele różnych sposobów można zrealizować dokładnie to samo zadanie, czyli zaimplementować parę funkcji Register/Resolve. Dodatkowych rekomendacji nie mam: hulaj dusza, piekła nie ma. Tym bardziej, że zmiana kontenera na inny nie powinna wiązać się z ogromnym nakładem pracy (chociaż raz – we wspomnianym projekcie w Nancy – tak się niestety zdarzyło i wpięcie Autofaca zajęło mi tydzień z okładem).

Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.

11 Comments

  1. Pingback: dotnetomaniak.pl

  2. siararadek on

    Ja używam w pracy Ninject’a i sobie chwalę. Ma dużo rozszerzeń spinających go z ASP.NET’em, FluentValidatorem, konwencje bindowania automatycznego, dobre zarządzanie lifetime’m.

  3. Osobiście jestem wielkim fanem Ninjecta, jak do tej pory nigdy mnie nie zawiódł, a i korzystanie z niego jest czystą przyjemnością.

    Unity jest ogromną kobyłą, więc jeśli mam duży projekt to mogę to rozważyć. Wbrew pozorom, nie jest tak źle jakby się mogło wydawać. W przypadku mniejszych projektów nie ma sensu go zaciągać.

    Przyznam też, że nigdy nie miałem do czynienia z Autofac, więc chyba najwyższa pora wypróbować, skoro tak go zachwalasz ;)

    Pozdrawiam

    MJ

  4. simpleinjector fajna sprawa, potrafi z bomby resolvować dekoratory. ma jedną wadę – jest oparty na “jedynych słusznych” założeniach i trzymają się ich w 100% – przez co np nie ma “rejestracji nazwanych”, przez co odpada w niektórych zastosowaniach…

  5. Z Ninjecta ani SimpleInjectora nie korzystałem, jakoś tak na samym początku postawiłem na Autofac i od tamtej pory nie potrzebowałem go zmieniać. Ale na pewno są dobre, bo czemu nie? :)

  6. Ja podobnie jak Maciek, raz użyłem StructureMap i tak już zostało. Jak działa, spełnia moje wymagania to nie zmieniam. :)

  7. W sumie wybor kontenera do IoC to chyba tylko kwestia gustu. Ja korzystam z ninjecta i lubie to ;) Wykorzystuje go nawet do malych projektow, bo konfiguracja nie jest jakas skomplikowana, a sporo przyspiesza i ulatwia prace.

  8. Pingback: DI: użycie Autofac | Maciej Aniserowicz o programowaniu

  9. Ja osobiście używałem kiedyś ObjectBuilder (CAB/SCSF), Spring.NET, potem Unity, a od jakiegoś czasu używam niezmiennie Castle.Windsor. Przejrzyste API, interceptory, wsparcie dla WCF, itd. Przychylam się do opinii, że wybór kontenera IoC to często kwestia gustu, a może nawet przypadku. Myślę, że stosunkowo bezboleśnie mógłbym się w tym momencie przesiąść na np. Autofac.

Newsletter: devstyle weekly!
Dołącz do 1000 programistów!
  Zero spamu. Tylko ciekawe treści.
Dzięki za zaufanie!
Do przeczytania w najbliższy piątek!
Niech DEV będzie z Tobą!