как Разбивать базу проекта на Domain и Application Logic

Проверенные VDS на SSD в Европе от $4 и России: Датацентр №1 от 199руб

Тема в разделе "Вопросы по теории программирования", создана пользователем ВеликийПрограмист, 21 сен 2017.

  1. ivanov77

    ivanov77 Новичок

    Сообщения:
    57
    Ваш город:
    South Pole
    Address:
    Fort Lee, United States
    Country:
    Location on Map:
    Эти фикстуры используются для интеграционных тестов, а не чистых модульных, которые выше советовал @fixxxer
    Интеграционными то да, тестируется нормально.
     
  2. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    6.750
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    Подумай немного над значением слова "модуль" во фразе "модульный тест". Тест модуля. Одного. Active Record - это обертка нескольких слоев. Для тестирования связи нескольких слоев используются интеграционные тесты.
     
    Последнее редактирование: 12 окт 2017
  3. ivanov77

    ivanov77 Новичок

    Сообщения:
    57
    Ваш город:
    South Pole
    Address:
    Fort Lee, United States
    Country:
    Location on Map:
    А что конкретно считаете вредным в той статье? Касается это того его подхода по работе с AR?
     
  4. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    6.750
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
  5. Yoskaldyr

    Yoskaldyr Новичок Партнер клуба

    Сообщения:
    419
    Ваш город:
    Varna, Bulgaria
    Address:
    Varna, Bulgaria
    Country:
    Location on Map:
    Просто прежде чем что-то советовать, надо сначала хорошо разобраться с темой совета.
    Если автор бы статью назвал "Еще один подход работы с Active Record в Yii" и не делал громких заявлений Data Mapper - говно, то было все норм, а так что по коду что по тексту видно что у чела в голове каша.
    И каша - это не плохо, и очень часто это норма, но пусть он сам ей питается и не пытается кормить окружающих.
    А так он просто показал как он решил собственные неудобства при работе с Active Record от Yii
     
  6. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.462
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Там в комментариях все правильно написали.
     
  7. AnrDaemon

    AnrDaemon Продвинутый новичок

    Сообщения:
    4.131
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    У меня, человека далёкого от темы как AR, так и DM, возник вопрос, как это автор статьи так резво перепыгнул от выяснения достоинств и недостатков двух подходов на демонстрацию приёмов работы с конкретным фреймворком.
    И даже не столько "как", сколько "зачем" он это сделал?
     
  8. ivanov77

    ivanov77 Новичок

    Сообщения:
    57
    Ваш город:
    South Pole
    Address:
    Fort Lee, United States
    Country:
    Location on Map:
    Там сказано, что для примера.
    И весьма удачного примера, т.к. в том числе на yii сейчас идет большая критика, и хороший такой пласт этой критики идет на то как разработчики пользуются ее AR. Когда начинаешь выяснять "что не так" все в результате сводится к "не используй AR вообще т.к. это плохо", а используй datamapper-ы. Без вариантов.
    Но это очень радикальный совет и его принять не просто.
    Поэтому всякие поиски правильного пути использования AR в yii - вовсе не праздный вопрос, а весьма как раз насущный.
    Неплохо что и тот автор таким вопросом задался, но его статье не хватает системности, многие вещи и ограничения указаны просто как утверждения, без логического обоснования, поэтому применить его советы на практике... кодить без понимания что и для чего делаешь, это выльется в кашу.

    Вообще эта ситуация немало сбивает с толку. AR использовался и используется годами и повсеместно - RoR, Django, Yii, Laravel, а ищешь есть ли какие то реальные howto как ею пользоваться с минимальными проблемами, пришли ли сообщества к какому то общему знаменателю, и ничего не находишь.
     
  9. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    При использовании маппера код становится чище, сущности легкие (нет этого conneection в каждой сущности), тестирование в большинстве случаев не требует базы данных.
    Yii плюс ко всему (я точно не знаю но гляжу примеры) привязывает весь проект к себе, избавиться от него будет практически невозможно. там в большем количестве каждом классов есть зависимости от framework.
    если на секунду представить что в день Х появится версия Yii3 которая не совместима с предыдущей версией, поймешь проблему.
     
  10. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    @ivanov77 я всё же советую почитать комменты, там много из того, что примерно возразил бы я, сказал тот же Fesor.

    Если очень вкратце, в чём проблема автора из того, что я вижу в самом начале статьи:
    • он не понимает, что чтение и изменение совершенно разные операции, которые желательно размещать в разных сервисах («в любом серьезном приложении»), гуглится по CQRS; тогда нет никакой проблемы использовать голый SQL для чтения «множества записей»; с изменениями вообще никаких проблем нет — несколько простых UPDATE — это не проблема изначально;
    • он называет сущности «пассивными записями» (ну, те, которые в DataMapper пихают) и чуть далее «Особенно хорошо это заметно в CRUD-приложениях» — иными словами «сущности — анемичны, особенно это хорошо заметно, когда они анемичны», это порочный круг; более того, скорее всего при детальном рассмотрении так называемые «CRUD-приложения» — это то, как сам автор называет свои приложения, потому что не видит логики и что ещё более опасно — не видит бизнес-глаголы и мыслит свойствами;
    • «Правильный способ получения зависимостей — внедрение через конструктор» — просто голословное утверждение; сущность — это как человек, человек получает информацию извне (команды) и как-то внутренне меняется (события); глаз человека можно назвать в данном контексте сервисом, но статическим, поскольку он работает в пределах нашего тела, нам в голову не протянут провод откуда-то снаружи, чтобы мы могли видеть. То есть, рассчитать какой-то нибудь md5 или расстояние между двумя точками на сфере — это статическая логика, которую можно вызывать в самой сущности, всё остальное можно передавать через обычные методы сущности, поскольку, очевидно, это внешняя для сущности информация. И нам не меняют свойства напрямую, мы получаем множество сигналов через наши органы чувств, методы сущности — это и есть те самые органы чувств — внешний интерфейс сущности. btw, я не использую double dispatch, а передаю результат работы нужного мне внешнего сервиса, т.е. я передаю в методы только скаляры и value objects.
    Ну и там куча мелких и не очень логических подтасовок и некорректных утверждений, лень комментировать.

    ActiveRecord в принципе устроен так, что он работает на неверных предпосылках, которые я перечислил выше. Здесь я пытался показать, что работать с Yii «правильно» просто неудобно. Переход на DataMapper не является достаточным условием того, что твой код станет правильным, если ты будешь допускать те же ошибки, но он в определённом смысле является необходимым.
     
    Последнее редактирование: 14 окт 2017
  11. ivanov77

    ivanov77 Новичок

    Сообщения:
    57
    Ваш город:
    South Pole
    Address:
    Fort Lee, United States
    Country:
    Location on Map:
    Ну а в реалиях php, такое решение выльется в безальтернативность использования Doctrine2?
    Маппинг дело то непростое, видел я как люди пробуют велосипедить, все эти непростые решения, создание объектов без вызова конструктора, распривачивание св-в через рефлексию, чтобы заполнить. Кто все такое поддерживать будет?... Вон вы про зависимость от Yii печетесь, а зависимость от Doctrine вас почему то не тревожит.
     
  12. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    5.961
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    в самом маппинге нет ничего сложного, doctrine делает еще кучу других вещей
    PHP:
    class User{
      private 
    $id;
      private 
    $name;

      public function 
    rename($name){
        
    $this->name $name;
      }

    // это только потому что поля приватные и рефлексией пользоваться не хотим, можно в trait вырезать или в маппере заюзать http://php.net/manual/ru/closure.call.php
      
    public function hydrate($arr){
        
    $this->id $arr['id'];
        
    $this->name $arr['name'];
      }
      public function 
    extract(): array{
        return [
    'id' => $this->id'name' => $this->name];
      }
    }

    class 
    UserMapper{
      private 
    $db;
      public function 
    read$id ): User{
        
    // чтоб представление иметь что происходит внутри
        
    $arr $this->db->sql('select id, name from users where id=?', [$id])->row();
        
    $user = new User;
        
    $user->hydrate($arr);
      }
      public function 
    update(User $user){
       
    $arr $user->extract();
       
    $this->db->sql('update users set name=? where id=?',[$arr['name'],$arr['id']])->execute();
      }
      
    // остальные методы сам додумай
    }

    class 
    UserService{
      private 
    $mapper;
      public function 
    rename($id$name){
        
    $user $this->mapper->read($id);
        
    $user->rename($name);
        
    $this->mapper->update($user);
      }
    }
    чтоб выкинуть доктрину нужно просто переписать маппер, чтоб выкинуть yii придеться переписать все
     
  13. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.462
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Потому что ее нет. :)

    Я пользуюсь Analogue ORM, могу легко заменить его на Doctrine, не поменяется вообще ничего, кроме реализации репозиториев и конфигурации маппинга. То есть, на картинке Вурдалака с 3-й страницы поменяется только кусочек Infrastructure.

    Ну вот, поддерживают как-то:
    doctrine/doctrine2: 536 contributors
     
    Последнее редактирование: 14 окт 2017
  14. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Я ещё раз глянул комменты к статье на хабре и, если честно, они радуют. Если несколько лет назад такую бы статью заплюсовали, то теперь подобный треш встречают вполне сносными комментариями. Прогресс идёт, товарищи.
     
  15. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.462
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Это легко (и правильно) сделать, когда внешнему сервису не требуется знать о состоянии сущности.

    А когда требуется - вспомним мой старый пример с хэшом, который солится приватным полем - тогда double dispatch мне видится меньшим злом, чем добавление геттеров.
     
  16. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Тут хитрость вот в чём: если в сущности есть нечто, то это «нечто» либо туда как-то попало снаружи, либо были вычислено внутри сущности, а значит скорее всего фигурировало в событии. По событию мы могли записать это значение в read model и оттуда считывать. Я как бы и не лезу в саму сущность, всё по-честному, я лезу в её проекцию, которая знает о сущности ровно столько, сколько она сама ранее сообщила.

    Если же говорить про тот пример с солью, мне он кажется неудачным :) Он вроде бы технические ограничения пытается задать, но ...
    Во-первых, я бы хешер не стал бы делать внешним сервисом. password_verify()/password_hash() прямо внутри сущности.
    Во-вторых, если уж всё-таки это сервис, то я бы просто соль заново сгенерил. Не вижу практических причин переиспользовать то же самое значение.
    В-третьих, читерство, описанное выше, даёт возможность обойти практически все подобные проблемы, включая эту.

    Я на практике пока не встречал ни одного случая, когда мне double dispatch был действительно необходим. В то время, когда мы это на форуме обсуждали, у меня была какая-то глупая мотивация из разряда «для согласованности модели», т.е. якобы для того, чтобы контракты модели не позволяли в явном виде передать напрямую в сущность какой-то мусор снаружи, только через реализацию доменных сервисов. Но по факту это какой-то бессмысленный пуризм, в модели в первую очередь важны сами действия и логика внутри, а не то каким образом мы получили внешние данные.
     
  17. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    И немного ретроспективы (просто нашёл в том топике, где был пример с солью):
    Вот нафиг не нужно делать реальную проверку существования MX-записи в сущности, пусть и через заинжекченный через double dispatch сервис. Нужен просто сигнал сущности, который будет включать в себя флаг bool $mxRecordExists (если для модели вообще имеет смысл ситуация с $mxRecordExists === false; иначе просто до модели не должно доходить дело). Модель просто как-то реагирует на поступающие сообщения и не должна лезть сама, пусть и опосредованно, во внешний мир. Если я захочу, я могу обманывать модель, подпихивая ей вымышленные сообщения. На то она и модель, чтобы моделировать различные ситуации.
     
    fixxxer нравится это.
  18. fixxxer

    fixxxer К.О. Партнер клуба

    Сообщения:
    12.462
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Ну, пример высосанный из пальца, да, на практике я так и не делал. Я к тому, что если мне понадобится выбирать между
    PHP:
    $bar $barService->calcBar($entity->getFoo());
    $entity->somethingWithBar($bar);
    и
    PHP:
    $entity->somethingWithBar($barService);
    то я выберу второе.

    Хотел сейчас найти в своем коде реальный пример, где вроде у меня был Double Dispatch, но открыл код и вспомнил, что после рефакторинга там Double Dispatch-а не стало. Так что, может быть, и действительно почти никогда не надо :)
    Да, это я сейчас уже понимаю :)
     
  19. Вурдалак

    Вурдалак Newbie

    Сообщения:
    6.032
    Ваш город:
    Russia, Moscow
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Я понимаю о чём ты, но у меня интуитивное ощущение, что тут проблема изначально в том, что эта логика в сущности. Если на основании каких-то свойств сущности мы что-то делаем, то сама сущность уже это не контролирует. Нарушением инкапсуляции в каком-то смысле можно считать признание самого факта, что какое-то свойство существует, ведь по-хорошему мы не знаем каким образом реализовано поведение (логика записи событий). Это покажется странным, но я скорее предпочту геттер, но не у сущности, а у read model, поскольку с моей точки зрения эта логика изначально не относится непосредственно к сущности, она внешняя по отношению к ней.

    Вспомни тот пример с отправкой письма: ты ведь не делаешь это через double dispatch? Откуда ты берёшь email? Я либо беру из event'а, если он там есть, либо из read model. Я не считаю это нарушением инкапсуляции, поскольку сущность сама сообщает через события про свой email и это общеизвестное значение для домена.

    Дополнительно, я все изменения сущности провожу через транзакцию, поэтому мне некомфортно от самой мысли, что я буду в транзакцию передавать некий сервис, ведь этот сервис либо не будет поддерживать транзакцию, либо я могу как-то нежелательно повлиять на внешние данные (откатить какие-то логи, например). Я хочу иметь детерминированное поведение в рамках транзакции, и некий умный сервис его не гарантирует. Скажем, по этой же причине я никогда не получаю текущее время в самой сущности, я его передаю в саму команду.
     
  20. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    6.750
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    Тебе нужна декомпозиция. Выбрать вопрос - и его обсуждать. Отдельный вопрос - в отдельной теме, лимита на вопросы нет. Пишешь здесь про то, про это - какое, все-таки, наивное дитя. Тебе за жизнь и отвечают.

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

    Критика на Yii сейчас? Да всегда. П$%ть - не мешки ворочать. Саппортить фреймворк - это очень много сил, и на этом вообще не зарабатывают. Я в этой теме инсайдер.
    Yii - это проект, где русские учат китайцев дизайну, а китайцы русских - трудолюбию :)

    AR - отстой, на каждую сущность пишем по 4 класса. Value Object, Mapper, Validator, Test. Вы держитесь здесь, всего вам доброго! (Только денег нет).
    BMW лучше, чем Geely? Больше всего людям нужны автобусы.

    Сообщества давно уже пришли. Противопоставление мапперов и AR - теоретическое, при желании их можно использовать одновременно.
    Инкапсуляцию AR не отменяет, композиция все еще лучше наследования. Проблема всегда в дизайне, и никогда не в инструменте. Можно не наследоваться и не дописывать код в автосгенерированные кассы. Можно переписать PDO для соблюдения CQRS, в конце концов :)
    Чтобы разобраться в архитектуре - надо учиться архитектуре, читать обсуждение состава цемента недостаточно.
     
    Последнее редактирование: 15 окт 2017
    ivanov77 нравится это.