Pluralis-funktionalitet

11 views
Skip to first unread message

Jimmy

unread,
Jan 20, 2010, 10:42:53 AM1/20/10
to DDD Sverige
Hej alla!

Dan påminde mig om en diskussion vi hade för ett drygt halvår sedan.
Eric Evans och Peter var också med. Diskussionen sprang ur att jag sa
att jag inte gillade att använda ordet repository ihop med
domänexperter (vilket vi ju hade en tråd om här häromdagen). En
detalj, javisst, men ändå en detalj som ofta distraherar. Hur som
helst så hängde Eric på och sa att han funderat mycket på
funktionalitet som distinkt hör ihop med "pluralis-definitionen" av en
entitet och att han inte hittat någon riktigt bra lösning. (Peter och
Dan, var snälla och fyll på för att förtydliga/komplettera!)
:-)

Hur går era tankar kring ovan?

/Jimmy

http://jimmynilsson.com/blog/
http://twitter.com/jimmynilsson

Dan Bergh Johnsson

unread,
Jan 20, 2010, 11:04:52 AM1/20/10
to dddsv...@googlegroups.com
Den 20 januari 2010 16.42 skrev Jimmy <Jimmy....@jnsk.se>:
Hej alla!

Dan påminde mig om en diskussion vi hade för ett drygt halvår sedan.
Eric Evans och Peter var också med. Diskussionen sprang ur att jag sa
att jag inte gillade att använda ordet repository ihop med
domänexperter (vilket vi ju hade en tråd om här häromdagen). En
detalj, javisst, men ändå en detalj som ofta distraherar. Hur som
helst så hängde Eric på och sa att han funderat mycket på
funktionalitet som distinkt hör ihop med "pluralis-definitionen" av en
entitet och att han inte hittat någon riktigt bra lösning. (Peter och
Dan, var snälla och fyll på för att förtydliga/komplettera!)
:-)


I det numer hädangångna EJB2-ramverket gjorde man åtminstone en sak rätt när man i införde "Home"-metoder som hade som syfte att vara just "grupp-operationer". Ett exempel kan vara att i ett bibliotek hitta alla böcker där lånetiden gått ut, anse dem som "saknade" och summera deras värde, vilket man vill ha rapporterat. Uppenbarligen är detta funktionalitet som man inte vill lägga i någon enskild bok, utan skulle läggas i "BookHome"-interfacet.

I DDD-tolkning tycker jag detta blir repository-funktioner, men i och med att det är funktioner med starkt domänlogiskt intresse känns det onaturligt att lägga dem i något som är så "tekniskt" namngivet som "BookRepository".

I just dethär fallet kanske "Library" skulle kunna vara ett naturligt alternativt namn på "BookRepository", men i ett bibiloteks-system är nog den termen mer omfattande än bara boksamlingen. Kanske "BookCollection" skulle kunna vara ett lämpligt namn på funktionalitet och egenskaper som inte finns hos de enskilda böckerna, utan mer i samlingen som helhet.

Ungefär här slår insikten att vi kan kalla denna abstraktion för "Books" kort och gått.

Erics ide gick ytterligare ett steg längre och vidareutvecklade detta till en generaliserad plural-typ "Plural<X>", i detta fall skulle vi skapa "Plural<Book>".

(Sedan försvann diskussionen djupare in i kvällens tema "Pie and Ale" så jag försöker mig inte ens på att rekonstruera vidare tankar från det tillfället.)

   Dan


--
blog: Dear Junior, http://dearjunior.blogspot.com
twitter: @danbjson

Peter Backlund

unread,
Jan 20, 2010, 11:50:05 AM1/20/10
to dddsv...@googlegroups.com
> Dan påminde mig om en diskussion vi hade för ett drygt halvår sedan.
> Eric Evans och Peter var också med.

Jag tror bestämt att du menar Patrik, men det är ok. Jag (vi) är vana
att alla (och jag menar alla) tar fel på våra namn. Min teori är att
det har med tvillingarna Peter och Patrik Sundström att göra.

Patrik, ordet är ditt :-)

Jimmy

unread,
Jan 20, 2010, 1:30:35 PM1/20/10
to DDD Sverige
Oj oj oj, blush, förlåt Peter och Patrik!

/Jimmy

Patrik Fredriksson

unread,
Jan 20, 2010, 1:32:14 PM1/20/10
to dddsv...@googlegroups.com
Hmm, jo, något om Pie och Ale känns vagt bekant.

Lite kan man ju kanske fundera på om det handlar om vad som är viktigt
i samanhanget av det [problem] man försöker lösa. Library skulle ju
också kunna vara en aggregatroot, och aggregatet Library innehålla den
funktionalitet för gruppen Books som man söker. Det skulle alltså
kunna handla lite om var man skär i sin objektgraf. Men det löser
förstås inte problemet, för var slår man upp just den biblioteksfilial
som man vill arbeta med? Poängen är snarare att om det visar sig att
Library har en viktigare funktion i vår modell än "bara" att vara ett
ställe där vi söker efter böcker, så kanske det inte är ett
Repository.

/Patrik

2010/1/20 Peter Backlund <peter.b...@gmail.com>:

> --
> Det här meddelandet skickas till dig eftersom du prenumererar på gruppen DDD Sverige i Google Groups.
> Om du vill göra ett inlägg i den här gruppen skickar du e-post till dddsv...@googlegroups.com.
> Om du vill sluta prenumerera på den här gruppen skickar du e-post till dddsverige+...@googlegroups.com.
> För fler alternativ, besök gruppen på http://groups.google.com/group/dddsverige?hl=sv.
>
>
>
>

--
Web: http://www.citerus.se
Blog: http://weakreference.blogspot.com
Twitter: @weakreference

Tomas Karlsson

unread,
Jan 21, 2010, 11:56:06 AM1/21/10
to DDD Sverige
Hej!


Utan att lägga några värderingar på vad som är bra och dåligt, så
känner jag att det är läge att berätta hur vi har gjort i det projekt
som jag sitter i nu. Lösningen är lite intressant eftersom
"repository" är helt avskaffat i och med att vi väljer att ha en
tjänst på toppen av all information (=domain enligt DDD). Såhär ser
det ut, med Customer som exempel på entitet:

- EJB 3 med SLSB och entiteter
- << SLSB >> CustomerCRD (=crete, retrieve, delete - men inte update.
Återkommer till varför senare)
- På denna CRD-tjänst finns metoder enligt följande mönster:
- CustomerCRD.create(...minsta mängden information som behövs för
att skapa ett - för verksamheten - meningsfullt objekt...)
- CustomerCRD.retrieve(customerId);
- CustomerCRD.retrieveAll();
- CustomerCRD..deleteAll();
Detta är ett minimum för att göra något meningsfullt, kunna testa och
för att rensa setUp() före test.

Finns det fler sätt att skapa (meningsfulla) objekt på så är det bara
att fylla på med metoder som börjar på create. Hämta och radera mer
blir också enkelt. Dessutom så har jag nyligen infört metoder av typen
CustomerCRD.countAll() om man bara är intresserad av antalet och inte
har lust att returnera hela listan och göra List.size() på den. På tal
om returer, så har vi den här strategin:
- create(...) -> ID tillbaka, alltså inte hela objektet. Det beror på
att objekt kan vara riktigt stor
- retrieveXxx(...) -> ett objekt eller java.util.List
- deleteXxx(...) -> void, alternativ kan man argumentera för int med
information om antal objekt som har tagits bort - om det behövs. Jag
tror att jag har implementerat något fall där man vill ha "i object(s)
deleted" som information till användaren.
Object som kommer ut från retrieveXxx(...) ska betraktas som read-only
även om metoderna för uppdatering finns där. Men det här är inget
problem eftersom alla i projektet är väl införstådda med att det är
såhär vi gör. (Vi har funderat på att göra ett interface CustomerVO
som bra exponerar getters, men kommit fram till att det vore att låta
renlärigheten övergå i dumhet. Värdet understiger jobbet med god
marginal...)

Uppdatering görs i en SLSB som heter - lågt odds - CustomerUpdate. Om
Customer.addSomething(something) är en metod på domänobjektet Customer
så finns följande kod:

public void addSomething(UUID customerId, Something something) {
// If something has to be validated against a service/masterdata,
the validation goes here.
Customer customer = em.find(Customer.class, customerId);
customer.addSomething(something);
em.merge(customer);
// Side-effects, for example sending a mail or updating an
alternative model in CQS implementations, goes here.
}

Det är just sidoeffekterna och beroenden till andra tjänster som gör
att vi föredrar att göra alla uppdateringar inom tjänsten. Om det är
risk för "chatty" så kan man implementera "command" på toppen av
detta. Möjligen så kommer vi att behöva en @Local böna också för att
få upp hastigheten i detta lite. Hur som helst, att inte tillåta
"detached objects" ger ett extremt skydd av informationen vilket gör
att vi - utan att tveka särskilt mycket - skulle släppa på ett annat
system för att uppdatera information direkt i vår domän. Inbyggd SOA -
liksom. Den här effekten får man inte alls med ett vanligt POJO som
repository.

Vi har även valt att vara konsekventa, så att alla känner igen sig i
stora delar av koden. I vissa fall blir det lite over-kill, men det
extra jobbet är så litet att värdet av att all kod ser ut på samma
sätt överväger med god marginal.

/Tomas

Tomas Johansson

unread,
Feb 1, 2010, 4:28:00 AM2/1/10
to DDD Sverige
Citatet nedan kommer från tråden "UL på svenska" (
http://groups.google.com/group/dddsverige/browse_frm/thread/d673d49901a4e93f
), men passar bättre in i den här tråden med rubriken "Pluralis-
funktionalitet":

On Jan 18, 10:12 pm, Jimmy <Jimmy.Nils...@jnsk.se> wrote:
> Den namnsättningsstil
> jag har testat lite på sistone vad gäller just repositories är att
> namnsätta i pluralis, t ex så här:
>
> verkstäder.HämtaAllaI(växjö)
> eller
> verkstäderna.HämtaAllaI(växjö)
>

Pluralis brukar ofta användas i variabelnamn för kollektioner, t.ex.
"List<HandlingEvent> handlingEvents" som i exemplet nedan från
referensapplikationen:
https://dddsample.svn.sourceforge.net/svnroot/dddsample/tags/dddsample-1.1.0/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingController.java
private HandlingEventRepository handlingEventRepository;
...
final List<HandlingEvent> handlingEvents =
handlingEventRepository.lookupHandlingHistoryOfCargo
(trackingId).distinctEventsByCompletionTime();

Om jag inte missförstår förslaget att använda pluralis i
namnsättningen i stället för suffixen Repository, så skulle väl
ovanstående kod i stället se ut så här:
private HandlingEvents handlingEvents;
...
final List<HandlingEvent> handlingEvents =
this.handlingEvents.lookupHandlingHistoryOfCargo
(trackingId).distinctEventsByCompletionTime();

såvida man inte kanske vill döpa om variabeln till något annat, t.ex.
final List<HandlingEvent> handlingEventList =
handlingEvents.lookupHandlingHistoryOfCargo
(trackingId).distinctEventsByCompletionTime();
(vilket är en typ av namnsättning som också används i
referensapplikationen, t.ex. här:
https://dddsample.svn.sourceforge.net/svnroot/dddsample/tags/dddsample-1.1.0/src/main/java/se/citerus/dddsample/interfaces/booking/facade/internal/BookingServiceFacadeImpl.java
final List<Cargo> cargoList = cargoRepository.findAll();
)

Det sistnämnda tycker jag nog inte är alldeles optimalt, dvs att
använda ett variabelnamn där ordet List ingår.
Det kan nämligen tolkas på olika sätt, t.ex. som att variabelnamnet
syftar till att beskriva att datatypen är en List<HandlingEvent>
snarare än att den är av t.ex. typen Collection<HandlingEvent> eller
Iterable<HandlingEvent>, vilket inte nödvändigtvis kommer att vara
sant vid en refaktorisering som byter från List till Collection utan
att samtidigt ändra variabelnamnet till exempelvis
handlingEventCollection.
Å andra sidan behöver man inte nödvändigtvis tolka suffixet List som
den specifika dataypen List, utan snarare som ett generellt koncept
List, men eftersom det råkar finnas en sådan datatyp så kommer nog
vissa utvecklare att tycka att det är missvisande att namnsätta en
variabel av t.ex. typen Collection med List-suffix.
Med andra ord är det nog lite subjektivt om man t.ex. tycker att något
av följande skulle se okej ut:
Collection<HandlingEvent> handlingEventList
Collection<HandlingEvent> listOfHandlingEvents
men det kan man alltså tycka om man betraktar List som ett koncept
snarare än att tolka "List" i ett variabelnamn som den specifika
datatypen List.

När det gäller plural versus repository-suffix så tycker jag i alla
fall att följande borde se tydligare ut för alla som känner till ett
DDD repository:
List<HandlingEvent> handlingEvents =
handlingEventRepository.lookupHandlingHistoryOfCargo(...)
jämfört med
List<HandlingEvent> handlingEvents =
this.handlingEvents.lookupHandlingHistoryOfCargo(...)

Man skulle också kunna förbättra den sista raden ovan (och därmed som
en positiv bieffekt minska förrvirringen av namnkollisionen) genom att
man försöker vara konsekvent med att inte använda sig av sådana icke-
specifika variabelnamn, utan i stället försöker lägga in mer semantik
i variabelnamnen för sina listor, t.ex. så här:

final List<HandlingEvent>
distinctCargoHandlingEventsSortedByCompletionTime =
this.handlingEvents.lookupHandlingHistoryOfCargo
(trackingId).distinctEventsByCompletionTime();


/ Tomas

Reply all
Reply to author
Forward
0 new messages