Полностью согласен. Я, кстати, когда писал топик боялся, что он скатится в холивар-сравнение легковесных Isolation Framework c тяжеловесами, способными подменять не виртуальные и статические методы. Но вон как оно вышло. Никогда не угадаешь заранее.
Мне не нравится слово оппонент. Я рассматриваю дискуссию как способ улучшить топик, так он как раз пытается его улучшить. Жаль, конечно, что его желание самоутвердиться немного мешает процессу, но я отношусь к этому философски.
Спасибо всем поучаствовавшим в обсуждении. Я на хабре неделю и мне очень неприятно, что мой второй по счету топик скатился в холивар. Но нет худа без добра, благодаря живому обсуждению у топика появилось заключение.
Поиск идеальной архитектуры — бесполезное занятие.
Юнит тесты — это отличная проверка вашей архитектуры на низкую связанность между модулями. Но всегда ли это необходимо конкретному приложению? На этот вопрос правильного ответа нет. Проектирование сложных технических систем — это всегда поиск компромисса. Идеальной архитектуры не бывает, так как учесть все возможные сценарии развития приложения при проектировании невозможно. Качество архитектуры зависит от множества параметров, часто друг друга взаимоисключающих. Есть старая шутка, что любую проблему дизайна можно решить путём введения дополнительного уровня абстракции, кроме проблемы слишком большого количества уровней абстракций. Поэтому не стоит рассматривать как догму, что взаимодействие между объектами должно быть построено только на основе интерфейсов, главное чтобы выбор, совершенный вами, был осознанным и вы понимали, что код, допускающий взаимодействие между реализациями, становится менее гибким и, как следствие, теряет возможность быть протестированным модульными тестами.
В случае, если мы сейчас говорим о взаимодействии deal и прикладного слоя, вы вправе сделать dal статическим, если вы
не собираетесь отдельно тестировать прикладной слой. Но вы лишаетесь гибкости и можно придумать кучу вариантов при которых использование статических классов начнёт вас смущать
То есть вы собираетесь процесс обращения к базе данных размазать по нескольким обьектам чтобы добиться факта, что тестировать ваши объекты по отдельности смысла не имеет. Изящно.
Архитектурно, реализация датафасада содержит в себе ORM контейнер. ORM контейнер является неотъемлемой частью реализации, а не внешней зависисмостью. Понимаете? Никакого собственного функционала, который можно протестировать в отрыве от ORM контейнера, у датафасада нет. Ваш пример надуман.
Пример со светильниками неудачен. Проводку тестируют индикаторной отверткой, вполне себе аналог юнит-теста. И люстру вы тоже можете отдельно в магазине протестировать. Оба модуля протестированы, соединяем и делаем интеграционный тест. Все счастливы.
Зачем вводить интерфейс между датафасадом и ORM-ом то?.. В вашем случае датафасад инкапсулирует в себе ORM контейнер. Это не разные модули, их не нужно друг от друга изолировать.
Пример притянут за уши. Ваш датафасад, скрывающий структуру БД, это интерфейс. А его реализация — это объект, инкапсулирующий в себе работу с ORM контейнером. Зачем отделять ORM от вашего датафасада слоем для меня загадка.То есть примера нет.
Для рабочего проекта — да. В качестве примера к топику — нет. Лично меня бы раздражало в чужом топике сначала искать приватный метод тремя строчками, а потом возвращаться к месту где он был вызван. Лучше уж так.
Так, стоп. Давайте вы не будете подменять IoC на связность (высокую или низкую). IoC — это один из путей к низкой связности, но не единственный.
Я ничего не говорил про IoC. Вопрос следующий, в каких случаях прямое взаимодействие между объектами лучше, чем взаимодействие через интерфейс.
И отдельно не надо путать IoC и DI. Второе — частный случай первого, но не наоборот.
Как вы в фразе
Сейчас мы переписываем проект, оказавшийся погубленным отсутствием этого самого dependency injection.
нашли что то про IoC?
когда вы понимаете, что интерфейсы нужно оставлять так, чтобы они были видимы везде
А вот это в корне не верное рассуждение. Представьте, что у вас приложение разбито на несколько слоев — слой приложения, слой бизнес логики и слой доступа к данным. Так вот, слой приложения видит только интерфейсы слоя бизнес логики и ничего не знает об интерфейсах слоя доступа к данным. О существовании этих интерфейсов знает только слой бизнес логики.
Приведите пожалуйста хоть один пример, почему высокая связанность может оказаться в итоге лучшим решением. Я таковых не знаю. А чем плоха высокая связанность знаю на собственном опыте очень хорошо. Из недавнего — повторное использование кода. Сейчас мы переписываем проект, оказавшийся погубленным отсутствием этого самого dependency injection. Проект состоит из нескольких модулей и часть из них нам кажется неплохой. Но использовать повторно их никак не получится, потому что все модули так крепко связаны между собой, что перетащить можно только все целиком, но никак ни один кусочек.
В общий метод сетап не вынесешь. Можно, конечно, создать несколько методов, по отдельности для каждого мока, id и т.д. Но лучше от этого код не станет.
не собираетесь отдельно тестировать прикладной слой. Но вы лишаетесь гибкости и можно придумать кучу вариантов при которых использование статических классов начнёт вас смущать
Я ничего не говорил про IoC. Вопрос следующий, в каких случаях прямое взаимодействие между объектами лучше, чем взаимодействие через интерфейс.
Как вы в фразе нашли что то про IoC?
А вот это в корне не верное рассуждение. Представьте, что у вас приложение разбито на несколько слоев — слой приложения, слой бизнес логики и слой доступа к данным. Так вот, слой приложения видит только интерфейсы слоя бизнес логики и ничего не знает об интерфейсах слоя доступа к данным. О существовании этих интерфейсов знает только слой бизнес логики.