POCO or DTO?

  Рет қаралды 15,153

Ardalis

Ardalis

Күн бұрын

Пікірлер: 48
@tunawithmayo
@tunawithmayo 4 ай бұрын
I like the term Passive Data Object; PDO. If you're going to transfer something to somewhere else you might call it a DTO, but it is implicitly just a Serializable.
@Miggleness
@Miggleness 4 ай бұрын
I don’t know. I don’t want to ask the question “have you created the ‘p-do’ class yet?”
@Ardalis
@Ardalis 4 ай бұрын
I've never seen that term before. You're welcome to try to make it a standard term, but regardless you'll run into folks already using the terms DTO and/or POCO in the dev community today. As I noted in other comments, it's useful for everyone to understand these terms so when folks use them, there's no confusion.
4 ай бұрын
”Microservices experiment” :) I have been there.
@Ardalis
@Ardalis 4 ай бұрын
:)
@alphamaster2
@alphamaster2 4 ай бұрын
Now lets throw "Model" into the mix
@Ardalis
@Ardalis 4 ай бұрын
Yeah, that's an overloaded term, which is why usually it's prefixed. There's Domain Model on one end and ViewModel on the other. I also see (and have used) ApiModel (since there are no views) as well, and a host of other variants. Domain Models should not be DTOs but ideally should be POCOs as much as possible. ViewModels in MVC should be DTOs, typically. But in MVVM frameworks ViewModels are where the logic lives, so it's not a 100% rule at all - depends on context. ApiModels I've only seen in MVC and are just used for transferring data over the wire, so should be DTOs.
@simonkalu
@simonkalu 3 ай бұрын
Nice... Thanks for sharing
@Ardalis
@Ardalis 3 ай бұрын
Welcome 😊
@mgkeeley
@mgkeeley 4 ай бұрын
Where do you think validation should go? On the DTO? Or in the ingress function that accepts the DTO? For our internal Model classes, our team likes to do validation in the constructor; but I'm not so sure that is really necessary. Validation should perhaps only be for external interfaces?
@VoroninPavel
@VoroninPavel 4 ай бұрын
Both ;-) DTO requires structural correctness (required fields have values of the required length, etc), POCO (or Behavior Rich Object) guards business invariants. As you told, this is usually a responsibility of constructor or method whcih mutate state. And ther's also a validation which covers a set of aggreates, this is effectively a buiness requirement.
@ErazerPT
@ErazerPT 4 ай бұрын
Think. What is validation? Behavior. What does DTO's NOT have? ... Or to put it simply, it it has anything but data, it might be many things, a DTO is NOT one of them. Which is why, IMHO, thinking about DTO's without instantly thinking "Interfaces at transmission boundaries" is deleterious, because it muddies the waters if there is no a) interface or b) transmission. Structure it like this, for a "perfect world": - there's a plain data class PDC that presents the DTO in it's simplest form, ie, plain data - there's an interface PDI that presents the DTO in it's simplest form, ie, plain data - PDC, by force of definition implements PDI and should have a constructor that takes in PDI to create a PDC - there's a business class BC that has a .New(PDI) method that returns BC ( if all is well ), or even a Tuple where enum represents either OK or some error - at the egress side of the transmission, you create a PDC, and ship it out as PDI Now at the ingress side of the transmission you have two options: - you receive PDI and turn it into PDC via PDC's PDI constructor, and pass it around as plain data, which has no guarantees of sanity, or - you receive PDI and turn it into BC via BC's .New(PDI) method. And HERE is where you perform validation. If all is well, the data was sane and you move forward, if not, you do whatever is appropriate While this might sound like a lot of work, it's a minute or two per DTO, and literally peanuts if you do it from the go. And you win on the fact that a) both sides MUST respect the interface and nothing but the interface and b) with strong "gatekeeping" of the interface, nobody will go around changing it willy nilly and breaking things. It might ruffle some feathers at the start, because some people are cowboys, but eventually they "fall in line".
@Ardalis
@Ardalis 4 ай бұрын
I prefer separate classes for non-trivial validation, using a library like FluentValidation. This keeps DTOs from having this. I will say that it's generally fine for DTOs to have *static* methods on them for things like validation or mapping, for instance. The *objects* are DTOs and have no behavior; the static methods are just functions that happen to be attached to those class definitions. You generally do not want to have a bunch of guard clauses or constructor-enforced rules in your DTOs. They should just be getters and setters. No encapsulation. No checks. They can have attributes to assist with validation. Why? Because you don't want serialization/deserialization to fail midway or with an exception. You'd almost always rather have a nice list of validation errors than a serialization exception with a stack trace.
@Ardalis
@Ardalis 4 ай бұрын
I don't usually use interfaces for DTOs - in fact that's a likely subject of an upcoming video. There are times when it's useful but most of the time the DTO *is* the contract and there's no need to add another type that mirrors it. I have seen some good uses cases for using interfaces with DTOs but usually they're not 1:1 but rather an interface that requires a certain subset of properties that many different DTOs might have which then allows for those DTOs to be treated a certain way collectively. But having one interface for ever one DTO class isn't something I've seen value in.
@ErazerPT
@ErazerPT 4 ай бұрын
@@Ardalis I don't use it as a requirement but as a "nice to have". IMHO, the interface defines the DTO and the DTO implements the definition. By using an interface, which by definition is JUST a contract, both side are STRONGLY discouraged from relying on any internals of the DTO. Or even thinking about them ;) It does add a bit of work on the deserialization side, but i find that to be worth it in the long run.
@kwameaddo1007
@kwameaddo1007 4 ай бұрын
Thank you
@Ardalis
@Ardalis 4 ай бұрын
You're welcome
@ItsSalesGabriel
@ItsSalesGabriel 4 ай бұрын
Nice video, tkss
@Ardalis
@Ardalis 4 ай бұрын
You're welcome!
@kurokyuu
@kurokyuu 4 ай бұрын
Does a record really fit into the dto defintion? There's bunch of compiler generated code like PrintMembers, Deconstructer, a different constructor where you can also pass the record and it'll set the values from the object. it has it's own equality operators and stuff like that. Wouldn't a record in this case be more like a Poco since it has behaviour. If you're really nitpicky under the hood properties are compiled down to getter/setter which then change a private backing field~ Or, to come back to the main question, does compiler generated code not count and as long as you don't put custom code in it the record would still be considered as a dto?
@Ardalis
@Ardalis 4 ай бұрын
You're not wrong, records *do* have a bunch of behavior, but it's mostly hidden away. They're very frequently used purely for data transfer purposes, though, which is why I tend to consider them DTOs by default, assuming no methods are added to them. Of course once you add your own custom/bespoke methods to your records, they cease to be DTOs.
@kurokyuu
@kurokyuu 4 ай бұрын
@@Ardalis Okay, thanks for the answer. I'm using records too very often since they're very handy if your data-object is not too complex, and can be created very fast. One of the best features they've added into C#.
@josephmoreno9733
@josephmoreno9733 4 ай бұрын
@@kurokyuu Take care, most of the built-in behaviors in records are not used but can increase the complexity of some scenarios, especially when using AOT.
@VitaliiShmidt-UA
@VitaliiShmidt-UA 4 ай бұрын
Which kind of behavoir in Domain models do you talk about? Didn't get that one. All the examples of DDD's structure that I've seen uses anonymic domain-models.🤔
@Ardalis
@Ardalis 4 ай бұрын
Like these, for very simple examples: github.com/ardalis/CleanArchitecture/blob/main/sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Project.cs github.com/ardalis/CleanArchitecture/blob/main/sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItem.cs Obviously in real world systems there would be even more special cases, invariants, events, etc.
@VitaliiShmidt-UA
@VitaliiShmidt-UA 4 ай бұрын
@@Ardalis very interesting, thank you for sharing 🫡
@jz5153
@jz5153 4 ай бұрын
To be honest this knowledge will be useful on interview and only there :).
@yetanotherdex
@yetanotherdex 4 ай бұрын
not quite. just had a discussion about this with a dev 2 days ago
@Ardalis
@Ardalis 4 ай бұрын
This would be a pretty dumb interview question to ask, IMO. It's useful mostly for clarity on teams. If one team members suggests to another to use a DTO for something, that *means* something specific. Likewise if a complicated class is depending on some 3rd party library, suggesting replacing it with a POCO means something very clear as well... as long as you know what a POCO is. If you think POCO and DTO are the same thing, you're going to be be confused (or make the wrong change).
@br3nto
@br3nto 4 ай бұрын
@@ArdalisI don’t think DTO is a useful concept to talk about. It’s useful to talk about the design of the public APIs of your app; e.g where there are modular boundaries, network boundaries, public API boundaries, it’s useful to talk about what that interface looks like. But the language used should always use the terminology of the problem domain - e.g a web request returns a response; it doesn’t return a DTO. Based on the primacy of your chosen domain model nomenclature, DTO or Dto should never be added to a class name or namespace. Otherwise you’d get superfluous names like “Responses.UsersDto” or “UsersResponseDto” or “Dtos.Users”.
@kaustavchakraborty3244
@kaustavchakraborty3244 4 ай бұрын
So the classes the Mediatr library uses as commands are not either DTO or POCO, as it depends on an interface.
@Ardalis
@Ardalis 4 ай бұрын
They don't have behavior, so I consider them to be DTOs. You're correct, they're not POCOs, because they require a (marker) interface to function. My next video will probably be on the topic of interfaces and DTOs (and then I hope to move away from the whole DTO topic, but I might do ONE more after that).
@kaustavchakraborty3244
@kaustavchakraborty3244 4 ай бұрын
@@Ardalis looking forward to that.
@redspidermkv4525
@redspidermkv4525 4 ай бұрын
I'm a little confused.. your DTOs have public setters but the POCO you demonstrated with an Update method isn't a DTO. So a DTO can only have a default setter, if you have logic in your setter (or getter) its not a DTO?
@Ardalis
@Ardalis 4 ай бұрын
Correct. DTOs are just properties. I mentioned in another comment you could have static methods for mapping or validation or whatever and that doesn't break this rule because they're not on the instance.
@nkesteren
@nkesteren 4 ай бұрын
All these years I felt free to share a video with friends. Oh noes. 😂 👍😉
@Ardalis
@Ardalis 4 ай бұрын
What? Without explicit permission from the KZbinr? How could you! 😉
@peepeefrog_
@peepeefrog_ 4 ай бұрын
Why would I care about the theoretical definitions?
@JansthcirlU
@JansthcirlU 4 ай бұрын
Rumpelstiltskin principle
@Ardalis
@Ardalis 4 ай бұрын
For better team communication mainly. If one team members suggests to another to use a DTO for something, that *means* something specific. Likewise if a complicated class is depending on some 3rd party library, suggesting replacing it with a POCO means something very clear as well... as long as you know what a POCO is. If you think POCO and DTO are the same thing, you're going to be be confused (or make the wrong change).
@br3nto
@br3nto 4 ай бұрын
The difference between a POCO and a DTO: a DTO has Dto in the class name or namespace. TL;DR - don’t do that. They are both just classes, records, or structs. All classes, records, and structs are used to transfer data, otherwise there wouldn’t be a point to them. I’ve never encounter a situation where it’s useful to make a distinction that a POCO is being used as a DTO, because that’s just naturally what they are for. It’s just not useful to talk about Dto’s. Maybe you have some classes that specifically represent the API between an app boundary like between modules, or returned from web requests, or from library calls; it’s better to name these classes based on your domain model - a class, record, strict, or namespace should never have Dto or DTO in the name.
@Ardalis
@Ardalis 4 ай бұрын
Yeah like I said elsewhere, use the “Dto” suffix as a last resort. And no, not all classes are used to transfer data. Consider any service, and in particular stateless services.
@occularmalice
@occularmalice 4 ай бұрын
We still have to explain the difference between POCOs and DTOs to people in this day and age? Faith in humanity lost.
@Ardalis
@Ardalis 4 ай бұрын
Every day someone starts their programming journey. Actually, a lot of someones...
5 Rules For DTOs
17:56
Ardalis
Рет қаралды 45 М.
Sqlite Is Getting So Good
28:52
ThePrimeTime
Рет қаралды 208 М.
coco在求救? #小丑 #天使 #shorts
00:29
好人小丑
Рет қаралды 45 МЛН
СКОЛЬКО ПАЛЬЦЕВ ТУТ?
00:16
Masomka
Рет қаралды 3,6 МЛН
What's New in .NET 9 with Examples
25:02
Nick Chapsas
Рет қаралды 53 М.
Domain-Driven Design: The Last Explanation You'll Ever Need
21:05
Software Developer Diaries
Рет қаралды 11 М.
Car Management System: Complete GO Lang Project
4:40:00
Code Alley with Anurag
Рет қаралды 2,4 М.
.NET and C# are in trouble. Here is what I'd do.
10:57
Ed Andersen
Рет қаралды 107 М.
Testing in .NET is About to Change
12:54
Nick Chapsas
Рет қаралды 83 М.
Linus Torvalds: Speaks on Hype and the Future of AI
9:02
SavvyNik
Рет қаралды 263 М.
C# Primary Constructor Tips
17:03
Ardalis
Рет қаралды 4,8 М.
Using Ardalis Specifications with EF Core 8
13:06
Ardalis
Рет қаралды 7 М.
What's New in Clean Architecture Template 9.1
11:27
Ardalis
Рет қаралды 15 М.
coco在求救? #小丑 #天使 #shorts
00:29
好人小丑
Рет қаралды 45 МЛН