POKERithm is a multi-player web application enabling beginner players to hone their skills by competing with each other and world-class poker stars. Built with such powerful technologies as Elixir, C++, and AWS Lambda, the application provides lightning-fast user experience and simple interface.
The task was to design and develop a web application for playing poker.
- create a unique design with poker specifics in mind (color palette, user experience, interface elements, etc.);
- implement high-performance architecture from scratch;
- implement continuous deployment with hot code reloading.
- develop a piece of functionality to predict the odds of winning and calculate game statistics.
Before we proceeded with the development process, we conducted research and highlighted the crucial features a good poker app should have.
Among them are easy to use User Interface, appealing vector graphics, engaging features in the game, and strong technical support provided by the poker game software providers. All of these criteria have been successfully implemented in our application.
Let’s take a closer look at every step of Pokerithm’s implementation.
Every project has its story
What is the very first step of the project implementation? Based on our longstanding experience, we made sure that you shouldn’t start developing the project without thorough research. When we got the Pokerithm project, we conducted research and found there were a bunch of similar poker apps in the market. However, this didn’t discourage us.
Do you remember that before Facebook there was MySpace and before Google – Yahoo. It’s all about the approach, the solution, and the quality of execution.
We collected all the clients’ requirements and started creating a storyboard for future application. At this point, we put ourselves in the users’ shoes and looked at the challenges from the users perspective.
To make a storyboard as accurate as possible, we tried to consider every possible user choice. To do so, we planned out each interaction in our storyboard, where any given action takes the user next.
On the one hand, it may be easy to design core sections. However, the most difficult part is how to show each success and failure state, how to display forms (where you need a keyboard to pop up), and mapping out the multiple paths users can take to other screens.
We didn’t spend too much time on making our storyboard and trying to make everything perfect. The main goal was to approximate at an early stage what the minor and major features of the application would be.
We also didn’t use any custom fonts except the defaults ones. Our point was not to distract people from the storyboard but to help them focus on the most important elements.
As soon as we finished with a storyboard and it was approved by the client, we came to the design itself. Our task was to create a simple registration flow and an easy-to-navigate interface; one that would allow users to fully concentrate on their game. We designed a unique color palette and the main interface elements.
In the foundation of our application lies the Elixir programming language. The reason why we chose Elixir as the main technology for POKERithm is because it’s fast. REALLY FAST. It allowed us to achieve unprecedented performance and reduce the risk of possible delays, which is crucial for an online multiplayer application.
This technology was a perfect choice for us as it provides specific nonfunctional requirements that relate to the business logic of the project. As a result, we were able to see the number of resources needed for application performance. Additionally, a client of the project could connect to the server literally anytime.
POKERitm was one of the first projects, where we used Elixir. And we were amazed by the speed and stability of the product, the ease of hot deployments, and the intuitiveness of Elixir’s syntax. It was a pleasure to work with concurrency, the codebase was extremely easy to maintain and it didn’t take much cluster’s resources.
The very first reason why we chose Elixir is that it’s really fast and you can’t argue with that. In July 2015, Phoenix developers compared their framework with Ruby on Rails. It turned out that firebird stayed a bunch of steps ahead the Ruby on Rails. And it used just one fourth of the processing power and just one sixth of the total memory.
If you want to develop a poker app, you need to consider the fact that thousands and thousands of users may be playing it at the same time. This means you need to make it scalable. It should be an app that would simultaneously support millions of users around the world, who run dozens of processes at the same time. Elixir comes in handy here.
This language is based on the libraries that form the backbone of the most reliable systems in the world. Start concurrent tasks and services that are fully supervised. If one of them crashes, Elixir would restart in the last known good state, including any tainted related service.
The Development Step
The first thing we did was the specification for the project. Our project managers worked closely with the client to prepare a clear and informative description of the features to develop. To make sure we’re on the same page with the client, we followed the good old iterative approach, i.e. every time a new piece of design or functionality was ready, it was shipped to the client. This allowed us to save time for future improvements.
Next was the technical implementation of the project. We are great aficionados of modern and robust technologies such as Elixir and Amazon AWS, so working on POKERithm was a genuine pleasure.
Be it a web or a mobile application, architecture is arguably its most important part. Since we’ve been developing the web application from scratch, we used this opportunity to leverage our best web development practices and created a powerful and scalable architecture.
Each session of this game can last for 4 hours, where can participate about 4 players. There’s a fixed time limit for each player to make a move. So there were the following non-functional requirements:
- concurrency and availability (our game should always answer and can’t be blocked by other processes on the server);
- bidirectional communication (the data should be retrieved by the client both on his request and the server’s initiative);
- save server upgrade (there should be a mechanism for updating the servers without losing any data);
- performance (this requirement is especially important when it comes to games);
As we already mentioned, for writing the functionality, we used Elixir. This programming language uses the famous Erlang virtual machine – BEAM. Perfect pro-competitive measures and multithreading, exchange of asynchronous notifications in accordance with the actors’ models: that’s all we need to lay a proper foundation for our app.
One of the things a game server is responsible for is to be an initiator for some changes along with players. It shouldn’t only broadcast notifications from one player to another.
This means that there should be a distinct process, which will be responsible for this task. Proper work with processes is a “must-have.” The more effective it is, the better it is.
There are some games that stop their servers for updating. On the other hand, there are games that add new servers and allow old games to finish. However, all these processes overload DevOps department.
There’s one more option: upgrade a server code on-the-fly. Despite the fact that there are not so many processes with this feature, we found it in BEAM. This allowed us to provide communication between a server and clients. Having used web-sockets with a hot code swapping, we got rid of any problems with an internet connection during the updating. However, the time of a client’s connection to the server may negatively influence the game results. This created a challenge with time synchronization.
To created the best user-experience, we needed to solve the challenge with real-time synchronization. Simply put, we needed to shorten the response time of the servers.
At first, we tried to work with the local time of a browser but soon abandoned this idea as this created certain inconveniences. For example, a user could change his browser local time and then everything would go wrong.
That’s why we found another solution – monotonic time.
Short aside: You can use monotonic clocks to determine elapsed time. If you want to display the time to users, you query the time of day. On the other hand, if your goal is to measure the elapsed time, you need a timer that would provide you with the right answer even if the user changes the time on the system clock.
To safely measure the elapsed time in a program, you need a clock that tick out time continuously, without any jumps when a user sets the system time. This clock is also known as a monotonic clock.
This is the solution, which we decided to use for real-time synchronization. Luckily for use, Elixir has as internal monotonic time so that we didn’t have any with it.
However, the real difficulties came with the browser. We used a “performance.now” tool that helped monitoring our browser’s performance. This gave us some kind of a monotonic time as it always goes ahead. However, this didn’t save us from the mistiming between the server and the client’s actual time.
To solve this challenge, we sent a server’s time to every web socket message.
Alright, let’s come back to the development process.
So we reserve the right to use the first two options, if necessary. It’s always cool to have several options, isn’t it?
Since speed is crucial criteria for every game, we don’t have to choose between In-Memory state and persistence. Our games are isolated from each other so that we use a separate process for every game (GenServer), which save a condition in itself.
In case, we wanted to create something like that on Ruby (one of the main tool we use), we’d probably use celluloid. When reviewing the issues on Github, our attention was attracted to the following issues memory leak with timers. At the same time, we need to consider the fact that the version 0.17.3. is considered as a stable one. Elixir, in its turn, doesn’t have such a challenge as BEAM provides an automatic garbage collection for every process individually. As we put the results of the game into the persistent database only after the end of the game, this provides us with a high speed.
Nevertheless, there’s no need to concentrate exclusively on stateless and 12-factors. Otherwise, it may significantly complicate the project implementation by looking for the technologies you won’t need at all. Mainly it happens because of the main tools limitation.
Finally, we implemented another cool feature in our project, which is also known as continuous deployment with hot reloading.
Hot reloading allows reloading parts of your code on-the-fly without reloading the entire page. This is especially useful when you want to maintain the current state of your page while making User Interface updates. This way you don’t have to refill a form or do some action over and over again after updating your code. Additionally, hot reloading allows updating actionable code without reloading the page, such as the function for when a button is clicked.
In a nutshell, it allows developers to push out new features to production without having to stop or pause the application. In other words, if you’re playing poker with your friends while a new feature is being released, you won’t get thrown out of the game and you won’t even notice any glitches.
Feature for calculating the winning odds
To make our application even more engaging, we decided to implement a feature that would calculate the game stats and predict the winning odds. To make it real, we used C++ language with Amazon’s latest technology, which is also known as “Lambda.” From the technical perspective, Lambda is a web service for serverless computing that performs code in response to certain events and automatically manages computing resources.
In our turn, Lambda helped us focus on writing a reliable code as well as saving for the client as much resources as possible.
We’ve developed a blazing-fast multiplayer web application with a unique design and intuitive user interface.
The heart of Pokerithm is Elixir programming and this was the right decision.
We chose Elixir programming language for being high-concurrency and low-latency. So when it comes to processing data at high volume at the same time we want our app to run quickly and smoothly without the delays, nothing can be better than Elixir.
Elixir is the perfect solution for building applications that can handle millions of users at one time without affecting website performance.
Our development team implemented a highly scalable and robust architecture that allows for future changes and improvements; whether minor or major.
Despite the fact that Pokerithm hasn’t got its #1 rank in the App Store and Forbes didn’t talk about it yet, like it was we an application we made, it has great potential.
Having implemented Pokerithm, we reached a conclusion that the main ingredients of a successful project are a good idea, experienced development team, and wisely chosen technology stack. Combine them all and you’ll get a successful project. You’ll get Pokerithm.
- Amazon AWS
- AWS Lambda