Jag hade en diskussion med en person i fall man ska låta sina entiteter i affärslagret vara åtkomliga i GUI:t. Jag föredrar nog att man ska kunna tex skicka upp ett customer-objekt till GUI:t via en repository eller liknande. GUI:t gör sedan ändringar i objektet och skickar därefter ner det till repositoryn igen. Jag tycker att det låter som en sund ide. Vi brukar separera domänobjekt från direct acces från ev. gui genom att använda "data transfer objects". Det ger bra separation mellan gui och domän modell. Det är just användningen av DTO som jag är lite fundersam till. Det låter vettigt att separera GUI och domän modellen åt men samtidigt tror jag vinsten rent generellt är relativt låg i en icke distrubuerad applikation. Hej Krister, /om/ applikationen är 1 tier så håller jag med. Men om tanken är att det skall vara mer än 1 tier så måste man börja fundera på vad man skickar över nätverket och varför. Jag håller med dig i det du säger, Johan. Syftet med DTO:er är väl bland annat det du tar upp, Patrik, dvs att minska nätverkstrafik genom att foga samma det man behöver i ett objekt. Detta tycker jag dock går mycket in på distrubuerade applikationer eller där applikationslagren ligger på olika servrar. Jag tror man skall börja med att skilja på vad du och din kompis diskuterade egentligen. Det verka på dig som du använder dig av DTO-objekt som ditt BLL opererar på, medans din kompis har en domän-modell där objekte är både databärare och businesslager. Det är ju 2 helt olika sätt att angripa problemet på och kommer även ge upphov till olika lösningar för att visa datat i GUI:et. "Är det inte mer intressant att se på om applikationen är distribuerad eller om applikationslagren ligger på skilda servrar än vilken tier det är? För de flesta applikationer är ju inte 1-tier applikationer." Ajdå, jag blandade ihop tier och lager med varandra :) Men det verkar som vi håller med varandra. Jag är nästan säker på att vi prata pratade om samma sak. Om du tittar på tex den länken som Andreas tipsade om: http://www.infoq.com/articles/ddd-in-practice Services i DDD och i SOA är inte samma sak. En service i DDD är en klass som hanterar bussiness cases som inte passar in i själva domänmodellen. Instämmer med Patrik. Services i denna diskussion syftar till det "service layer" som Fowler beskriver i POEAA (http://martinfowler.com/eaaCatalog/serviceLayer.html) . Dvs det lager som "frontar" för all affärsfunktionallitet. Ok, jag tror det jag kallar för fasadlager är detsamma som servicelager i DDD. Om jag inte minns helt fel så har jag nog gjort någon sådan notering i Fowlers bok. Jag upplever ofta att gui:t har ett behov av att presentera data i ett mer "aggregerat" format än det som entiterna representerar. I detta fallet ser jag nog inga problem med att använda en DTO för att returnera "komplex" datastruktur. Jag trodde du använda DTO:er på en mycket lägre nivå än bara aggregat, dvs för väldigt enkla entitetet också. Tex om vi fortsätter på ditt boksajtexempel så skulle varje entitet ha en DTO, dvs book -> bookDTO, image -> imageDTO, category -> CategoryDTO. Vi antar att du har ett enkelt administratörsgränssnitt för att lägga till och ändra kategorier. I nedanstående exempel har category endast en egenskap: Om du bara korsar layers behöver du inte ha 1-1 mappning av DTO -> DM klasser. Det var ett bra uttryck, "1-1 mappning"! Det är just denna form av mappning som jag inte förstår mig på och som jag ifrågasätter. Det låter bra att få bort beroendet mellan GUI och BLL men när det kommer till 1-1 mappning så tycker jag det skapar mer jobb än nytta. Det känns mer som att man följer en princip lite för strikt. Varje abstraktion behöver ett syfte, delar du tiers så är det intressant med 1-1 mappning av den enkla anledningen att du skall kunna ändra insidan av ett tier utan att påverka konsumenters beroenden. Det finns fler fördelar med 1-1 för tiers. Men för 1-tier så genererar de egentligen bara mervärde om de också agerar presentation model (Fowler) eller används till någon annan form av projicering (rapportering etc). Det stämmer att jag oftast brukar köra DTO:er för även "enkla" entiteter (ex. CategoryDTO i ditt exempel ovan). Dock så brukar vi även använda riktlinjen att där det är praktiskt genomförbart använda "value-typer" i anrop till service-lagret och endast använda DTO:er för data som returneras. Så i exemplet med admin av katagorier så skulle det bli något stil med: Jag håller med Krister, det låter som lite väl mycket jobb att ha ett objekt för presentation och ett i BLL som representerar en entitet. Det känns som att det bara är relevant vid distribuerade system. En lösning är ju att gömma funktionaliteten för andra lager via internals som Patrik skriver eller att ha interface för varje entitet som visas utåt. Validering av datan finns givetviss i mina entiteter eftersom jag tycker att vis validering inte skall behöva en rundtrip neråt för att valideras. Och det är så validering som om de är null, eller personnummer-kontroll osv osv.. Ok då är jag med dig. Vill citera Andrew Hunt gällande alla frågor och synpunkter. "It depends!" :-) Jag använder domän modellen så mycket som möjligt i GUI:it. Ett fåtal gånger har jag skapat presentationsentiteter när det finns behov för presentationsspecifika attributer och logik (tex FullName, Color, etc). Nej jag menar internal :) Mitt favorit attribut är "internalsvisibleto" vilket låter mig styra vilka andra dller / exe som får direkt access till interfacen. På det sättet kan jag säkerställa att bara mitt presentationslager och mitt bussinesslager, tex, kommer åt den logik jag tänkt mig. Ok, nu förstår jag bättre, låter intressant. Har använt en liknande metod (en entitet som implementerar flera interface med olika fokus) fast inte internal interface. Entiteter åtkomliga i GUI:t?
Detta sätt fungerar väl relativt bra i icke distruberade applikationer. Eller hur ser ni på det hela? Fördelar/nackdelar?Sv: Entiteter åtkomliga i GUI:t?
http://www.infoq.com/resource/articles/ddd-in-practice/en/resources/ArchitectureDiagram_lg.gif
(http://www.infoq.com/articles/ddd-in-practice)Sv:Entiteter åtkomliga i GUI:t?
Jag tror Johan Normén förespråkar något liknannde om jag inte missförstått honom. Johan, du kanske kan dela med dig av dina tankar :)Sv: Entiteter åtkomliga i GUI:t?
Glad midsommar får jag väl börja med, även om det regnar här :-(
Japp jag ser inget fel med att göra på det sätt du gör. Då du har entiteterna i domänlagret så är det oxå rätt självklart att det är dem man använder i Sitt UI. Applicerar man MVC möntret så kan man ex se Vyerna där som ens entiteter.
DTOer använder jag i de fall jag har flera olika UIs från olika medier, mobil, web etc..
Jag binder även listor med mina domänobjekt mot ex griddar m.m. Detta för att jag vill att alla mina dataitems skall spegla värdlen så mycket som möjligt och att jag vill ha så mkt OO/OOP i min applikation jag bara kan. Detta för att jag förespråkar lättläst och självbeskrivande språk samt enklare modifierbar kod före något annat. På så vis blir allt annat automatiskt lättare m.m.
Nu skall jag rusa till bilen, åka till Lysekil och fira midsommar i regnet... Ha det gott Krister...
Vi hörs... Hoppas se dig på nästa SweNug i höst :-)
Mvh JohanSv:Entiteter åtkomliga i GUI:t?
Är en produkt alltid en produkt och behöver jag alltid skicka all produktinformation fram och tillbaka?Sv:Entiteter åtkomliga i GUI:t?
Det kan dock finnas fall där man inte vill låta GUI-lagret komma åt tex vissa av objektets metoder men det ser jag som ganska sällsynta fall. Då finns det också andra vägar man kan gå än att använda sig av DTO:er.
Det som jag inte gillar med att mappa sina domänobjekt mot DTO:er är att det dublicerar kodmängden, ökar förvaltningen samt komplexiteten. Jag vet inte om jag missförstod dig gällande en mening du skrev men jag tycker att mappning av domänobjekt mellan tex GUI och BLL är mer "strikt" OO än om man gör sina domänobjekt åtkomliga i GUI:t. Detta för att man bland annat bygger upp ett mindre beroende mellan GUI och BLL och lättare kan byta ut sitt BLL mot ett annat. Det låter bra när det sägs men jag tycker det blir lite av överdesign av arkitekturen.Sv: Entiteter åtkomliga i GUI:t?
Är det inte mer intressant att se på om applikationen är distribuerad eller om applikationslagren ligger på skilda servrar än vilken tier det är? För de flesta applikationer är ju inte 1-tier applikationer.Sv: Entiteter åtkomliga i GUI:t?
Själv brukar mina entiteter endast innehålla data och dessa skickas mellan de olika lagern/applikationern som databärare, och sedan så får mina BLL opererar på dessa entiteter. Frågan blir då hur mycket man kan återanvända dessa entiteter, alltså kan jag ha samma entitet i 2 olika services, eller skall det vara 2 olika entiteter som skall mappas emellan?
Ibland så blir det samma entitet som delas mellan de olika servicerna och ibland blir det olika entiteter som måste mappas mellan de olika servicerna. Men generellt så kan jag säga att ju fler som kommer vilja använda servicen destu viktigare blir det att den inte är beroende av något annat.
- MSv:Entiteter åtkomliga i GUI:t?
Tier = fysisk separation, Layer = logisk separation. Så jo, väldigt många applikationer är 1 tier men massor av layers.
Det man måste vara nog med är att man har en tillräckligt hög "separation of concern" i sina lager så att /om/ man behöver distribution så skall man inte behöva slita isär hela sin applikation.
Det gör man vanligtvis genom att börja med att använda sin domänmodell som den är även i en 1-tier applikation. Om man vill dölja delar av sin domänmodell eller hantera access till den så kan man antingen använda Presentation Models (Fowler) eller Local Services (Evans) för att kapsla in GUI't access till den underliggande domänmodellen. PM jobbar som ett lager ovanför DM och LS som ett lokalt tjänstelager som står för funktionaliteten och abstraktionen av den underliggande modellen och tillhörande infrastruktur.
Sv: Entiteter åtkomliga i GUI:t?
Sv:Entiteter åtkomliga i GUI:t?
I den artikeln står det bland annat så här: "From a DDD perspective, DTO's also help maintain the separation between Service and UI layers where DO's are used in the domain and service layers and DTO's are used in the presentation layer.".
I och för sig, nu när jag tänker efter så verkar den lösning som man tar upp baseras på distrubuerade applikationer. För man pratar om ett service lager och via ett sådant kan man skapa ett bättre stöd för distrubuerade applikationer. Men om man i princip vet att det inte är en distrubuerad applikation då ser jag det som överdesign att använda sig av DTO:er. Eller hur ser du på det?Sv: Entiteter åtkomliga i GUI:t?
Sv:Entiteter åtkomliga i GUI:t?
En regel vi brukar köra med är att användargränssnitt, web-services , "Dataladdningsmojänger" osv endast får referera till detta lager. Detta för att på så sätt se till att domän logik inte "läcker" ut till gui:n m.m.
Jag håller dock med om att det blir mer "kod att skriva" så användetdet måste alltid avvägas mot nyttan. ( så i mindre applikationer kanske det inte alltid är nödvändigt att vara "strikt") Då ca 80% totalkostnaden för ett system ligger i förvaltning så tycker jag att fördelarna med tydliga lager och bra inkapsling oftast motiverar användandet av DTO:er.Sv: Entiteter åtkomliga i GUI:t?
Du säger att inkapslingen blir bra när du använder dig av DTO:er och det håller jag med om att den blir om man kör det strikta spåret. Men har ni upplevt någon nytta av denna inkapsling? Ge gärna något konkret exempel på vilket sätt den har det. Jag ska ta mig en funderare där också :) Någon annan får gärna också dela med sig av sina erfarenheter i området. Patrik eller Johan har ni några mer tankar kring detta? Det låter bra med inkapsling men har vi nytta av det i en icke distrubuerad applikation?Sv:Entiteter åtkomliga i GUI:t?
Ett exempel kan vara sökresultat för en boksajt. Där har du förmodligen entiteter för book, publisher,image, category osv. Men när du söker vill du returnera en IList<SearchResultDTO> som gui:t kan visa en i nån form av lista med sökresultat.Sv: Entiteter åtkomliga i GUI:t?
CategoryDTO Category = new CategoryDTO();
Category.Name = "Fun";
...Insert(Category);
Skulle du använda DTO:er även på denna låga nivå, just för att uppnå inkapsling?
(Jo, en sak till. Man behöver väl egentligen inte returnera en DTO i boksajtsexemplet. Det beror väl lite på hur man byggt upp sin bokentitet. Men det är en annan fråga. Den tar vi inte här.)Sv:Entiteter åtkomliga i GUI:t?
Däremot skall man fundera litegranna på vad man egentligen är ute efter. Som jag sa förut, är en produkt alltid en produkt för alla aspekter av din applikation? Eller är det Produkt, ProduktLeveransInformation, ProduktLagerInformation osv?Sv: Entiteter åtkomliga i GUI:t?
Sv:Entiteter åtkomliga i GUI:t?
Däremot skall man vara förskitig med vad man lämnar ifrån sig från BLL. Om DM har en massa bussiness logik som inte skall kunna anropas från ett GUI gör man klokast i att gömma dem på ett eller annat sätt.
Min favorit just nu är internal interface med explicita implementationer. (Man kan sätta attributet internalsvisibleto för att visa det för alla projekt i sitt BLL).
Då ser DM ut som DTOer så länge jag inte tittar på dem genom mitt logik interface.
Fast jag kommer säkert hitta ngn anledning till att inte gilla det imorgon ;)Sv:Entiteter åtkomliga i GUI:t?
//list all categories for display in dropdown
IList<CategoryDTO> categories = adminService.GetAllCategories();
.....
//Create new category
CategoryDTO newCat = adminService.CreateCategory("My new category","Some other property of the new category");
Logger.DebugFormat("New category with id: {0} created",newCat.Id);
.....
//Delete category
adminService.DeleteCategory(3);
Detta för att skapa tydliga gränssnitt samt att slippa instantiera en massa DTO:er i onödan. Sv:Entiteter åtkomliga i GUI:t?
Jag håller också med Johan's inlägg i tråden.
Min fråga till Magnus är där han skriver att hans entiteter bara är databärare, finns det aldrig tillfällen där du lägger logik i dina entiteter t.ex. validering av värden om de är null eller ej. Samt skapande av relationer t.ex. om jag har en Order.AddOrder(orderItem); som kopplar Order till orderItem och orderItem till Order? Men oftast så innehåller inte Entiteterna så mycket logik.Sv: Entiteter åtkomliga i GUI:t?
Dessutom så när man använder entiteterna med bindings, så kommer det en del logik i dessa, men det är inte unika för programmet. Det viktiga tycker jag att man inte använder logik i entiteterna som är unikt för en applikation, utan om jag vill ta mina entiteter och använda i en annan applikation så skall jag kunna göra det. Det är där som jag lägger riktlinjen. Tyvärr fungerar det inte alltid, och i mitt senaste projekt så har jag knutit mina entiteter väldigt hårt till det projektet, och dessa kan inte användas någon annanstans....
Men det bygger på att man har en gemensam domänmodell, där man har definerat upp hur en Person skall se ut, eller en Order. Och sedan så kan alla projekt använda sig av dessa, och behöver de implementera egen logik eller egna properties så får man ärva från dessa och skapa sin egen person-entitet. Det man vinner här är att väldigt sällan så behöver man lägga till jättemycket till dessa entieter, oftas rör det sig om några egenskaper som är unika för projektet och vips så har man sluppit mycket kod...
Själva logiken för koppla orderrader till en order, har jag inte i mina entiteter, de finns i affärslagret, skicka ner order och orderraden, sen får affärslogiken göra kontroller och sedan lägga till orderraden till order, eller så finns det en lista med orderrader i order som man gör Add() direkt på. Helt beroende på om det skall finnas kontroller eller ej med när man lägger till orderraden. Kan väl säga att det alltid börjar med en lista och när behovet av valideringar kommer till så flyttar jag ner det till mitt affärslager.
- MSv:Entiteter åtkomliga i GUI:t?
Även om jag hade lagt valideringskontrollen av t.ex. ett orderitem på Order objekt. Där jag kan styra kontrollen utanför Order med Open Closed principen. Men det är ju en smaksak :)Sv: Entiteter åtkomliga i GUI:t?
Det är så vi bygger vår arkitektur, allt beror på, och det är som Patrik säger, är det 1 skikt? eller fler skiktsapp, skall ens entiteter kunna accessas från flera olika UIs från olika skikt, skall en entiteter vara kontrakt i WCF etc etc... Hur man då löser detta är helt enkelt en "It depends!"...
Spelar ingen roll hur mkt man tycker det kan bli dubbel kod, dvs Category inkl business logik vs CategoryDTO utan business logik. Båda finns där för olika syften baserat på krav.
CategoryDTO kanske t om har färre attribut (OO ord för Properties) än sitt orginal etc etc.
DTOer och Entitete blir bara redundant kod i mina ögon när man använder dem för samma sak och inte anpassar dem för dess syften. DTO är en bärare medans entitet är ett tillstånd.
Mvh JohanSv:Entiteter åtkomliga i GUI:t?
Jag försöker använda DTO objekt så lite som möjligt pga av den extra overhead (i kodmängd) som krävs (en till klass, plus mappning), men dom har sina användningsområden, tex om man ska exponera data via en web service.
Vet inte riktigt om jag förstår Patriks lösning "internal interface med explicita implementationer." Du menar väll att de explicita implementationerna är internal och interfacet är publikt?? För det är ju en intressant lösning, men blir det inte problem om GUI-lagret, tex en controller i ett MVC scenario vill skapa ett nytt domän objekt?
/Torkel Sv: Entiteter åtkomliga i GUI:t?
Lösningen ser ut ungefär så här:
internal interface IProductBasicInformation
{
string Name;
int Id;
}
internal interface IProductForPricing : IProductBasicInformation
{
decimal Price;
}
public class Product : IProductBasicInformation, IProductForPricing
{
string IProductBasicInformation.Name {get; set;}
string IProductBasifIncormation.Id {get; set;}
decimal IProductForPricing.Price {get; set;}
}
Typ sådär. Det fina med det här är att NH klarar av att mappa mot det också. Jag håller på att skriva en artikel för infoQ, en kortare blogpost och skall prata om det här på Öredev i höst (och förhoppningsvis på TechEd). Länk till öredev här: http://www.oredev.se/topmenu/program/trackarchitecture/patriklowendahl.4.3efb083311ac562f9fe80001055.html
>>men blir det inte problem om GUI-lagret, tex en controller i ett MVC scenario vill skapa ett nytt domän objekt?
Nej egentligen inte. Du använder factories som skapar objekten iaf. Sv:Entiteter åtkomliga i GUI:t?