Developing Mau King — Test Driven Development of the Server

This story is part of a series “Developing Mau King, the card game for Android

The server side for Mau King has been written solely in Node.js, with the bottom-up, test-driven development approach

Genesis

In the beginning, there was no code. Just a blank screen in the Vim editor, and an initialized Git repo with zero commits. A feeling of peace and clarity.

When I decided I would actually start writing this program, I spent around a week just planning in my head the objects and their relations in the fundamental layer, like cards, table, players and communication between them. On my way home from work I was at risk of getting hit by a car with my head in the clouds. At home, I was grateful to my company for the sleek notebooks on which I scribbled.

Once I had enough confidence, one day I wrote the first line of code:

function test_MauCard_matching_if_same_color_or_number()

This was the first line of code and the test that followed failed because there was no such thing as MauCard — yet. It was the Test Driven Development coming up in all its glory —

With TDD, you travel a long and winding road with little worry

The idea was to build the server with the bottom-up approach, in which lower layer objects were built first: cards, card-piles, the table. Then layers would be built on top, like game sessions and the playground and so on.

Having expected things would get messy pretty soon, and having played with TDD ideas just months before this project, I concluded that was the best way to go. And to this day I am grateful that I did.

The testing framework

The story of this server started in late 2015 when I worked in the London office of Bloomberg L.P. as a full-time C++ developer. The only advanced testing frameworks I used to work with, were those related to C++

As for JavaScript frameworks, I once saw my young and talented colleague Thomas Kaminski use Jasmine so I knew which one I would take, but I was so excited and preoccupied with plans for MauServer, that it felt too boring to learn another testing framework. Additionally, I decided a testing framework should be extremely light-weight and completely adaptable to my own needs, so gradually I wrote my own — I mean, how hard can it be? It is all about expecting true and false in a few flavors. The real head-scratcher is what you put inside.

Indeed, those few test helpers I wrote then turned out to be sufficient to this day. And if they had not, I always had the option of turning back to Jasmine or whatever.

Discipline

I know most of you wrote unit tests before, so I am not going to talk about how they are written or good practices. Anyway, there is so much good literature about it on the Internet already.

Instead, I would like to emphasize how important it was to be patient and disciplined enough to follow through with always writing a test first, then the logic to make that test pass. While many people state that every practice and methodology should be adapted to “the company’s own needs and tradition”, I believe you always get the best tests if you write them beforehand, and when you miss doing so, you leave vulnerabilities behind and it starts taking away your confidence.

Even if you plan to write that omitted test later, you either never do it because something else is always more important, or you write them later just formally to ease your conscience, which means they are of low quality. But if you start with a test beforehand, by specifying the behavior you want to achieve and the interface you want to get, then you really start thinking outside the box.

What is Legacy Code?

I kept writing code for that server after my regular work hours for the next 2.5 months. I did not have any UI whatsoever. My only consumers were tests, which were often whole game scenarios. The feeling of safety you get when some of these policemen blow their whistles and report your accidental breakage of some old behavior was irreplaceable. Rules are being followed, games are being created and played in this virtual universe, new features are added and you know everything still works correctly. But another benefit I got from such high code coverage was even more valuable and I will tell you about it immediately.

Around 2.5 months after I started working on the server, I stopped the development altogether for reasons I will talk about some other time. And then two long years passed without any activity. Then one day I decided I would take that old project of mine and give it life again. I had in my memory that the server was almost complete, and I just needed to build the client from scratch. Soon as the client progressed I realized I needed a lot more from the server, and I found myself digging through the codebase I hadn’t seen for 2 years. The instance I modified something, a test failed — I was confused for a second, then burst into a happy laughter.

Those tests I had were PRICELESS. After so much time I could continue developing the server with confidence, even though I forgot so many details. In some cases, it took me a lot of time to remember why something was written in a certain way and why some test is failing, but tests with meaningful descriptions were there to help me, like:if User disconnects before joining or creating game, then no merging is offered on reconnect. And if you delete a condition in file MauGame.js line 234, the test fails. Of course!


Teasers: Idea, Requirements, Project Management, Technologies, React Native, Expo, Node.js, Git, Test Driven Development, Gimp, UX, Graphical Design, Task Management, Prioritization, Financial Cost, Commercial Aspect, Ethereum, 3rd Parties, Audio, Android, Styled Components, Motivation, Time Management, Marketing, Facebook SDK, Google Play Store, Google Ads, Performance Testing, and MORE.