wk voetbalpool webapp: dag 7

 
12 april 2010

Een nieuwe week is begonnen, en het wordt nu tijd om het domein eens wat uit te bouwen. Vrijdag ben ik al bezig geweest met wat event-typen die we in het domein zeker nodig gaan hebben, en daarbij viel het me op dat je per ‘user story’ of ‘use case’ meestal drie events nodig hebt, bijvoorbeeld:

// registering as a new user
case class Registering extends EventType
case class Registered extends EventType
case class RegisterFail(reason: String) extends EventType
 
// logging in as an existing user
case class Loggingin extends EventType
case class Loggedin extends EventType
case class LoginFail(reason: String) extends EventType

Het ‘-ing’-eventtype is (meestal) een commando/request dat vanaf de UI binnenkomt; de ‘-ed’- en de ‘-fail’-varianten zijn de events die worden afgevuurd door het domein zodra een actie is afgerond (met meer of minder succes).

Ik was vrijdag al van plan om iets van een ‘eventphase’ in te voeren – dat scheelt tiepwerk omdat je dan elke user story maar met een enkel eventtype representeert, die in verschillende fasen kan zitten. Maar Jan-Willem vond dat een slecht idee: het zijn namelijk wel echt verschillende events die afgevuurd worden. Nu ik met het uitbouwen van het domein bezig ben zie ik nog een interessant voordeel aan mijn oorspronkelijk idee (alleen is EventPhase inderdaad niet zo’n gelukkige naam, misschien UserStoryPhase?): je wil bijvoorbeeld alle ‘-fail’-events loggen en/of mailtjes sturen. Met de opzet zoals in het codevoorbeeld hierboven moet ik tig events gaan filteren, wat een waslijst aan cases oplevert, terwijl met een UserStoryPhase dat het enige ding is waarop ik events moet filteren en ik dus met een enkele case klaar ben:

{
  case Event(LoginFail(), eventargs) => {log.debug(...)}
  case Event(RegisterFail(), eventargs) => {log.debug(...)}
  case Event(xyzFail(), eventargs => {log.debug(...)}
  // ...meer...
}

of:

{
  case Event(eventtype@_, UserStoryPhaseFail(), eventargs) => {log.debug(...)}
  // dat is alles
}

Gelukkig is er tijdens de stand-up meeting overeenstemming dat dit de manier is om verder te gaan.

Er ontstaat een discussie over hoe je de REST-URL’s ziet: is het min-of-meer stateful en haal je een deel van de requestdata uit je usersession, of uit de requestdata, of is het puur een platte schil om je events heen? Het verschil is als volgt, bijv. bij een aanvraag tot meespelen in een bepaalde pool:

  /groups/<groupname>/member/<username>/join

of

  /groups/<groupname>/join

of

  /groups/<groupname>/join
  (requestdata: username)

In alle gevallen is er een session cookie wat de ingelogde gebruiker meestuurt, dus waarom zou je de eerste of de derde vorm gebruiken? Verder kan je ook nog informatie verpakken in je request-(JSON-)data, dus uiteindelijk is de vraag of het uberhaupt veel uitmaakt of je 1 of 3 gebruikt.

REST is niet een vaststaand protocol, maar meer een conventie waar je zelf nadere invulling aan kan geven. Je kan dus verschillende visies ontwikkelen over welke data in de URL moet en welke in de requestdata. Ik was er in eerste instantie voor om alles zoveel mogelijk in te perken, en dus de tweede vorm te gebruiken waarbij je de gebruiker bepaald aan de hand van een session cookie. Je kan ook de visie hebben dat REST een deel van je objecten-graaf beschrijft, waarbij het laatste element dan een methode op een object is, en je de request-data als methode-argumenten beschouwt; dus de 3e variant. Dat komt dan dus min-of-meer direct overeen met een Java-call Groups.get(groupname).join(String username).

Of je kan alles zoveel mogelijk uitschrijven in de URL, zoals in de eerste variant. Hier blijken toch wel een paar voordelen aan te zitten: als je die eerste vorm aanhoudt, dan kan je de actie ook door een administrator laten uitvoeren namens die gebruiker – je kijkt dan of de gebruiker behorende bij het session cookie overeenkomt met de usernameof behoort bij een administrator. Daarnaast is de URL een stuk beter zelf-beschrijvend, en kan je het als ‘geserialiseerde’ versie van je event zien. We besluiten om dus de ‘lange’ versie te gebruiken.

En even later blijkt al hoe handig dat is, althans in de ontwikkel-fase. Het is veel makkelijker om vanuit je browser alleen een ingewikkelde URL op te vragen dan een simpele URL maar waarbij je dan ook nog requestdata moet verpakken. Het blijkt dat we inmiddels de ontwikkelomgeving aardig poten hebben en dat we Scala toch ook steeds beter beginnen te begrijpen, wat het steeds makkelijker maakt om nieuwe code te ontwikkelen. Het grootste deel van de dag zijn we dus bezig met nieuwe actoren aan te maken, zoals een EmailActor (die nu nog alleen maar doet alsof, voordat we zelf helemaal gek worden van de testmailtjes), een LoggingActor, een GroupActor en een GroupFactory om een nieuwe pool aan te maken en te representeren.

We maken ook onze eerste views. Dit zijn zelf ook actoren, omdat ze naar berichten vanuit het domein moeten luisteren, maar, geheel volgens CQRS, ook een aantal synchrone methoden hebben om hun viewdata op te vragen. We hebben nu een view waarin alle te spelen wedstrijden opgevraagd kunnen worden (incl de stand als ze al gespeeld zijn), een view waarin de algemene top-10 van beste deelnemers van iedereen in staan, en tenslotte willen we nog per GroupActor een GroupViewActor bouwen waarin de stand per pool (GroupActor) als view wordt bijgehouden. Daarbij bedenken we dat de algemene top-10 eigenlijk ook domweg zo’n groupview is, als we bij het opstarten van de applicatie een groep ‘iedereen’ aanmaken, en bij registratie van gebruikers ze automatisch daar lid van laten worden.

Aan het eind van de dag is de Scala-code naar schatting meer dan verdubbeld, alleen zitten we nu met een nieuwe uitdaging voor morgen: voorheen was de algemene top-10 een Scala Object (lees: Singleton) en kon je altijd een referentie vinden. In de nieuwe opzet is dat lastiger. We zullen waarschijnlijk een synchroon uitvraagbare GroupRepository moeten bouwen waarin we bijhouden welke groepen er zijn, zodat als de top-10 van een bepaalde groep wordt opgevraagd, daar ook synchroon een antwoord op kan komen.

We hebben tijdens de stand-up meeting van vandaag afgesproken dat we als mijlpaal aan het eind van deze week de basisfunctionaliteit zo’n beetje klaar willen hebben. Als het zo doorgaat als vandaag halen we dat makkelijk. Anatoly en Christa hebben voor het front-end al steeds meer om tegenaan te praten zodat ze hun GWT-code beter kunnen gaan testen. Rikkert gaat zich inmiddels richten op Apache CouchDB, een document-georiënteerde database die via, daar is’ie weer, een REST-gebaseerde JSON-interface aangesproken kan worden. Want hoewel het applicatiedomein in principe altijd live is, zou het zomaar kunnen dat er iets crasht en we alle data kwijt zijn. Bovendien kan het nuttig zijn om de applicatie gecontroleerd up of down te brengen. Dus genoeg te doen voor deze week.

En daarmee werd het half zes, en alles was wel.


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development


Reacties (3)

  • Johan Scholten schreef:

    Leuke discussie over die rest-link. Ik zou het ook redelijk op een java-call willen doen lijken, en dus zou ik intuitief voor de 3e gaan. Maar meer verpakt als:
    /groups//join?username=*** of /groups//join/.
    Of als je de volgorde om wilt draaien members//join/ (maar da’s een andere discussie).
    Korter en duidelijker, vooral ook omdat als je de eerste variant bekijkt uit java-perspectief het lijkt alsof iemand al een member is van de groep, en dan nog eens gaat joinen.

    Trouwens, lijkt me lastig om elke dag een stukje te schrijven, maar het is wel leuk om te lezen, bedankt.

    Geplaatst op 13 april 2010 om 6:50 Permalink

    • Jasper Stein schreef:

      @Johan – Ik neem aan dat er wat dingen tussen <haken> zijn weggevallen door een overijverig HTML-filter op deze blog, en dat je bedoelde /groups/<groupname>/join?username=xyz enz…? (Hopelijk komt dit wel over…?)

      Mee eens over welke variant het meest op Java lijkt. De 1e variant geeft inderdaad mogelijk een wat rare indruk.

      Het schrijven kost inderdaad wel elke dag even aardig wat tijd, maar ik krijg wel veel leuke reacties. Keep’em coming! ;-)

      Geplaatst op 14 april 2010 om 8:40 Permalink

      • Johan Scholten schreef:

        Klopt, de generic dingetjes werden opgevat als tags :(.

        Geplaatst op 14 april 2010 om 17:24 Permalink