Как стать автором
Обновить

Комментарии 24

Логика в Entity, пусть даже немного, это как-то стрёмно. Вообще интересно, что автор доклада имел в виду под Entity. Если то, что использует JPA, то есть вопрос. Как я понял, он собирается эти Entity использовать в слое, который описывает бизнес логику. Что делать, если нужно порефакторить структуру БД? Править код во всех местах, которые используют Entity?

Что делать, если нужно порефакторить структуру БД? Править код во всех местах, которые используют Entity?

Править код во всех местах вам придется, если вы используете паттерн Active Record, дяд Боб же в своей книге рекомендует отделять зависимости бизнес-логики от деталей (БД или что вы там используете для персистентности) и юзать паттерн Data Mapper, таким образом вам не придется править код во всех местах, если поправите структуру БД или вообще решите сменить какой-нибудь MySql на Mongo, это затронет только имплементацию модуля доступа к данным.

Логика в Entity, пусть даже немного, это как-то стрёмно. Вообще интересно, что автор доклада имел в виду под Entity.


Не скажу что имел ввиду автор статьи, но Роберт Мартин в своей книге разделяет бизнес логику на две:
1. application-specific business rules — они же юз кейсы, они же интеракторы.
2. application independent business rules — они же entities — это соединение в одной сущности критических бизнес данных и критических бизнес правил, которые оперируют на этими данными. Как он сказал: «мы называем эти правила так, потому что они критические непосредственно по отношению к самому бизнесу и будут существовать даже если не будет никакой системы автоматизирующей их». С критическими бизнес данными тоже самое, они будут существовать в бизнесе, даже если не будет автоматизирующей системы для этого бизнеса.
Править код во всех местах вам придется, если вы используете паттерн Active Record

Если использовать JPA, то тоже придётся, хотя это не Active Record. Код придётся рефакторить если поля классов, которые используются в системе один в один соответствуют полям таблиц БД. Я думаю, именно это вы и хотели сказать.


дяд Боб же в своей книге рекомендует отделять зависимости бизнес-логики от деталей (БД или что вы там используете для персистентности) и юзать паттерн Data Mapper

У меня сложилось впечатление, что автор доклада не советует.


application independent business rules — они же entities

Это не те Entity, в которых поля один в один соответствуют полям таблиц в БД, да?

Я не Java разработчик, по этому не знаю что там в JPA и как.

Это не те Entity, в которых поля один в один соответствуют полям таблиц в БД, да?

Не, не те. Они вообще не имеют никакого отношения к способу хранения информации в постоянной памяти. Вы их можете сохранять хоть в обычном файле вместо БД. Код бизнес логики это вообще никак не затронет.
Код придётся рефакторить если поля классов, которые используются в системе один в один соответствуют полям таблиц БД.

Да дело даже не в том соответствуют они один в один или нет, а дело в направлении зависимости. Если ваша бизнес логика зависит от БД, то еще как придется менять. А если ваша бизнес логика скажем использует всего лишь интерфейс, что-то вроде такого IOrderDataAccess и у этого интерфейса есть допустим методы: saveOrder(Order o), findOrdersByDate(Date d), где Order — это как раз и есть entity, то какая разница как имплементация этого интерфейса хранит данные Order — в одной таблице, в 10-ти, в обычном файле или вообще на марсе через http api third party сервиса какого нибудь. Тут как раз направление зависимости другое — имплементация IOrderDataAccess зависит от вашей бизнес логики, а не наоборот.

Entity здесь из мира DDD. По сути это идентифицируемый объект, который можно сохранить и восстановить из БД. В JPA Entity он превращается только в Repository. В простейших случаях Entity равно JPA Entity по хранимым данным.
В последнее время я склоняюсь к тому, что не нужно лениться разделять Entity и JPA Entity, чтобы не было больно рефакторить БД. Но об этом же говорится и в статье. БД — это внешние данные для домена :)

Они не обратили внимание, что двойка во всех трёх случаях имеет совершенно разный смысл

Нет же:


double START_PRICE = 2;
int MIN_DURATION = 2;
double DAY_PRICE_MULTIPLIER = 1.5;

double price = START_PRICE;
if (daysRented > MIN_DURATION) {
    price += (daysRented - MIN_DURATION) * DAY_PRICE_MULTIPLIER;
}
return price;

И тогда сразу понятно, что здесь 2 сущности.

Здесь 3 сущности. DAY_PRICE_MULTIPLIER, MIN_DURATION и NOT_COUNTED_DAYS

Это что тогда за use-case? "Если арендуете больше, чем на 5 дней, то будете доплачивать за каждый день, начиная с третьего дня..." Так, что ли?


Все-таки стандартный случай будет: "200 руб. за первые 2 дня + 50 руб. за каждый следующий день".


Если же это действительно какой-то странный случай, то тем более надо убирать magic numbers, добавлять пояснение, ну и проверку усиливать, чтобы цена в минус не ушла.

В докладе речь была не про то, что выносить в константы не нужно, а про преждевременную оптимизацию.
Объединить все двойки под одной константой — красиво, но совершенно не корректно.
Объединить две двойки(которые про количество дней) — уже лучше, но ТАКЖЕ не корректно. Это такая же преждевременная оптимизация, которая может в последствии выйти боком.

При чем тут оптимизация? Тут magic numbers, в которых путаются их программисты, и совершенно непонятно, что менять, если условия аренды изменились. Две здесь сущности или три – это вопрос к их бизнес-логике, но это совершенно точно не должны быть просто какие-то числа.


И уж совсем непонятно, что этот пример (который неудачный даже для объяснения DRY) делает в пункте "Предпочитайте композицию наследованию".

Пример не очень удачный, согласен. Но давайте, на минутку, представим, что докладчик представил просто идеальный пример, на пять страниц кода, с неочевидными зависимостями и сложной логикой. Выиграл бы от этого доклад? Очевидно, что нет.
Формат доклада со слайдами диктует свои ограничения, причем довольно жесткие.

— А вон в этом примере надо было использовать не ArrayList, а LinkedList!
— Ээээ? Ну наверное да, но пример-то про Dependency Injection, а не про правильное использование коллекций…
— Вы не увиливайте! В коллекциях не разобрались, а все туда же — учить лезете!
Об этих DTO… Когда-то нужно было быстро написать Enterprise-подобное приложение для одного предприятия. Взял AngularJS + некий Breeze js и обошелся без этих самых DTO вообще. Breeze js позволял прямо из js запрашивать объекты из базы (с ORM на клиенте), редактировать эти объекты в js, коммитить на сервер дельту и автоматически применять ее к базе.
В итоге на не сервере изначально не было кода вообще и все работало. Потом появился код для проверки прав пользователя на доступ и изменения. Потом код для очень сложных запросов групп доменных объектов, которые тормозили при реализации на клиенте.
На клиенте же Angular прекрасно показывал доменные объекты и их же менял.
Обычно вроде так не пишут (не могу понять почему), но для меня это была архитектура, позволяющая в одиночку написать максимальное количество юз-кейзов в минимальные сроки практически при полном отсутствии кода или логики не относящихся непосредственно к решению основных задач приложения.
И этот комментарий я разместил потому, что заголовок статьи «Чистая прагматичная архитектура» и мне интересно делал ли еще кто-то так как я, а не потому что я считаю эту схему пригодной для больших проектов.
Спасибо за перевод, но сама по себе статья выглядит несколько сомнительно. Основной тезис «Т.к сложно освоить нормальную доменную модель, то можно фигачить проекты на анемичной, юзая некоторые паттерны нормлаьной разработки чтобы было не так уж паршиво». Ну и некоторые тезисы вообще смотрятся как то печально. В частности автор дает неверное определение SRP, предлагает сувать «немного логики в DTO» и т.д. А в конце автор перечисляет основне идеи архитектуры Порты и Адаптеры, но подаёт их под именованием «Прагматичная луковица». Вобщем, статья, конечно прочиталась легко, тем боолее в условиях дифицита материалов об архитектуре ПО на хабре, но вот читать ее надо с повышенным уровнем критичности, особенно новичкам.

По большому счету, выбор между DDD и Transaction Script определяется габаритами предметной области. Если она мала (и таковой и останется), то особого смысла в DDD нет.


Собственно основной посыл, как я понял


Как можно дольше (и чего бы это ни стоило) соблюдайте простоту: избегайте «переинженерии» и запоздалой(wtf? подозреваю, что это баг перевода и должно было быть "преждевременной") оптимизации, не перегружайте приложение;

А вот определение DRY автором подано как-то очень странно. Мне всегда казалось, что это как раз про переиспользование, а не про "каждый раз пиши заново".

Хорошее выступление. Хотя не понравилось традиционное упоминание «композиции вместо наследования». Почему бы не использовать этот тезис в его правильной трактовке: иногда вместо наследования лучше применять композицию?

Еще момент: разбиение фасада на кусочки пройдет легче, если вообще не делать фасадов из нескольких методов. Пиши каждый метод в отдельном классе и будет щасте.
Сейчас очень популярно говорить, что наследование вообще нигде не нужно. Особенно, налседование реализации. Возможно, просто дань моде.

Скорее всего потому что наследование в смысле расширения функциональности (интерфейса) противоречит принципу подстановки.

Почему бы не использовать этот тезис в его правильной трактовке: иногда вместо наследования лучше применять композицию?

Потому что тогда надо будет рассказать как отличить случаи когда вместо наследования лучше применять композицию от случаев, когда можно применять наследование. Плюс, когда вы говорите о правильной трактовке, надо иметь в виду, что многие считают правильной трактовкой следующую: иногда вместо композиции лучше применять наследование.

НЛО прилетело и опубликовало эту надпись здесь

В таком случае это вместо композиции иногда надо применять наследование, а не наоборот.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий