• Если ли смысл в ОРМ для моего случая?

    magary4:

    Программер начинает писать проект на симфони - видит в документации доктрину, описывает свои энтити. Сначала обычный crud но очень скоро все усложняется группами и категориями


    Есть такая штука - культ карго. Вот вы сейчас описали это поведение человека.

    Т.е. использовать ОРМ изначально ошибка как я вас понял?


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

    Задачи аля:

    - добавить фотку
    - добавить лайк
    - добавить коммент

    это все сводится к OLTP поскольку у нас задействовано малое количество объектов. Есть еще такой термин как агрегат сущностей, которым описывают все объекты учавствующие в бизнес транзакции. И вот ORM-ки делают это дико удобным.

    Но проект развивается и вот в нашем инстраграме нужно уже отображать:

    - список фоток всех друзей
    - на главной странице надо отображать трендовые фотки - по одной из каждой страны
    - примешивать в трендинг фотки проплаченный контент (мы ж хотим зарабатывать?)

    И все это - не является задачами из разряда OLTP но доктрина предоставляет нам свой query builder и если нам не нужны потом объекты - мы можем сразу гидрировать результаты в массивчик. А можно вообще свои гидраторы сделать. А можно даже так:

    select new SomeResultDTO(u.name, p.image, c.countryFlag) from Pictures WHERE ...

    то есть сразу смэпить все на какие-то промежуточные объекты которые содержат только то что нужно.

    Но вот это уже не является частью непосредственно ORM - это чуть другой уровень.
  • Если ли смысл в ОРМ для моего случая?

    magary4: пока у вас нет OLTP - вам не нужна ORM. Если вам нужно сделать репорт или просто выдать вот этот список категорий - то вам хватит SQL (в случае реляционных баз данных, в случае solr хватит средств solr-а).

    Но давайте придумаем такой пример. Допустим вам нужно выбрать все категории так как предложил index0h и потом сделать с каждой что-то. Это уже подходит под задачи OLTP, просто надо разделить все на два этапа:

    1) мы выбираем id-ки категорий при помощи обычного SQL с джойнами и т.д.
    2) мы грузим категории по отдельности (можно по нескольку штук через where in но это уже оптимизации) и каждая операция с категорией будет расцениваться как маленькая транзакция. Вот в этом ключе ORM-ки оправданы, особенно если мы делаем что-то сложное и нам удобнее это описать в виде взаимодействия объектов.

    p.s. рекомендую вам глянуть: https://www.youtube.com/watch?v=rzGeNYC3oz0
  • Если ли смысл в ОРМ для моего случая?

    magary4: просто любым удобным способом достаете что надо, просто выносите это в отдельный какой объект у которого только эта задача и больше никаких других задач нет. Так мы прячем это и выполняем задачу.
  • Если ли смысл в ОРМ для моего случая?

    Ну а для выборок как вы описали и так есть замечательные вещи - такие как SQL (а в доктрине еще и DQL если хочется сохранить абстракцию от базы данных).
  • Если ли смысл в ОРМ для моего случая?

    Повторюсь. Вот этот пример с юзер группами и категориями выходит далеко за рамки OLTP, где речь идет о обработке транзакций включающих относительно небольшое количество объектов.
  • Возможно ли использование APC (APCU) только для кеша ключ => значение (без кеширования байткода) в паре с ZendOpcache?

    catanfa: APCu предпочтительнее в той ситуации, когда вам нужно держать какой-то оооочень горячий кэш который никогда не нужно будет выносить на отдельный сервер. Например кэши для ORM-ок и подобное, что вне контекста PHP смысла не имеет.

    Держать в APCu что-то другое - сомнительное развлечение но можно конечно.
  • ES-2015 для juniora?

    uniquenicknqame: видал, не пользуюсь сорсмэпами при дебаге (с сорсмэпами иногда выходят приключения), В целом первое время непривычно но норм.
  • Как использовать Принцип подстановки Барбары Лисков применительно к PHP?

    Guy Fawkes: попробую выразить свою мысль более явно. И да, с double dispatch я несколько все же был не прав.

    Начнем с перегрузки методов и почему "она не нужна" в php в том виде в котором существует в таких языках как Java.

    class SimplePrinter implements Printer
    {
        public function print(Circle $shape) {}
        public function print(Rectangle $shape) {}
        public function print(Square $shape) {}
    }


    так как в PHP вся диспетчеризация и так происходит в рантайме, у нас будет что-то типа:

    class SimplePrinter implements Printer
    {
        public function print(Shape $shape) 
        {
               $shapePrinter = [
                    Circle::class => [$this, 'printCircle'],
                    Rectangle::class => [$this, 'printRectangle'],
                    printSquare::class => [$this, 'printSquare'],
               ][get_class($shape)] ?? null;
    
               if (null === $shapePrinter) {
                     // throw exception
               }
    
               $shapePrinter($shape);
        }
        private function printCircle(Circle $shape) {}
        private function printRectangle(Rectangle $shape) {}
        private function printSquare(Square $shape) {}
    }


    Минусы очевидны. Если мы добавим форму, нам придется поправить все реализации принтера. Налицо нарушение SRP. Да и код не очень то красивый, теряется информация для статического анализа.

    Double Dispatch в том виде в котором он может существовать в PHP:

    interface Printer
    {
        public function printRectangle(Rectangle $shape);
        public function printCircle(Rectangle $shape);
        // ...
    }
    abstract class Shape
    {
        abstract public function print(Printer $printer);
    }
    
    class Rectangle extends Shape
    {
        public function print(Printer $printer)
        {
             $printer->printRectangle($this);
        }
    }


    Именно это я подразумеваю под double dispatch. Когда мы передаем ответственность за выбор способа печати самому объекту, который мы хотим распечатать.

    Минусы у нас все еще остаются. Если добавляется новая форма, нам надо поправить интерфейс и все реализации. Зато вся информация о типах на месте.

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

    Можно вынести логику печати отдельных шэйпов в отдельные сервисы и применить chain of responsibilities.

    interface Printer
    {
        public function supports(Shape $shape);
        public function print(Shape $shape);
    }
    
    class DefaultPrinter implements Printer
    {
         private $printers;
         public function __construct(array $printers) { $this->printers = $printers; }
    
         public function supports(Shape $shape) { return true; }
         public function print(Shape $shape)
         {
               foreach ($this->printers as $printer) {
                    if ($printer->supports($shape)) {
                         return $printer->print($shape);
                    }
               }
         }
    }
    
    class CircleDefaultPrinter implements Printer
    {
        public function supports(Shape $shape)
        {
              return $shape instanceof Circle;
        }
    
        public function print(Shape $shape) 
        {
            // ...
        }
    }


    но это опять же много лишнего кода. Для упрощения можно вынести логику печати прямо в объекты Circle.

    То есть в данном случае либо мы соблюдаем SRP либо LSP. Если честно вариант с double dispatch и "много методов в интерфейсе" мне нравится больше всего.

    В языках типа Python это решается так же при помощи создания новых функций:

    printer = Dispatch();
    printer.add_call((Circle), default_circle_printer)
    printer.add_call((Rectangle), default_rectangle_printer)
    
    printer(shape) // multiple dispatch


    тоесть информацией о типах мы так же жертвуем по сути (разве что наш статический анализатор умеет в случае Python такие штуки распознавать).
  • Зачем в Angular есть Jsonp?

    HoHsi: ну и такие ситуации случаются)
  • Как правильно написать unit тест?

    klinnov: тесты после кода - время на ветер. Ну в целом я где-то 70/30 делаю. Иногда мне проще запилить прототип и потом покрыть его тестами, но чаще сначала тесты. Ну и еще бывают проекты где я вообще тесты не пишу и немного стыдно потом.

    Весь профит в написании тестов ДО кода заключается в том, что вы думаете что пишите. У вас не выйдет написать нетестируемый код если вы сначала пишите тесты. Это налагает небольшой оверхэд особенно в случае с Laravel (active record и unit тесты например не совместимые практически вещи). Но елси брать интеграционные тесты то все обычно хорошо.

    Но мне это будет труднее спрогнозировать струтуры например тех же JSON объектов на выходе если у меня ещё нет кода.


    Вы же когда делаете API вы же примерно продумываете что API должна отдавать? Ну мол, хоть какое-то представление что делает метод API и зачем вы его пишите в голове имеется? Опишите свои ожидания в виде теста и все будет хорошо.

    Я к примеру перед тестами еще документацию к API пишу. Ну то есть я сначала в apiary описываю что буду делать, скидываю людям которые будут писать под это клиент, и они могут на основе mock-сервера уже начинать фигачить свою часть. А я набросаю тестик, и потом уже пишу код.
  • Как использовать Принцип подстановки Барбары Лисков применительно к PHP?

    Guy Fawkes:

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


    повторюсь еще раз. В языках с динамической системой типов "явная" перегрузка и "явная" двойная диспетчеризация не нужна так как диспетчеризация и так происходит в рантайме.

    Зачем? Можно так сделать, но не вижу ничего плохого, если есть ряд методов, связанных одной задачей.


    Зависит от этой "одной задачи" конечно, но все во имя Single Responsibility. Маленькие специфичные вещи проще менять.

    Хендлеры делают разные вещи, это, так сказать, источник проблемы.


    наиболее похожий на ваш случай пример можно наблюдать в реализации Command Bus. Там так же есть хэндлеры и они выполняют совершенно разные вещи. Но у них у всех один и тот же интерфейс.

    Проблема на высоком уровне такова:


    1) у сервисов которые что-то ищут одинаковый интерфейс, так? Можно ли завернуть результаты их работы в объекты?
    2) мы можем вынести "специфичные" вещи прямо в объект с результатом? Таким образом спрятав детали поближе к реализации и сохранив "единнобразие" интерфейса?
    3) мы можем применить тот самый double dispatch?
  • Как правильно написать unit тест?

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

    Если коротко - чем быстрее вы узнаете что вы что-то сломали, тем вероятнее что вы вспомните что именно вы сделали. Если тесты отрабатывают долго (минут 10) вы будете дергать их хорошо если раз в час. А за час можно столько всего сломать. Если тесты происходят руками - то вы узнаете о проблеме хорошо если через сутки. Ну и идею вы поняли.
  • Как правильно написать unit тест?

    klinnov:

    1) потому что у вас идет вызов Company:: findOrFail как минимум. Эта штука имеет свое поведение, оно лезет во внешний мир и ломает "изоляцию" теста одного модуля подключая пару сотен других. Это не тест "одного класса" - это тест среза системы. А unit - там все поведение которое нам сейчас не интересно должно мокаться, и оставаться должны только данные (сущности, объекты значения, модельки, можно воспринимать как данные и не мокать).

    2) юнит тесты которые тестируют отдельные сервисы, отдельные бизнес правила и ограничения. Например у меня есть сервис который... ну не знаю... проверяет может ли пользователь совершать покупку. Он знает только как это проверить и тесты тестируют только его. В результате у меня есть сервис который может мне гарантировать что пользователь не купит ничего если он заблокирован, или у него нет денег на счету или еще чего. И этот маленький сервис оттестирован. То есть я могу просто его дернуть и спать спокойно. А в других тестах я уже этот сервис могу замокать и эмитировать то что он мне вернет.

    Ну то есть разделяй и влавствуй. Иначе количество тестовых сценариев будет настолько велико что не уместится в голове и поддерживать тесты станет больно.

    3. а вот тут увы никак. Мои фронтэндщики не пишут e2e тестов. Они так же покрывают периодически сложные штуки юнит тестами и не более. На двух проектах тестировщики сами покрыли критически важные штуки тестами какой-то штукой на основе electron но увы я не помню названия. Там одна из фич была в том что есть плагин для хрома который записывает действия юзера (для силениума тоже такие штуки есть).
  • Должен ли программист знать ассемблер?

    ну и еще полезно для профилирования скриптов, определения мест которые не может оптимизировать JIT компилятор браузера и куча другого. Но это совсем другой уровень разработки.
  • Что можно сделать на одностраничниках с помощью JavaScript?

    dhat: в целом сложные выборки из firebase это не очень просто, и тут надо хорошо продумывать как строятся агрегации.
  • Что можно сделать на одностраничниках с помощью JavaScript?

    dhat: ну оно похоже на mongodb но очень много специфичных вещей которые заставляют чуть по другому моделировать данные. Да и чуть больше возможностей вроде регистрация через соц сети из коробки. На этом собственно строится распределение прав на доступ к записям.

    Для сайтов... с firebase могут быть сложности в плане поиска, но если вы поиск имплементите не через свою базу данных а так же через сторонние сервисы - то как бы ок.
  • Что можно сделать на одностраничниках с помощью JavaScript?

    dhat: firebase это и есть готовый бэкэнд. Для простеньких приложенек более чем норм. Для чего-то посложнее (или того что фаербэйз не умеет) возможно придется прикручивать свой бэкэнд на ноде (банально удобненько).
  • Как по максимуму использовать Bootstrap 3 на Symfony 3?

    Иван Антонов: наверное проще будет поставить ноду и компилить ассеты
  • Как использовать рефлексию для метода?

    dev400: рефлексия не "современная конструкция", это просто механизм интроспеции. Оно как бы не столь важно, но все же не стоит зацикливаться.