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

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

Первым делом обратимся к паттернам и их определениям модели:

Вы когда говорите об определениях — вы бы на источник-то определения ссылались?


Вот это самое правильное определение для модели. Модель — это исключительно бизнес-логика и ничего больше!

"Правильное" по каким критериям? Вам так нравится?

Вы когда комментарии пишите, сначала статью до конца дочитайте ;)
А источники да, добавил.
Вы когда комментарии пишите, сначала статью до конца дочитайте ;)

А зачем, если первоначальная посылка ошибочна:


После того как решили что модель — это исключительно бизнес-логика, перейдем к вопросу формирования этих моделей.

Из ложной посылки можно сделать любые выводы, но какая в них ценность?


А источники да, добавил.
источник design-pattern.ru

Это не источник, а на заборе написано. Вот, например, вы их цитируете:


MVC (Model View Controller) — модель данных.

Открываем PoEAA, на который они, типа, ссылаются:


The model is an object that represents some information about the domain. It’s a nonvisual object containing all the data and behavior other than that used for the UI. In its most pure OO form the model is an object within a Domain Model (116). You might also think of a Transaction Script (110) as the model providing that it contains no UI machinery. Such a definition stretches the notion of model, but fits the role breakdown of MVC.

Мораль: не читайте то, что написано на заборе, читайте первоисточники.

Кстати, еще об определениях.


DM (Domain Model) — каждый объект представляет собой отдельную значащую сущность.
[...]
перейдем к вопросу формирования этих моделей.
[...]
Каждый репозиторий работает только с 1 моделью.

Создается ощущение, что вы решили, что (в Domain Model) модель и сущность — это одно и то же. Так вот, нет:


Domain Model
An object model of the domain that incorporates both behavior and data
[..]
Putting a Domain Model in an application involves inserting a whole layer of objects that model the business area you’re working in. You’ll find objects that mimic the data in the business and objects that capture the rules the business uses.

(снова PoEAA)


Объектная модель домена. То есть, внезапно, слово "модель" относится к целому, а не к его частям. Вот подтверждающая цитата, где модель и составляющие ее объекты противопоставляются:


A common concern with domain logic is bloated domain objects.

… это, конечно, если мы говорим в терминах Фаулера. Если мы перейдем к терминам Эванса, картинка может и поменяться.

Это конечно замечательно, что вы столько выдержек из теории выдали (спасибо, правда), НО из этих выдержек абсолютно не следует, что представление модели изложенное в статьи противоречит этим определениям.

Мораль: не читайте то, что написано на заборе, читайте первоисточники.

Да, каюсь, некорректно привел информацию о модели в парадигме MVC, но речь в статье НЕ заключалась в объяснении MVC, а рассмотрение конкретного примера работы с моделями.

Из ложной посылки можно сделать любые выводы, но какая в них ценность?

А в чем тут ложность? Вы сами приводите сноску о том, что модель — это объект предоставляющий информацию о домене. По вашему домен != бизнес-логика?

Создается ощущение, что вы решили, что (в Domain Model) модель и сущность — это одно и то же. Так вот, нет:

А что в вашей сноске подтверждает ваше утверждение? Модель и сущность — это термины означающие одно и то же: объект предметной области обладающей поведением и данными данной предметной области. Если вы имеете ввиду различные вспомогательные ValueObject и определяете их как сущности — это опять вопрос терминологии. Даже если мы возьмем такой пример VO как «деньги», то это тоже модель, но без поведения как такового.

Объектная модель домена. То есть, внезапно, слово «модель» относится к целому, а не к его частям. Вот подтверждающая цитата, где модель и составляющие ее объекты противопоставляются:

Вообще не подтверждающая цитата. Здесь лишь говорить о том что модели могут раздуваться до огромных размеров, но это уже вопросы проектирования и реализации, а не подхода как такового. В статье идет разделение на «целое и часть» в рамках конкретной сущности бизнес-логики (например «пост — комментарий»).

То есть допустим, если у нас есть объект «Департамент», который действительно может быть большим, НО большой объект != сложный объект. Если декомпозировать эту модель на его «части» и логику реализовать с помощью бизнес-операций (пример реализации в статье), то объект будет просто большим, но ничуть не сложным.
НО из этих выдержек абсолютно не следует, что представление модели изложенное в статьи противоречит этим определениям.

Эти, выдержки, однако, показывают, что ваше утверждение, что "модель — это исключительно бизнес-логика", ими не подтверждается.


рассмотрение конкретного примера работы с моделями.

Ну так не надо выдавать конкретный пример за единственно правильный.


А в чем тут ложность?

В том, что модель — это исключительно бизнес-логика.


Вы сами приводите сноску о том, что модель — это объект предоставляющий информацию о домене. По вашему домен != бизнес-логика?

Домен — это бизнес-логика. Но "объект, предоставляющий информацию о домене" — это не только бизнес-логика. В описании Model из MVC Фаулер явно пишет: "all the data and behavior other than that used for the UI". Не "данные домена", а "все данные, кроме используемых исключительно для UI". В частности, поведение, отвечающее за работу с БД, тоже окажется здесь. Или за вызов сторонних сервисов. Или за логирование.


А что в вашей сноске подтверждает ваше утверждение?

То, что model и object в ней никогда не употребляются как синонимы. Domain Model — это слой (layer).


Модель и сущность — это термины означающие одно и то же: объект предметной области обладающей поведением и данными данной предметной области.

Нет, это вы так придумали. Но ни в понятии Domain Model, ни в понятии MVC слово Model это не обозначает.


Здесь лишь говорить о том что модели могут раздуваться до огромных размеров

"bloated domain objects". Не модели, а объекты.

Нет, это вы так придумали. Но ни в понятии Domain Model, ни в понятии MVC слово Model это не обозначает.

Окей, разберемся в терминах. Чуть выше я привел пример объект «деньги», который по моему мнению тоже модель (без поведения, просто данные). Вы говорите что это не модель, а объект домена — все верно?
Т.е. модели — это то что отражает объекты предметной области (неважно есть поведение или нет), а объекты домена — это вспомогательные сущности без поведения предметной области?
Т.е. модели — это то что отражает объекты предметной области (неважно есть поведение или нет), а объекты домена — это вспомогательные сущности без поведения предметной области?

Нет. В рамках Domain Model, как это понятие введено Фаулером, domain objects — это объекты, описывающие бизнес, как данные, так и поведение. А domain model — это совокупность этих объектов (и их связей).


Модели, множественное, в этой терминологии возможны только тогда, когда вам надо декомпоновать сложный бизнес на несколько более простых областей (то, что у Эванса называется bounded context).


А в рамках MVC, опять же, по Фаулеру, model — это все, что не UI.

Ну собственно когда я говорю модель — я имею ввиду domain object. А Domain Model — это по сути концепция/подход, а не сущность/объект. Вроде в этом ключе все и описано в статье, но в любом случае пройдусь еще раз, чтобы не было недопонимания. Спасибо!
Ну собственно когда я говорю модель — я имею ввиду domain object.

А другие люди понимают другое. На этом фоне ваш пост с заголовком "как должны выглядеть модели" и вступлением "все ли понимают что такое модель" выглядит неуместно. Потому что, внезапно, вы понимаете под словом "модель" что-то свое, но радостно провозглашаете свое мнение правильным.

Эээ чуть выше вы сами написали что в разных концепциях термин «модель» имеет разные значения (MVC и DM). Поэтому мое мнение НЕ не правильное, а отличающееся от концепции MVC и ложащееся в концепцию DM (domain objects).

Я и не провозглашал, что мое мнение истина в последней инстанции. Я лишь сказал что модели — это исключительно бизнес-логика. И это мнение правильное для меня, и абсолютно не ложится в термины MVC. Я эту идею транслирую, так же как Фаулер транслирует свою. Это разные точки зрения (да и по большому счету «о разном») и как-то сравнивать 2 термина из разных концепций странное занятия (естественно у Фаулера запас доверия куда бооооооольше, но это не значит что мое мнение ничего не стоит).
ложащееся в концепцию DM (domain objects).

Нет, потому что в концепции Domain Model под model понимается не то, что у вас.


Я и не провозглашал, что мое мнение истина в последней инстанции.

Тогда в чем смысл вопроса "все ли до конца понимают, что эти слова означают?". Мы вот выяснили, что вы — не понимаете.


Поэтому мое мнение НЕ не правильное, а отличающееся

Проблема не в вашем мнении. Проблема в том, что ваш пост написан с позиции "я знаю, как правильно, и правильно — вот так (и только так)" — или, по крайней мере, читается, как написанный с такой позиции. При этом продвигаемые вами идеи — спорны.

Тогда в чем смысл вопроса «все ли до конца понимают, что эти слова означают?». Мы вот выяснили, что вы — не понимаете.

Мы вроде выяснили что я понимаю не так как Вы, а ваша аргументация почему мое понимание не ложится в концепцию DM слабо выглядит.
Определение Фаулера (краткое):
A Domain Model creates a web of interconnected objects, where each object represents some meaningful individual, whether as large as a corporation or as small as a single line on an order form.

Объекты отражающие сущности бизнес-логики (о чем в статье и речь). Если вы это определение воспринимаете иначе, то это уже проблема восприятия, а не формулировок.
я понимаю не так как Вы

Не так, как я, не так, как MVC, и не так, как Domain Model.


Объекты отражающие сущности бизнес-логики (о чем в статье и речь)

Еще раз. У Фаулера Domain Model и domain object — это разные вещи (одно — часть другого). А у вас — одно и то же.

Еще раз. У Фаулера Domain Model и domain object — это разные вещи (одно — часть другого). А у вас — одно и то же.

«Модель» != «Domain model», а «Модель» = «Domain object». Я вроде уже раза 4-5 это обозначил.

Ну так это и есть ваше собственное понимание. В рамках Domain Model у Фаулера нет никакой другой модели, кроме Domain Model.

Как мы славно прыгаем по концепциям и терминам. Я для этого вначале статьи специально написал, что «модель — это бизнес-логика». Видимо чтобы было понятно для вас слово модель везде надо было заменить на «domain object», тогда бы вопросов не возникло?

Причем когда мы говорим про AR, такого вопроса почему то не возникает, и по-умолчанию понятно что является моделью. Хм…
Я для этого вначале статьи специально написал, что «модель — это бизнес-логика».

Ну да. Это выбранное вами определение, которое вы навязываете, как правильное.


Видимо чтобы было понятно для вас слово модель везде надо было заменить на «domain object», тогда бы вопросов не возникло?

… начиная с заголовка поста, да.


Причем когда мы говорим про AR, такого вопроса почему то не возникает, и по-умолчанию понятно что является моделью.

Я просто не говорю про AR.

Я как раз и обозначил вначале статьи что подразумевается под моделью. Потому что иначе пришлось бы рядом со словом модель писать пояснения для всех концепций (в рамках MVC — модель, в рамках DM — domain object и т.д.).
Занятное чтиво бы получилось. И наверняка нашелся бы тот (или какая-либо концепция), чье понимание я не отразил. Так что слово «модель» в рамках данной статьи, отражает именно то, что написано в статье.
Никогда бы не подумал что краткий референс на Domain Model сломает до такой степени понимание.
Я как раз и обозначил вначале статьи что подразумевается под моделью.

Угу.


все ли до конца понимают, что эти слова означают?
Все ли понимают что такое модель

Не надо так.


Потому что вы начинаете с захода "сейчас я объясню, что такое модель", потом пишете "самое правильное определение для модели", а потом выясняется, что это просто вы подразумеваете под моделью.


Никогда бы не подумал что краткий референс на Domain Model сломает до такой степени понимание.

Дело не в референсе, а в том, что вы подаете свое мнение как "самое правильное".

Потому что вы начинаете с захода «сейчас я объясню, что такое модель», потом пишете «самое правильное определение для модели», а потом выясняется, что это просто вы подразумеваете под моделью.

А почему «пишу самое правильное определение» это не тождественно равно «подразумеваю под моделью»? Синонимы как по мне.

Дело не в референсе, а в том, что вы подаете свое мнение как «самое правильное».

Дак а я не увидел опровержений. Модель — это все что касается бизнес-логики. У Фаулера (с ваших слов) Модель — это все что не UI. Чем мое определение хуже, чем у Фаулера?
Касаемо DDD — термина модели нет, есть Агрегат, Сущность, VO — что по факту является детализацией/конкретизацией термина «модель»
А почему «пишу самое правильное определение» это не тождественно равно «подразумеваю под моделью»? Синонимы как по мне.

Нет, не синонимы. "Самое правильное определение" — это утверждение, а не мнение. А "я подразумеваю под моделью" — это введение определения, использующегося в посте, но не за его пределами.


Чем мое определение хуже, чем у Фаулера?

Тем, что оно сужает Фаулеровское и заставляет людей, работающих с MVC, думать, что они делают что-то неправильно.


что по факту является детализацией/конкретизацией термина «модель»

Нет, не является. Это вы вводите термин "модель", который является, по вашим словам, их обобщением. Можно ли их обобщать — вопрос отдельный.

domain object — это любой из объектов, составляющих Domain Model: сущность, объект-значение, даже инстанс сервиса.


Причем когда мы говорим про AR, такого вопроса почему то не возникает, и по-умолчанию понятно что является моделью.

ActiveRecord можно назвать моделью, но моделью какой-то сущности, именно сущности — части общей доменной модели.


А тому, кто ввёл в обиход class User extends Model, я б не советовал встречать со мной на какой-нибудь афтерпати :)

начали возможно и правильно о способах работы и субьективно выбрали вариант "domain model" и нарисовали картинку со слоями (domain, service, data), а дальше на примерах понесло.


У вас у "модели" Post куча сеттеров и геттеров, где тут бизнес логика?


интерфейс репозитория зависит от КЛАССА, абстракция зависящая от реализации, окей.


далее там даже коментить не охото где di это singleton который юзается в других singleton и тд


вот хороший пример, хороших практик по моделям http://ocramius.github.io/doctrine-best-practices/#/

У вас у «модели» Post куча сеттеров и геттеров, где тут бизнес логика?

Об этом было ближе к концу в разделе бизнес-операции. Ну либо если это не является бизнес-логикой, то даже не знаю какой должна быть БЛ у блога.

интерфейс репозитория зависит от КЛАССА, абстракция зависящая от реализации, окей.

В данной ситуации, когда 1 интерфейс = 1 реализация, а вторая не планируется не ранее чем никогда, делать очередной интерфейс — излишество.

далее там даже коментить не охото где di это singleton который юзается в других singleton и тд

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

вот хороший пример, хороших практик по моделям ocramius.github.io/doctrine-best-practices/#

Просто шикарная подача информации! На каком слайде нужно остановится про модели?)
Об этом было ближе к концу в разделе бизнес-операции. Ну либо если это не является бизнес-логикой, то даже не знаю какой должна быть БЛ у блога.

Ваша модель может быть в некорректном состояние, если ей после создания не проставили title например, а тайтл обязателен с точки зрения бизнес логики(если такое условие есть).


Чтобы не допускать ситуаций когда "модель" в невалидном состояние можно обязательные аргументы например передать в конструкторе (один из вариантов).


Публичные сеттеры стоит избежать пример http://ocramius.github.io/doctrine-best-practices/#/33 из той же презентации, через несколько слайдов будет пример с убранным сеттерами.


В данной ситуации, когда 1 интерфейс = 1 реализация, а вторая не планируется не ранее чем никогда, делать очередной интерфейс — излишество.

смысл от этого интерфейса репозитория? который зависит от конкретной модели?


чтобы сделать мок? мокать можно и классы внезапно https://phpunit.readthedocs.io/en/9.0/test-doubles.html


Зачем в итоге этот интерфейс репозитория ?


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

У вас примере не внедрения зависимостей, singleton перемещанный с service locator.


внедрения зависимостей это инструмент который проставляет необходимые зависимости, главное отличие di от service locator что класс куда проставляются зависимости знать не знает о di и ему без разницы кто передает зависимости какая то библиотека di или созданно в ручную.


Отсюда существуют основные способы передачи зависимостей


  1. Иньекция через конструктор
  2. Иньекция через методы
  3. Иньекция через свойства

Ну и далее лучше почитать https://martinfowler.com/articles/injection.html


то что далее там наворотили с этими бизнес операциями, это у вас по сути обработчики эвентов after creation например, но если обратить внимание код в примерах не рабочий у NotifyAuthorAboutComment есть метод setPost, но он например нигде не вызывается :)


Просто шикарная подача информации! На каком слайде нужно остановится про модели?)

Ссылку выше кинул с примером про сеттеры, я бы советовал начать http://ocramius.github.io/doctrine-best-practices/#/25


Как итог комменты получаются размерами как статья чтобы указать на те нюансы статьи где ее можно было бы улучшить, основная причина я думаю это кричащий заголовок, "Как должны выглядеть модели", при этом отсекаются кейсы где AR вполне может быть применим или другие подходы, а остается единственно верный путь (silver bullet), я бы изменил заголовок на что то вроде "как мы создаем модели на проектах".
Ну и в статье примеры бы изменил убрав все публичные методы из модели которые не относятся к бизнес логике, убрал бы реализацию sigleton через service locator, но это ваша статья ...

внедрения зависимостей это инструмент который проставляет необходимые зависимости, главное отличие di от service locator что класс куда проставляются зависимости знать не знает о di и ему без разницы кто передает зависимости какая то библиотека di или созданно в ручную.

Дак собственно createInstance создает объект которые инициируется через конструктор (в коде пример неправильный, исправил). Реализацию контейнера я посчитал добавлять сюда лишнее, потому что речь не про DI.

но если обратить внимание код в примерах не рабочий у NotifyAuthorAboutComment есть метод setPost, но он например нигде не вызывается :)

Вызывается в методе addComment — это было и до исправлений :)

смысл от этого интерфейса репозитория? который зависит от конкретной модели?
чтобы сделать мок? мокать можно и классы внезапно phpunit.readthedocs.io/en/9.0/test-doubles.html
Зачем в итоге этот интерфейс репозитория?

Интерфейс репозитория — для разных реализаций репозитория, а не разных реализаций поста. Никто не мешает наследоваться от КЛАССА внезапно!
Дак собственно createInstance создает объект которые инициируется через конструктор (в коде пример неправильный, исправил). Реализацию контейнера я посчитал добавлять сюда лишнее, потому что речь не про DI.

достаточно было в статье написать классы придерживаясь DIP иньектя зависимости в конструкторе например, а как они будут иньектится уже другой вопрос, можно было сослаться на psr/container.


Вызывается в методе addComment — это было и до исправлений :)

ок проставляется, не заметил под спойлером что реализация поста отличается от той что без спойлера.


все равно считаю это не правильным.


Интерфейс репозитория — для разных реализаций репозитория, а не разных реализаций поста. Никто не мешает наследоваться от КЛАССА внезапно!

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


Тестить вы будете конкретный хэндлер например (создание поста) он зависит от репозитория (интерфейса или класса без разницы в тестирование эту зависимость можно мокнуть)


Еще будете тестить саму модельку, но она к бд не привязана и знать не знает о репозитории интерфейсе или конкретном классе.


Ну и тестить сам репозиторий (тогда мокается сама моделька)


нафига в этих случаях отдельный интерфейс репозитория? когда захотите тестить создание поста и вместо реально бд юзать sqlite? (этот вопрос зачем так делать и здоровая ли это фантазия оставим за кадром)


а вот как вы будете тестить $post->addComment ?(там внутри бизнес экшен через singleton проставляется, который никак нормально не мокнуть), я имею ввиду здоровые варианты без overload.


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


я просто напомню что мне изначально не понравилось


  1. Что domain model как единственно верный вариант (смотри заголовок поста)
  2. Что домейн модели это набор сеттеров и геттеров (вместо отражений действий домена и их поведений)
  3. Что di в примерах показан как singleton и service locator
  4. Не вижу смысла в интерфейсе репозитория в текущих требованиях.
  5. Интерфейс репозитория зависит от конкретного класса (абстракции потекли).

думаю этих 5 пунктов достаточно чтобы показать что можно улучшить.


ну и мои решения этих 5 пунктов


  1. domain model не единственная правильная реализаций моделей(альтернативы вы перечислили), она возможно более гибкая, но более требовательная на начальных этапах.
  2. Спрятать все эти сеттеры и геттеры в private публичными оставить только те действия которые могут осуществленны с моделью.
  3. Убрать все эти getInstance и просто придерживаться DIP иньектя зависимости через конструктор например
  4. Убрал бы интерфейс репозитория в текущих требованиях.
  5. Нет интерфейса нет проблемы.

у меня нет настроения продолжать вы останетесь при своем мнение, я при своем я указал что мне не понравилось, но это ваша статья и ваше мнение, в любом случае спасибо за труд.

смысл от этого интерфейса репозитория? который зависит от конкретной модели?

чтобы сделать мок?

Именно, чтобы сделать мок. Вчера был на докладе Себастьяна Бергмана, автора phpunit, так вот он как раз на примере интерфейса репозитория показывал тесты: мок репозитория работает с коллекцией в памяти, просто в массив складывает данные и достаёт оттуда. И это не createMock или ещё что-нибудь, а полноценный класс, который можно заинжектить как реализацию интерфейса репозитория

речь о том что мок нужен в тот момент когда тестируется код который использует репозиторий (например хэндлер зависящий от репозитория).


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


__setup()
   $this->repo = $this->createMock(SomeClassOrInterface::class);
   $this->handler = new RealHandlerForCreateBlog($this->repo);

если мы не хотим юзать createMock а прям писать свою реализацию то получим следующее


__setup()
    $this->repo = new class() implement RepoInterface {
    // methods stub
    }
    $this->handler = new SomeHandler($this->repo);

__setup()
    $this->repo = new class() extends RepoClass {
    // overwrite methods in base class
    }
    $this->handler = new SomeHandler($this->repo);

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

1) у меня обычно реализация репозитория final
2) в слой доменной логики вводить инфраструктуру в виде очень специфичного репозитория не хочется
3) Реализации и на практике разные бывают, например, DoctrineOrderRepository заменяется на RestOrderRepository при переходе на микросервисы

  1. вы сами ограничиваете себя, не используете createMock, используете final, я напомню что я комментировал статью и там у репозитория нет final, поэтому вам и решать как быть в вашем коде, я бы использовал createMock в такой ситуации.
  2. Слой доменной логики понятие не имеет о репозитории, домен это моделька, она не зависит от способа хранения.
  3. Вот когда возникает такая необходимость тогда и вводится интерфейс, а не заранее далеко не всем это необходимо и статья не о способах отвязаться от способа хранения данных.

я просто напомню что я писал выше


  1. Я не вижу смысла в интерфейсе репозиториев в рамках этой статьи
  2. Я не вижу смысла в интерфейсе который использует конкретные классы (как в этой статье), если вводить интерфейс то делать это нормально.
  1. final я использую не для ограничений себя, а для документирования того факта, что ничего для обеспечения консистентности и сохранения инвариантов в наследниках не делалось, например, активно используется self, а не static


  2. Интерфейс (не реализация) репозитория — часть доменного слоя. Домен — это сущности ("модельки"?), объекты-значения, доменные события, доменные сервисы, репозитории и фабрики доменных объектов.


  3. Статья, вроде как, о методах моделирования предметной области.





Либо в статье вообще не надо было упоминать о репозиториях, что было бы странно. Либо упоминать в нормальном виде, что и было сделано. То, что интерфейс PostRepository зависит от Post — нормально. Цель интерфейса PostRepository — абстрагирование от конкретного способа хранения сущностей Post.

интерфейс репозитория зависит от КЛАССА, абстракция зависящая от реализации, окей.

Одно из немногих мест, где у автора нормальный поход.

Что-то я запутался… А не наоборот ли должно быть?

Abstractions should not depend on details. Details should depend on abstractions. © Robert Martin

Так всё нормально. Абстракция репозитория не зависит от деталей реализации репозитория, от того что у него там под капотом, мощная ORM, наколеночная или вообще репозиторияй по HTTP ходит в какой-нибудь S3 за JSON.


И от деталей класса User интерфейс UserRepository не зависит, работает либо со значениями, либо с объектами класса User целиком, под капот к ним не заглядывая.


Ну а то, что он зависит от класса User — абсолютно нормально: это его прямая ответственность работать с этим классом, он только для этого и создан. А интерфейс User, абстрактный тип или конкретный класс — ему без разницы, лишь бы тип совпадал.

Интересно, после того как закончится эра блогов с постами и комментариями, какой оторванный от реальной жизни пример станет следующим героем интернет-чтива для хеллоуворлд-разработчиков?

Существует 2 подхода к разработке: code-first и database-first. Они оба имеют право на жизнь. Говорить, что какой-то из них "в корне неправильный" может только слепец. Дальше читать не стал.

Очень зря) Я не говорю что базой вообще не стоит заниматься, я говорю что строить сущности на основе таблиц в корне неправильно с точки зрения последующей реализации бизнес-логики будут проблемы (в статье это есть).
По сути база — это единственный источник правды в Вашем клиент-серверном приложении. И если ее структура не соответствует бизнес-логике — у Вас тоже будут проблемы. В конце концов, если взглянуть чуточку шире, то весь Ваш бек-енд — это всего-лишь буковка С в аббревиатуре MVC, а моделью в этом случае выступает база. Не думали с этой точки зрения? Просто не стоит быть настолько категоричным. Все очень относительно.
Повторюсь что это не правильная точка зрения. В формулировке:
весь Ваш бек-енд — это всего-лишь буковка С в аббревиатуре MVC, а моделью в этом случае выступает база

Вы делаете Модель «тупым» хранилищем с которым проводит какие-то операции Контроллер. Таким образом вы раздуваете контроллеры и даете им слишком много ответственности. Перемешиваете слои домена, сервиса и приложения, ну и т.д. Такой проект в последствии будет проблематично расширять и поддерживать.

В данном случае я думаю стоит быть категоричным, т.к. тут нет «относительности». Большой контроллер с массой ответственности — плохо при любом раскладе.
Это Вы предлагаете делать базу тупым хранилищем. По-моему, база должна гарантировать консистентность и обеспечивать инвариантность. Тогда mapper слой можно свести к минимуму.
Еще раз, я не пытаюсь сказать, что Ваш вариант неправильный. Я о том, что он не единственный правильный.
Дак база все это и может делать, я же говорю положить болт на БД, а говорю что она ВТОРИЧНА, а логика ПЕРВИЧНА. Ну и собственно контроллеры не должны обрабатывать бизнес-логику, а должны делегировать это моделям (которые отражаются сущности предметной области), а Mapper'ы это уже слой данных.
Выше (в другой ветке) уже писали, что в концепции MVC, модель — это все что не касается интерфейса. Поэтому по факту M включается в себя слой данных и домена, а C — представляет из себя слой приложения. И где-то рядом еще сервисный слой должен лежать.
Не нужно ограничивать себя рамками MVC и считать, что модель — это база (повторюсь, это неверно).
Это в Вашем мире логика первична и только так. Я предлагаю посмотреть с другой стороны. Данные — это содержание. Код — это обертка.
Докажите, что Ваш подход единственно правильный вот этому парню.
Bad programmers worry about the code. Good programmers worry about data structures and their relationships

А почему вы решили что фраза «беспокоятся о данных и их связях», речь про БД? Бизнес-логика — это данные. Нужно продумывать взаимодействия объектов, то как объекты будут выглядеть и функционировать. А уже ПОТОМ думать о том как они будут хранится.

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

P.S. уверен есть и маститые парни которые которые за code-first подход :)
Еще раз, я не пытаюсь сказать, что Ваш вариант неправильный. Я о том, что он не единственный правильный.

ну камон
По-моему, база должна гарантировать консистентность и обеспечивать инвариантность.

Базы разные бывают, некоторые даже не то, что не претендуют на это, а прямо заявляют "наше дело — хранить данные и всё".

Вот еще к "единственно правильному мнению":


Не должно быть репозиториев типа [...] PostRepository который сохраняет еще и комментарии.

А про доменные агрегаты и репозиторий-на-агрегат из DDD вы не слышали, да?

Ох, чувствую надо сначала определить термины, чтобы мы на одном языке разговаривали:
Агрегат (Aggregate) – самостоятельный объект, имеющий идентичность.
Сущность (Entity) – несамостоятельный объект, имеющий идентичность.
Значение (Value Object) – несамостоятельный объект, не имеющий идентичности.

Про эти агрегаты речь? Если да, то определим, что моя концепция не разделяет эти 3 сущности и все 3 является моделями. Собственно при ТАКОМ контексте, в чем проблема?
надо сначала определить термины

Что такое "самостоятельный" и "несамостоятельный" объекты?


Собственно при ТАКОМ контексте, в чем проблема?

Я не знаю, что в "таком" контексте, а в нормальном контексте (у Эванса) в агрегате — несколько сущностей, на то он и агрегат. Соответственно, репозиторий, который на агрегат (а не на сущности), работает с несколькими сущностями сразу. В частности, комментарии могут быть частью агрегата поста и сохраняться репозиторием поста.

И опять возвращаемся к терминологии: Post — это агрегат, а Comment — это сущность. Но я в статье не упоминал про данные термины (потому что это очередное усложнение в рамках данной статьи и вообще понятия Модель, которое необходимо лишь для понимания нотации DDD). И даже если говорить про агрегаты, то в любом случае репозиторий агрегата, не должен сохранять/удалять другие сущности/агрегаты, для которых есть собственные репозитории (aka собственные таблицы). Если сущность хранится в той же таблице, что и агрегат, то да, такую сущность репозиторий может обработать. Связи между сущностями (связи M:N через дополнительные таблицы) тоже можно обрабатывать.

Я не знаю, что в «таком» контексте, а в нормальном контексте (у Эванса) в агрегате — несколько сущностей, на то он и агрегат.

Если бы я писал про DDD, я бы изначально ввел ряд терминов для понимания о чем речь. В данной статье использовался термин Модель, с смыслом описанным вначале.
И опять возвращаемся к терминологии: Post — это агрегат, а Comment — это сущность.

Да нет, и то, и другое — сущности. Просто Post — это головная сущность соответствующего агрегата.


И даже если говорить про агрегаты, то в любом случае репозиторий агрегата, не должен сохранять/удалять другие сущности/агрегаты, для которых есть собственные репозитории (aka собственные таблицы).

Нет, не aka. Репозитории (опять же, по Фаулеру, я не знаю, что вы под этим понимаете) привязаны к бизнес-сущностям, а не к таблицам.


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


Кстати, отсюда же проистекает и ваше непонимание, что делать с Condition — описывать его в терминах домена, как и полагается Query Object (снова Фаулер). Да, придется мапить. Но репозитории неизбежно предполагают маппинг, вы никуда от этого не денетесь.

Нет, не aka. Репозитории (опять же, по Фаулеру, я не знаю, что вы под этим понимаете) привязаны к бизнес-сущностям, а не к таблицам.

Да, согласен.

Кстати, отсюда же проистекает и ваше непонимание, что делать с Condition — описывать его в терминах домена, как и полагается Query Object (снова Фаулер). Да, придется мапить. Но репозитории неизбежно предполагают маппинг, вы никуда от этого не денетесь.

И это по вашему правильно и удобно? В теории может все и красиво, но если мы говорим про практику, то на дальную перспективу отдельные методы куда удобнее.
Тут речь не в понимании, а в том, что на реальных (а не теоритических в учебнике) проектах, это впоследствии вызывает проблемы
И это по вашему правильно и удобно?

Да, конечно.


на дальную перспективу отдельные методы куда удобнее.

Нет, не удобнее. Их слишком много, они плохо расширяются, они не компонуются.


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

Ну я про реальные проекты и говорю. В моем опыте как раз репозитории с отдельными методами создают проблемы.

Они перестают быть удобными когда просят сделать очередной экран, ака "грид" с фильтрами и сортировками.

репозиторий агрегата, не должен сохранять/удалять другие сущности/агрегаты, для
которых есть собственные репозитории (aka собственные таблицы).

Зачем вам тогда "модели" и репозитории? Берите ActiveRecord, которая чётко декларирует "один класс — одна таблица". Суть DataMapper, что мы отвязываемся от жёсткой привязки "класс-таблица, поле-столбец"

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

Публикации