Thursday, December 22, 2011

This post is a technical overview of my Tic-Tac-Toe implementation. It is a zero server-side logic, pub-sub based, realtime, multiplayer game which uses Redis and Backbone as the key enablers of real-time and moving logic to the client side, respectively. Now that all the buzz-words are out of the way, the source code is on Github. There are rough edges with reliable communication, security holes do exist, but for the most part it works well.
I would specially like to thank Nicolas Favre-Félix for Webdis without which this would’ve been impossible.

Basic functioning

On visiting the home page the user has an option to either join a game, or play with a friend. The join game option pairs the player with another player who also wants to play (if you are the only one online, you’ll have to wait). If you play with a friend you get a link you can send him/her so you can play together.
The players are asymmetric in the sense that there is a ‘hoster’ and a ‘joiner’, whose roles I’ll get into in a bit.

Technology Stack

Tic-Tac-Toe game me the opportunity to experiment with a ton of technologies/products I hadn’t handled before. The stack goes like this.

Yep, thats a lot of stuff for something so simple, so I’ve tried to rationalize it below :P

Clients

All clients are identified by a UUID. The ‘host’ player’s UUID is used as the name of the Redis Pub/Sub channel. The ‘joiner’ will also subscribe to this channel and publish to it. This is why the ‘host’, ‘join’ bifurcation, so that a common channel can be used for communication. All messages are JSON objects.
All communication is initiated by the ‘joiner’. The host player keeps waiting. The joiner starts the game, after which both players keep sending each other the moves made by the humans playing. After each move, both sides check for a win/lose/draw. Again, the joiner sends a gameover message when it detects somebody has won (or it’s a draw). The host then verifies that this is actually true, and responds back with it’s own gameover message. Then both parties change their UI accordingly. This causes the slight delay between the actual win and the notification.

Server side

The first question is ‘why both nginx and haproxy?’ I could’ve run Webdis and nginx on two different ports since Webdis supports CORS, but Opera does not support it. Running just nginx web-facing and then proxying to Webdis based on path is also not possible since nginx does not currently support HTTP chunked replies, while haproxy does. Chunked replies are used by Webdis to relay Pub/Sub messages.

Implementing ‘Join Game’

To allow two people to be paired, a Redis list is maintained. When a client clicks Join Game it attempts to LPOP a UUID off the list. If none are found (no other players), it RPUSHes itself onto the list.

Client side

The client side has all the logic and so is more interesting. I won’t go deep (you can read the source), but will discuss the key areas.
Once a game has been initiated, both clients open a XMLHttpRequest to the subscriber channel. They watch for readystatechange events and try to parse the messages. This is the Subscriber which fires events when it receives valid messages.
The Publisher component is used to send messages, while Webdis is used for other Redis commands (currently only LPOP and RPUSH).
The GameRouter is the controller, sets up models and views, watches for gameover and beginning a host or join. HTML5 pushState or hashes are used to offer permalinks for games. /host/UUID is for hosting and /play/UUID is the joiner. Backbone’s Router and History is used to cleanly handle this. One feature I wish there was, is a way to query what the current route is via Backbone instead of mucking with window.location.
The GridModel drives the game once it begins, triggering gameover events and checking the grid after every move, also handling the turns. GridView handles rendering the SVG grid and pieces based on GridModel and processes clicks while HUDView notifies the user of his turn, piece and game state. Events are an integral part of this entire setup and Backbone makes it very simple and modularized.
One thing that stands out in my use of Backbone is the absence of Sync. I’ve not used it, although it integrates well with Backbone. The game model didn’t seem suited to it, being more event-based rather than the model reflecting the game state. Collection is also not used since there is only one grid.

Issues

The lack of any server side code does lead to certain issues. None of them are serious when it comes to Tic-Tac-Toe but some affect the user experience and others are security issues.

Usability

On the usability front, the current code is very fickle. The joiner only tries to initiate the connection the first time it starts. If the host fails to respond for some reason (e.g. network connectivity) then both parties will keep waiting. If a joiner refreshes his page mid-way through a game, the game will restart for both parties (a good idea if you are a joiner and you are losing \:P). If the host refreshes the page, the joiner has to refresh after him.
The slight lag to decide win/lose/draw was probably unnecessary. Rather than verifying both sides are on the same page, the notification could’ve been shown directly since this is just a game. The UX would’ve benefited.

Security

Webdis sports a HTTP interface to Redis, but there is no real authentication support, which means the Redis instance hosting Tic-Tac-Toe is also effectively a public domain database (although the command set is restricted). Ideally this should run only in a trusted intranet. Ideally Webdis itself would be capable of serving files and deliver something like a nonce which it would then use to ensure that only its own connections are allowed to relay messages. Similarly nothing is stopping someone from grabbing the UUID and then playing future moves using a bot of some kind to always play optimally. In the case of Tic-Tac-Toe this is just a minor prick, but for actual client-side MVC applications this requires fixing.

Conclusion

Tic-Tac-Toe demonstrates that with a data structure server and HTTP interface to it, web applications where all logic is client-side are possible. Using the server as a Pub/Sub relay also allows near real-time performance, with WebSockets or SPDY possibly leading to better performance. Security policies still mean that true peer-to-peer isn’t possible. Authenticity and authorization also remain to be solved. On trusted intranets, such applications could be used for non-critical tasks. Meanwhile, games like this at least can be safely implemented and played as long as you have no sore losers :).

In fact I didn’t particularly like most of my CS courses either. There were a few gems like System Software and Computer Networks at DA-IICT, but the rest were totally out of sync with the real world. So if you are a precocious hacker should you drop out of college in India? (Assuming your Indian parents will let you do that!)

NO!

Try your utmost to get into a good college with good infrastructure. Here is why you would want to do so. Not only is the infrastructure itself important, it also attracts the smartest people. Do well in college while improving your own skills and knowledge.

My reasons are based on personal experience, and in ways document some of my shortcomings too :P

Like minded people

Unlike the dense technological concentration of Silicon Valley, India doesn’t have technological hotspots. Even in Bangalore, very few people are passionate about technology and are hacking on open source software or launching startups (while this is pretty high in India terms, it is nothing in Bangalore terms). FOSS talent is instead concentrated in the students of engineering colleges. (I focus on FOSS because it’s a good way to filter out passionate people.) You will get to discuss problems, hack on code and be inspired by these people. A concentration of geeks also leads to geek events like hackathons. During various college fests there will be programming contests and so on. You’ll get to have fun. Finally there will be a lot of smart people doing things other than computer science. But they will be equally as passionate as you are, they will be liberal and forward looking and it will be a pleasure to interact with them. Oh and please don’t think of every person you approach as a potential future employer, employee or general networking and increasing contacts kind of person. Sometimes you (and certain people in the Valley too) just need friends. Face it, do you want to spend the next few years talking to your mom about why REST-ful APIs are the bomb or why this is funny?

Facilities

High-speed Internet access in India is still not too common, but colleges will usually have a great LAN setup, a lease line to the Internet and generally good connectivity. Use these to experiment with your peer-to-peer applications, host websites, or write the next great DDoS program (I’m not advocating this). That said they also may have ridiculously bureaucratic system administrators, censorship and the like. You just have to deal with in (and in some cases, circumvent).

Your college will also have a certain ‘relic from the past’ which is far more useful than any of our modern day, 140 characters technology. The library. Specific technology education is always best done via Internet, but general concepts and deep theory is still found in books. Use it well, you will regret the day you leave college and books will have to be purchased. (To overseas readers – there is hardly a public library system in India.) Oh, and do remember the fiction section.

Motivation and Persistence

When you are working on personal projects it’s very easy to give up or change tracks. You also tend to focus only on the things you like. College courses will force you to persist at subjects you don’t like, and keep you onto one thing for 3-4 months. Valuable lessons when your first commercial project is 90% done and you don’t want to polish it up because node.js just came along and is much more fun to play with. Do a great and challenging final project and end your education on a high note.

Find some other interests

Your life isn’t going to be just about CAP theorems, cache invalidation and naming your projects. You will have to interact with society. Take a humanities course. Learn to loosen up a bit — travel, listen to music and play sports. Waste time with friends once in a while. Don’t burn out before you’ve even started. Your whole life before 25 should not be spent being a workaholic. Sometimes I think the Valley propagates Minimum Viable Product, pitching to VCs and beer and pizza far too much. You don’t want to end up like this. You might also want to try some of these things.

So if you were thinking of dropping out, just give it a second thought. If you are still convinced you should drop out, do it. But please let me know at nsm.nikhil@gmail.com why you did so.