Юра
Это создает накладные расходы. Если что-то создает накладные расходы оно же должно взамен давать что-то? Вот мне и интересно что это дает конкретно. Ради чего эти расходы7
Юра
И по поводу неожиданностей кстати имутабл убирает одни неожиданности но и другие привносит спокойно на раз два
Юра
Одна ищ неожиданностей что надо не забывать везде писать $builder = $this->buildMessage($builder);
Юра
Сейчас в мире облаков и модели плати за ресуры, каждая вот такая на первый взгляд мелоч выливается потом и суммируется во вполне конкретные расходы в виде долларов. Один полтзователь ну мелочь. А если тебе надо отправить сто тысяч сообщений? Теперь тебе надо сделать примерно 100 тыс * количетво вызовов методов билдера, клонирований
Vlad
это кто тому что это копейки, которые не сумируются не фига. На счет клонирование будешь запраиватся в последнию очередь.
Юра
Ну я соглашусь наверное что если у тебя пхп в облаке то все остальное уже копейки и мелочи
Dmitry
Ну я соглашусь наверное что если у тебя пхп в облаке то все остальное уже копейки и мелочи
В том и дело, что экономия на лишней переменной даст всего 0,000001 секунды и несколько байт памяти.
Юра
0,000001 на чем оно даст?
Юра
Мой бенч показывает что вариант с мутабл быстрее в два раза чем вариант с имутабл
Павел
Мой бенч показывает что вариант с мутабл быстрее в два раза чем вариант с имутабл
Эти два раза надо смотреть по отношению к задаче. Понятно что какой то $a=1; Быстрее чем $a=1; $b=2 Но только хоть весь проекта рандомно этими $b=2 обкинуть, врядли это тормознет проект.
Юра
факт в том что время увеличилось в два раза. Причем это чисто ЦПУ время. А значит нагрузка на ЦПУ увеличилась в два раза. Я понимаю что не весь код проекта обклеен созданием месаджей и их отправкой. Но.. сейчас месадж, потом имутабл энтити, потом имутабл квери билдер, имутабл дто, имутабл коллекии. И это все копится. Просто странно с одной стороны у нас разрабы ядра, где парятся над тем как выровнять структуры в памяти чтобы быстрее кеш линии работали, разрабы компиляторов, которые десятилетиями оптимизируют всякие JIT компиляторы со спецулятивными оптимизациями, векторизациями и хвостовыми рекурсиями, где экономия ассемблерной инсрукции считается победой, а с другой стороны мы, которые берем и суем clone там где можно спокойно без него обойтись
Павел
факт в том что время увеличилось в два раза. Причем это чисто ЦПУ время. А значит нагрузка на ЦПУ увеличилась в два раза. Я понимаю что не весь код проекта обклеен созданием месаджей и их отправкой. Но.. сейчас месадж, потом имутабл энтити, потом имутабл квери билдер, имутабл дто, имутабл коллекии. И это все копится. Просто странно с одной стороны у нас разрабы ядра, где парятся над тем как выровнять структуры в памяти чтобы быстрее кеш линии работали, разрабы компиляторов, которые десятилетиями оптимизируют всякие JIT компиляторы со спецулятивными оптимизациями, векторизациями и хвостовыми рекурсиями, где экономия ассемблерной инсрукции считается победой, а с другой стороны мы, которые берем и суем clone там где можно спокойно без него обойтись
Не ну так то мысля 100% логична. Особенно что иммутабл это даже не архитектура проекта, а некая "антивыстрел в ногу", который спасает очень редко. Но опять же в рамках проекта наверное это будет спичка среди спичек.
Юра
С одной стороны да. Опять же, если у нас пхп и ларавель где на каждый запрос создаётся все заново, то наверное имутабл билдер последнее о чем будешь думать при оптимизации
Юра
Ну а если чисто по коду, то немного бесит это смешивание value и ref семантики, где одни методы меняют, другие возвращают измененный. Приходится мозг перенастраивать каждый раз. Типо так тут у нас имутабл, тут мутабл и т..д.
Юра
Я как-то переписал один фронт проект на имутабл. Работает норм. Но какие же я там баги ловил. К примеру когда у тебя генерируется некое событие, и есть листенеры, каждый получает ссылку на имутабл объект. И если раньше я просто менял этот объект и все, то с имутабл каждый листенер получается создавал свою копию объекта, и другие листенеры ничего о ней не знали
Юра
Юра
Юра
It works
Vlad
its laravel style)
Юра
Но блин это удобно )
Юра
Ну вообще это мне кажется легко сделать и через среднюю энтити явную, просто писанины больше
Юра
Чтобы поменять состояние
Vlad
По хорошему в ивенте должна быть дто
Юра
Я же про фронт писал
Dmitry
факт в том что время увеличилось в два раза. Причем это чисто ЦПУ время. А значит нагрузка на ЦПУ увеличилась в два раза. Я понимаю что не весь код проекта обклеен созданием месаджей и их отправкой. Но.. сейчас месадж, потом имутабл энтити, потом имутабл квери билдер, имутабл дто, имутабл коллекии. И это все копится. Просто странно с одной стороны у нас разрабы ядра, где парятся над тем как выровнять структуры в памяти чтобы быстрее кеш линии работали, разрабы компиляторов, которые десятилетиями оптимизируют всякие JIT компиляторы со спецулятивными оптимизациями, векторизациями и хвостовыми рекурсиями, где экономия ассемблерной инсрукции считается победой, а с другой стороны мы, которые берем и суем clone там где можно спокойно без него обойтись
> факт в том что время увеличилось в два раза Это факт для одной строки, а не кода в целом. Если в скрипте из 1000 строк время работы одной строки увеличилось в два раза, то условно вместо 1000 операций получится 1001. Замедление от таких микровещей можно заметить только если билдером собираем в цикле тысячи сообщений, а не одно.
Юра
Ну а если тебе надо в цикле отправить 1000 сообщений. Да не важно. Если у тебя пхп то это реально все спички
Юра
Мне просто непонятно в каких случаях делать имутабл в каких не делать. Давайте все имутабл делать если это реально круто, получится хаскель в итоге.
Юра
Но как по мне какое-то натягивание совы на глобус
Юра
Билдер не является валью обджектом, билдер обычно не хранится в десяти местах, зачем его дедать имьютабл вот и весь вопрос был
Юра
Но я уже понял зачем конкретно там так сделано. Там просто объект и билдер в одно намешано
Dmitry
факт в том что время увеличилось в два раза. Причем это чисто ЦПУ время. А значит нагрузка на ЦПУ увеличилась в два раза. Я понимаю что не весь код проекта обклеен созданием месаджей и их отправкой. Но.. сейчас месадж, потом имутабл энтити, потом имутабл квери билдер, имутабл дто, имутабл коллекии. И это все копится. Просто странно с одной стороны у нас разрабы ядра, где парятся над тем как выровнять структуры в памяти чтобы быстрее кеш линии работали, разрабы компиляторов, которые десятилетиями оптимизируют всякие JIT компиляторы со спецулятивными оптимизациями, векторизациями и хвостовыми рекурсиями, где экономия ассемблерной инсрукции считается победой, а с другой стороны мы, которые берем и суем clone там где можно спокойно без него обойтись
> а с другой стороны мы... Для того и придумали высокоуровневые языки программирования, чтобы программировать программу, а не двигать байты. А так да, в официальной реализации PHP значение: $a = 1; хранится не просто числом, а большой структурой zval в ~48 байт.
Dmitry
Мне просто непонятно в каких случаях делать имутабл в каких не делать. Давайте все имутабл делать если это реально круто, получится хаскель в итоге.
Мутабельными можно оставить только сохраняемые в БД сущности с идентификатором и другим пользовательским состоянием. А в всё остальное удобнее сделать как раз иммутабельным по умолчанию. Тогда путаницы не будет.
Юра
Мне кажется имутабл нужен там где нужен некий снапшот состояния
Юра
Если тебе нужны наоборот самые актуальные данные, то там имутабл вообще не нужен
Юра
Кто-то сталкивался с проблемой доктрины и постгрес когда нужно сделать default current_timestamp?
prophet
Кто-то сталкивался с проблемой доктрины и постгрес когда нужно сделать default current_timestamp?
обычно если не работает на уровне базы или подружить не получается то делали hasLifeCycle для entity и добавляли PrePersist в котором поле заполнялось
Юра
Я там разобрался в чем проблема на самом деле. Но не пойму просто неужели никто не сталкивался
Юра
Там получается у постгрес платформ надо заменить на now()
Юра
Иначе он постоянно потом пытается обновить схему
Юра
Но у меня постгрес старый на новом я не тестил возможно это не актуально на новом
Денис
Товарищи, подскажите, пожалуйста, я верно понял, что доктрина не умеет в cascade persist для OneToMany? То есть, я использую api platform и хочу при изменении сущности передать массив связанных сущностей. Но их сохранение не работает. Но судя по гуглу, у некоторых все же работает
Павел
хм, спасибо, проверю
Ну и плюс сами настройки платформы, надо группы номрализацией/денормализаций для коллекций настроить тоже. Были какие то заморочки
Павел
О, спасибо, наверное в этом дело, так как сеттерами порядок, они выполняются
Поидее у вас на второй сущности которая Many должны быть тоже группы , которые юзаются в главной сущности. Чтобы деномрализация сработала
Павел
Ну либо в главной сущности указать группы дочерней. Короче стратегии разные есть, но главное чтобы группа денормализации запроса была у обоих сущностей
Денис
Ну либо в главной сущности указать группы дочерней. Короче стратегии разные есть, но главное чтобы группа денормализации запроса была у обоих сущностей
Блин, чота фигня какая-то. Уже все варианты перепробовал. Группы из одной сущности в другую и наоборот и вообще убирал их. Не сохраняется...
Павел
Блин, чота фигня какая-то. Уже все варианты перепробовал. Группы из одной сущности в другую и наоборот и вообще убирал их. Не сохраняется...
Хз, надо смотреть, дебажить. Я смотрел - вроде ничего сверхъестестенного нет. Геттеры, аддеры (даже сеттеров на коллекции нет). Группа деномализации в главной, и такая же группа на свойствах вдочерней
Павел
Блин, чота фигня какая-то. Уже все варианты перепробовал. Группы из одной сущности в другую и наоборот и вообще убирал их. Не сохраняется...
Вы скиньте код сущностей (только со связями и настройками платформы, остальные проперти и логика не нужна), мб я что подкажу, мб кто-то еще
Денис
Вы скиньте код сущностей (только со связями и настройками платформы, остальные проперти и логика не нужна), мб я что подкажу, мб кто-то еще
Тут еще другая беда появилась, может дело в ней The total number of joined relations has exceeded the specified maximum. Raise the limit if necessary with the \"api_platform.eager_loading.max_joins\" Аттрибут #[MaxDepth(1)] не помогает
Денис
Это хз, еше вспомнил момент: вроде вторая сущность тоже должна быть ресурсом платформы. Но это не точно.
Она ресурс тоже... ... #[ApiResource( collectionOperations: [ 'get', 'post', ], itemOperations: [ 'get', 'put', 'delete' ], denormalizationContext: ['groups' => [Group::PROVIDER_ACCOUNT]], normalizationContext: ['groups' => [Group::PROVIDER_ACCOUNT]], )] ... class ProviderAccount { use EntityCreatedTrait; use EntityUpdatedTrait; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: Types::SMALLINT, options: ['unsigned' => true])] #[Groups([Group::PROVIDER_ACCOUNT])] private ?int $id = null; /** * @var Collection<MerchantAccount> */ #[ORM\OneToMany(mappedBy: 'providerAccount', targetEntity: MerchantAccount::class, cascade: ['persist'])] #[Groups([Group::PROVIDER_ACCOUNT])] private Collection $wallets; public function __construct() { $this->wallets = new ArrayCollection(); } public function getWallets(): Collection { return $this->wallets; } public function setWallets($wallets): self { $this->wallets = ($wallets instanceof Collection) ? $wallets : new ArrayCollection($wallets); return $this; } public function addWallet(MerchantAccount $wallet): self { if (!$this->wallets->contains($wallet)) { $this->wallets->add($wallet); } return $this; } public function removeWallet(MerchantAccount $wallet): self { if ($this->wallets->contains($wallet)) { $this->wallets->removeElement($wallet); } return $this; } } ... #[ApiResource( itemOperations: ['get', 'put'], subresourceOperations: [ 'merchant_orders_get_subresource' => [ 'method' => 'GET', 'path' => '/merchant_orders', 'controller' => 'App\Controller\Common\Api\Admin\Entity\MerchantOrder\GetAllActionClass' ] ], denormalizationContext: ['groups' => [Group::MERCHANT_ACCOUNT, Group::PROVIDER_ACCOUNT]], normalizationContext: ['groups' => [Group::MERCHANT_ACCOUNT, Group::PROVIDER_ACCOUNT], 'disable_type_enforcement' => true] )] ... class MerchantAccount { use EntityCreatedTrait; use EntityUpdatedTrait; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: Types::INTEGER)] #[Groups([Group::PROVIDER_ACCOUNT, Group::MERCHANT_ACCOUNT, Group::GATEWAY, Group::COMMISSION, Group::HOLD])] private ?int $id = null; #[ORM\ManyToOne(inversedBy: 'wallets', targetEntity: ProviderAccount::class)] #[Groups([Group::MERCHANT_ACCOUNT, Group::PROVIDER_ACCOUNT])] private ?ProviderAccount $providerAccount = null; ... public function getProviderAccount(): ?ProviderAccount { return $this->providerAccount; } public function setProviderAccount(?ProviderAccount $providerAccount): self { $this->providerAccount = $providerAccount; return $this; } ... }
Павел
Она ресурс тоже... ... #[ApiResource( collectionOperations: [ 'get', 'post', ], itemOperations: [ 'get', 'put', 'delete' ], denormalizationContext: ['groups' => [Group::PROVIDER_ACCOUNT]], normalizationContext: ['groups' => [Group::PROVIDER_ACCOUNT]], )] ... class ProviderAccount { use EntityCreatedTrait; use EntityUpdatedTrait; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: Types::SMALLINT, options: ['unsigned' => true])] #[Groups([Group::PROVIDER_ACCOUNT])] private ?int $id = null; /** * @var Collection<MerchantAccount> */ #[ORM\OneToMany(mappedBy: 'providerAccount', targetEntity: MerchantAccount::class, cascade: ['persist'])] #[Groups([Group::PROVIDER_ACCOUNT])] private Collection $wallets; public function __construct() { $this->wallets = new ArrayCollection(); } public function getWallets(): Collection { return $this->wallets; } public function setWallets($wallets): self { $this->wallets = ($wallets instanceof Collection) ? $wallets : new ArrayCollection($wallets); return $this; } public function addWallet(MerchantAccount $wallet): self { if (!$this->wallets->contains($wallet)) { $this->wallets->add($wallet); } return $this; } public function removeWallet(MerchantAccount $wallet): self { if ($this->wallets->contains($wallet)) { $this->wallets->removeElement($wallet); } return $this; } } ... #[ApiResource( itemOperations: ['get', 'put'], subresourceOperations: [ 'merchant_orders_get_subresource' => [ 'method' => 'GET', 'path' => '/merchant_orders', 'controller' => 'App\Controller\Common\Api\Admin\Entity\MerchantOrder\GetAllActionClass' ] ], denormalizationContext: ['groups' => [Group::MERCHANT_ACCOUNT, Group::PROVIDER_ACCOUNT]], normalizationContext: ['groups' => [Group::MERCHANT_ACCOUNT, Group::PROVIDER_ACCOUNT], 'disable_type_enforcement' => true] )] ... class MerchantAccount { use EntityCreatedTrait; use EntityUpdatedTrait; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: Types::INTEGER)] #[Groups([Group::PROVIDER_ACCOUNT, Group::MERCHANT_ACCOUNT, Group::GATEWAY, Group::COMMISSION, Group::HOLD])] private ?int $id = null; #[ORM\ManyToOne(inversedBy: 'wallets', targetEntity: ProviderAccount::class)] #[Groups([Group::MERCHANT_ACCOUNT, Group::PROVIDER_ACCOUNT])] private ?ProviderAccount $providerAccount = null; ... public function getProviderAccount(): ?ProviderAccount { return $this->providerAccount; } public function setProviderAccount(?ProviderAccount $providerAccount): self { $this->providerAccount = $providerAccount; return $this; } ... }
Ну так то вроде +- так же. Единственное что еще есть в сущностях: enable_max_depth=true и collectionOperation:get у дочерней сущности
Павел
Тут еще другая беда появилась, может дело в ней The total number of joined relations has exceeded the specified maximum. Raise the limit if necessary with the \"api_platform.eager_loading.max_joins\" Аттрибут #[MaxDepth(1)] не помогает
Есть вариант разделить группы нормализации на чтение и запись. И при чтении не читать глубоко, например в дочерней вообще не указывать группу чтения основной сущности
Павел
Но возможно кривота, и не факт что это что-то решает.
Денис
Но возможно кривота, и не факт что это что-то решает.
Ну да, все так. Ладно, буду думать. Спасибо за помощь!
Юра
А как кто работает с энамами в постгрес?
Юра
есть DoctrineEnumBundle но он как бы хранит в виде строки
Юра
это не энам по сути, ну в плане мускуль хранит варианты только и экономит место, а там в случае постгре получается varchar
Юра
где инт?
Vlad
В бд
Юра
ну в случае DoctrineEnumBundle там varchar
Vlad
Но вообще какая разница как там enum'ы валяются)
Vlad
ну в случае DoctrineEnumBundle там varchar
В случае с доктриной они из коробки есть
Vlad
Если мы про нативные
Юра
Кто нативные? инты?
Юра
или энамы?
Vlad
Enums
Vlad
Згачения инамов могут быть интами или стрингой
Юра
ты про новый аттрбует enumType ?
Vlad
Да