Size: a a a

Software Design/Architecture/Zen

2021 November 28

AI

Arthur Irgashev in Software Design/Architecture/Zen
Если несколько агрегатов нужно потрогать, то через ивеншуал консистенси можно обновлять так. Отличие только в том, что комит в бд всё же будет до выполнения ивентов


Ну или через доменные ивенты дополнительную логику делать (типа записать что-то в аутбокс), тогда будет в рамках транзакции
источник

NF

Nikita Fedorov in Software Design/Architecture/Zen
Да, конечно, разница в гарантиях. Но не в монолите смотреть в кэш орм для обнаружения изменений это очень сомнительная практика имхо, тем более после комита он же очищается, так что в любом случае придется как-то извращаться на эту тему.
источник
2021 November 29

NC

Nikita Chaykin in Software Design/Architecture/Zen
Всем привет, подскажите пожалуйста правильно ли думаю/делаюЮ, есть условные users, posts, products, сущности products, posts на уровне бд завязаны на users, но products, users, posts -> 3 отдельных модуля, то есть мы можем получить просто все посты или все продукты или всех юзеров, вопрос такой, когда мы через userModule будем тянуть все сущности заджоиннные на users(то есть posts, products), то нам придётся на (users)presentation layer шарить dto из postModule и productModule, то есть у нас получается, что userModule завязан на infrastructure layer(postModule, productModule) и еще впридачу на presentationLayer(postModule, productModule) это норм?
источник

SP

Sergey Protko in Software Design/Architecture/Zen
it depends. если у тебя за каждый модуль и presentation layer подуктов и постов отвечают разные команды - это не норм. Есть варианты как с этим сражаться. Чаще всего отказом от джойнов. Если у тебя маленький проект где пара человек и больше важно "влоб" то норм

выпиши для себя чего ты хочешь добиться и оттуда смотри норм тебе иили нет.
источник
2021 November 30

AB

Andrey Bakharev in Software Design/Architecture/Zen
общался сегодня с одним java-разработчиком
у себя на канале она статью про dip, di и иже с ними выложила
и в примере с dip был там следующий код:
class Service {
   LoggerInterface logger;
   public function Service() {
       logger = new FileLogger();
   }
}

я до этого читал, что dip - это никаких упоминаний реализаций (в частности потому как они тянут за собой компилирование вашего пакета) + у дядюшки Боба читал, что никаких import, require или use быть не должно, и поэтому считал, что вот это вот new FileLogger() является как раз нарушением этого принципа

пообщался с автором поста, она топит за то, что dip - это когда твой код с интерфейсом работает, а не с реализацией и инициализация сюда не входит
типа инициализация - это уже di скорее, а к dip'у только боком относится
и на мое замечание "тогда можно создать конкретный класс, перед каждым использованием приводить его к интерфейсу (типа ((LoggerInterface)logger)->log()) и всем говорить, что у нас соблюдается dip" она ответила, что да, это и будет dip
и вот интересно стало: а правда где?

я понимаю ее подход, но так же понимаю и подход "никаких упоминаний реализаций" и последний мне ближе
а потом подумал, будет ли следующий код соответствовать dip:
abstract class Service {
   abstract function getLogger(): LoggerInterface;
}

?
вроде здесь никаких упоминаний реализации, но получается, что мы реализацию перекладываем на клиента, а он внутри getLogger() может как конкретный объект создавать, так и возвращать заинъекченный по интерфейсу
и вот в моем понимании в первом случае будет нарушение dip, а во втором - нет
т.е. и абстрактный класс как бы завис: нарушать или нет?

и вот как правильно? включать инициализацию по интерфейсу, чтобы можно было говорить про dip? или работу с объектом через интерфейс и считать dip? даже если двумя строчками выше идет инициализация конкретной реализации
если последнее, то как тогда называется, когда у нас dip + инъекция по интерфейсу? по любому же название есть
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
кстати, 10е ноября уже прошло, может пора пин отпиннить?
источник

A

Alexander in Software Design/Architecture/Zen
Это, наверное, можно считать DIP только в рамках одного метода. Но класс Service в целом завязан на конректной имплементации, и если под единицей языка понимать класс, то, можно считать, что DIP не был соблюден
источник

AV

Alexey Vetrov in Software Design/Architecture/Zen
а собственно как тестировать ее подход - это самый первый вопрос, который вы должны были задать
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
ну там же чисто пример, можно и через Service(FileLogger logger) инициализировать, а для тестирования просто замокать логгер
для нее суть не поменяется - она же по прежнему работает внутри класса с LoggerInterface
и для меня не поменяется - все равно упоминание реализации есть ))
источник

AV

Alexey Vetrov in Software Design/Architecture/Zen
вот когда файллоггер перенесется в конструктор, тогда уже вопрос отпадет, а пока он остается
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
я тоже так считаю, но че-то по озвученным причинам сомневаться стал, может я и не совсем прав, оказываюсь?
источник

AV

Alexey Vetrov in Software Design/Architecture/Zen
А можно ссылку на статью?
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
ну ок, перенесли мы в конструктор, это dip стало? или все-таки нет? ведь упоминание реализации есть, хоть напрямую и не работаем с нею
у раз упоминание есть, то и комплиятор может наш код перекомпилить при изменениях в реализации, хотя по коду нам менять нечего - мы же с интерфейсом работаем
источник

AV

Alexey Vetrov in Software Design/Architecture/Zen
class Service {
   LoggerInterface logger;
   public function Service(LoggerInterface logger) {
       this.logger = logger;
   }
}
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
че-то большая статья получилась ))) щас по-другому попробую
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
нет, если вот так:
class Service {
   LoggerInterface logger;
   public function Service(FileLogger logger) {
       this.logger = logger;
   }
}
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
здесь - dip
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
здесь - нет
источник

AV

Alexey Vetrov in Software Design/Architecture/Zen
так это смысла не меняет, зачем оно
источник

AB

Andrey Bakharev in Software Design/Architecture/Zen
ссылка на статью: https://t.me/java_fillthegaps/342
Telegram
Java: fill the gaps
Чем отличаются Dependency injection, Dependency invertion и Inversion of Control

Прошлый пост про Liskov, как говорится, "взорвал мой директ", поэтому на этой неделе расскажу про ещё два популярных принципа.

Сегодня про букву D из SOLID — Dependency Inversion. Что это, и чем отличается от Dependency injection и Inversion of Control. Понимание пригодится на собеседованиях, при чтении статей по дизайну и архитектуре.

Будем разбираться на простом примере: класс Service записывает логи в файл через класс FileLogger:

class FileLogger {…}
class Service {
 FileLogger logger=new FileLogger();
}

Сделаем код чуть лучше с помощью разных принципов:

1️⃣ Dependency injection
—  компоненты создаются не внутри класса, а где-то в другом месте.

Как реализовать: перенести инициализацию логгера в конструктор или сеттер:

class Service {
 FileLogger logger;
 Service (FileLogger logger) {
   this.logger=logger;
 }
}

✅ Класс занимается только своей бизнес-логикой
✅ Можно вынести всю конфигурацию в одно место. Или спихнуть…
источник