Никогда не встречал такого на практике, чтобы это было не костыльно. В каком-то ява-подобном языке, это выглядело бы как:
модуль A
модуль B
интерфейс реализуемый модулем А, который дергает модуль B
интерфейс реализуемый модулем B, который дергает модуль A
Такое решение может иметь место, но в очень специфическом случае - когда абстракция протекает, и мы с этим смирились. Например в 95% случаев мы из бизнес логики дергаем драйвер базы данных для персиста. Но в каких-то редких случаях, для оптимизации, драйверу будет полезно знать состояние системы выше уровнем, чтобы знать - персистить сейчас или пододождать еще пару вызовов персиста и потом сразу записать бОльший объем данных.
А в 95% случаев во всех системах что я видел - один интерфейс, который реализуем модуль B для дерганья из модуля А. Это если мы говорим об "уровнях" в архитектуре, которая действительно иерархически построена, как то: база > ентити > репозиторий > контроллер.
Но уровни как таковые не всегда есть. Например, при попытке причесать сложный монолит, часто можно столкнуться с взаимными зависимостями вроде бы равноправных кусков бизнес логики. Например корзина хочет знать наличие остатка на складе, а склад хочет знать количество корзин и товаров, зарезервированных в каждой в данный момент.
Поэтому очень важно разделять рассматриваемые сценарии реализации инверсии зависимоти по типу архитектуры. Для равноправных взаимозависимых модулей нужно 2 интерфейса, для иерархически зависимых нужен 1 интерфейс.
Если появляются такие вопросы, то наличие-отсутствие удаленки в этом месте работы - это вообще последняя проблема в вашем списке.
Никогда не встречал такого на практике, чтобы это было не костыльно. В каком-то ява-подобном языке, это выглядело бы как:
модуль A
модуль B
интерфейс реализуемый модулем А, который дергает модуль B
интерфейс реализуемый модулем B, который дергает модуль A
Такое решение может иметь место, но в очень специфическом случае - когда абстракция протекает, и мы с этим смирились. Например в 95% случаев мы из бизнес логики дергаем драйвер базы данных для персиста. Но в каких-то редких случаях, для оптимизации, драйверу будет полезно знать состояние системы выше уровнем, чтобы знать - персистить сейчас или пододождать еще пару вызовов персиста и потом сразу записать бОльший объем данных.
А в 95% случаев во всех системах что я видел - один интерфейс, который реализуем модуль B для дерганья из модуля А. Это если мы говорим об "уровнях" в архитектуре, которая действительно иерархически построена, как то: база > ентити > репозиторий > контроллер.
Но уровни как таковые не всегда есть. Например, при попытке причесать сложный монолит, часто можно столкнуться с взаимными зависимостями вроде бы равноправных кусков бизнес логики. Например корзина хочет знать наличие остатка на складе, а склад хочет знать количество корзин и товаров, зарезервированных в каждой в данный момент.
Поэтому очень важно разделять рассматриваемые сценарии реализации инверсии зависимоти по типу архитектуры. Для равноправных взаимозависимых модулей нужно 2 интерфейса, для иерархически зависимых нужен 1 интерфейс.