You are on page 1of 22

5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

QCon PlusJune
InfoQ Live (May22:10-20):
How do Uncover emerging
traditional trends
approaches scale and practices
in the Cloud? from domain
Register Now
experts.

Exploring Architectural Concepts


Building a Card Game
Key Takeaways

A real time card game involving more than one player represents a good
playground to exercise some architectural concepts: flexibility in cloud
deployment models, reactivity in the front end, testability of complex scenarios.
The first concept to test is flexibility when it comes to deploying in the cloud.
The best deployment model to adopt depends on the context, so it is important
to stay flexible and minimize the effort needed to move from one deployment
model to another if circumstances require a change.
The second concept is on the Front End. We want to use a reactive model and
check up to which point we can move our logic to a pure Javascript / Typescript
layer minimizing the dependencies on the specific library / framework we
choose to use. 
The third concept is about testing, in particular testing interactive multi user
scenarios. In these scenarios more than one client is connected to the app and
uses it concurrently with other clients, which makes testing more challenging.
But, even in such cases, it is possible for developers to run BDD test suites on
their laptop, without complex setups and, at the same time, granting a high level
of confidence. 
In addition to bringing some fun, building a card game app is an opportunity to
see these architectural concepts in action with real code and increase the level of
confidence on the possibility of applying such concepts to real business
scenarios.

One of the things I missed during the pandemic were my friends, the possibility to
meet them, discuss with them and, why not, play some cards with them.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 1/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

Zoom could
InfoQ Live partially
June 22: Howwork as a substitute
do traditional for physical
approaches presence,
scale in the Cloud? but what about
Register Now
cards? What about our games of Scopone*?

So I decided to implement an app to play Scopone with my friends and, at the same
time, test “in the code” some architectural concepts which had been intriguing me for
some time.

All the source code of the app can be found in this repo.

What I wanted to find out

Freedom when it comes to deploy a server

An interactive card game app involving more than one player has to have a client part
and a server part. The server part has to reside somewhere in the Cloud. But where in
the Cloud? As a component running on a dedicated server? As a Docker image on a
managed Kubernetes? As a serverless function?

I did not know which was the best option but I wanted to check whether it was
possible to maintain the core of the logic of the game independent from the
deployment model I would have eventually chosen.

Independence from the framework or library chosen to


develop the UI

“Angular is best”. “No, React is much superior and faster”. I read too much of this.
But is it really relevant? Shouldn’t we have most of the Front End logic as pure
Javascript or Typescript code completely independent from the UI framework or
library which we will eventually end up using? I had the feeling this was possible, but
wanted to try it for real.

Possibility to test automatically interactive multi-users


scenarios

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 2/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

A cardLive
InfoQ game,
Juneas other
22: Howinteractive applications
do traditional nowadays,
approaches scale has multiple
in the Cloud? users
Register Now
interacting with each other in real time via a central server. For instance, when one
plays a card, all others need to see in real time the played card. At the beginning it
was not clear to me how to test this type of application. Would it have been possible
to test it automatically with simple Javascript testing libraries like Mocha and
standard testing practices?

The Scopone app: a good playground to answer my questions

The Scopone app represented a good ground to try to answer in a concrete way the
questions I had. So I decided to try to implement it and see which lessons I could
draw from it.

The big picture

The rules of the Scopone game

Scopone is a traditional italian card game which is played by 4 players, split in 2


teams of 2, with a 40 cards deck.

At the start of the game all players are given 10 cards each and the first player plays
the first card which is put on the table face up. The second player then plays its card.
If this card has the same rank as the card on the table, the second player “takes” the
card from the table. If no cards are left on the table, the player taking the cards scores
a “scopa”. Then the third player plays its card and so on and so forth until all cards
have been played.

Enough of rules. The key point to remember here is that when a player plays a card,
they change the state of the game, for instance in terms of “which cards are face up
on the table” or “which player can play the next card”. 

Structure of the app and tech stack

The Scopone app requires one server instance and four client instances that are
launched by the four players from their devices.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 3/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

If we look at the interactions among the various elements of the game, we note that

Players perform actions, for instance a player play a card


As a consequence of a player’s action, all players need to be updated with the
new state of the game

This means that the clients and the server need a two-way communication
protocol, since the clients have to send commands and the server needs to push the
updated state. WebSockets is a popular protocol suitable to this aim and available
in various languages.

The server is implemented in Go since it has good support for WebSockets and fits
well with the different deployment models at hand, in other words it can be deployed
as a dedicated server, as Docker image, or as a Lambda. 

The client is a browser-based application implemented in two different flavors: one


with Angular and one with React. Both versions use Typescript and leverage a
reactive design implemented via RxJs.

The following diagram represents the general architecture of our game app.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 4/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

Commands and events

In a nutshell, the app works like this:

A client sends a command through a message to the server


The server updates the state of  the game
The server pushes the new state of the game to the clients through a message to
the clients
When a client receives a message from the server it treats it like an event that
triggers the update of the state for that specific client.

This cycle is repeated until the game is over.

Freedom when it comes to deploying the server


part of the app
The server receives messages representing commands sent by clients. Based on
these commands, it updates the state of the game and sends messages to clients
with the new updated state.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 5/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

A command
InfoQ is 22:
Live June a message sent by a client
How do traditional via a scale
approaches websocket channel
in the Cloud? which is
Register Now
transformed into the invocation of a specific API of the server.

The response produced by the invocation of the API is a picture of the new state
which is transformed into a set of messages that have to be sent to each client over
the websocket channel.

So, in the server implementation there are two distinct layers with distinct
responsibilities: the game logic layer and the websockets mechanics layer.

Game logic layer

This layer is responsible for implementing the game logic, that is to update the state
of the game based on the command received and return a picture of the new state to
be sent to each client.

This layer therefore can be implemented with an internal state and a set of APIs
implementing the command logic. The APIs return the new state that has to be
communicated to the clients.

Websocket mechanics layer

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 6/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

This
InfoQlayer is responsible
Live June 22: How dofor transforming
traditional a message
approaches scale inreceived over
the Cloud? the websocket
Register Now
channel into the invocation of the corresponding API with the expected
parameters. Additionally,  it transforms the updated state, received as a
response from the API invocation, into the set of messages that have to be pushed to
the respective client.

Dependency relationships between layers

Based on the previous discussione,  the game logic layer is independent from
the concept of websocket. It is just a set of APIs returning a state.

The websockets mechanics layer, on the other hand, is where the websockets
specificities are implemented. This layer will depend on the specific deployment
model chosen. 

For instance, if we decide to deploy as a dedicated server, we will have to deal with
the specific package chosen to implement the websocket protocol (in our case the
Gorilla package), while if we decide to deploy as an AWS Lambda function, we have
to rely on the Lambda implementation of the websocket protocol.

If we keep the game logic layer strictly separated from the websockets
mechanics layer, with the latter importing the former (and not vice versa) we are
sure that we can use the game logic layer regardless of the specific deployment
model chosen.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 7/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

Applying this strategy, it was possible to develop a single version of the game logic
with the freedom to deploy the server where most convenient.

This brought several advantages. For instance, during the development of the client it
is very convenient to run against a local Gorilla websocket implementation, maybe
even launched in debug mode from within VSCode. This makes it possible to place
breakpoints in the server code and step through the logic triggered by the various
commands sent by the clients while playing a real game.

When the time came to deploy the server for production, which was more convenient
for real play with my friends, it was possible to deploy the same game logic to the
Cloud, for instance to Google Application Engine (GAE).

Furthermore, when I discovered that Google was charging a minimum fee regardless
of whether we played or not (GAE always keeps at least one server on), I decided to
move the server to AWS Lambda for a full “on demand” model with no change in the
game logic code.

Independence from the framework or library


chosen to develop the UI

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 8/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

And
InfoQthen
Live came theHow
June 22: big do
question: Angular
traditional or React?
approaches scale in the Cloud?
Register Now
But then I also asked myself another question: is it possible to code most of the client
logic as pure Typescript, independent of which framework or library will be used to
manage the view part of the Front End?

It turned out that it is possible, at least in this case, with some interesting benefits as
side effects.

The design of the Front End of the app: view layer and service
layer

At the base of the design of the Front End part of the app there are three simple
ideas:

The client in split into two layers:


The view layer, implemented as composable components (yes, both
Angular and React share the same basic concept of creating UIs as
composition of components) to implement the pure presentation logic.
The service layer, implemented in Typescript with no dependency
whatsoever on any part of Angular or React, to hold state and implement
any logic that manages such state, including the invocation of commands
on the remote server and the interpretation of the responses in terms of
state changes (in other words a home-made bespoke store).
The service layer exposes two types of APIs to the view layer:
Public methods that can be called to invoke commands on the remote
server or, more generally, to change the state of the client.
Public streams of events, implemented as RxJs Observable, which can
be subscribed by whichever UI component wants to be notified of state
changes.
The view layer keeps only two simple responsibilities:
Intercept UI events and turn them into invocations of the service layer
public API methods.
Subscribe to the public API Observables and react to the
notifications received with the appropriate changes in the presentation.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 9/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

An example of View-Service-Server interaction

A player can play a card by clicking on it (suits in the picture are traditional north-
eastern italian)

To make it more concrete, let’s consider what it means to play a card.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 10/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

Let’s
InfoQ assume Player_X
Live June istraditional
22: How do the playerapproaches
that is to play
scale the next
in the card.
Cloud? Player_X clicks on
Register Now
the card “Ace of Hearts” and this UI event triggers the action “Player_X has played
Ace of Hearts”.

These are the steps the application goes through:

1. The view layer intercepts the user generated event and calls the service layer
invoking the method playCard passing Ace of Hearts as parameter.
2. The service layer sends the remote server the message “
Player_X
has played Ace of Hearts”.
3. The remote server updates the state of the game and informs all clients of the
state changes. For instance it tells all the clients which card Player_X played
and who is the next player that can play a card.
4. The messages with the state updates sent by the remote server are received
by the service layer of each client and turned into notifications of specific
events over Observable streams made public for clients consumption. For
instance, the service layer in the client instance of
Player_X
will notify false on the stream
isMyTurnToPlay$
since
Player_X
is certainly not the next player. On the other hand, if the other player is
Player_Y
, the service layer on the client of
Player_Y
will notify a true on the stream
isMyTurnToPlay$
.
5. The view layer of each client has subscribed to the streams of events published
by the service layer and will react to the events notified updating the UI as
required. For instance, the view layer of
Player_Y
(the next player) will enable its client to play a card while all other clients
serving the other players will disable such a possibility.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 11/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

View layer and service layer interactions

Light components and heavy services

Following these rules we end up building “light components”, which manage only the
UI concerns (presentation and UI event handling) and “heavy services” where all of
the logic is kept.

The most important consequence though is that the “heavy services”, which contain
most of the logic, are completely independent from the UI framework or library used.
There is no dependency on either Angular or React.

More details on the way the UI layer works can be found at the end of the article.

The benefits

Which are the benefits of such an approach?

Certainly not the portability between different frameworks and libraries. Once
Angular is chosen it is unlikely that someone wants to switch to React and vice versa.
But there are still advantages.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 12/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

A firstLive
InfoQ advantage
June 22:of
Howsuch
do an approach
traditional is that, ifscale
approaches implemented thoroughly,
in the Cloud? it
Register Now
standardizes the way we develop the Front End and makes it easier to reason about
it. At the end of the day, it is just another way to design a unidirectional flow of
information using a bespoke store (the service layer is just a bespoke store). Being
bespoke has the advantage of a lower level of abstraction and greater simplicity at,
maybe, the cost of a bit of “reinventing the wheel” feeling.

The biggest benefit though lies in better and easier testability of the application. 

Testing UI is complex, no matter which framework or library you use. 

But if we move most of the code to a pure Typescript implementation, testing


becomes easier. We can test the core logic of the application using standard testing
frameworks (in our example we use Mocha) and we can also approach complex
testing scenarios in a relatively simple way, as we discuss in the next and last section.

Automatically testing interactive real time


multi-users scenarios
We have seen that Scopone is a game played by four players.

Four clients have to be connected simultaneously to a central server via WebSockets.


Actions performed by one client, for instance “play a card”, trigger updates (side
effects) on all clients.

This is an interactive real time multi-user scenario. This means that we need to have
multiple clients and a server running at the same time if we want to test the behavior
of the app in its entirety.

How can we test such scenarios automatically? Can we test them with standard
testing Javascript libraries? Can we test them on a standalone developer
workstation? These were the questions to answer next. It turns out that all these
things are possible, at least up to a large extent.

What is a test in an interactive real-time multi-user scenario 

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 13/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

Let’s
InfoQ imagine,
Live June with a simple
22: How example,
do traditional that we want
approaches tothe
scale in testCloud?
the correct distribution of
Register Now
the cards among all players at the beginning of a game. As soon as a new game is
started, all clients receive ten cards each  from the server (the Scopone deck is
composed of 40 cards of which each player gets ten).

If we want to test this behavior automatically from a single standalone machine (say,
the developer’s machine) we need a local server. This is possible since the server can
run locally as a Container or a WebSockets server. So we assume to have a local
server up and running on our machine.

But, for the test to run, we need also to find a way to create the right context assumed
by the test and launch the action that triggers the side effects we want to test (the
distribution of the cards to the players is a side effect of the fact that one player has
started the game). In other words we need to find a way to simulate the following:

Four players launch the app and join the same game (create the right context)
One player starts the game (trigger the side effects we want to test)

Only then can we check whether the server sends the expected cards to all players.

A test in a multi user scenario

How to simulate multiple clients

Each client is composed of a view layer and a service layer.

The APIs of the service layer (methods and Observable streams) are defined in a class
(called ScoponeServerService in the implementation code).

Each client creates an instance of this service class and connects it to the server. The
view layer interacts with its instance of the service class.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 14/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

Therefore, if we22:
InfoQ Live June want
Howto
dosimulate four
traditional clients, we
approaches have
scale toCloud?
in the first create four different
Register Now
instances of the service class and connect all of them to our local server.

Create 4 service class instances representing 4 clients

How to create the context for the test

Now that we have four clients available and connected, we need to build the right
context for the test. We need four players and we need that each of them joins the
same game. 

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 15/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

Setting the context for the test

Finally, how to test

After we have created the four clients and built the right context, we can run the core
of the test. We can have one player sending the command to start the game and then
we can check that each player receives the expected amount of cards.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 16/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditionalRunning thescale


approaches test in the Cloud?
Register Now

Wrapping it up

The test of an interactive multi-user scenario is a function that:

Creates one service instance per user


Creates the context of the test by sending a sequence of commands to the
services in the right order
Sends the command that triggers the side effects we want to check (we can say
this is the command under test)
Verifies that the notifications emitted by the Observable APIs of each service, as
consequence of this command (the side effects), contain the data expected

It is BDD run at APIs boundaries of the service layer

We can see this approach as a form of behavior-driven development (BDD)


performed against the APIs offered by the service layer. 

The behavioral specifications are provided, in line with the BDD approach, such as:

Given the initial context: 4 players joining a game


When: a player starts a game
Then: we expect each player to receive 10 cards. 

The function representing the test is written with a sort of DSL which is composed of
ad-hoc helper functions whose combination sets up the context (an example of helper
function is playersJoinTheGame). 

It is not end-to-end, but it can be very powerful

This is not a full end-to-end test. We are not testing the view layer. 

But it can still be a very powerful tool, especially if we stick to the rule “Light
components and heavy services”.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 17/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

If the Live
InfoQ view layer
June is made
22: How up of light
do traditional components
approaches scaleand most
in the of the
Cloud? logic is
Register Now
concentrated in the service layer, then this approach allows us to cover the core of
application behavior, both on the client and on the server side, with a relatively
simple setup, pretty standard tools (we use Mocha as testing library, definitely not
the latest shiniest thing) and on a standalone developer’s machine. 

The net benefit is that developers can create test suites that are fast to run and
therefore can be executed often. At the same time, such test suites are really testing
the entire application logic, from client to server, giving a high level of confidence
even with a multi-user real time application.  

Conclusions
Building a card game app has been an interesting experience. 

Apart from bringing some relief during the darkest days of the pandemic, it gave me
the opportunity to explore some architectural concepts with some code.

We often use architectural concepts as abstractions to express our point of views. I


find that looking at these concepts in action, even in simple proof-of-concept
scenarios, increases our understanding of them and our level of confidence when we
eventually use them in a real project.

Appendix: The view layer mechanics


The components of the View layer do two things:

Handle UI events and transform them into commands for the service.
Subscribe to streams exposed by the service and react to incoming events by
updating the UI.

To be more concrete about what the last point means, we can look at one example of
logic: how to determine who is the player that can play the next card.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 18/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

As weLive
InfoQ said, one22:
June rule of do
How thetraditional
game is that playersscale
approaches can in
play
thecards one
Cloud? after the other. So,
Register Now
for instance, if Player_X is the first player and Player_Y is the second, after
Player_X plays a card only Player_Y can play the next card. All other players can
not play any cards. This information is part of the state which is kept by the server.

Any time a card is played the server sends a message to all clients specifying which is
the next player.

The service layer turns this message into a notification over an Observable stream
called enablePlay$. If the message says that the player can play the next card, the
service layer will notify true over enablePlay$ otherwise false.

The component that enables for a player the possibility to play a card has to subscribe
to the enablePlay$ stream and react accordingly to the data notified.

In our React implementation this is the functional component Hand. This


component defines a state variable, enablePlay, that governs the possibility of
playing a card. The Hand component subscribes to the enablePlay$ Observable in
an effect hook and, any time it receives a notification from enablePlay$, it sets the
value of enablePlay triggering the redraw of the UI.

The relevant code for this particular functionality implemented by the  Hand
component using React is the following.

export const Hand: FC = () => {

const server = useContext(ServerContext);

. . .

const [handReactState, setHandReactState] = useState<HandReactState


. . .

enablePlay: false,

});

. . .

useEffect(() => {

. . .

. . .

const enablePlay$ = server.enablePlay$.pipe(

tap((enablePlay) => {

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 19/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

setHandReactState((prevState)
InfoQ Live June => in
22: How do traditional approaches scale ({the
...prevState,
Cloud? enablePlay
Register
})
Now

);

const subscription = merge(

. . .

handClosed$

).subscribe();

return () => {

console.log("Unsubscribe Hand subscription");

subscription.unsubscribe();

};

}, [server]);

. . .

return (

<>

. . .

<Cards

. . .

enabled={handReactState.enablePlay}

></Cards>

. . .

</>

);

};

The Angular counterpart to this example  is logically identical and is implemented in


HandComponent. The only difference is that the subscription to the enablePlay$
Observable is made directly in the template via the async pipe.

About the Author

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 20/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

InfoQ Live June 22: How do traditional approaches scale in the Cloud?
Register Now

Enrico Piccinin

Enrico Piccinin is a man with passion for code and for some strange things that
sometimes happen in IT organizations. With many years of experience in the space of
IT development, he likes to see what happens when the “new IT” is applied to
traditional organizations. Enrico can be found at enricopiccinin.com or LinkedIn.
Views and thoughts here are my own.

Show more
Show less

Inspired by this content? Write for InfoQ.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 21/22
5/6/22, 2:51 PM Exploring Architectural Concepts Building a Card Game

Becoming an editor
InfoQ Live June fordo
22: How InfoQ was one
traditional of the best
approaches scaledecisions of
in the Cloud? my career. It has
Register Now
challenged me and helped me grow in so many ways. We'd love to have more
people join our team.

Thomas Betts
Lead Editor, Software Architecture and Design @InfoQ; Senior Principal Engineer
Write for InfoQ

Discuss

Please see https://www.infoq.com for the latest version of this information.

https://www.infoq.com/articles/exploring-architecture-building-game/?utm_source=programmingdigest&utm_medium=email&utm_campaign=470 22/22

You might also like