wk voetbalpool webapp: dag 8

Het gebruik van naamgeving begint af en toe grappige vormen aan te nemen. Om een pool te representeren hebben we nu een GroupActor die wordt aangemaakt door een GroupFactoryActor, en heeft een corresponderende view om data over de groep op te vragen, namelijk de GroupViewActor, die op zijn beurt weer wordt aangemaakt door een GroupViewFactoryActor. En om alle wedstrijdgegevens te kunnen bekijken is er nog een GamesOverviewViewActor. Misschien kunnen we eens nadenken over het hernoemen van sommige van deze dingen…?

De functionaliteit hebben we nu inmiddels zover op de rit (het vooraf definieren van eventtypes bleek erg te helpen) dat we eens wat nauwkeuriger moeten gaan kijken naar wat we eigenlijk allemaal al hebben en wat we nog missen. Daarnaast wordt het tijd om de REST API eens wat te documenteren, zodat de front-end ook makkelijker erop aangesloten kan worden. Hiervoor gaan we dan de interne Wiki gebruiken. Bijna alle panelen voor het front-end zijn nu gemockt (en we weten inmiddels welke panelen er allemaal moeten zijn), en er is al een begin gemaakt met het aanspreken van de bestaande back-end API. Hier gaat de komende paar dagen meer de nadruk op liggen. Over het algemeen vordert het front-end werk ook gestaag.

Rikkert is bezig geweest met wat stoeien met CouchDB. Het blijkt nog niet helemaal een sine-cure te zijn om die op Windows draaiend te krijgen. Het idee ziet er goed en makkelijk aanspreekbaar uit; er is een administratieve UI aanwezig, en de DB zelf kan met REST-requests met JSON-data aangesproken worden, en hij luistert in elk geval ook naar de normale HTTP verbs (GET, POST, PUT, DELETE, …), waarna er een JSON response terugkomt. Met Lift zouden we die makkelijk moeten kunnen parsen. De testresultaten op Windows zijn nog bedroevender dan de documentatie doet vermoeden; bijna alle meegeleverde tests falen. Gelukkig ontwikkelen we de back-end ook al op een CentOS (Linux) virtuele machine, en Jan-Willem heeft op zijn VM CouchDB ook al geinstalleerd. Niet veel later op de dag meldt Rikkert dat deze versie inderdaad een stuk beter werkt: op een enkele na slagen alle tests.

Het testwerk voor de back-end is tot nog toe voornamelijk de ‘happy flow’ geweest. We moeten nu ook gaan nadenken over wat er gebeurt met verschillende vormen van dingen die fout gaan. Wat te doen bij bijvoorbeeld het opvragen van een top-10 van een niet-bestaande groep? Wat als de binnenkomende JSON-data ongeldig is? Wat als er iets misgaat binnen het domein? Dit gaan we vandaag verder uitwerken en in de API-beschrijving opnemen. Geven we een JSON-melding terug? Geven we een lege response? Geven we een HTTP error-code 404 of andere?

Het wordt ook wel weer eens tijd om terug te koppelen met onze klant Simon, om eens een kleine demonstratie te geven. Agenda-technisch wordt het ofwel morgenmiddag ofwel pas over een week. Bij het overleg om de front- en back-end aan elkaar te koppelen blijkt dat we voor een ‘mooie’ demonstratie toch nog net wat teveel puzzelstukjes missen om morgenmiddag haalbaar te maken (nog afgezien van minder belangrijke functionaliteit zoals de slow-chat of nieuwsberichten). We willen als demonstratie het volgende scenario laten zien: (incl. login/logout-functionaliteit)

  • Admin voert een te spelen wedstrijd in
  • Een gebruiker registreert zich en logt in
  • Hij voert een wedstrijdvoorspelling in
  • Admin voert een wedstrijduitslag in voor die wedstrijd
  • De gebruiker krijgt een overzicht van zijn (geupdate) puntentotaal na die wedstrijd

De login-functionaliteit wordt nog een interessante kwestie, waar ik me op ga richten: bij een Login-request wil je een synchrone afhandeling hebben, omdat je meteen in het response een session token (session cookie) oid wil meegeven. Maar het ingelogd-zijn wordt bijgehouden in het domein, wat alleen een asynchrone verwerking kent. Het login-componentje zal dus expliciet moeten wachten totdat er een loginSuccess-bericht of een loginFail-bericht uit het domein terugkomt. Het is dus een vreemd hybride componentje dat niet echt een view is omdat hij berichten naar het domein stuurt, maar ook niet echt een Actor omdat het componentje niet constant live als actor in het domein hangt. Voor elke login-request moet er een nieuw object aangemaakt worden, omdat je niet alle login-resultaten door en enkel object wil laten afhandelen: de synchrone aard ervan zou betekenen dat er maar één iemand tegelijkertijd met inloggen bezig kan zijn. Toch is het noodzakelijk om hier de Actor trait te extenden omdat we toch op de EventBus aangesloten moeten kunnen worden zodat we naar LoginSuccess- en LoginFail-events moeten kunnen luisteren die uit het domein komen.

Ik dacht hierbij handig te zijn door een ‘synchrone’ login()-methode te maken waarin ik een ‘tijdelijke’ loop { react { ... } }-lus opstart die na het LoginStart-event wacht op een LoginSuccess of een LoginFail, en daarna nog wat post-processing doet om de data naar de gebruiker te kunnen doorsturen. Maar helaas: dat vindt Scala niet leuk. Ook de operator ?! kan ik niet gebruiken om ‘synchroon’ op antwoord op mijn LoginStart-event te wachten: doordat we die naar de EventBus sturen, en alle andere actoren ook via de EventBus communiceren, is het waarschijnlijk dat er eerst een niet-relevant ander event langskomt. Uiteindelijk komt het erop neer dat ik in de login()-methode deze actor start en hem bij de EventBus registreer, en ik o.a. een var loginSucces: Option[Boolean] = None toevoeg aan de klasse. Als de event handling loop de juiste events detecteert zal die deze variabele een andere waarde geven. In mijn login()-methode staat nu dus een busy wait loop (while(loginSucces==None) { }) om het resultaat af te wachten. Niet erg netjes, maar het werkt… (Al zou je toch verwachten dat er een betere manier is…)

En daarmee wordt het half zes, en alles is wel.