»
S
I
D
E
B
A
R
«
Domain Command Query Separation
Nov 30th, 2009 by Rikard Qvarforth
Är det någon mer som bråkar med hibernate i sin domän? räck upp sin hand… de som inte gjorde det var god lämna sidan…

Bra då är det bara vi kvar..

Utan närmare krusidull så vill jag dela med mig av följande problem som uppstod i koden efter ett tag.

Vi har en vy som skall visa upp ett stycke information allt går fint requestet går via sessions bönan ned till slut till domänen som sedemera plockar i hop det data som vyn vill ha .. STOP vänta här han använder inte ett repository nått är tok .. okej en annan implementation vi går till repositoryn och den frågar domänen genom HQL vad vyn vill ha och sedan så får vyn sitt data antigen genom ett frisläppt hibernate proxy aka entiteter eller för hoppningsvis en DTO eller ett Vy objekt, Vy objekt tycker jag beskriver det bättre.

Okej vad är det hemska med detta då kan man fråga? Jo

1. Om DTO/VY lösning med repository där implementation anväder HQL leder i de flesta fall till att man måste mappa upp relationer i domänen som endast är betydelse fulla för dto/vy objekt inte för domänen. aj aj ….

2. Om inte en DTO/Vy utan frisläppta entiteter och open-session-in-view lösning .. en hel massa extra sql slagningar till DB samt en potential “hoppsan jag råka traversera upp min produktion Databas i vyn” … ajajajajaj

3. Samma som ovan fast med restriktionen att entiteter inte är kopplade till en session. Leder detta till en massa LacyInitException i loggen samt arga användare. haha nä.. ajaj

Så vad göra? en lösning på detta om man vill behålla sin rika domän är att endast betrakta sin domän som write-only. Alltså du kan endast skapa,ändra eller tabort data i din domän.

Vill vyn ha data , aggregerat data eller en tårtbit av sin domän-kaka eller blandad data som finns på en helt annan databas så låt den få det men blanda förguds skull inte in domänen i det eller hibernate för den delen. Kör plain SQL eller jdbc template eller dylika.

Detta leder till så mycket mindre huvud bry så du anar inte :)

Mer läsning finnes av killen som myntat detta i DDD Greg Young

Rille
Selenium + ExtJs
Aug 26th, 2009 by Rikard Qvarforth
Selenium och ExtJs är inte ett klockrent giftemål. Den största nackdelan är att ExtJs auto genererar sina id’en på sina komponenter och under element. Men det finns hopp :)

Med xpath kan man få en hyfsad stabilt Selenium test med ExtJs. Men varför inte fråga ExtJs komponenterna själva vilket värde de har?

Till exempel vill man i sitt Selenium test kunna testa att vissa värden är förvalda i sin ExtJs kombobox. Med hjälp av Selenium’s metod

String evalResult getEval(String evalMe);

Kan man göra följande: String defaultValue = selenium.getEval(window.Ext.getCmp(‘myCombo’).getValue());

Ser ni att man använder sig av window.Ext… .. ?! där har vi fixen för att detta skall fungera :)

En kunglig kollega till mig listade ut att i eval körs med scopet av kommando fönstret och INTE av scopet av den sidan som just nu testas av Selenium!

Så gör icke detta om ni vill spara erat hår: selenium.getEval(Ext.getCmp(‘myCombo’).getValue());
utan selenium.getEval(window.Ext.getCmp(‘myCombo’).getValue());

om man kombinerar detta med PageObject pattern så får man även undan selenium api mojs i sina tester :)

Men mer om detta i annan post ..

NamedParameters
Jun 2nd, 2009 by Rikard Qvarforth
Parametrar i allmänhet är rätt svårtydliga speciellt om det är parameterar som är av rå-typ tex String, int etc. Som Martin Fowler så kan det vara ett tecken på
primitive obsession
Men ett annat problem med parametrar är själva ordningen, hur tvingar man en klient att rätt parameter kommer i rätt ordning?

Ett sätt är att skapa named parameter i java.

Här nedan har vi vår test klass över den lilla klassen Person. Persons konstruktor tar i dags läget in två parameterar förNamn och efterNamn.

 Java |  copy code |? 
01
public class PersonTest {
02
 final static String firstName = "Firstname";
03
 final static String lastName = "Lastname";
04
 
05
 @Test
06
 public void shouldCreatePersonWithFirstNameAndLastName() {
07
 Person person = new Person(firstName, lastName);
08
 assertThatNameIsSetOnPerson(person, firstName, lastName);
09
 }
10
 
11
 @Test
12
 public void shouldCreatePersonWithParameterName(){
13
 Person person = new Person(firstName(firstName).lastName(lastName));
14
 assertThatNameIsSetOnPerson(person, firstName, lastName);
15
 }
16
 
17
 @Test
18
 public void shouldCreatePersonWithDiffrentFirstName(){
19
 String karin = "Karin";
20
 Person person = new Person(firstName(karin).lastName(lastName));
21
 assertThatNameIsSetOnPerson(person,karin, lastName);
22
 }
23
 
24
 private void assertThatNameIsSetOnPerson(Person person, String firstName, String lastName) {
25
 assertThat(person, notNullValue());
26
 assertThat(person.getFirstName(), is(firstName));
27
 assertThat(person.getLastName(), is(lastName));
28
 }
29
 
30
}
31

 Java |  copy code |? 
01
02
package domain;
03
 
04
public class Person {
05
 
06
 private String firstName;
07
 private String lastName;
08
 
09
 public Person(final String firstName, final String lastName) {
10
 this.firstName = firstName;
11
 this.lastName = lastName;
12
 }
13
 
14
 public Person(Name name) {
15
 this.firstName = name.firstName;
16
 this.lastName = name.lastName;
17
 }
18
 
19
 public String getFirstName() {
20
 return this.firstName;
21
 }
22
 
23
 public String getLastName() {
24
 return this.lastName;
25
 }
26
 
27
}
28

 Java |  copy code |? 
01
02
 
03
package domain;
04
 
05
public class Name {
06
 
07
 public final String firstName;
08
 public final String lastName;
09
 
10
 private Name(String firstName, String lastName) {
11
 this.firstName = firstName;
12
 this.lastName = lastName;
13
 }
14
 
15
 public static NameBuilder firstName(String firstName) {
16
 return new NameBuilder(firstName);
17
 }
18
 
19
 public static class NameBuilder{
20
 
21
 private String firstName;
22
 
23
 private NameBuilder(String firstName){
24
 this.firstName = firstName;
25
 }
26
 
27
 public Name lastName(String lastName){
28
 return new Name(firstName,lastName);
29
 }
30
 }
31
 
32
}
33
 
34
TDD DSL – make it production code
Mar 8th, 2009 by Rikard Qvarforth
Inom vårt team fick vi högst prioterat in en bugg som låg mitt i våran domän model, våran prismodell! Detta leder till att en heldrös objekt är inblandade i skapandet av diverse priser. Jag börjde titta på de tester vi har på just på det området inom vår domän och insåg att det var otroligt mycket kod som var duplicerad samt svårtydlig. När sedan bug rättning storyn startade i sprinten tittade jag på olika lösningar inom tdd att arrangera våra fixturer.

Jag såg följande alternativ:

  • ObjectMother - en static factory lösning som ger utvecklaren den fixtur som behövs inför sitt enhetstest
  • BuilderPattern - en DSL liknande lösning att ge utvecklaren en flexibel fixtur test data lösning baserat på standarn val.
Jag måste ge Nat Pryce super kred! killen är grym! Såg hans exempel på Builder pattern för sina texturer och insåg att detta är det spår vi måste ta.

Efter närmare undersökning så insåg jag att vi redan hadde en hybrid av Object Mother genom en abstract class som inehöll static metoder enligt “create” så som:

createCampaingWithEnclosingBudgetWtihLimitOnClick();

Dessa metoder förökade sig som svampar! genom att varje test i sig är unikt, vilket är bra! Dock leder detta till en Object Mother som är mer som en sur gammal mormor.

Genom att i ställer ta en annan approch genom builder-pattern och att ha smarta default-värden. Plus att ge (enligt tips från Nat pryce) Builders i Builders anrop slippa se en harang av build().build().build(), så får man ett fluent dsl i sin test fixtur. Ruskigt fint för ögat samt att man har den trevliga sideffekten att sina test builders kan leva i test sourcen tills man inser att detta borde ligga i produktions koden direkt!

Ett exempel (Campaign är aggregat objekt):

 Java |  copy code |? 
1
2
//Given
3
Currency sek = Currency.getInstance("sek");
4
Long id = new Long(1L);
5
Campaign campaign = aCampaign(id).andCurrency(sek).
6
                   withBudget(aLimit(100L).withEvent(aEvent().asClick())
7
                                                       .withPrice(50D).build()
8

En annan sid effekt blir att varje test inte behöver lägga till ett ytterligare createMetod bara pga av ett ytterligare test fixtur. Lägg til buildern med ett smart default värde/builder istället!

Som Josua Bloch propagerar borde varje new vara inkapslat av en builder, så låt nu dina test builders blir riktiga medlemmar av din domän istället!

Finns ruskigt bra argument varför man ska kapsla in new operatorn! men det i en annan post :)

AnemicDomainModel
Mar 6th, 2009 by Rikard Qvarforth
Såg detta från vår käre vän martin fowler och jag tycker det han skriver är synnerligen bra. Jag behövde argument och en påminnelse om detta .

Här är länken AnemicDomainModel

Preconditions, Design by Contract
Mar 6th, 2009 by Rikard Qvarforth
Är det någon mer än jag som hatar dessa ständiga null check kollar i java, i enlighet med Design by contract?!

Och är det någon som har skapat någon “kollaOmNull”-metod som återfinns i någon util klass?

om ja på något av alternativen så kolla in detta i GoggleCollections…


 Java |  copy code |? 
1
2
public Person(final Long id, final String name, final Integer age) {
3
 
4
Preconditions.checkArgument(id != null);
5
 
6
}
7


Samt om du vill se i en lista eller dylika om det har smygit sig in något null värde.


 Java |  copy code |? 
1
2
public void setNames(List<String> names){
3
 
4
Preconditions.checkContentsNotNull(names,"A null name was in the Collection!");
5
 
6
this.names = names;
7
 
8
}
9
En myckettrevlig klass för att kolla preconditions finns i flera olika varienter.

Om ni inte vill ta in hela google-collections så ta bara java sourcen och klistra in ;) (copy paste kodning är bra ibland

kommentarer, har ni inte en util-klass liggandes någonstans som gör något liknade?
»  Substance: WordPress   »  Style: Ahren Ahimsa
© copyright@alltomjava