#begin 

In the previous six blogs about clean code we checked out the first six chapters of the clean code book by Robert C. Martin aka. Uncle Bob. If you have not read them yet; Get back there and read them! In the mean time, the rest of us are going to continue reading and discussing chapter 7 of the book.

 

Error Handling

So chapter 7 is all about Error Handling. The first sentence in this chapter states that and I quote “it might seem odd to have a section about error handling in a book about clean code” And Uncle bob is right, but, there is always a but. Error handling can be a massive issue in code, especially in games.

In the first blog about clean code where we discussed meaningful names and functions we talked about how functions must be short and the level of indenting should at most be 1. We also touched upon the topic that said that the body of a try block for a try-catch should only contain 1 line, a function that is called. When we were talking about this I discussed that throwing exceptions in real time systems like video games is a bad idea because you will suffer a massive performance hit by doing it. Trust me, I’ve learned this the bad way. So never throw exceptions in so called mission critical code. I think many of us have heard that advice before, if not, well here it is; don’t throw exceptions in mission critical code. And find some safe way to work around exceptions. A simple example people give for this is the following; Imagine you need to get some value from a dictionary. You can do that in a couple of ways. The easy way is to simply pass the key into the dictionary and get it’s value. But that’s not safe since if the key does not exist, and exception will be thrown and you will need to catch it. But you can also use the TryGetValue function on a dictionary to get a value. This function returns a bool and passes the result value as an out argument of the function. So this way you can easily wrap the TryGetValue in an if-statement and, if the if-statement passes, you can use the value because you know it not null.

I always though this was a nice example for how to make code safe in an easy manner. I also talked about how I use the TryGetValue strategy in many parts of my code and thus do not agree with Uncle Bob on his advise about not using our arguments in functions because they can be really handy. But Yeah, that was all in Part 1 of the Clean Code series of this blog series so, if you have not read to it, go check it out!

But for now, let’s jump into chapter 7, Error Handling. And, Uncle Bob starts with a topic I sort of agree with depending on it’s scenario and I guess, that all the advise he gives in this chapter is dependent on the context, where and when the error is thrown or caught. So if it’s in mission critical code, or in some random Update loop of some game object, throwing exceptions is just a bad idea because the performance of your game will tank. But on the other hand, if the exception I thrown in some code that does not impact frame-rate then it’s ok and exceptions are a very easy, clean and nice language feature to use.

So his first advise is to use exceptions rather than error codes. He says that when you do not use exceptions and use error codes in log messages your code can become very obscure because you need to check for many weird conditions in your code. And yeah, Uncle Bob is right. In Unity, where we do not want to throw exceptions we cover the code in lots of if-statements that make sure nothing can go wrong. So you check for many situations where errors can pop-up and if there are incorrect things, you use Debug.LogError for example to make it appear in the log, yet not throw an exception because your performance will suffer. So yeah, his advice is to use exceptions over logs since it will make the code cleaner but I think that in this case, we need to take his advise based on the context we are in. As I said for a couple of times now already, don’t throw exceptions in mission critical code, find some other way to make the code safe.

His next advise is about how you should always write your try-catch-finally statement first. He says that try-catch-finally statements are a bit like transactions in a database. So no matter what happens in the try-block, if it encounters an exception, the catch-block needs to make sure your game is left in the state as before the try-block got executed. I think this is a really nice analogy. So what ever magic you do in the try-block, if an exception is thrown, you must undo it in the catch-block. An example would be make sure any side-effects created in the try-block are taken care of, with the most obvious example being closing a file stream. So you open some stream in the try-block, and execute some logic but it throws an exception. Now you will need to close that stream in the catch-block or else you have a memory leak in your system plus you can no longer open a stream to the same file because it still exists and is still in use as far as the code is aware. So you must close that stream in the catch-block. I think this is really great advise and you should consider this carefully.

Uncle Bob continues his rant with a section about checked exceptions. But this is truly a java problem not a C# problem. In java you can define which type of exceptions can be thrown by certain methods. Which is useful but also stupid if you ask me. When you define concrete exceptions types that can be thrown by methods, you create, you guessed it, dependencies. So if you change the type of exception that is thrown in a method, all the code that calls that method in any way must recompile and thus you lose the ability to create independent systems. We in C# cannot state what type of exception is returned by a method, although we can add a summary to a function and describe it there but we do not state concrete types that can be thrown by functions. This is good by the way haha. I think this is one feature of java, we as .net devs are glad we don’t have. I don’t think we are missing any of the Java features any way.

The next thing he describes is something I do agree with heavily and that is that you should provide context with exceptions. I mean, an exception is thrown for a reason, you throw it because you validated some data or whatever and thus you know why you throw it. You should provide useful information in the exception by a message for example. So if you throw a nullreference exception because your player prefab is null when you try to instantiate it, add a string saying: “Failed to instantiate the player because the prefab is null”, or something. Just make sure that the exception does not create confusion.
Next Uncle Bob says that you should create your own exception classes to fit the caller’s need. So always create exceptions that provide information to the class or classes that are calling that code. So define custom exceptions in such a way that they define how they are caught. So, as in my previous example where the player prefab is null, you could throw a simple out of the box nullreference exception, or you create a custom exception with a type like PrefabNullException to create a more finegrained exception type. Me personally, don’t create much custom exception types that often because, well as I said before, we try to not throw exceptions in Unity3D since the performance penalty is often to high. So, when I do throw exception I often just use what C# provides to me unless the exceptions just don’t match with the problem. But most of the time, just a simple nullreferenceexception with a proper message provides more than enough information for the calle.

Then Uncle Bob says that if you follow the practices for error handling we have discussed so far you can get a good separation between business and error handling code. But in some cases exceptions are also used to define the flow of a system. And let me give you a fun example in a Unity context; Imagine you have a player class, which holds a reference to a JetPack class, because why not jetpacks are awesome. Now when you press the “Jump” button you need to check for the jetpack being there. If you have a reference, you invoke the jetpack, else you simply jump. Some people like to model this condition using an exception. But you should model it with a simple if statement. If you throw an exception in this case it can be very confusing since jump is still a valid action to take, you just don’t have a jetpack. So don’t throw exceptions in the normal flow of your game, use exceptions for, well exceptions that happen in your code.

The last subject Uncle Bob talks about I this chapter is that you should never return or pass null to a function. And although this sounds nice and I would agree with in a non-unity context. I still often return null from functions since it does not allocate any memory. Uncle bob makes the case that if you return or pass null into function you will find out quickly that your code will be riddled with null checks for any kinds of data. And, yes he is right, but in a Unity Context, you need to do many null checks anyway. I mean, don’t just rely on having a reference to a gameobject for example, always check it for null before manipulating it because it could have been destroyed at any time. But Uncle Bob says that having all these nullchecks in your code makes the code less clean. And he’s probably right here, but I still do prefer returning null over some expensive memory allocation thing, especially again, in code that impacts the FPS of the game. You don’t want to start allocate memory inside an update loop, because you are going to notice that garbage collector kicking in. Trust me, you will see the hiccup. I do how ever agree with his statement that you should never, intentionally pass null into a function. Like with me previous example with the jetpack, if your jump method required that jetpack reference, and you know for a fact you do not have a jetpack, don’t just call the jump function with null as an argument. Create another function that does not take arguments and call that.

So, that’s again a wrap for another chapter of the clean code book. Chapter 7, error handling. I hope you enjoyed this entry in the clean code series of blogs and that you have learned something. I know I may have repeated myself a bit too much in this chapter but error handling is a really interesting subject since it can make or break your game.

I hope you join me in the next blog as well. Bye Bye!

 

#end

01010010 01110101 01100010 01100101 01101110.

Hey, sorry to bother you but you can subscribe to my blog here.

Never miss a blog post!

You have Successfully Subscribed!