Комментарии 10
Здравствуйте, спасибо за статью
А как в рамках концепций из статьи относитесь к декортатору dataclass и их методу "__post_init__"?
Часто встречал в коде, что "математику" располагают там.
Заранее, спасибо
Здравствуйте. Рад, что статья оказалась интересной для вас)
По поводу post_init: Нужно смотреть конкретные примеры, что там происходит.
Если там происходит создание новых полей на основе тех, которые пришли в init, то в рамках эволюции при создании объекта, мне такой подход нравится меньше.
Если условная фабрика полностью конструирует объект, то post_init как будто доделывает чью-то работу. Выходит, что он не забирает на себя всю сложность создания. Эта сложность размазывается между init и post_init.
Учитывая, что они неразрывно связаны, то получается, что это то же самое, что, если бы мы в конце init вызывали post_init(За нас в данном случае это делает механизм dataclass)
Подытожу: При написании бизнес-логики я бы старался не использовать post_init для целей создания одних полей на основе других или валидации данных.
Но не забывайте о том, что как dataclass, так и архитектура кода, это инструменты, которые мы используем для решения бизнес задач.
Поэтому всем нам нужно учиться балансировать между "качеством кода" и "скоростью разработки". Далеко не всегда есть время писать так, как правильно, но лучше осознано оставлять тех долг, чем неосознанно писать некачественный код.
Большое спасибо за такой подробный и обстоятельный ответ. Подчерпнул для себя, как из статьи много дельных мыслей
Поэтому всем нам нужно учиться балансировать между "качеством кода" и "скоростью разработки".
Тоже для себя по опыту работы сделал для себя такой вывод. Кратко для себя и коллег всегда говорю: "Что в каждом случае нужно о ужас думать?. Ну или хотя бы задумываться, а не слепо следовать, каким-то парадигмам".
Про dataclass уже сказали. Сам pydantic не пользовался, но вот примерный псевдокод:
from typing_extensions import Self
from pydantic import BaseModel, ValidationError, model_validator
class PriceRequestData(BaseModel):
method: str
path: str
content_type: ContentTypeEnum
data: dict[str, Any] | None = None
headers: dict[str, Any] | None = None
@field_validator('method')
@classmethod
def clean_method(cls, value: str) -> str:
if value not in ('POST'), 'GET'):
raise ValueError('Method name not valid.')
return value
@model_validator(mode='after')
def clean(self) -> Self:
if self.method == 'POST' and not self.headers.get('X-authorization-id'):
raise ValueError('Authorization headers not found.')
return self
Я стараюсь не тащить сторонние библиотеки в бизнес-логику.
Для меня DTO не должен быть валидатором и сериализатором.
В контроллере или адапторах да, без проблем. В бизнес логике только DTO, value object, entity, которые являются простыми классами или dataclass
Может быть и зря. Оборачивать каждый класс в фабрику и размазывать логику по фабрике выглядит странным. Например, в расте принят интересный подход: объект можно сконструировать только через статический метод try_new
, если у вас объект создан, то можно всегда гарантировать, что его состояние корректно (все поля проверены итд). Для этого и существует система типов.
У вас же класс кто-нибудь может импортировать напрямую и сконструировать объект не через фабрику. И потом: ой, разве здесь не должно быть валидаторов? Что-то в другой системе теперь null.
Конструируйте без фабрики, нет проблем. Клас лишь ожидает пачку примитивов, если вы смогли их получить без фабрики, то пожалуйста. Но тогда вы будете нарушать dry.
Я лишь показал свой путь эволюции при усложнении создания объектов.
А так да, большинство механизмов(репозитории, клиенты, источники и т п) имеют фабрики для создания, что бы не перегружать контроллер этой работой
Возможно у вас большие и сложные проекты где мой подход кажется вам плохим. В компании где я работаю используется микросервисная архитектура, и мы отлично справляемся с ценностями чистой архитектуры(Мартин), и не тянем сторонние библиотеки в бизнес-логику.
Если так рассуждать, можно и Джанго модели считать DTO? Повторюсь, для меня pydantic это валидация и сериализация.
Мне кажется, если мои объекты изначально на pydantic, то нехотя бизнес-логика может начать готовить ответ сразу клиенту прямо в бизнес-логике, примешивая уровень презентации.
И я не предлагаю серебряную пулю. Я рассказываю свою историю. Я так делаю и для меня это работает :)
Может быть у вас был другой опыт, и вы нашли лучшее или просто другое решение, которое вас устраивает. Это хорошо!)
А по поводу того, что кто-то может не так использовать код - да, может. Я не боюсь этого. Мы специалисты не просто так, ну и никто не отменяет анализаторов и подсветки idea, которые решают 99% подобных проблем, если вы качественно аннотируете код :)
В копилку к тому, что кто-то, что-то сделает не так - мы применяем TDD при разработке, и вполне уверены в коде который пишем )
Интересная статья, кое-что обязательно возьму на вооружение.
Единственная просьба - орфография (как в "Нелюбой объект в коде") и пунктуация, которая порой сбивает с мысли.
Python — Эволюция создания объектов (первая часть)