Другим же альтернативным подходом, к которому я склоняюсь на данный момент, является организация работы микрокомандами по несколько человек (от 2 до 4), которая каждая делает свой проект, а с другими командами общается только на уровне интеграции.
Как же вы интеграцию без автоматизированного модульного тестирования делаете?
Я, собственно, отвечал на комментарий а не на статью. То есть мой комментарий нужно рассматривать в контексте как протестировать не сложнее чем через экстракцию интерфейса и мок.
Тут напрашивается событийная модель. То есть в конце выполнения метода изменяющего состояние заказа он инициирует событие — «Заказ изменен». И все кто подписался на это событие его получают. Это, собственно, другой вариант получить слабую связанность в данном месте (и, как мне кажется, архитектурно тут более правильный). А уже обработчик события имеет зависимость от SMTP. При тестировании мы подписываем только мок обработчик, который нам сообщает, что событие произошло.
А смысл? Есть пара книжек, которые это прекрасно описывают: Programming Entity Framework Code First и Programming Entity Framework DbContext. А в статью все не уместишь.
Есть разница между прикладной программист сделал запросы сам (через IQueryable) и с каждым 10-м нужно разбираться потому что он тормозит и разбираться с каждым запросом прикладного программиста. Это банально удорожает и усложняет процесс разработки.
А каким был интерфейс репозитория? Универсальным, т.е. выставлялся IQueryable или его аналог, или просто содержал конечный набор методов, который и определял набор возможных запросов?
Конечный набор методов. То есть там был набор CRUD для корней агрегатов и дополнительные методы для работы с объектами и коллекциями вложенных в агрегат сущностей. Но надо понимать, что это была конкретная часть хранилища с такой спецификой, по ней не предполагалось поисковых и фильтрующих запросов, нужен был только CRUD.
И еще интересно было бы узнать Ваше мнение. Допустим в некой задаче нет необходимости поддерживать разные хранилища/ORM, есть только EF и, к примеру, SQL Server. Но в то же время набор возможных запросов к БД сильно ограничен и расширяется очень предсказуемо. Стали бы Вы оборачивать EF в репозиторий с простым интерфейсом, или же просто использовали бы DbContext?
Я не вижу смысла городить тут репозиторий, хотя, возможно, выставил бы интерфейс с ограниченным набором методов вместо Generic интерфейса с Set (этот ограниченный набор методов реализовал бы прямо на DbContext)
Но, такие интерфейсы очень быстро разрастаются до нескольких десятков методов и тут важно быстро это прекратить и свести к Set.
В моей практике ORM скрывался за репозиторием когда источником данных выступала как реляционная бд, так и Key-Value хранилище. И подмена эта происходила в рантайме в зависимости от неких параметров.
Очень интересуют ответы на три вопроса:
1. На сколько процентов уменьшилось время выполнения маппинга?
2. Сколько времени в среднем занимает получение DO объекта из бд и отправка DTO объекта в вебсервис
3. Сколько человеко-часов было потрачено на разработку вашего маппинга на Т4 шаблонах?
Я бы сказал, что автор этой статьи плохо понимает SOLID и когда применял SOLID страдал от overarchitecture. Ну и по пунктам:
Dependency Inversion это не «используй интерфейсы». Это о том, что зависимости должны передаваться снаружи, а не создаваться внутри потребителя этой зависимости. И «Передайте сами данные, но уберите получатель данных» — это тоже инверсия зависимостей. Более того, «Передайте сами данные, но уберите получатель данных» это еще и принцип единственности ответственности. Потому что тот класс или метод, который данные обрабатывает, не должен отвечать и за получение данных
И вот тут начинается Пичаль, тоже с большой буквы. Из песни слова не выкинешь, слой абстракции из Фреймворка не уберешь — где-то в другом проекте на него кто-то завязался… LinkedList на ArrayList не заменишь — кто-то ведь и к его поведению мог привязаться, применений-то у Фреймворка не счесть…
Простите, но либо у вас уровни абстракции либо возможность для потребителя завязаться на конкретную реализацию коллекции. Вы уж определитесь. А то похоже, что Фреймворк хреново спроектирован с точки зрения ООП.
На самом деле эта ситуация не так редка как может показаться. Она может возникнуть, когда последний элемент находится в другой ветке относительно элемента который мы удаляем.
Собственно, когда я реализовывал этот самый алгоритм Дийкстры, я при реализации «кучи» сделал только утопление, считая, что если я поменял с последним элементом, этот элемент должен потонуть обратно вниз. Потом сутки пытался понять почему у меня с вероятностью 70% получается неверный результат.
И то и другое — это вызвать метод всплытия а потом метод утопления. Потому что когда вы удаляете объект из середины, вы меняете удаляемый объект с последним элементом, после этого элемент нужно расположить на нужном уровне. И этот уровень может быть как выше так и ниже. При этом один из вызовов в данном случае делает только проверку что перемещать объект не надо и выходит.
При вытаскивании элемента из середины — не важно, для удаления или для перевесовки, — нужно сделать либо то, либо другое, в зависимости от отношения весов элементов.
Дешевле всего вызвать и то и другое. По количеству операций получается не больше операций чем если проверять соотношение весов и вычислять направление «всплытия»
Как же вы интеграцию без автоматизированного модульного тестирования делаете?
Конечный набор методов. То есть там был набор CRUD для корней агрегатов и дополнительные методы для работы с объектами и коллекциями вложенных в агрегат сущностей. Но надо понимать, что это была конкретная часть хранилища с такой спецификой, по ней не предполагалось поисковых и фильтрующих запросов, нужен был только CRUD.
Я не вижу смысла городить тут репозиторий, хотя, возможно, выставил бы интерфейс с ограниченным набором методов вместо Generic интерфейса с Set (этот ограниченный набор методов реализовал бы прямо на DbContext)
Но, такие интерфейсы очень быстро разрастаются до нескольких десятков методов и тут важно быстро это прекратить и свести к Set.
Это называется «Poor man DI» — DI бедняка.
1. На сколько процентов уменьшилось время выполнения маппинга?
2. Сколько времени в среднем занимает получение DO объекта из бд и отправка DTO объекта в вебсервис
3. Сколько человеко-часов было потрачено на разработку вашего маппинга на Т4 шаблонах?
Dependency Inversion это не «используй интерфейсы». Это о том, что зависимости должны передаваться снаружи, а не создаваться внутри потребителя этой зависимости. И «Передайте сами данные, но уберите получатель данных» — это тоже инверсия зависимостей. Более того, «Передайте сами данные, но уберите получатель данных» это еще и принцип единственности ответственности. Потому что тот класс или метод, который данные обрабатывает, не должен отвечать и за получение данных
Простите, но либо у вас уровни абстракции либо возможность для потребителя завязаться на конкретную реализацию коллекции. Вы уж определитесь. А то похоже, что Фреймворк хреново спроектирован с точки зрения ООП.
Собственно, когда я реализовывал этот самый алгоритм Дийкстры, я при реализации «кучи» сделал только утопление, считая, что если я поменял с последним элементом, этот элемент должен потонуть обратно вниз. Потом сутки пытался понять почему у меня с вероятностью 70% получается неверный результат.
Дешевле всего вызвать и то и другое. По количеству операций получается не больше операций чем если проверять соотношение весов и вычислять направление «всплытия»