• Что может содержать DTO?

    AleksandrB
    @AleksandrB
    Совсем недавно вывел "Hello world"
    Я считаю, что может (можно сюда еще)

    Логика простая - DTO не может содержать бизнес логики. DTO используется для переброски данных между слоями, сериализацияне является бизнес поведением, это просто разные способы представления плоской структуры данных. Самое главное что бы в сериализации не происходила трансформация. Это может являться частью логики. А делать отдельный класс для каждого дто для сериализации - слишком запарно.

    Лично я использую сериализацию в dto.
    Ответ написан
    Комментировать
  • Как правильно работать с большим количеством данных?

    batyrmastyr
    @batyrmastyr
    - получение данных об общем количестве записей для построения пагинации, это SELECT count(id)

    1. count(*), а не count(id)
    2. если вас не сильно интересует абсолютно точное значение для миллионов результатов, то делаете оценку количества, начать проще с EXPLAIN <текст запроса> вы можете получить оценку количества результатов. Мы для себя решили, что если по оценке меньше 50 000 строк, то вслед за этим делаем обычный SELECT count(*) для получения точного количества.
    Потом дергается запрос для получения данных на экспорт

    1. Пожалуй, вам от этого нужно избавляться в первую очередь. Нажал человек на кнопку "экспортировать" - экспортируете, а до этого и дёргаться нет смысла. Фильтры можно получить либо при клике, либо из заголовка referer
    2. Если вам нужно абсолютно все данные, то ставите задание на экспорт в очередь и выполняете его в отдельном процессе, сохраняете в файл. Для пользователя рисуете прогресс выполнения и выводите его в нажатую пользователем кнопку, хотя можно тупо на отдельной странице выводить список "заказанных" выгрузок и ссылки на скачивание.
    Запросы на каждый выпадающий список в фильтрах - SELECT distinct field_name

    Можно с какой-то периодичностью выгружать выхлоп таких запросов в материализованное представление / справочную таблицу / ENUM. Для обновления таких справочников "в реальном времени" можно повесить триггер на вставку в основную таблицу который будет делать INSERT INTO dictionary (value, column_oid) ON CONFLICT / ALTER TYPE ADD VALUE IF NOT EXISTS
    После чего в основной таблице заводите рядом поле под идентификатор в справочнике и индексируете уже его.
    Запрос при фильтрации и сортировке - SELECT * FROM some_table WHERE field_name LIKE '%value%'

    1. если у вас значения длинные (от 8 - 10 символов), то стоит попробовать триграммные индексы. Но на коротких значениях они могут замедлить поиск раза в полтора-два.
    2. Полнотекстовый поиск. В частности есть поиск лексемы по префиксу ts_tsquery('сло:*') (быстро найдёт и "слово" и "словарь", но не найдёт "однословное")
    3. Для полей по которым вы сделаете словари лучше делать поиск через словарь SELECT * FROM table WHERE column_dictionary_id IN (SELECT id FROM dictionary WHERE value LIKE '%текст%'). В словаре у вас наверняка на порядок - три меньше значений, а несколько сотен или тысяч значений в IN постгрес нормально пережуёт.
    Полей много, разные даты, guid, названия проектов, данные из поля типа json, цены.

    Активнее используйте функциональные и частичные индексы.
    Например, у нас есть кадастровые номера. Триграммный индекс по ним весит 56 мбайт, а BTREE по номерам урезанным до кадастровых кварталов - 15 мбайт, в поиске к "cadastre_id LIKE '11:22:333333:1%'" добавился "AND to_quarter(cadastre_id) = '11:22:333333'", но сам поиск получается на порядок быстрее (~5 мсек вместо 50 - 70).
    Главное не забывайте о стоимости этих самых функций - индекс по to_quarter может строиться всего в 1,5 раза дольше нефункционального, если делать LEFT(cadastre, -(position(':' IN reverse(cadastre))), а может и в 100 раз, если использовать регулярку.
    На все индексы не поставишь, тем более что один индекс может добавить гигов 5-10 к весу.

    Если ещё не обновились, то обновляйтесь на 13-ю версию, там размер BTREE индексов уменьшили в 3 раза. Ну и посмотрите, возможно вам где-то нужны GIST, GIN или BRIN индексы.
    Ответ написан
    2 комментария
  • Можно ли использовать GraphQL для админки где нужно не только обновлять, выводить данные, но и выполнять какие-то действия?

    vabka
    @vabka
    Токсичный шарпист
    В GraphQL есть концепция Mutation-ов - по сути просто функции/процедуры, которые можно вызывать.
    Так что да - можно.
    Ответ написан
    3 комментария
  • Что значит single responsibility в контроллере?

    ThunderCat
    @ThunderCat Куратор тега PHP
    {PHP, MySql, HTML, JS, CSS} developer
    Сколько людей - столько мнений. Не стоит прям вообще всех слушать, кто высказывает какие-то "гениальные" откровения. Даже внутри крупных фреймворков многие вещи реализованы по разному, и каждый считает что именно так надо, и никак иначе. Думаю автор статьи просто искал дешевого хайпа, на практике никто так не делает. Контроллер по сути не модель, а управляющая конструкция, в ней нормально внутреннее ветвление на методы. С таким же успехом можно решить что для модели нужно 4 репозитория, на каждое действие CRUD...
    Ответ написан
    1 комментарий
  • Использовать ли геттеры в классе где объявлены приватные свойства?

    @12rbah
    это экономит (в рамках тысяч использований) память и работает быстрее
    Не имею ничего против пхп, но если вы хотите экономить память и заниматься оптимизацией на 10 наносекунд то вам не к этому языку. Если у вас миллион раз вызовется гетер, то вероятно, затраты на его вызов будут ничтожно малы по сравнению с временем работы всей функциии. Если вы писали hft бота на си, который подключен напрямую к бирже, где сетевые задержки минимальны, то еще был бы смысл думать над этим. А в реальности такие "оптимизации приведут только к проблемам".
    Ответ написан
    1 комментарий
  • Использовать ли геттеры в классе где объявлены приватные свойства?

    saboteur_kiev
    @saboteur_kiev
    software engineer
    геттеры и сеттеры именно для этого и нужны - чтобы далеко далеко в будущем, когда будет много других классов, и которым нужны эти данные, и вдруг тип данных нужно будет поменять (например перейти от int32 к int64), то будет достаточно просто поменять тип приватных данных, поправить геттеры, чтобы они конвертили в int32 для старых зависимостей и сделать два новых 64-битных геттера для новых.
    И потом уже все кто лазили за данными, либо будут потихоньку переходить на новые геттеры, либо сидеть на старых, но с ограничением.

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

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

    Все зависит от приоритетов. Нужна скорость - делаете одно. Нужна совместимость - делаете другое. Нужно и то и то - ищете архитектурный подход, где от геттеров все зависит мало.
    Ответ написан
    1 комментарий
  • Как составить аналогичный запрос, если поле text, а не json?

    freeExec
    @freeExec
    Участник OpenStreetMap
    SELECT ('{"data": "test", "count": 8}'::json->>'count')::int + 2
    Ответ написан
    2 комментария
  • Как составить аналогичный запрос, если поле text, а не json?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Можно ли написать такой же запрос, если поле raw не jsonb, а text?

    Ну офигеть проблема - заменить tp."raw"->>'errorCode' на tp."raw"::JSONB->>'errorCode'

    Кстати, это применимо к полю обоих типов. Просто для JSON - избыточно.
    Ответ написан
    1 комментарий
  • Стоит ли добавлять декоратор для обработки исключений?

    @Akela_wolf
    Extreme Programmer
    Зависит от того какая в обработчиках исключений выполняется логика. Если там просто логирование исключений, никак не связанное с логикой консьюмера - то вполне оправданно эту логику отделить. Но можно и не отделять. Тут все зависит от желания переиспользовать консьюмер и декоратор. Также оправданно отделять подобные независимые вещи для облегчения юнит-тестирования.

    Но если же в обработке исключений более сложная логика, например, связанная с восстановлением после ошибки, переплетенная с логикой консьюмера - то отделять такую логику будет сложно и не всегда можно сказать нужно ли это делать не видя код.
    Ответ написан
    2 комментария
  • Как запоминать код, который писал две недели назад?

    @danSamara
    Значит вы ещё не программист, а кодер. Это не страшно, вопрос опыта.
    Главное отличие программиста от кодера - программмист пишет код в голове - набивание кода в IDE это самое нудное в программировании, весь смак - в проектировании. А вот кодер пишет код кусочками, которые берёт из интернета или из собственных внезапных озарений.

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

    ПРОФИТ!
    Ответ написан
    Комментировать
  • Сколько держит заряд Macbook pro на m1 при активной работе программиста?

    lamer350
    @lamer350
    กำลังสูงสุด
    у меня порядка 12ти часов, но открытый хром и вайбер уменьшает время почти в 2 раза, проблемы софта еще есть...
    Ответ написан
    Комментировать
  • Сколько держит заряд Macbook pro на m1 при активной работе программиста?

    @Drno
    Порядка 6-8ч
    Ответ написан
    Комментировать
  • Как общаться между контейнерами docker?

    @quiex
    Не нужно ничего запихивать в один docker-compose.yml, все должно работать и так.
    Docker-compose это всего лишь обертка над стандартным docker api, так что это равнозначно тому, что вы запустите контейнеры просто через docker run.

    Почему, конкретно у вас не работает, точно сказать не могу.

    Для начала посмотрите docker network ls: не создает ли compose сеть с префиксами/суффиксами.
    Попробуйте создать сеть извне, а в обоих файла прописать external.
    Ну и еще, возможно, это зависит от ОС, на которой вы все это делаете.(на маке, к примеру все работает)
    Ответ написан
    1 комментарий
  • Везде ли нужно проверять на существование элемента в массиве?

    pOmelchenko
    @pOmelchenko
    php-developer
    Посмотрите в сторону таких инструментов как phpstan psalm phan. Там можно объявлять какие ключи должны быть в массиве. Это поможет при написании кода - не забыть что-то важное. Но в рантайме, да - больше проверок к чему-то важному это всегда хорошо. Особенно если массивы кастить в дто. У объектов и api приятней. Всегда же удобней работать с методами/свойствами чем вспоминать корректное название ключа
    Ответ написан
    Комментировать
  • Когда стоит выделять данные в отдельную таблицу?

    romesses
    @romesses
    Backend инженер
    Ну вижу смысла выносить конкретное поле (флаг) в отдельную таблицу. Потому что ничего хорошего это частное отделение не даст:
    1. фактор неожиданности у коллеги: с какого перепугу была необходимость отделения конкретного флага?
    2. дополнительная таблица, для которой нужен JOIN.
    3. дополнительный код
    4. дополнительные миграции и поддержка


    На мой взгляд все эти настройки должны лежать в отдельной таблице product_settings, ну если уже в коде везде product, а не project. Так как по сути это настройки, а не прямая информация о продукте.

    Если уж отделять метаданные и настройки, так все сразу, а не ради одного флага. Тогда есть смысл в рефакторинге и приведении порядка.
    Ответ написан
    1 комментарий
  • Везде ли нужно проверять на существование элемента в массиве?

    profesor08
    @profesor08 Куратор тега PHP
    На мой скромный взгляд, проблема несколько шире. Вот почему someParam это массив, а не осмысленный объект? Пока его суть остается неопределенной, будут возникать неопределенные ситуации, когда непонятно что делать, падать в ошибку или городить полотно проверок. А ведь можно вынести всю валидацию на этап создания объекта, там же выбрасывать ошибки, так будет явно понятно, что ошибка в данных, а не где-то в логике, где данные уже должны быть.
    Ответ написан
    1 комментарий
  • Что можно использовать от фреймворка в DDD?

    @k2lhu
    При работе с Yii2 изначально стоит выносить любые компоненты в обертки, и их использовать по проекту, так вы легко сможете отвязаться от реализации, используя интерфейс обертки.

    Что касается DDD при работе с Yii2 и моделей - идеально было бы разделить приложение на различные слои, полностью отделив из средних слоев любые зависимости Yii2, но модели я бы не стал наделять интерфейсом, в этом плане вам поможет создание своего репозитория, в котором можете спрятать любые методы на выборки при помощи юшных моделей, а наружу отдавать уже самостоятельно смапленные Entity и уже их наделять интерфейсами и использовать дальше, но это именно для выборок конкретных записей. Если вам необходимо выбрать несколько записей - почти аналогично используюте Entity, создаете свою кастомную коллекцию которая имплементирует встроенные интерфейсы Iterator и Countable. Для их разделения можно использовать базовый класс как родителя, а дальше создавать нужный класс коллекции для смапленных Entity.

    Но вся ваша идеальная задумка DDD с Yii2 легко развалится при использовании ActiveRecord и базовых моделей - в них сразу пихается и валидация, и каст, и обработка поведений на сохранение/обновление/удаление, так еще в старых проектах еще и триггеры навешивают часто. Может стоит подумать, нужен ли вам вообще тут DDD? Если это сделано с целью отвязаться от фреймворка в любой момент - то используйте для моделей Entity, Collection и выносите сразу все в репозиторий, легко сможете мигрироваться на тот же симфони. Безболезненного перехода не бывает и так или иначе что-то да придется переписывать, но все сможете это сделать просто поменяв код ваших репозиториев и контроллеров с реквестами.
    Ответ написан
    1 комментарий
  • Что можно использовать от фреймворка в DDD?

    dmitriylanets
    @dmitriylanets
    веб-разработчик
    ваше направление и мысли полностью совпадают с моими, поэтому дополню то что уже писал k2lhu
    DDD это больше про агрегаты и контекст, может вам нужна гексогональная архитектура и все что связанно с clean architecture. Принцип простой, ваша бизнес логика не должна зависеть от деталей реализации, попробуйте написать код без фраймворка например сохранение , отображение простых сущностей, пользователей. У вас будет репозитории не работающие с базой а просто Mock-репозитоиии, но реализующие интерфейсы. Так у вас появится Domain layer и очень тонкий Infrastructure Layer. Далее попробуйте реализовать бизнес логику и сценариции для работы с вашими сущностями, например регистрация пользователя, у вас появится Application Layer. Далее вам нужно организовать контроллеры или модули который будут отображать элементы интерфейса, вы создадите контролеры, вьюхи, модули(виджеты) и тд. например форма регистрации пользователя, так у вас появиться Presentation Layer. Далее вы переведете на динамику ваши репозитории, адаптеры и реализуете сохранение ваших пользователей в базу с помощью Activerecord или DataMapper. Так появиться Infrastructure Layer.
    Плюсы, бизнес логика не зависит от фраймворка, на каждом этапе слоя вы можете подключать фраймворк на уровне как минимум в Infrastructure Layer, Presentation Layer. При смене фраймворка будите менять только их.
    Тесты можно внедрять без проблем особенно на уровне домена и бизнес логики.

    Золотые слова дядюшки Боба:
    Когда вы пишите приложение на фраймворке для заказчика вы гарантируете разработку приложения и его поддержку в течении жизненного цикла, но какую гарантию дает вам разработчик фраймворка?
    Ответ написан
    Комментировать
  • Хорошо ли использовать DTO в качестве объекта реквеста для api?

    myks92
    @myks92 Куратор тега PHP
    Нашёл решение — пометь вопрос ответом!
    Сложно понять Вашу картину и что имел ввиду Ваш коллега. Об этом лучше спросить самого коллегу. Однако постараюсь помыслить на эту тему...

    1. Конкретно DTO не совсем применима к API в чистом виде и работе с ней. Более правильно в запрос кидать json, а вот этот json уже маппить на вашу DTO, в которой будет высокоуровневая валидация от симфони и php7.4. Пример И само DTO.

    2. Так как у вас система микросервисная, то DTO передавать по сети точно не нужно. Вы можете использовать DTO внутри своего приложения, но не использовать его по сети. DTO позволяет Вам в сервис/хэндлер/команду передавать не сам Request и не кучу параметров, а своё DTO, которая должна создаваться на основе запроса. Таким образом вы отделяете слои и ответственности. При изменении названий параметров DTO не обязательно их менять в API и наоборот. Нет зависимости и это хорошо! Так же хорошо и для тестируемости.

    3. Если вы упомянули ParamConverter это по сути конвектор параметров, но опять же на уровне приложения, а не между запросами сети) Об использовании его можно почитать в документации симфони. С помощью него можно указать в методе DTO, которую он принимает, а конвектор, написанный вами, знает как это DTO создать на основе ваших переданных данных. То есть вы не DTO передаёте в запрос, а те же параметры, просто этот конвектор делает вам из этих параметров DTO. Использовать его или нет - дело ваше. Вы правильно подметили, что в Yii2 такого нет. Можно заморочиться написать свой, но смысла от этого нет вообще) Использовать DTO я бы рекомендовал. Так как профит будет: разделение слоев, меньшая связанность и возможность валидации. А вот использовать конвектор - решение команды или разработчика. Оно позволяет вам создать вашу DTO на основе переданных параметров. Параметры никуда не денутся, они просто сразу лягут в DTO это один профит - чище код.
    Ответ написан
    2 комментария
  • Хорошо ли использовать DTO в качестве объекта реквеста для api?

    glaphire
    @glaphire Куратор тега PHP
    PHP developer
    DTO просто помогает отвязаться от прямой работы с сущностью/моделью и выносить туда всю предварительную инициализацию/обработку/валидацию, получается как дополнительный слой ответственности передачи данных, чтобы не решать это на уровне тех же моделей/сущностей или сервисов.
    С DTO на разных сторонах двух микросервисов вопрос сложный)
    ParamConverter (и ArgumentResolver) это дополнительные прослойки в жизненном цикле запроса симфони, это просто разруливатели сырых параметров запроса и их валидация/преобразование в объекты до этапа попадания в экшен контроллера. Судя по документации, в Yii2 такого функционала нет и действительно надо делать самому или упрощать его.
    Ответ написан
    8 комментариев