212 похожих чатов

Окей. давай по другому скажу. для начала контекст: 1. у нас

есть современные IDE с автоматическими средствами рефакторинга. То есть если у тебя была зависимость от какого-то класса и тебе понадобилось подменить его на абстракцию - не вопрос, 5 минут и у тебя выделен интерфейс и все референсы поменялись. Для многих языков это достаточно безопасная операция которую ты просто делаешь коммитишь и готово.
2. сегодня подавляющее большинство систем делают таким образом что тебе так или иначе нужно "пересобрать все" что бы работало. Ну то есть средний проект на джавах шарпах и т.д. будет требовать рекомпиляции. Или там запакавать в новый образ докеровский. Тип в любом случае сборка деплой и тестирование подразумевают новый артефакт который ты будешь уже промоутить на прод.

Если наш контекст отличается (у нас там проект разделен на под проекты с динамической линковкой и артефакты могут независимо заменяться, пусть не в рантайме но без необходимости пересобирать все) - то там отдельный разговор и будут свои ограничения которые будут требовать больше внимания к DIP. но я хз кто сейчас так делает. Последнее что припоминаю - знакомые мобильщики так делали на больших проектах с целью распаралелить разработку. Но обычно люди которые таким занимаются уже понимают че куда зачем и как. Или как минимум "неверный выбор абстракций" начинает конфликтовать с тем ради чего динамическую линковку завозили и хоть какие-то явные сигналы что что-то не так идет.

Теперь дальше. "подменить репозиторий". В 90% ситуаций мы не будем этого делать. Ни в тестах (ибо не понятно что мы тестим) ни в чем-либо то нибыло. Да мы можем декорации какие применять, для этого нужен интерфейс но наличие интерфейса не означает соблюдение DIP (если у тебя направление зависимостей между модулями не меняется то какая разница).

Для оставшихся 10% или когда ситуация поменялась и понадобилось - выделяешь интерфейс и вперед.

Если мы говорим про то как большинство делает у тебя репозиторий это класс с 100500 методов выборок которые юзаются каждый в паре мест. И просто лепить на такое интерфейс уже как-то глупо. Да можно попытаться разбить интерфейс через ISP и тогда как бы уже интереснее и больше смысла. Но опять же для чего? В тестах подменять? Тут уже больше вариантов если разным модулям разное надо.

Если выше смотреть, "репозиторий" обычно не шарится между модулями. Тип если у тебя есть модуль какой-то подсистемы которая отвечает за свои аспекты системы, то репозиторий наружу мы никогда не будем отдавать. Вместо этого будут другие точки интеграции с другими модулями и там можно чет смотреть. Тип для организации каких-нибудь anti-corruption layers. и прочего. Обычно полезно между легаси частями приложений и новыми частями.

Потому и говорю что на примере репозитория просто не особо много пользы от DIP. Можно было бы говорить о какой-то пользе если бы у нас "репозиторий" был классический, тип просто key-value стор без выборок и прочего. Тогда это можно было бы представить какой-то более-менее понятной абстракцией которую удобно подменять и т.д. Тогда можно надежно говорить о том что мы стор базы подменили на in-memory стор и ничего не поменялось и мы все еще понимаем что тестим. Но ты много таких систем видел? Я не много.

12 ответов

105 просмотров
Sergey-P Автор вопроса

у тебя ситуация когда репозиторий это простой интерфейс для работы с коллекцией через ключ значение и больше ничего? Никаких методов save или find some very specific things? Если так - могу представить себе где это может быть нужно. Но большинство "репозиторием" называют просто точку взаимодействия с базой, где у тебя в каком-нибудь условном OrderRepository будет жирный кусок SQL или квери билдер или LINQ с джойнами на другие сущности и прочей хуйней. И подменять такое - обычно смысла нет ибо 50% того что может потенциально сломаться это сами запросы и взаимодействие с базой. А так как "база" это обычно managed out-process dependency то есть под нашим контролем хоть и вне границ процесса - нам не обязательно это дело отделять. Мы все еще можем достаточно легко обеспечить изоляцию тест кейсов даже с реальной базой.

Sergey P
у тебя ситуация когда репозиторий это простой инте...

Бывает и то, и то. В последнее время я пришел к разделению на write model и read model. Для write это обычно getById + save + delete, а для read уже сложные выборки. Первое я подменяю кастомной полноценной реализацией

Sergey-P Автор вопроса
Блья ✖️➕➖➗
Бывает и то, и то. В последнее время я пришел к ра...

ну вот я не встречал пока в природе ситуации где такие тесты дают хоть какой-то уровень уверенности в том что система работает как надо.

Sergey-P Автор вопроса
Блья ✖️➕➖➗
Бывает и то, и то. В последнее время я пришел к ра...

а ты уверен что в этом случае ты что-то тестишь а не просто фиксируешь текущую реализацию?

Sergey P
а ты уверен что в этом случае ты что-то тестишь а ...

На сложные запросы у меня есть тесты на сам репозиторий (реальный)

Sergey-P Автор вопроса
Блья ✖️➕➖➗
На сложные запросы у меня есть тесты на сам репози...

я про "моки которые ассертят что пришло в метод репозитория".

Sergey P
я про "моки которые ассертят что пришло в метод ре...

Я тестирую что код правильно составил запрос в репозиторий, и правильно использовал ответ). И этот код я пишу ещё до того как написал код реального репозитория.

Sergey-P Автор вопроса
Блья ✖️➕➖➗
Я тестирую что код правильно составил запрос в реп...

а можешь псевдокодом каким показать пример такого теста?)

Sergey P
а можешь псевдокодом каким показать пример такого ...

Сейчас у меня этими методами пользуется код, который отвечает за http api. Тест +- такой Дано: http запрос с такими-то урлой и телом Подменяем репозиторий, экспектим такие то параметры, возвращаем такой список сущностей Проверяем что http api правильно отрендерил ответ. Думал ещё это все сделать через query bus, чтобы апи не пользовался репозиторием напрямую, но пока и так норм)

Sergey-P Автор вопроса
Блья ✖️➕➖➗
Сейчас у меня этими методами пользуется код, котор...

ну то есть тест по факту фиксирует реализацию а не проверяет поведение

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
вы делали что-то подобное и как? может есть либы готовые? увидел картинку нокода, где всё линиями соединено и стало интересно попробовать то же в ddl на lua сделать. решил с ч...
Victor
8
Подскажите пожалуйста, как в CustomDrawCell(Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); получить наз...
A Z
7
Ребят в СИ можно реализовать ООП?
Николай
33
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
1
Он в одиночку это дело запилил или была какая-то команда?
Aquinary
12
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Всем привет, нужна как никогда, нужна помощь с IO в загрузчике. Пишу в code16 после установки сегментных регистров, пишу вывод символа. Пробовал 2 варианта: # 1 mov $0x0E, %a...
Shadow Akira
14
Карта сайта