Рецензия на книгу Марка Сиимана «Dependency Injection in .NET»



    Открывая книгу по «новомодной технике проектирования», такой как инверсия зависимостей ожидаешь увидеть описание очередной серебряной пули. Дескать, вот, до этого все мы жили неправильно, а теперь, вооружившись ломом контейнером и какой-то матерью мы сможем писать новые приложения за 10 минут.
    Поскольку сам я к подобным новомодным инструментам отношусь с некоторой осторожностью, то я был приятно удивлен тем, что в книге Марк делает акцент на общепринятых практиках проектирования, роли стандартных паттернов проектирования, да и вообще, рассматривает принципы управления зависимостями в отрыве от конкретных инструментов.


    ЦИТАТА
    Если вы думаете, что DIтребует использование DI контейнера, то это еще один момент, который нужно переучивать. DI – это набор принципов и паттернов, и DI контейнер является хотя и полезным, но необязательным инструментом.
    Глядя на типовое использование инверсии зависимостей во многих проектах складывается впечатления, что DI противоречит основным принципам проектирования, о которых так много пишут Мейер и Буч.

    В угоду якобы «слабосвязанного дизайна» выделяются десятки ненужных интерфейсов, направо и налево используются сами контейнеры в роли Service Locator-ов, создаются классы с десятком параметров конструктора, обязательные зависимости классов передаются через свойства и т.д. Глядя на все это складывается впечатление, что DI-контейнеры противоречат таким вещам, как инварианты класса и четкий контракт между классом и его клиентами.

    ЦИТАТА
    DI – это не самоцель. Управление зависимостями ведет к слабой связанности (loosecoupling), что ведет к более сопровождаемому коду.
    Марк начинает с того, что старается развеять основные мифы о DI, и лишь потом начинает описание основных концепций. Так, автор с первых страниц говорит о том, что Service Locator является анти-паттерном и контейнер должен использоваться лишь в одном месте, в «корне приложения» (в так называемом Composition Root), говорит о том, что IOC != DI, пишет о проблемах с использованием файлов конфигурации для управления содержимым контейнера и многом другом.

    ЦИТАТА
    Не ждите, что использование DI контейнеров волшебным образом сделает ваш код слабосвязанным. DI контейнер может сделать управление зависимостями более эффективным, но ваше приложение должно быть прежде всего спроектировано с учетом DI техник и принципов.

    Очень порадовало то, что главной целью книги автор поставил не рассмотрение конкретных библиотек, а сделал акцент на общих принципах управления зависимостями и показал связь этих принципов со стандартными паттернами проектирования и ОО принципами (ведь большая часть классических паттернов проектирования используют управление зависимостями в том или ином виде: так, декоратор использует Constructor Injection, а стратегия – Method Injection или Constructor Injection и т.д.).

    На протяжении первых трех частей вообще не используются никакие контейнеры и во всех примерах используются «самопальное» управление зависимостями (так называемый Poor Man’s DI).

    ЦИТАТА
    DI-контейнер – это лишь инструмент, и как любой инструмент, его можно использовать правильно, а можно и неправильно.

    Очень порадовало, что помимо самих принципов и паттернов автор описывает и то, когда они применимы, а когда нет. У любого паттерна есть своя область применения, один из них подходит в одном случае и не подходит в другом. А некоторые паттерны вообще кажутся весьма привлекательными, а на деле оказывается, что их использование может привести к серьезным проблемам. Именно по этой причине целая часть книги посвящена основным DI-паттернам и анти-паттернам; и хотя это не гарантирует их правильного применения в наших проектах, это дает достаточно пищи для размышлений, и делает шансы на использование этого инструмента корректным образом максимально большими.

    ЦИТАТА
    Чрезмерное количество параметров конструктора (ConstructorOver-injection) не является проблемой управления зависимостей вообще, и передачи зависимостей через конструктор (ConstructorInjection), в частности. Скорее, это показатель того, что у рассматриваемого класса слишком много ответственностей. Этот душок (codesmell) идет от класса, а не от передачи зависимостей через конструктор; и мы, как обычно, должны использовать его, как стимул для улучшения нашего кода.

    Если посмотреть на разные DI контейнеры, то можно обратить внимание, что одни и те же концепции во многих местах называются по разному. Любой контейнер поддерживает определенный набор стратегий управления временем жизни зависимости (lifetime management), и хотя многие из них аналогичны очень часто они называются по разному.

    В этом плане, книга решает две дополнительные задачи. Во-первых, автор вводит согласованную терминологию (Auto Wiring, Composition Root, Bastard Injection etc), а во-вторых, дает знания основных принципов, которые можно использовать с любым контейнером или без него. Эти знания можно спокойно использовать повторно, что сэкономит время на изучение новых библиотек, а также позволит увидеть картину управления зависимостями целиком.

    ЦИТАТА
    Добавление Швов в приложение требует дополнительных усилий, поэтому добавлять их стоит только в случае необходимости.
    (Марк о выделении интерфейсов и создании дополнительных швов приложения)

    У этой книги есть один недостаток – это последняя четвертая часть, посвященная описанию шести DI-контейнеров. У меня сложилось впечатление, что автор посчитал, что книга из 350 страниц выглядит не солидно, либо же главным KPI для него было именно количество страниц.

    В любом случае, КПД последних 200 страниц крайне мало. Первая проблема заключается в том, что каждый контейнер является достаточно серьезным монстром, и его невозможно описать на 50 страницах. Во-вторых, автор сделал разумную попытку унифицированного описания каждого контейнера, что привело к большому количеству «копи-пасты» (вплоть до одинаковых абзацев), и отсутствию описания уникальных возможностей контейнеров.
    В результате, 200 страниц потрачены практически впустую, поскольку текущего описания хватает лишь для сравнения наиболее ключевых моментов, но их недостаточно даже для выбора контейнера для своего проекта, не говоря уже за их полноценное использование.

    Подводя итог, хочу сказать, что “Dependency Injection in .NET” является наиболее полным и последовательным источником информации по управлению зависимостями. Я бы рекомендовал первые 3 части этой книги к обязательному прочтению всем командам, которые используют DI контейнеры в своих проектах.

    Оценка: 5+ (для частей 1-3) и 2 (для части 4).
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 17

      +2
      Марк, весьма педантичный и перфекционист к тому же, но книга хорошая. Я её читала в самолёте, пока летела из Дании.

      Как-то я попросила отсортировать в порядке личного предпочтения DI-контейнеры, и Unity оказался на втором месте из-за следующего поведения:

      var container = new UnityContainer();
      
      container.RegisterType<IModule, Module1>();
      container.RegisterType<IModule, Module2>("AAA");
      container.RegisterType<IModule, Module2>("BBB");
      
      var case1 = container.Resolve<IModule>();
      var case2 = container.ResolveAll<IModule>();
      
      


      Дак вот, в первом случаи (case1) мы получим реализацию Module1, а во втором случаи массив из реализаций Module2

      Для Марка такое поведение не очивидно, почему-то)
        0
        Мало чего понял из вашего комментария, но тот же Autofaq тоже умеет ResolveAll (несколько специфически).
          0
          Напишите отсортированный список, пожалуйста.
          –9
          DI это новомодное явление в С#? Интересуюсь как джавист, просто банальный интерес.
            +3
            нет. Это просто один из способов организации архитектуры приложения.
                0
                В Java так же практикуют DI.
                  0
                  А порекомендуйте что почитать/посмотреть на тему DI in Java.
                  0
                  DI это новомодное явление в С#? Интересуюсь как джавист, просто банальный интерес.

                  >> DI – это набор принципов и паттернов

                  DI не привязан к языку.
                    0
                    Я почему и спросил что в джава оно сплошь и рядом, это как стандарт, а тут в заголовке увидел
                    Открывая книгу по «новомодной технике проектирования», такой как инверсия зависимостей
                    вот и удивился. Попросил прокоментировать, и тут сразу минусяторы набежали (
                      +3
                      Кавычки для кого там написаны?
                  0
                  Одна из моих любимых книг. После прочтения уже не могу писать сильно связанный код.
                    0
                    про Service Locator у Марка три года назад статья была — Service Locator is an Anti-Pattern
                      0
                      Добавлю: Марк пишет у себя в блоке в основном о том, как те или иные проблемы в его проектах решаются, и иногда резюмирует, вроде как Service Locator is an Anti-Pattern. Рекомендую его блог, а ещё он отвечает в StackOverflow

                      Короче, мужик умный, но задрот :)
                        +2
                        > Короче, мужик умный, но задрот :)
                        На таких и держится индустрия…
                      0
                      К сожалению, в книге не описаны ChildContainers и зачем они нужны, это до сих пор загадка для меня :)
                      А так, книга просто шикарная. И глава 4 тоже не настолько плоха, она позволяет сложить поверхностное впечатление о существующих на рынке контейнерах.
                        0
                        Child контейнеры (в Unity) нужны, чтобы разделить логику резолва зависимостей. К примеру для классов такого-то типа резолвить IContext в Context1, для других — в Context2.
                        В Windsor это достигается путем добавления SelectionHandler-ов

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое