Юра
Есть обертки уже которые и так абстрагируют бекенд
Юра
Вопрос делать ли обёртку над обёрткой
Михаил
Если у вы скачали обёртку, то вы не сможете сделать инверсию зависимостей не реализовав свою обёртку
Павел
У меня стороння апишка, я обращаюсь к ней из php по HttpClient.
Вопрос:
Некоторые методы этой апишки принимают 50+ полей глубокой вдоженности, а в ответе мне нужны только 2 поля из 30 в конкретном сервисе.
Мне сделать один класс и принимать все возможные параметры для этого метода апишки (будет очень много DTO с вложенностями) и валидировать все возможные ошибки, или делать отдельно изолированные запросы в каждом сервисе
Стоит разделять апп запросы(какие то конкретные задачки бизнеса через апи) и сдк (класс для работы с апи)
Если пишите свое сдк - лучше делать ее максимально отдаленной от вашего приложения и чисто под апиху сервиса, чтобы туда не протекали ваши бизнес задачи. Но да, для экоомии можно делать куцо, а не всё сразу. Например не все фильтры или не все ответы
Если есть готовое, то лучше сделать над ним свою обертку (чтобы заменить в случае чего только либу, а свой код не трогать), но это может быть достаточно геморойно и сильно абстрактно, почти как писать своё в варианте1, а главное почти бессмысленно. Поэтому как вариант, сделать обертку бизнесовую, т.е. какую то прокладку по вашим конкретным задачам с апи, которая ходит в это сдк по его правилам. Но там только обращение к апи. Таким образом можно будет и переиспользовать, и как то даже куцо тестировать блоки по работе с апи, так же их мокать более просто. Т.е. будете мокать не либу, а просто dto входа и выхода, в которых только нужные вам поля.
Михаил
То есть у вас есть модуль по работе с профилем пользака, если пользак создаётся то вам нужно привести ту картинку которую он загрузил к нормальному виду.
Сделать так, что бы модуль пользака напрямую зависел от имежика - плохая идея, поэтому вы через интерфейс делаете инверсию зависимости. Пишите свой класс-адаптер который реализует этот интерфейс и живёте спокойно.
Хотя можно и на какой-нибудь ивент подписаться и в подписчике напрямую либу заюзать, но как по мне это утекание бизнес логики (если обрезка аватарки входит в бл)
Daw
Сброшу матeриалы (Python, Java, c++, Боты tg, так же имеется разработка игр, приложений)
Возможно кому-то будет полезно, поделюсь бесплатно)
Михаил
@wcdi_captcha_bot
Вадим
привет!
Кто работал с pdf в Imagick?
Я делаю сервис в который юзеры загружают pdf с растровой картинкой внутри. Надо преобразовать pdf в растр. Проблема в том что я не знаю исходнго резрешения картинки которая внутри pdf, а они могут быть разные. Разрешение мне нужно установить в Imagick перед конвертацией чтобы получить корректные размеры получаемого растрового изображения.
Юра
Размеры пдф можно высчитать по-моему
Юра
А сам имаджик не поддерживает пдф?
Вадим
А сам имаджик не поддерживает пдф?
поддерживает, но ему надо разрешение указать перед чтением, а если не указать то будет 72х72 и результирующая растровая картинка дргого размера чем она в pdf.
Юра
Прям перед чтением?
Юра
Ну тогда хз
Alfred
Вадим
хотя можно и потом, там другой метод есть
Вадим
Михаил
Аааа, разрешение
Михаил
Сорян
Вадим
Михаил
угу
Только это, выбери надёжную утилиту. Вся эта фигня с чтением пользовательских файлов может быть опасной
https://www.xpdfreader.com/pdfimages-man.html
Тут вот вроде есть альтернативы, найди подходящую и подревнее версию 😅
Вадим
Михаил
а чо опасного
Вот так вот. Сначала «а чо опасного» а потом всю бд с бэкапами шифруют)
Вадим
Вадим
аа, ты про это
Вадим
та не, это другое
Михаил
кто?
где?
У нас просто на проекте одна утилита стояла для обработки видосов пользовательских. И вот в этой утилите пару раз точно находили RCE. Это же вообще трындец.
Всегда смеялся над проггерами-параноиками но после таких приколов реально ссыкатно что-то от пользаков засовывать в какие-то утилиты.
Вадим
Alfred
Как по мне взломать можно что угодно, было бы время и ресурсы. Что бы обезопасить себя обновляй утилиты и смотри как безопасно интегрировать в свои системы. Ничему не доверяй что идет из вне.
Вадим
привет!
Как валидировать данные перед денормализацией и православно ли это?
Дело в том что в процессе денормализации я создаю валью обжекты чтобы сохранить их в БД, и если значение не валидное то мой валью обжект падает.
Kirill
есть инварианты, есть валидация, не надо путать
Kirill
кривой велью обжект - это не валидация, а виолейшн инварианта/прекондишена
Kirill
а валидация - это процесс проверки существующих данных на соответствие предметной области
Kirill
Если постараться +/- предметно, то:
X строка - это инвариант
X email - валидация
Вадим
это всё понятно
Вадим
что делать - непонятно :)
Kirill
для начала стоит определиться что это за велью обжекты и к какому слою они относятся)
Kirill
сохранение в БД - это инфраструктура, само понятие VO - часть доменного слоя, а процесс денормализации или аппликейшн или презентейшн
Kirill
отсюда и решение должно быть
Kirill
если это проблема слоя представления, то на уровне домена должны быть соответствующие валидаторы, которые допускают нужные VO до персиста или кидают throw new InvalidValueException('XXX required');
Kirill
если выше, то выше ошибка, типа хттп бэд реквест
Kirill
ну так у тебя контроллер получает форму, если она битая, то ошибка бед реквест
Kirill
дальше контроллер делегирует аппликейшн или доменному сервису
Kirill
сервис получает данные и проверяет на свои правила
Kirill
потом возвращает ответ или исключения
Kirill
контроллер обрабатывает исключения и преобразовывает их в нужные, типа хттп
Kirill
view -> dto/form request -> controller -> app service -> domain service <- persist over ioc
Kirill
а в app/domain уже валидация
Kirill
ошибка инфры почти всегда 500, кроме случаев uniq constraint или чего-то такого, что может случиться на репликах из-за отставания чтения. Но это всегда должно быть описано на уровне интерфейса в любом случае, что оно может вернуть какую-то ошибку подобную
ошибка домена или апп - логическая ошибка, типа "число Х должно быть больше 0" или "почта уже есть" и зависит от предметной области сервиса или воркфлоу, можно в анпрацессбл энтити такое конвертить
ошибка представления - бед реквест, когда структура, формат или ещё что не соответсвтуют
Вадим
Kirill
ну хз, я постарался довольно просто описать без загонов про порты, адаптеры и прочее
Kirill
а так, изи гуглится жеж https://habr.com/ru/articles/267125/
Вадим
ну да, это хорошо когда она гексагональная
Kirill
А если хочешь с адскими загонами и оверинжинерингом, то есть фулл вариант https://habr.com/ru/articles/718916/
Хотя мне кажется что там есть лишние вещи довольно
Вадим
мне бы понять куда мне код писать
но вроде понял, надо в стейт процессоре создавать мои VO из уже отвалидированных данных
Вадим
а не в денормализаторе
Kirill
у тебя есть папочка, отвечающая за обработку запросов
Kirill
и папочка, отвечающая за данные
Kirill
обе отвечают за корректность, но на разных уровнях
Kirill
Попробуй форму выразить в DTO формате. Если формат данных не впихивается в эту DTO - это ошибка запроса, если же там всё ок, а данные просто некорреткные - ошибка валидации
Kirill
вот и всё)
Вадим
ну ошибку запроса тоже ж валидатором делать
Вадим
значит 2 валидации выходит
Вадим
первая на соответствие формату данных, вторая - на соответствие бизнес логике
Kirill
ну я с этого и начал)
Вадим
понял
Kirill
есть инварианты, есть валидация
Kirill
и одно может перетекать технически в другое, например UserId может быть int<1, max> (не может быть нулём или отрицательным)
Kirill
и тут уж как решишь, с одной стороны это можно выразить типом а-ля unsigned int32, а с другой стороны - ошибка логическая (валидации)
Kirill
а остальное довольно просто и очевидно разграничивается, bool - тип данных, значит если там будет float, то косяк с запросом
Kirill
а если строка, но которая не почта или уже существующая почта (во время регистрации), то валидация уже и возникает в "юзер сохраняторе"
Kirill
и может выкидывать типа:
UserCreator::create(...) -> throws EmailNonUniqueException extends EmailException
Kirill
или InvalidEmailException)
Вадим
и типа коды ответов разные
Kirill
ну зависит от тебя, в любом случае у тебя есть какой-то UserSaver или UserDeleter или ещё что
Kirill
может быть процесс, типа UserDelitionProcess