Пусть будет известно, что я большой поклонник внедрения зависимостей (DI) и автоматизированного тестирования. Я мог бы говорить об этом весь день.
Фон
Недавно наша команда только что получила этот большой проект, который должен быть построен с нуля. Это стратегическое приложение со сложными бизнес-требованиями. Конечно, я хотел, чтобы он был красивым и чистым, что для меня означало: ремонтопригодность и возможность тестирования. Поэтому я хотел использовать DI.
сопротивление
Проблема была в нашей команде, ДИ это табу. Он был поднят несколько раз, но боги не одобряют. Но это не обескуражило меня.
Мой ход
Это может звучать странно, но сторонние библиотеки обычно не одобрены нашей командой архитекторов (подумайте: «не говорите о Unity , Ninject , NHibernate , Moq или NUnit , чтобы я не порезал вам палец»). Поэтому вместо того, чтобы использовать установленный DI-контейнер, я написал чрезвычайно простой контейнер. Он в основном связал все ваши зависимости при запуске, внедрил все зависимости (конструктор / свойство) и удалил любые одноразовые объекты в конце веб-запроса. Это было чрезвычайно легко и просто делало то, что нам было нужно. И тогда я попросил их пересмотреть это.
Ответ
Ну, чтобы сделать это коротким. Я встретил тяжелое сопротивление. Основным аргументом было: «Нам не нужно добавлять этот уровень сложности в уже сложный проект». Также «Это не значит, что мы будем подключать различные реализации компонентов». И «Мы хотим сделать это простым, если возможно, просто собрать все в одну сборку. DI - это ненужная сложность без выгоды».
Наконец мой вопрос
Как бы вы справились с моей ситуацией? Я не очень хорошо представляю свои идеи, и я хотел бы знать, как люди будут представлять свои аргументы.
Конечно, я предполагаю, что, как и я, вы предпочитаете использовать DI. Если вы не согласны, пожалуйста, скажите почему, чтобы я мог видеть другую сторону медали. Было бы действительно интересно увидеть точку зрения того, кто не согласен.
Обновить
Спасибо за ответы всех. Это действительно ставит вещи в перспективе. Достаточно приятно иметь другой взгляд, чтобы дать вам обратную связь, пятнадцать - это действительно здорово! Это действительно хорошие ответы, которые помогли мне увидеть проблему с разных сторон, но я могу выбрать только один ответ, поэтому я просто выберу один из лучших. Спасибо всем, что нашли время ответить.
Я решил, что это, вероятно, не лучшее время для внедрения DI, и мы не готовы к этому. Вместо этого я сконцентрирую свои усилия на том, чтобы сделать тестируемую конструкцию и попытаться представить автоматизированное модульное тестирование. Я знаю, что написание тестов - это дополнительные издержки, и если когда-нибудь будет решено, что дополнительные издержки не стоят того, лично я все равно буду считать это выигрышной ситуацией, поскольку дизайн все еще подлежит тестированию. И если когда-либо выбор или DI - выбор в будущем, дизайн может легко справиться с этим.
Ответы:
Взяв пару встречных аргументов:
Вы хотите, чтобы система была тестируемой. Чтобы быть легко тестируемым, вам нужно взглянуть на макетирование различных уровней проекта (базы данных, коммуникаций и т. Д.), И в этом случае вы будете подключать различные реализации компонентов.
Продайте ДИ на тех преимуществах тестирования, которые оно вам дает. Если проект сложный, то вам понадобятся хорошие, надежные юнит-тесты.
Еще одним преимуществом является то, что при кодировании интерфейсов, если вы придумаете лучшую реализацию (быстрее, с меньшим потреблением памяти) любого из ваших компонентов, использование DI значительно упростит замену старой реализации на новый.
Здесь я говорю о том, что вам нужно рассмотреть преимущества, которые приносит DI, а не спорить о DI ради DI. Заставляя людей согласиться с утверждением:
Затем вы переносите проблему. Вы должны убедиться, что DI является ответом на это утверждение. Таким образом, вы, коллеги, будете владеть решением, а не чувствовать, что оно навязано им.
источник
Из того, что вы пишете, не DI сам по себе является табу, но использование DI-контейнеров, а это совсем другое. Я полагаю, что у вас не возникнет проблем с вашей командой, когда вы просто напишите независимые компоненты, которые получат другие компоненты, которые им нужны, например, через конструктор. Только не называй это "DI".
Вы можете подумать, что для таких компонентов не использовать DI-контейнер утомительно, и вы правы, но дайте своей команде время, чтобы выяснить это для себя.
источник
Так как вы спросили, я встану на сторону вашей команды против DI.
Дело против внедрения зависимости
Существует правило, которое я называю «Сохранение сложности», которое аналогично правилу в физике, называемому «Сохранение энергии». В нем говорится, что никакие технические разработки не могут уменьшить общую сложность оптимального решения проблемы, все, что он может сделать, - это изменить эту сложность. Продукты Apple не менее сложны, чем продукты Microsoft, они просто переносят сложность из пользовательского пространства в инженерное пространство. (Однако это ошибочная аналогия. Хотя вы не можете создавать энергию, инженеры имеют неприятную привычку создавать сложности на каждом шагу. На самом деле, многим программистам нравится добавлять сложность и использовать магию, что по определению сложность, которую программист не до конца понимает. Эту избыточную сложность можно уменьшить. Обычно то, что выглядит как уменьшение сложности, просто переносит сложность куда-то еще, обычно в библиотеку.
Точно так же DI не уменьшает сложность связывания клиентских объектов с серверными объектами. Что он делает, так это берет его из Java и перемещает его в XML. Это хорошо, потому что он объединяет все в один (или несколько) XML-файл (-ы), где легко увидеть все, что происходит, и где можно что-то изменить, не перекомпилируя код. С другой стороны, это плохо, потому что файлы XML не являются Java и, следовательно, недоступны для инструментов Java. Вы не можете отлаживать их в отладчике, вы не можете использовать статический анализ для отслеживания их иерархии вызовов и так далее. В частности, ошибки в структуре DI становятся чрезвычайно трудными для обнаружения, идентификации и исправления.
Поэтому намного сложнее доказать правильность программы при использовании DI. Многие люди утверждают, что программы, использующие DI, легче тестировать , но тестирование программ никогда не сможет доказать отсутствие ошибок . (Обратите внимание, что связанному документу около 40 лет, и поэтому он имеет некоторые тайные ссылки и цитирует некоторые устаревшие практики, но многие основные утверждения все еще остаются в силе. В частности, что P <= p ^ n, где P - вероятность того, что в системе нет ошибок, p - вероятность того, что компонент системы не содержит ошибок, а n - количество компонентов. Конечно, это уравнение упрощено, но оно указывает на важную истину.) Авария NASDAQ во время IPO Facebook - недавний пример, гдеони утверждали, что потратили 1000 часов на тестирование кода и до сих пор не обнаружили ошибок, вызвавших сбой. 1000 часов - это половина человеко-года, поэтому они не скупятся на тестирование.
Правда, вряд ли кто-нибудь когда-либо предпримет (не говоря уже о том, чтобы выполнить) задачу формальной проверки правильности любого кода, но даже слабые попытки доказательства выбивают большинство режимов тестирования для поиска ошибок. Сильные попытки доказательства, например L4.verified , неизменно выявляют большое количество ошибок, которые тестирование не обнаруживало и, вероятно, никогда не обнаружит, если тестировщик уже не знал точную природу ошибки. Все, что затрудняет проверку кода при проверке, можно рассматривать как уменьшение вероятности обнаружения ошибок , даже если это увеличивает возможность тестирования.
Кроме того, DI не требуется для тестирования . Я редко использую его для этой цели, так как я предпочитаю тестировать систему на реальном программном обеспечении, а не на какой-либо альтернативной версии тестирования. Все, что я изменяю в тесте, хранится (или может быть также) в файлах свойств, которые направляют программу к ресурсам в тестовой среде, а не в рабочую среду. Я бы скорее потратил время на настройку тестового сервера базы данных с копией рабочей базы данных, чем потратил бы время на кодирование фиктивной базы данных, потому что таким образом я смогу отслеживать проблемы с производственными данными (проблемы кодирования символов - только один из примеров ) и ошибки системной интеграции, а также ошибки в остальной части кода.
Инъекция зависимости также не требуется для инверсии зависимости . Вы можете легко использовать статические фабричные методы для реализации инверсии зависимости. Именно так и было сделано в 1990-х годах.
По правде говоря, хотя я использую DI в течение десятилетия, единственное преимущество, которое он обеспечивает, я нахожу убедительным, - это возможность настроить сторонние библиотеки для использования сторонних библиотек (например, настроить Spring для использования Hibernate и оба для использования Log4J). ) и включение IoC через прокси. Если вы не используете сторонние библиотеки и не используете IoC, то в этом нет особого смысла, и это действительно добавляет необоснованную сложность.
источник
Извините, что ваша проблема, учитывая то, что ваши коллеги сказали в вашем вопросе, носит скорее политический характер, чем технический. Есть две мантры, которые вы должны иметь в виду:
Конечно, вы можете привести множество контраргументов с вескими техническими причинами и преимуществами, но это поставит вас в плохую ситуацию с остальной частью компании. У них уже есть позиция, что они этого не хотят (потому что им удобно, как все работает сейчас). Так что это может даже повредить вашим отношениям с коллегами, если вы будете настойчивы в этом. Поверьте мне в этом, потому что это случилось со мной и в конечном итоге меня уволили несколько лет назад (молодым и наивным, каким я был); это ситуация, в которую ты не хочешь ввязываться.
Дело в том, что вам нужно достичь определенного уровня доверия, прежде чем люди зайдут так далеко, чтобы изменить свой нынешний способ работы. Если вы не находитесь в положении, когда вам доверяют, или вы не можете решать такие вещи, как роль архитектора или технического руководителя, вы очень мало можете сделать, чтобы повернуть своих коллег. Потребуется много времени, чтобы убедить и приложить усилия (например, предпринять небольшие шаги по улучшению), чтобы завоевать доверие и изменить свою корпоративную культуру. Мы говорим о временном интервале в несколько месяцев или лет.
Если вы обнаружите, что текущая культура компании не работает с вами, то, по крайней мере, вы знаете еще одну вещь, которую следует спросить на следующем собеседовании. ;-)
источник
Не используйте DI. Забудь это.
Создайте реализацию фабричного шаблона GoF, который «создает» или «находит» ваши конкретные зависимости и передает их вашему объекту, оставляя его при этом, но не называйте его DI и не создавайте сложную обобщенную структуру. Держите это простым и актуальным. Убедитесь, что зависимости и ваши классы таковы, что переключение на DI возможно; но держите фабрику мастером и держите ее чрезвычайно ограниченной по объему.
Со временем можно надеяться, что он вырастет и даже в один прекрасный день перейдет на DI. Пусть ведущие приходят к выводу самостоятельно и не торопятся. Даже если вы никогда этого не достигнете, по крайней мере, ваш код имеет некоторые преимущества DI, например, код, тестируемый модулем.
источник
Я видел проекты, которые доводили DI до крайности, чтобы проводить модульное тестирование и макетировать объекты. Настолько, что конфигурация DI стала языком программирования сама по себе с такой конфигурацией, которая необходима для работы системы, как с реальным кодом.
Страдает ли система сейчас из-за отсутствия соответствующих внутренних API-интерфейсов, которые невозможно протестировать? Вы надеетесь, что переключение системы на модель DI позволит вам лучше провести модульное тестирование? Вам не нужен контейнер для модульного тестирования вашего кода. Использование модели DI позволит вам проще провести модульное тестирование с объектами Mock, но это не обязательно.
Вам не нужно переключать всю систему, чтобы она была совместима с DI. Вы также не должны произвольно писать модульные тесты. Рефакторинг кода по мере его появления в вашей функции и ошибок рабочих билетов. Затем убедитесь, что код, к которому вы прикоснулись, легко тестируется.
Думайте о CodeRot как о болезни. Вы не хотите начинать произвольно взламывать вещи. У вас есть пациент, вы видите больное место, поэтому вы начинаете фиксировать это место и все вокруг него. Как только эта область станет чистой, вы переходите к следующей. Рано или поздно вы коснетесь большей части кода, и для этого не потребовалось это «масштабное» изменение архитектуры.
Мне не нравится, что тестирование DI и Mock являются взаимоисключающими. И после того, как я увидел проект, который, из-за отсутствия лучшего слова, безумно использовал DI, я бы тоже устал, не видя пользы.
Есть несколько мест, где есть смысл использовать DI:
Требование, чтобы каждый разработчик знал, где находится файл конфигурации DI (я понимаю, что контейнеры могут быть созданы с помощью кода, но зачем вам это делать.), Когда они хотят выполнить RegEx, разочаровывает. О, я вижу, что есть IRegExCompiler, DefaultRegExCompiler и SuperAwesomeRegExCompiler. Тем не менее, нигде в коде я не могу выполнить анализ, чтобы увидеть, где используется Default и SuperAwesome.
Моя личность отреагировала бы лучше, если бы кто-то показал мне что-то лучше, а затем попытался бы убедить меня своими словами. Есть кое-что, что можно сказать о ком-то, кто потратит время и силы на улучшение системы. Я не считаю, что многие разработчики заботятся о том, чтобы сделать продукт по-настоящему лучше. Если бы вы могли обратиться к ним с реальными изменениями в системе и показать им, как она сделала это лучше и проще для вас, это стоит больше, чем любое онлайн-исследование.
Таким образом, лучший способ добиться изменений в системе - медленно делать код, к которому вы сейчас обращаетесь, лучше с каждым проходом. Рано или поздно вы сможете превратить систему в нечто лучшее.
источник
DI не требует инвазивных контейнеров Inversion of Control или поддельных структур. Вы можете отделить код и позволить DI через простой дизайн. Вы можете проводить модульное тестирование с помощью встроенных возможностей Visual Studio.
Чтобы быть справедливым, ваши коллеги имеют точку зрения. Неправильное использование этих библиотек (а поскольку они незнакомы с ними, будут проблемы с обучением) вызовет проблемы. В конце концов, код имеет значение. Не испортите свой продукт для ваших тестов.
Просто помните, что компромисс необходим в этих сценариях.
источник
Я не думаю, что вы можете продавать DI больше, потому что это догматическое решение (или, как @Spoike назвал его более вежливым, политическим ).
В этой ситуации спорить с общепринятыми лучшими практиками, такими как принципы разработки SOLID, уже невозможно.
Кто-то, кто имеет больше политической власти, чем вы, принял (возможно, неправильное) решение не использовать DI.
Вы, с другой стороны, выступили против этого решения, внедрив собственный контейнер, поскольку использование установленного контейнера было запрещено. Эта политика свершившегося факта, которую вы попробовали, могла еще больше усугубить ситуацию.
Анализ
По моему мнению, DI без разработки на основе тестов (TDD) и модульного тестирования не имеет существенного преимущества, которое перевешивает первоначальные дополнительные затраты.
Этот вопрос действительно о
или это больше о
[Обновить]
Если вы видите свой проект из классических ошибок в представлении управления проектами , вы видите
пока остальные видят
источник
Если вам придется «продать» принцип своей команде, то вы, вероятно, уже прошли несколько миль по неверному пути.
Никто не хочет делать дополнительную работу, поэтому, если то, что вы пытаетесь продать им, выглядит для них как дополнительная работа, то вы не будете убеждать их повторным призывом Высшего Аргумента. Им нужно знать, что вы показываете им способ уменьшить нагрузку, а не увеличить ее.
В настоящее время DI часто рассматривается как дополнительная сложность с обещанием потенциального снижения сложности в будущем , что имеет ценность, но не так много для того, кто пытается снизить начальную рабочую нагрузку. И во многих случаях DI - это просто еще один слой YAGNI . И цена этой сложности не равна нулю, на самом деле она довольно высока для команды, не привыкшей к этому типу паттернов. И это настоящие доллары, которые закапывают в ведро, которое никогда не принесет никакой пользы.
Поместите его на место.
Лучше всего использовать DI там, где это явно полезно, а не там, где это обычно. Например, многие приложения используют DI для выбора и настройки баз данных. И если ваше приложение поставляется со слоем базы данных, то это заманчивое место для его размещения. Но если ваше приложение поставляется со встроенной невидимой пользователем базой данных, которая в остальном тесно интегрирована в код, то шансы на необходимость замены БД во время выполнения приближаются к нулю. И продажа DI, говоря: «Послушай, мы легко можем сделать то, что мы никогда и никогда не захотим делать», - это, вероятно, поставит тебя в список «у этого парня плохие идеи» с твоим боссом.
Но, скажем, вместо этого у вас есть отладочный вывод, который обычно выводит IFDEF в выпуске. И каждый раз, когда у пользователя возникают проблемы, ваша группа поддержки должна отправить ему отладочную сборку, чтобы он мог получить вывод журнала. Здесь вы можете использовать DI, чтобы клиент мог переключаться между драйверами журналов -
LogConsole
для разработчиков,LogNull
для клиентов иLogNetwork
для клиентов с проблемами. Одна унифицированная сборка, конфигурируемая во время выполнения.Тогда вам даже не нужно называть это DI, вместо этого он просто называется «Хорошая идея Мела», и вы теперь в списке хороших идей вместо плохих. Люди увидят, насколько хорошо работает шаблон, и начнут использовать его там, где это имеет смысл в их коде.
Когда вы правильно продадите идею, люди не узнают, что вы в чем-то их убедили.
источник
Конечно, Inversion of Control (IoC) имеет множество преимуществ: он упрощает код, добавляет магию, которая выполняет типичные задачи и т. Д.
Тем не мение:
Это добавляет много зависимостей. Простое приложение hello world, написанное на Spring, может весить десяток МБ, и я видел Spring, добавленный только для того, чтобы избежать нескольких строк конструктора и сеттера.
Он добавляет вышеупомянутое волшебство , которое трудно понять посторонним (например, разработчикам GUI, которым необходимо внести некоторые изменения в бизнес-уровень). Посмотрите замечательную статью « Новаторские взгляды, а не мысли» - New York Times , в которой рассказывается, как эксперты недооценивают этот эффект .
Твердеть, чтобы отслеживать использование классов. В таких средах, как Eclipse, есть отличные возможности для отслеживания использования данных классов или вызовов методов. Но этот след теряется, когда происходит внедрение зависимости и отражение.
Использование IoC обычно не заканчивается внедрением зависимостей, оно заканчивается бесчисленными прокси-серверами, и вы получаете трассировку стека, насчитывающую сотни строк, 90% из которых являются прокси-серверами и вызываются с помощью отражения. Это значительно усложняет анализ трассировки стека.
Так что, будучи большим фанатом Spring и IoC, мне недавно пришлось переосмыслить приведенные выше вопросы. Некоторые из моих коллег - веб-разработчики, взятые в мире Java из мира Web, управляемого Python и PHP, и очевидные для javaist вещи для них не очевидны. Некоторые из моих коллег делают трюки (конечно, без документов), что делает ошибку очень трудно найти. Конечно злоупотребление IoC делает вещи легче для них;)
Мой совет: если вы будете принудительно использовать IoC на своей работе, вы будете нести ответственность за любое злоупотребление, которое совершит кто-либо другой;)
источник
Я думаю, что ChrisF во что-то правильно. Не продавайте ДИ в себе. Но продайте идею о модульном тестировании кода.
Один из подходов к включению контейнера DI в архитектуру может состоять в том, чтобы затем медленно позволить тестам превратить реализацию в нечто, что хорошо сочетается с этой архитектурой. Например, допустим, вы работаете с контроллером в приложении ASP.NET MVC. Допустим, вы пишете класс так:
Это позволяет вам писать модульные тесты, отделенные от фактической реализации пользовательского репозитория. Но класс все еще работает без контейнера DI, чтобы создать его для вас. Конструктор без параметров создаст его с хранилищем по умолчанию.
Если вы, коллеги, видите, что это приводит к гораздо более чистым тестам, возможно, они поймут, что это лучший способ. Может быть, вы можете заставить их начать кодировать так.
Как только они поймут, что это лучший дизайн, чем UserController, зная о конкретной реализации UserRepository, вы можете сделать следующий шаг и показать им, что у вас может быть компонент, контейнер DI, который может автоматически предоставлять нужные вам экземпляры.
источник
Возможно, лучше всего сделать шаг назад и спросить себя, почему вы хотите представить DI-контейнеры? Если вы хотите улучшить тестируемость, то ваша первая задача - заставить команду купить на модульное тестирование. Лично меня больше беспокоит отсутствие юнит-тестов, чем отсутствие DI-контейнера.
Вооружившись всеобъемлющим набором или наборами юнит-тестов, вы можете уверенно приступить к развитию своего дизайна с течением времени. Без них вы сталкиваетесь со все более и более сложной борьбой за то, чтобы держать свой дизайн в ногу с изменяющимися требованиями, борьбой, которую в конечном итоге проигрывают многие команды.
Поэтому я советую сначала протестировать юнит-тестирование и рефакторинг, а затем, в свою очередь, ввести DI и, наконец, DI-контейнеры.
источник
Я слышу несколько громких замечаний от вашей команды здесь:
«Никаких сторонних библиотек» - АКА «Не изобретено здесь» или «NIH». Опасение заключается в том, что, внедряя стороннюю библиотеку и, таким образом, делая базу кода зависимой от нее, если в библиотеке есть ошибка или дыра в безопасности, или даже просто ограничение, которое вам нужно преодолеть, вы становитесь зависимыми от этой третьей участник, чтобы исправить свою библиотеку, чтобы ваш код работал. В то же время, поскольку его «ваша» программа потерпела неудачу, была взломана или не выполняет то, о чем они просили, вы по-прежнему несете ответственность (а сторонние разработчики скажут, что их инструмент «как есть»). ", Используйте на свой риск).
Противоположным аргументом является то, что код, решающий проблему, уже существует в сторонней библиотеке. Вы строите свои компьютеры с нуля? Вы написали Visual Studio? Вы отказываетесь от встроенных библиотек в .NET? Нет. У вас есть уровень доверия к Intel / AMD и Microsoft, и они постоянно находят ошибки (и не всегда быстро их исправляют). Добавление сторонней библиотеки позволяет быстро получить работоспособную базу кода без необходимости заново изобретать колесо. А армия юристов Microsoft посмеется вам в лицо, когда вы скажете им, что ошибка в библиотеках криптографии .NET делает их ответственными за случай взлома вашего клиента при использовании вашей программы .NET. В то время как Microsoft непременно попытается устранить дыры в безопасности «нулевого часа» в любом из своих продуктов,
«Мы хотим собрать все в одну сборку» - на самом деле, вы этого не делаете. По крайней мере, в .NET, если вы вносите изменения в одну строку кода, вся сборка, содержащая эту строку кода, должна быть перестроена. Хороший дизайн кода основан на нескольких сборках, которые вы можете перестраивать настолько независимо, насколько это возможно (или, по крайней мере, нужно перестраивать зависимости, а не зависимости). Если они ДЕЙСТВИТЕЛЬНО хотят выпустить EXE, который является просто EXE-файлом (который имеет значение в определенных обстоятельствах), для этого есть приложение; ILMerge.
«ДИ это табу» - WTF? DI - это общепринятая лучшая практика на любом языке O / O с кодовой конструкцией «интерфейс». Как ваша команда придерживается методологий проектирования GRASP или SOLID, если они не слабо связывают зависимости между объектами? Если они не беспокоятся, то они увековечивают фабрику спагетти, которая делает продукт такой сложной болотой, какой она есть. Теперь DI увеличивает сложность за счет увеличения числа объектов, и, хотя он облегчает замену другой реализации, он усложняет изменение самого интерфейса (добавляя дополнительный слой объекта кода, который должен измениться).
«Нам не нужно добавлять этот уровень сложности в уже сложный проект», - они могут иметь смысл. Важной вещью, которую следует учитывать при разработке любого кода, является YAGNI; «Вам это не нужно». Дизайн, спроектированный SOLIDly с самого начала, - это проект, который сделан SOLID «на веру»; Вы не знаете, понадобится ли вам легкость изменений, которую обеспечивают дизайны SOLID, но у вас есть предчувствие. Хотя вы можете быть правы, вы также можете быть очень неправы; очень твердый дизайн может в конечном итоге рассматриваться как «код лазаньи» или «код равиоли», имеющий так много слоев или кусков размером с кусочек, что вносить кажущиеся тривиальными изменения становится трудно, потому что вам приходится копаться в таком количестве слоев и / или прослеживать такой сложный стек вызовов.
Я поддерживаю правило трех ударов: заставить его работать, сделать его чистым, сделать его твердым, Когда вы впервые пишете строку кода, она просто должна работать, и вы не получаете баллов за дизайн башни из слоновой кости. Предположим, что это разовое и делать то, что ты должен делать. Во второй раз, когда вы смотрите на этот код, вы, вероятно, хотите расширить или повторно использовать его, и это не тот случай, когда вы думали, что это будет. На этом этапе, сделайте его более элегантным и понятным путем рефакторинга; упростите запутанную логику, извлеките повторяющийся код в циклы и / или вызовы методов, добавьте несколько комментариев тут и там для любого клуджа, который вам нужно оставить на месте, и т. д. В третий раз, когда вы посмотрите на этот код, это, вероятно, будет большой проблемой. Теперь вы должны придерживаться твердых правил; вставлять зависимости вместо их построения, извлекать классы для хранения методов, которые менее связаны с «мясом» кода,
«Мы не будем подключать разные реализации» - у вас, сэр, есть команда, которая не верит в юнит-тесты на ваших руках. Я утверждаю, что невозможно написать модульный тест, который выполняется изолированно и не имеет побочных эффектов, не имея возможности «насмехаться» над объектами, которые имеют эти побочные эффекты. Любая нетривиальная программа имеет побочные эффекты; если ваша программа читает или записывает в БД, открывает или сохраняет файлы, обменивается данными по сети или периферийному сокету, запускает другую программу, выводит окна, выводит данные на консоль или иным образом использует память или ресурсы вне «песочницы» своего процесса, она имеет побочный эффект. Если он не делает ничего из этого, что он делает, и почему я должен его купить?
Честно говоря, модульное тестирование - не единственный способ доказать, что программа работает; Вы можете написать интеграционные тесты, код для математически проверенных алгоритмов и т. д. Однако модульное тестирование очень быстро показывает, что при заданных входах A, B и C этот фрагмент кода выводит ожидаемый X (или нет) и, таким образом, что код работает должным образом (или не работает) в данном случае. Наборы модульных тестов могут с высокой степенью уверенности продемонстрировать, что код работает должным образом во всех случаях, и они также предоставляют то, чего не может математическое доказательство; демонстрация того, что программа по-прежнему работает так, как она была задумана. Математическое доказательство алгоритма не доказывает, что он был реализован правильно, и не доказывает, что любые внесенные изменения были реализованы правильно и не сломали его.
Суть в том, что если эта команда не видит никакой ценности в том, что будет делать DI, то они не будут ее поддерживать, и все (по крайней мере, все старшие ребята) должны что-то купить, чтобы добиться реальных перемен. случаться. Они уделяют большое внимание YAGNI. Вы уделяете большое внимание твердотельному и автоматизированному тестированию. Где-то посередине лежит правда.
источник
Будьте осторожны, добавляя дополнительные функции (например, DI) в проект, если он не одобрен. Если у вас есть план проекта с ограничениями по времени, вы можете оказаться в ловушке, когда у вас недостаточно времени для завершения утвержденных функций.
Даже если вы сейчас не используете DI, примите участие в тестировании, чтобы точно знать, каковы ожидания от тестирования в вашей компании. Будет еще один проект, и вы сможете сопоставить проблемы с тестированием текущего проекта и DI.
Если вы не используете DI, вы можете проявить творческий подход и сделать свой код DI- «готовым». Используйте конструктор без параметров для вызова других конструкторов:
источник
Я думаю, что одна из их самых больших проблем на самом деле как раз наоборот: DI не делает проект сложным. В большинстве случаев это уменьшает сложность.
Просто подумайте без DI, что вы собираетесь получить зависимый объект / компонент, который вам нужен? Обычно это происходит из-за поиска в репозитории, или получения синглтона, или создания самого себя.
Первый 2 включает в себя дополнительный код для определения местоположения зависимого компонента, в мире DI вы ничего не сделали для поиска. Сложность ваших компонентов фактически снижена.
Если вы создаете себя в некоторых случаях, что не подходит, это даже создает больше сложности. Вы должны знать, как правильно создать объект, вам нужно знать, какие значения инициализировать объект до работоспособного состояния, все это создает дополнительную сложность для вашего кода.
Таким образом, DI не делает проект сложным, он делает его проще, делая компоненты проще.
Еще один важный аргумент - вы не собираетесь подключать другую реализацию. Да, это правда, что в производственном коде не принято иметь много разных реализаций в реальном производственном коде. Однако есть одно главное место, которое требует другой реализации: Mock / Stub / Test Doubles в модульных тестах. Чтобы заставить DI работать, в большинстве случаев он опирается на модель разработки, основанную на интерфейсе, что, в свою очередь, делает возможной насмешку / заглушку в модульных тестах. Помимо замены реализации, «интерфейсно-ориентированный дизайн» также делает дизайн чище и лучше. Конечно, вы все еще можете проектировать с интерфейсом без DI. Тем не менее, модульные тесты и DI подталкивают вас к принятию такой практики.
Если ваши «боги» в компании не считают, что «простой код», «модульные тесты», «модульность», «единая ответственность» и т. Д. - все это то, против чего они выступают, у них не должно быть оснований отказываться от использования DI.
источник
«Мы хотим, чтобы все было просто, если возможно, просто соберите все в одну сборку. DI - ненужная сложность без выгоды».
Преимущество заключается в том, что он способствует проектированию интерфейсов и позволяет легко издеваться. Что, следовательно, облегчает юнит-тестирование. Модульное тестирование обеспечивает надежный, модульный и легко обслуживаемый код. Если ваш начальник все еще придерживается своей плохой идеи, ну, вы ничего не можете поделать - это принятая лучшая в отрасли практика, против которой они спорят.
Заставьте их попробовать написать модульный тест с DI-фреймворком и библиотекой насмешек, они скоро научатся любить его.
источник
new
везде, и для написания фабричных классов, поскольку у вас есть все эти компоненты на месте.Работаете ли вы с этими людьми в каких-то небольших проектах или только в одном большом? Проще убедить людей попробовать что-то новое на вторичном / третичном проекте, чем хлеб с маслом команды / компаний. Основными причинами этого является то, что в случае неудачи затраты на его удаление / замену значительно уменьшаются, и гораздо меньше труда получить его повсюду в небольшом проекте. В большом существующем у вас либо есть большие начальные затраты, чтобы внести изменения везде одновременно, либо длительный период, в течение которого код представляет собой смесь старого / нового подхода, добавляющего трения, потому что вы должны помнить, как разработан каждый класс работать.
источник
Хотя одной из вещей, которые продвигают DI, является модульное тестирование, но я считаю, что в некоторых случаях оно добавляет уровень сложности.
Лучше иметь автомобиль сложным в тестировании, но легким в ремонте, чем легким в тестировании и трудным в ремонте.
Также мне кажется, что группа, выступающая за DI, представляет свои идеи только под влиянием того, что некоторые существующие подходы к проектированию плохие.
если у нас есть метод, выполняющий 5 различных функций
DI-люди говорят:
Я считаю, что лучше создавать наш собственный шаблон проектирования, который соответствует потребностям бизнеса, а не зависеть от DI.
в пользу DI это может помочь в некоторых ситуациях, например, если у вас есть сотни реализаций для одного и того же интерфейса, зависит от селектора, и эти реализации сильно отличаются по логике, в этом случае я бы использовал аналогичные методы DI или DI. но если у нас мало реализаций для одного и того же интерфейса, нам не нужен DI.
источник