DTO og entity
Fire slags objekter, der ligner hinanden
DTO'er bliver tit forvekslet med entities og value objects, fordi de alle sammen indeholder data. Forskellen ligger i, hvad de bruges til, og hvem der ejer dem.
| Type | Formål | Identitet | Logik | Lever |
|---|---|---|---|---|
| DTO | Flytte data over en grænse | Nej | Ingen | Kort, under ét kald |
| Entity | En ting i domænet, fx en ordre | Ja, et id | Forretningsregler | Længe, ofte i en database |
| Value object | En værdi, fx et beløb med valuta | Nej, kun værdien | Små regler om værdien | Som en del af en entity |
| View model | Data formet til én skærm | Nej | Visningslogik | Kort, under visningen |
Entity
En entity er noget med en identitet, der varer ved. En ordre er stadig den samme ordre, selv om der kommer en ny linje på. Entities indeholder forretningsreglerne, fx at en afsendt ordre ikke kan ændres, og de bliver typisk gemt i en database, ofte gennem en ORM.
Value object
Et value object er defineret af sin værdi og ikke af en identitet. To beløb på 100 kroner er det samme beløb. Value objects er uforanderlige og kan indeholde små regler, fx at et beløb ikke kan lægges sammen med et beløb i en anden valuta.
DTO
En DTO har hverken identitet eller regler. Den er en pakke med data, som kun findes for at blive sendt et sted hen. Den kan godt indeholde værdier fra både entities og value objects, men i en enkel form, der er let at serialisere.
View model
En view model er formet efter én bestemt skærm. Den kan fx indeholde en færdigformateret pris og en tekst til en knap. Den ligner en DTO, men den hører til i brugerfladen og ikke i API'et.
Hvorfor ikke bare sende entity'en?
Det er fristende at returnere sine entities direkte fra et API, og i et lille projekt kan det gå. Men det giver nogle velkendte problemer:
- Du sender for meget. Felter som adgangskode-hash, interne noter eller rabatsatser kan slippe ud.
- Klienten kan sætte for meget. Hvis den samme klasse bruges til at tage imod data, kan en klient måske sætte felter, den ikke burde, fx en rolle eller en pris. Det kaldes mass assignment eller over-posting.
- API'et bliver bundet til databasen. Omdøber du en kolonne, ændrer du samtidig dit API og får klienterne til at fejle.
- Serialisering kan gå galt. Relationer mellem entities kan give uendelige løkker eller hente store mængder data, når objektet bliver lavet om til JSON.
En DTO løser alle fire: den indeholder kun de felter, du vælger, i den form, du vælger.
Hvornår er en DTO for meget?
I et lille internt værktøj, hvor databasen og brugerfladen altid ændres sammen, kan ekstra DTO-klasser være spildt arbejde. Tommelfingerreglen er: jo flere klienter, og jo længere API'et skal leve, jo mere betaler en DTO sig.