Website logo depicts joriszwart.nl

I ❤ to create appealing stuff

I am so sorry, this article is in Dutch only :p however Google Translate does a pretty good job.

Introductie

Duotris is een spel voor twee spelers waarmee Tetris gespeeld kan worden over internet.

Als onderdeel van een assessment voor een klus heb ik hier een PoC voor gebouwd.

Het is een port van een eerder door mij gebouwd .NET 4.5 project en geporteerd naar .NET Core 2.0. Het één en ander is ontwikkeld onder Visual Studio Code op een Mac en draait ook onder Microsoft Windows.

Inhoud

Doel van het Proof of Concept

Het doel van het PoC is tweeledig en bestaat uit:

  1. porteren van .NET 4.5 naar .NET Core 2.0;
  2. toepassen van Dependency Injection.

Andere zaken zoals de front-end vallen buiten het PoC .

Portering

Zoals verwacht vormden externe dependencies het grootste struikelblok. Met name SignalR heeft een andere API gekregen én het was lastig om de juiste versie te vinden; ook omdat het – voor mij – niet onmiddellijk duidelijk was dat .NET Core 2.0 in tegenstelling tot .NET Core 2.1 nog geen SignalR aan boord had. Uiteindelijk heb ik de pre-release SignalR 1.0.0-rc1-final gebruikt. Het is nl. net iets te vroeg om .NET Core 2.1 op een Mac te gebruiken.

Daar tegenover staat dat het aantal expliciete dependencies van vijf naar één is teruggelopen. Dit komt grotendeels doordat OWIN onderdeel is geworden van Microsoft.AspNetCore.All. Met de komst van .NET Core 2.1 zal dit aantal zelfs teruglopen tot nul omdat SignalR dan ook onderdeel van Microsoft.AspNetCore.All is geworden. Hou je ogen op je mailbox voor een update!

Dependency Injection

Voor een dergelijke kleine applicatie is het eigenlijk overkill om DI toe te passen. Het ontwerp van SignalR maakt het echter wenselijk om toch DI te hanteren.

De SignalR hubs worden nl. per request geïnstantieerd. Hierdoor is het verleidelijk om de game state als static members in de SignalR hub op te nemen of zelfs globaal te declareren. Niet goed. Dit schendt natuurlijk werkelijk elk concept van SOLID op meerdere manieren!

Ik heb er voor gekozen om de classes GameList en PlayerQueue in DuotrisHub te injecteren als singletons (wah!) om dit op te lossen. Een refactorslag die nog zou kunnen plaatsvinden is het losser koppelen van DuotrisHub en de spellogica (methods QueueForMatch, Move, GameOver etc.). Bijvoorbeeld door het mediator pattern toe te passen. Dit valt buiten de scope van het PoC.

Duotris UML class diagram
Mandatory UML class diagram

Over het gebruik van SignalR

Er is gebruik gemaakt van SignalR om real-time communicatie te laten plaatsvinden tussen de game server en (browser-)clients. De spelers worden gepaard voor het spelbegin. Hiertoe worden er op de server twee lijsten bijgehouden; de eerdergenoemde game state.

  1. wachtende spelers; PlayerQueue
  2. lopende spellen; GameList

Als er genoeg wachtende spelers zijn (twee) worden deze van de wachtende spelers naar de lopende spellen verplaatst en begint het spel.

Opmerking: er had gebruik gemaakt kunnen worden van SignalR groups om spelers bij elkaar te houden, maar het groepenconcept in SignalR kent wat beperkingen; het is mogelijk om spelers aan een groep toe te voegen of te verwijderen. Het opvragen van spelers in een groep of zelfs het aantal spelers bepalen is echter niet mogelijk.

Over de front-end

De front-end is gebouwd in plain JavaScript en een snelle hack bovenop JavaScript Tetris in 1.5 KB (2004). Don't look at it :-)

Download

Zip met Git repository: duotris.zip.

Build en run

Gebruik dotnet run op een command-line om de applicatie te bouwen en te starten. Surf vervolgens twee keer naar localhost:5000 om een spel te starten.