It’s been a long time since my last update on my solo project – Reversi.

Since I’m busy with other personal matters, I can only work on the project at a slower pace. But I decided to have at least a little progress every week. Before continuing my journey, I want to talk about the design of the game.

This project aims to implement a full-stack multiplayer Reversi game with multiple rooms and real-time gameplay using WebSocket. My goal is to learn Go and WebSocket for backend development. I hope to gain enough skills so that I could implement an online Mahjong game in the future.

Multiplayer Turn-based Game

Multiplayer turn-based game, in a nutshell, is a variant of a chatroom.

In a chatroom app:

  1. Client A sends a message to the Chatroom Server.
  2. Chatroom Server processes the message, and broadcast a message in the room.
  3. Client B receives the message through the display of the Chatroom.
  4. Continue…

In a turn-based game:

  1. Client A sends a message containing the move details to the Game Server.
  2. Game Server validates the message, calculates the next state, and broadcast the result in the game room.
  3. Client B receives the results through the display of the game room.
  4. Continue…

Understanding how a chatroom works helps a lot in implementing a turn-based game. From here, we can split the implementation into 2 large phases.

  1. How a client interacts with the server (and other clients).
  2. The game mechanism itself.

This generalisation helps in building a game room engine that can be reused for other turn-based game, extended to support more than 2 players, or even enhanced to allow observers to join the game room, watch the players, and interact with each other.

Tech Stack Decisions

For the backend, I chose Go, as I want to use it in a more serious development rather than simply learning data structures and algorithms. There are 2 popular WebSocket libraries for Go: Gorilla WebSocket and Coder WebSocket (formerly known as nhooyr/websocket). The latter looks cleaner in its implementation, while the former has a larger community. As a new learner, it’s better to stick with the one that has more support and more references. Therefore, I chose Gorilla WebSocket for the implementation. Now, as I’ve gained more knowledge, I may try Coder WebSocket in my future projects and contribute more examples.

Choosing the frontend stack was mentally draining. Although I used Next.js for Mahjong101, I decided not to continue with it. Next.js is made for full-stack development. It’s fast to make new components and pages, but it encapsulates too many things and hides a lot of the details how things work. To be honest, after working for the frontend of Mahjong101 with Next.js for a couple of months, I still doubt if I really understand the concept behind it. Also, the implementation relies heavily on the backend, and Go is responsible for it. Using Next.js is simply an over-engineered decision because the backend functionality of Next.js is largely unnecessary in this implementation.

Then I debated between React and htmx. People often say htmx works smoothly with Go. htmx aims to simplfy frontend development without overwhelming developers with overly complicated JavaScript libraries. On the other hand, React is the most popular JavaScript library in the corporate world. Check LinkedIn for job postings for frontend or full-stack developers – most of them require knowledge in React.

Unfortunately, I know neither of them. If I chose either one, along with Go and Gorilla WebSocket, I would have to master 1 + 1 + 0.5 = 2.5 new technologies all at once while working on the game. This would cause cognitive overload and hinder my progress – I might spend too much time identifying problems where many aspects were unfamiliar.

Finally, I decided to push myself by using vanilla TypeScript. In my career, I spent a few years working with Ext JS, a legacy JavaScript framework. But I’ve never built a frontend without a library – just pure JavaScript. It’s time to brush up my fundamental JavaScript knowledge and master DOM interactions. I want to see how far I can push myself without using any other libraries or frameworks, except TypeScript. Yes, not even Tailwind CSS. I may change my mind later, but for now, I’ll stick with vanilla TypeScript.

I hope I won't need to add more dependencies.

In the end, the job of the frontend is to display the result provided by the backend, validate the user’s input, and pass it to the backend. Let the backend do the heavy work.


Next, I’ll dive into the client-server communication and the tradeoff between pure WebSocket and a hybrid of WebSocket and RESTful.

Roadmap

#FeaturesStatus
1Console version of local multiplayer
2Adopt Gorilla for WebSocket
3E2E backend flow from registering to announcing result🚧
4Basic frontend rendering🚧
5Unhappy flows handling, e.g., client(s) leaving unexpectedly🚧
6Cosmetic fine tune for frontend
7Security features
8Production ready
?Others, e.g., User account, Ranking, DB/Redis/AWS adoption