Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.

NOTE: This article is 3 years or older so its information may no longer be relevant. Read on at your own discretion! Comments for this article have automatically been locked, refer to the FAQ for more details.
As I've been working on the server code for my game, I've been noticing that the complexity of it is increasing but also duplicating unnecessarily. After thinking about it for some time and seeing why my code was exhibiting these traits I concluded that it was due to how I was handling errors.

The whole idea for the server was to prevent cheating as much as possible by the players and to reduce the work that the client has to do in validating every single action a player is allowed. What this meant on the server side is at the beginning of each method that dealt with a client request there would be a myriad of checks to make sure the client was not trying something funny.

For example the overall structure (in pseudo-code) would be like this:
method doSomething()
{
check is player logged in
check is player allowed to do this action
check does player have enough credits for this action
...
# finally do the real work
update player game state
generate response with updated state
return
}


Where the majority of the duplication was occurring was in those checks. On average there would be 100 lines of code just to make sure that the player had a valid session and had enough credits to do what they wanted to do. This was starting to get out of hand because every time I wanted to add a player action, I would be copy/pasting a lot of code. This also meant if I had to add an extra check as a part of the 'standard checks' then I would have to go through all of the implemented server actions and update every single one to include the check plus the handling code for it!

There had to be a better way.



To give a bit more detail each of these 'pre-flight' checks would look like this:
if (some condition doesn't match)
{
look up error to return
construct response object appropriate to the function return type
return response
}


That's a lot of code for every check! Also not easy to refactor due to that early return statement.

The goal was simply to reduce the amount of code needed for all the pre-flight checks. So I decided to introduce exceptions to my code. I didn't particularly want to have exceptions in the beginning because it's quite easy to make a mess of the whole exception design and the libraries that I was using didn't throw exceptions so it was natural for me to follow the same trend.

To do this I had to do a few things:
  • Create exception classes to deal with user/internal exceptions
  • Extract all the pre-flight check conditions into helper classes that would throw exceptions instead of returning false
  • Add a catch at the very top level that would convert the exception to an appropriate response object for the method


After doing all of this my pre-flight checks were a mere 5 lines on average, a fantastic simplification which will make the code more manageable in the future. This also meant that I could refactor other parts of my code to be reusable which was not possible before with so many separate return statements for every single error condition.

Now if there is an error condition or it's detected that the client code is trying to do something funny, I just throw an exception in the server code, the server response handler catches this and converts it to an error response. Simple.

The only thing I am not quite sure about is having a number of methods that have a conditional check that throws an exception, but that's something I can live with.

-i

Hope you found this post useful...

...so please read on! I love writing articles that provide beneficial information, tips and examples to my readers. All information on my blog is provided free of charge and I encourage you to share it as you wish. There is a small favour I ask in return however - engage in comments below, provide feedback, and if you see mistakes let me know.

If you want to show additional support and help me pay for web hosting and domain name registration, donations, no matter how small, are always welcome!

Use of any information contained in this blog post/article is subject to this disclaimer.
comments powered by Disqus
Other posts you may like...