Вот как возникнут задачи «а давайте кроме страниц дадим возможность комментировать картинки», вот тогда и делить.
как я сказал ранее:
Потому я предпочитаю рассматривать их как самостоятельные контексты, но в одном общем корневом контексте, по аналогии с моулями и подмодулями.
Контекст страниц и контекст комментариев к страницам находятся в одном контексте более высокого уровня.
То есть комментарии к странице это комментарии к странице и комментариями к картинкам они никогда не станут.
Разделять эти контексты или нет конечно дело каждого, но я вижу преимущества такого подхода.
Контекст из Ubiquitous Language можно организовать в независимый модуль в коде, который легко можно включать, отключать, переносить и изменять не затрагивая весь остальной проект и модуль страниц (контекст странц) в том числе.
А если нам понадобится комментарии к картинкам, то мы просто копируем модель комментариев к страницам и чуть-чуть дорабатываем напильником.
И так как в результате мы получим независимые модули мы можем изменять модуль коментирования картинок не затрагивая при этом модуль коментирования страниц.
Но конечно, кому-то это может показатся переусложнением и загромождением кода.
Я ни кого не принуждаю так делать.
Боюсь не найду обсуждение((
По моему обсуждение было в личке в контексте CQRS.
Могу процитировать его мнение по поводу маппинга в аннотациях из нашей переписки:
Часто встречаю что правила хранения (маппинг) описываются в YML файле.
С одной стороны правильно не смешивать домен и правила его хранения, с другой стороны аннотации удобнее и читабильней yml конфигов. И аннотации проще поддерживать в актуальном состоянии.
это делается для того что бы ваши сущности не зависили от доктрины (у вас в коде нет use Doctrine\ORM\Mapping и все такое). Это единственная причина для этого. Все остальное — вкусавщина. Авторы доктрины например настоятельно рекомендуют хранить это добро в xml и только если вы планируете шарить сущности между проектами. В пределах одного проекта норм и аннотации.
Почему бы не воспользоваться просто UUID-ом для генерации айдишки?
Можно и UUID. Кому как больше нравится. Но не стоит пренебрегать преимуществами естественных идентификаторов.
Аннотации от доктрины хоть и комменты, но все же часть инфраструктуры. При смене ОРМ-ки вы же их удалите? Или с какой целью они там лежат?
Можно и не удалять при смене ORM. Просто в этом случае они будут висеть мертвым грузом.
А можно мапинг описать не в аннотациях, а например в XML файле или в репозитории. От этого принципиально ничего не поменяется. Разница только в удобстве сопровождения.
Как вы соберете сущность, которая хранится в 2+ таблицах
В этом случае у нас связь OneToOne и связанная "сущность" это VO в агрегате. Эта "сущность" не будет иметь смысла вне агрегата как нормальный VO.
в разных хранилищах (к примеру каунтеры в редисе)
А каунтеры и не нужны в сущностях.
Они, как правило, относятся к уровню представления. Уже как-то обсуждали эту тему с Fesor.
Если на каунтерах завязаны бизнес ограничения, то ограничения описываются в сервисах доменного слоя, а сами каунтеры подтягиваются из репозитория.
На крайний случай, в репозитории можно смапить данные агрегата из разных хранилищ.
Я советую обратить ваше внимание на схему CQRS.
Реально поднимать домен нужно только на запись.
Хотя надо признать. Doctine накладывает ряд неприятных ограничений на структуру сущностей.
Согласен. Спорно. Но по моему мнению комментирование страниц напрямую не связано с самой страницей.
Странно былоб говорить о комментариях в процессе написания страницы или говорить о редактировании страницы в процессе написания комментария.
Потому я предпочитаю рассматривать их как самостоятельные контексты, но в одном общем корневом контексте, по аналогии с моулями и подмодулями.
нет, так как это только комментарии и в коде это не отражено)))
замена Doctrine на что-то еще ни как не повлияет на доменные сущности
в этом и суть переносимости домена
Скажите, а что по вашему мнению должно быть в Applicatoin layer?
Сущности и доменные сервисы в Domain layer.
Имплементация доменных сервисов и инфраструктурные сервисы в Infrastructure layer.
Миграции и Doctrine DBAL типы в Persistent layer.
Если следовать вашей логике, то контроллеры, консольные команды, формы, меня билдеры и наверное Query handlers в Presentation layer.
Тогда для Applicatoin layer останутся только Command handlers или Use Cases (Interactors)?
Эх… Как хорошо все начиналось, а скатилось к Anemic model, смешивании слоев Domain и Infrastructure, нарушению принципов агрегата, описанных в начале статьи, и двунаправленному связыванию (((
Про нейминг и говорить не хочется.
Есть в PHP нормальные шаблонизаторы. Например twig по умолчанию экранирует все. Ему нужно в явном виде указать если какую-то сущность не нужно экранировать.
Правда проблему с экранированием атрибутов, описанную в статье, он не решает по понятным причинам. Но атрибуты лучше вообще вырезать или использовать белые списки.
Недавно, на собеседовании в одну очень известную компанию, спросили знаю ли я SOLID.
И это при том, что я главный контрибьютер проекта Clean Code PHP и автор Русского форка.
Даже как-то обидно стало на минуточку.
Конечно, смотреть твой GiHub профиль ни кто не обязан, но меня лично раздражают люди которые не удосуживаются даже просто прочитать резюме соискателя перед началом собеседования.
Безусловно можно увеличить количество бит под timestamp. Я бы ещё добавил id процесса в котором генерируется id. Если это web приложение, то оно обычно крутится не в одном процессе и есть вероятность коллизии в пределах одного сервера. Таким образом мы всё больше и больше увеличиваем длинную id.
Да. Я видел подобные решения, когда за дату отсчёт а берут например начало этой эпохи 2000-01-01, но это не решение проблемы, а откладывание ее. Для начала эпохи переходный момент наступит 6 сентября 2069.
Я не знаю точно каким образом формируют ID в YouTube. Я только предполагаю. Возможно это и не случайно сгенерированный значения, а что-то на основе timestamp, как в случае с Snowflake. Но я в это сомневаюсь, так как длинна ID слишком маленькая для хранения в ней timestamp, и разброс ID у виде загруженных в одно время слишком большой для последовательного timestsmp.
А вопрос генерирования по-настоящему случайных чисел выходит за рамки этой статьи.
До 1 ноября 2004 timestsmp имел длинна 40 бит, а не 41 и нужен был ещё один бит перед timestamp, чтоб ограничить длину.
Однако это приводит к новой проблеме, ибо уже 7 сентября 2039 года timestamp будет иметь длину 42 бита, что может привести к плачевным результатам.
Я думаю, проблема закралась в том, что слово Underscore имеет несколько значений перевода и одно из них нижнее подчеркивание. От того в русском языке и устоялся этот термин, хотя если верить Википедии, то это Плеоназм и правильней говорить просто "подчеркивание".
Об этом и статья. Определитесь с потребностями и выбирайте соответствующее решение, а не берите UUID потому, что все так делают.
Я привел формулы и расчеты специально, для того, что бы каждый мог оценить свои потребности. Может кому-то и UUID окажется маловат.
Обсуждение было давно и я уже давненько не встречал маппинга в YAML.
А вот XML вполе используется, например в FOSUserBundle или SonataUserBundle.
как я сказал ранее:
Контекст страниц и контекст комментариев к страницам находятся в одном контексте более высокого уровня.
То есть комментарии к странице это комментарии к странице и комментариями к картинкам они никогда не станут.
Разделять эти контексты или нет конечно дело каждого, но я вижу преимущества такого подхода.
Контекст из Ubiquitous Language можно организовать в независимый модуль в коде, который легко можно включать, отключать, переносить и изменять не затрагивая весь остальной проект и модуль страниц (контекст странц) в том числе.
А если нам понадобится комментарии к картинкам, то мы просто копируем модель комментариев к страницам и чуть-чуть дорабатываем напильником.
И так как в результате мы получим независимые модули мы можем изменять модуль коментирования картинок не затрагивая при этом модуль коментирования страниц.
Но конечно, кому-то это может показатся переусложнением и загромождением кода.
Я ни кого не принуждаю так делать.
Боюсь не найду обсуждение((
По моему обсуждение было в личке в контексте CQRS.
Могу процитировать его мнение по поводу маппинга в аннотациях из нашей переписки:
Можно и UUID. Кому как больше нравится. Но не стоит пренебрегать преимуществами естественных идентификаторов.
Можно и не удалять при смене ORM. Просто в этом случае они будут висеть мертвым грузом.
А можно мапинг описать не в аннотациях, а например в XML файле или в репозитории. От этого принципиально ничего не поменяется. Разница только в удобстве сопровождения.
В этом случае у нас связь OneToOne и связанная "сущность" это VO в агрегате. Эта "сущность" не будет иметь смысла вне агрегата как нормальный VO.
А каунтеры и не нужны в сущностях.
Они, как правило, относятся к уровню представления.
Уже как-то обсуждали эту тему с Fesor.
Если на каунтерах завязаны бизнес ограничения, то ограничения описываются в сервисах доменного слоя, а сами каунтеры подтягиваются из репозитория.
На крайний случай, в репозитории можно смапить данные агрегата из разных хранилищ.
Я советую обратить ваше внимание на схему CQRS.
Реально поднимать домен нужно только на запись.
Хотя надо признать. Doctine накладывает ряд неприятных ограничений на структуру сущностей.
Согласен. Спорно. Но по моему мнению комментирование страниц напрямую не связано с самой страницей.
Странно былоб говорить о комментариях в процессе написания страницы или говорить о редактировании страницы в процессе написания комментария.
Потому я предпочитаю рассматривать их как самостоятельные контексты, но в одном общем корневом контексте, по аналогии с моулями и подмодулями.
нет, так как это только комментарии и в коде это не отражено)))
замена Doctrine на что-то еще ни как не повлияет на доменные сущности
в этом и суть переносимости домена
Если говорить о DDD, то по хорошему страницы и комментарии это два разных Bounded Context и соответственно они не должны иметь связей.
По хорошему, сущность комментария должна иметь примерно такой вид:
Хм. То есть книга писалась в январе 2014. Не старовата ли книжечка?
Скажите, а что по вашему мнению должно быть в Applicatoin layer?
Сущности и доменные сервисы в Domain layer.
Имплементация доменных сервисов и инфраструктурные сервисы в Infrastructure layer.
Миграции и Doctrine DBAL типы в Persistent layer.
Если следовать вашей логике, то контроллеры, консольные команды, формы, меня билдеры и наверное Query handlers в Presentation layer.
Тогда для Applicatoin layer останутся только Command handlers или Use Cases (Interactors)?
Эх… Как хорошо все начиналось, а скатилось к Anemic model, смешивании слоев Domain и Infrastructure, нарушению принципов агрегата, описанных в начале статьи, и двунаправленному связыванию (((
Про нейминг и говорить не хочется.
Есть в PHP нормальные шаблонизаторы. Например twig по умолчанию экранирует все. Ему нужно в явном виде указать если какую-то сущность не нужно экранировать.
Правда проблему с экранированием атрибутов, описанную в статье, он не решает по понятным причинам. Но атрибуты лучше вообще вырезать или использовать белые списки.
Может у вас не настроен realpath_cache_size?
Недавно, на собеседовании в одну очень известную компанию, спросили знаю ли я SOLID.
И это при том, что я главный контрибьютер проекта Clean Code PHP и автор Русского форка.
Даже как-то обидно стало на минуточку.
Конечно, смотреть твой GiHub профиль ни кто не обязан, но меня лично раздражают люди которые не удосуживаются даже просто прочитать резюме соискателя перед началом собеседования.
И при этом, для получения UUID чаще всего используют random_bytes(), mt_rand() и еще mt_rand() ну и openssl_random_pseudo_bytes() до кучи.
Безусловно можно увеличить количество бит под timestamp. Я бы ещё добавил id процесса в котором генерируется id. Если это web приложение, то оно обычно крутится не в одном процессе и есть вероятность коллизии в пределах одного сервера. Таким образом мы всё больше и больше увеличиваем длинную id.
Да. Я видел подобные решения, когда за дату отсчёт а берут например начало этой эпохи 2000-01-01, но это не решение проблемы, а откладывание ее. Для начала эпохи переходный момент наступит 6 сентября 2069.
Я не знаю точно каким образом формируют ID в YouTube. Я только предполагаю. Возможно это и не случайно сгенерированный значения, а что-то на основе timestamp, как в случае с Snowflake. Но я в это сомневаюсь, так как длинна ID слишком маленькая для хранения в ней timestamp, и разброс ID у виде загруженных в одно время слишком большой для последовательного timestsmp.
А вопрос генерирования по-настоящему случайных чисел выходит за рамки этой статьи.
До 1 ноября 2004 timestsmp имел длинна 40 бит, а не 41 и нужен был ещё один бит перед timestamp, чтоб ограничить длину.
Однако это приводит к новой проблеме, ибо уже 7 сентября 2039 года timestamp будет иметь длину 42 бита, что может привести к плачевным результатам.
Я думаю, проблема закралась в том, что слово Underscore имеет несколько значений перевода и одно из них нижнее подчеркивание. От того в русском языке и устоялся этот термин, хотя если верить Википедии, то это Плеоназм и правильней говорить просто "подчеркивание".
А верхнее подчеркивание называется Overline или Черта сверху.
Да. Хотел добавить это видео в статью, но не стал. Спасибо.
Об этом и статья. Определитесь с потребностями и выбирайте соответствующее решение, а не берите UUID потому, что все так делают.
Я привел формулы и расчеты специально, для того, что бы каждый мог оценить свои потребности. Может кому-то и UUID окажется маловат.