▲ | IshKebab 4 days ago | ||||||||||||||||
This seems ridiculously over-complicated. This guy would love Java. He doesn't even say why you should tediously duplicate everything instead of just using the Pydantic objects - just "You know you don’t want that"! No I don't. The only reason I've heard is performance... but... you're using Python. You don't give a shit about performance. | |||||||||||||||||
▲ | hxtk 4 days ago | parent | next [-] | ||||||||||||||||
The main “why” that I find is that it allows you to intentionally design your API types and know when a change is touching them. I worked on a project with a codebase on the order of millions of lines, and many times a response was made by taking an ORM object or an app internal data structure and JSON serializing it. We had a frequent problem where we’d make some change to how we process a data structure internally and oops, breaking API change. Or worse yet, sensitive data gets added to a structure typically processed with that data, not realizing it gets serialized by a response handler. It was hard to catch this in code review because it was hard to even know when a type might be involved in generating a response elsewhere in the code base. Switching to a schema-first API design meant that if you were making a change to a response data type, you knew it. And the CODEOWNERS file also knew it, and would bring the relevant parties into the code review. Suddenly those classes of problems went away. | |||||||||||||||||
▲ | photios 4 days ago | parent | prev | next [-] | ||||||||||||||||
The "gain" TFA is describing is very very questionable too. You're losing a lot in terms of complexity. You're going from a straightforward "Pydantic everywhere" solution to a weird concoction of: 1. Pydantic models 2. "Poor man's Pydantic models" (dataclasses) 3. Obscure third party dependencies (Dacite) Thanks, I'll pass. | |||||||||||||||||
▲ | chausen 4 days ago | parent | prev | next [-] | ||||||||||||||||
The article is written for those who want to apply DDD/onion architecture to Python apps using Pydantic. Those concepts explain the motivation and the article assumes the reading knows about them. As others are writing, it may not be worth it to apply this to simple apps, but as an app grows in complexity it will help make it more extensible, maintainable, etc. I'm not a Python expert, but looking into it briefly it seems like Pydantic's role is at application boundaries for bringing validation/typing to external data sources. If you are not working with external data, there is no reason to use it. So, if you separate out a domain layer, it brings no benefit there. Creating a domain layer where you handle business logic separately from how you interact with external data means those layers can evolve independently. An API could change and you only need to update your API models/mapping. | |||||||||||||||||
▲ | erikvdven a day ago | parent | prev | next [-] | ||||||||||||||||
Did I mention anything about performance? If so, my apologies, I'll need to revise the article, because this really has very little to do with performance. In fact, a reader who emailed me ran into a challenge where, if you have an aggregate with just one entity, for example, Bookcase -> list[Book] , and that list grows significantly, it can lead to performance issues. In such cases, you might even need to consider a solution to improve upon that. But that's a separate topic. What I was trying to highlight earlier were the whys behind the approach. And based on the feedback over here, it might be a good idea to update the post. I really appreciate all your input. As for the whys: The less your domain knows about the outside world, the less often you need to change it when the outside world changes. And the easier it becomes for new team members to understand the logic. It also separates your database models from your domain models, which is great IMHO. It makes it easier to change them independent from each other. You could have both, separated domain models and database models or API models and use Pydantic for all these layers, but why would you do that? If you need to make the translation anyways, why not to pure dataclasses?: no extra mental models, no hidden framework magic, just business concepts in plain Python. This does depend on your specific situation however, there are enough reasons to not do this. But if your application grows in size and is not so much a simple CRUD application anymore, I wonder if there are enough reasons to NOT keep Pydantic in the outside layers. So yes, for small simple applications it might be overcomplicated to introduce the overhead when your data stay relatively consistent across layers. | |||||||||||||||||
▲ | microflash 4 days ago | parent | prev | next [-] | ||||||||||||||||
For many cases, we don’t do these kind of things in Java; a single annotated record can function as a model for both data and API layers. Regardless of the language, the distinction becomes important when these layers diverge or there’s some sensitive data involved. | |||||||||||||||||
| |||||||||||||||||
▲ | franktankbank 4 days ago | parent | prev | next [-] | ||||||||||||||||
> you're using Python. You don't give a shit about performance. That's dumb. You may not care about max performance but you've got some threshold where shit gets obviously way to slow to be workable. I've worked with a library heavy on pydantic where it was the bottleneck. | |||||||||||||||||
▲ | slt2021 4 days ago | parent | prev | next [-] | ||||||||||||||||
>you're using Python. You don't give a shit about performance. Maybe it is true if you artificially limit yourself to a single instance single thread model, due to GIL. But because nowadays apps can easily be scaled up in many instances, this argument is irrelevant. one may say that Python has large overhead when using a lot of objects, or that it has GIL, but people learned how to serve millions of users with python easily. | |||||||||||||||||
| |||||||||||||||||
▲ | pletnes 4 days ago | parent | prev [-] | ||||||||||||||||
Pydantic seems to be fast (in the context, it’s written in rust) so it might make sense to keep using pydantic for performance reasons. | |||||||||||||||||
|