#begin

Today we are going to look at the next chapter of the Clean Code book by Robert C. Martin. In the previous blogs of this series we discussed the first two chapters of the book.

The next chapter dives deep into functions. Functions are a very important concept in programming since they will offer you the actions to get things done and they are one of the main concepts you can use to organize things. With just data, you can’t do much, you need functions to operate on that data and make something useful out of it. In this chapter we are going to explore all the advice Uncle Bob gives us to write proper, clean functions.

 

Functions

Well first of all, functions should be small, and even when you already think they are small, they must be smaller. Uncle bob proposes that they should be like 2 to 4 lines long. You might think this is impossible but he means there should only be as much as 4 executable lines of code in a function. So yeah braces don’t count. Because if they would count, a simple guarding if-statement at the top of your function would count as 3 lines, but there is only 1 line that actually does something. This is also the reason I personally adopted a C# style that uses as less braces as possible. In my opinion it makes the code far cleaner because, if you do not have braces for if-statements or loops , the body in the loop can ever be only 1 line, that contain, you guessed it, a function. I do admit that sometimes I write longer functions than 4 lines. But this is because it feels meaning less to extract more than I already did. Sometimes I have already extracted out all the logic that is on another level of abstraction and thus I can’t, meaningfully, extract more. So, see this advice as a guideline not as a rule. So I think we found another example of advice that feels a bit dated. Just remind yourself to keep functions as small as you can meaningfully get them. Now, let’s talk a bit about how you can get them as small as it takes.

So first of all, try to keep the level op indenting to 1. This might sound silly, but if you keep the level of indenting to 1, then it is pretty easy to keep the function short since you will need to call other functions in the body of the existing function. This is also a very nice piece of advice I use as much as I can, unless, again it feels meaningless to extract a function. A simple example is when you have a try catch block, and within it you have some if-statement or loop. This gets you to 2 levels of indenting. Uncle Bob says that you should always extract the code within a try catch block into its own function but that will sometimes feel meaningless. And, it might even be dangerous since, if you extract the function to some private function in your class, someone else can call that function but now it is no longer protected with a try catch block. So I still think the body inside the try-catch block should be as small as possible, but just extracting the method body into its own function merely to conform to this rule is a bit too much sometimes.
Next, functions should only do 1 thing. This piece of advice I highly recommend to follow and also agree with very heavily. Functions must only do one thing! This will keep your functions short and will also reduce the level of indenting. You probably know about some 100 line update functions in your code base somewhere. I bet that the update function is doing more than 1 thing. It might track Input, timing logic and movement in one massive Update function. So extract these things out to their respective functions and reduce the body of the Update function down to only do these three things in this case. In some functions you might be able to identify that it is divided into multiple stages like declarations and initialization, operations and cleanup. This might be a sign that your function does one thing, because it actually doe three things. Trying to keep your functions limited to do one thing can be really difficult, but once you get used to it will make your code look far cleaner and better to read. Trust me, I notice the difference!

And as I hinted at before, functions should only have one level of abstraction. So when you have a function that uses concepts like Player, Enemy and Weapon it uses a fairly high level of abstraction. Don’t start throwing around StringBuffers or http-requests in the same function. Extract those out into one of the classes the functionality belongs to and call that function. The same goes for having all kinds of Debug.Log statements that break the level of abstraction by logging weird data. Extract them out, keep your functions clean and make sure the level of abstraction is at the same level. So if there are two levels of abstraction in your function, extract the second level out to something new and just call that function. I really can’t keep up with how many times a day I smack the CTL+ALT+L shortcut in Rider to extract a function. Another aspect of using only small function everywhere is that you can very easily reuse functionality. You have probably committed the crime of coping the same logic around in the same class. I know I’ve done it before. If you use this approach, you don’t need to anymore since it’s in a function and you can simply call it. So this will also keep your code DRY, or don’t repeat yourself. Uncle bob also says you should organize the body of a function in a top down manner. What he means here is that a function must start at it’s highest level of abstraction, and as the function progresses it should call lower level functions. He compares this in one of his talks to the way news articles are structured. They start with a header, then some introduction that generally explains things, and the further you into the article the details increase and thus the level of detail is goes lower. I’ll try to hunt down the talk, but I think it’s a very old talk from the NDC conference Oslo in 2009 or 11 about, well, this chapter the book, called Functions.

Next he talks about Switch statements. Yeah, how would you keep switch statements with more than 4 cases, less than 4 lines. I mean, switch cases always do N number of things, not 1. Well, a very simple answer, you can’t. But what you can do is use that switch statement as less as you can. Don’t go copying that statement all over your code! Keep it isolated in some class and use that class because a switch statement can be a really big issue that introduces bugs into your system because. Some developer might use a switch statement with all cases individually, another might combine cases, yet another might use if-else statements, of simply only an if statement for a single case. If there are bugs in the system, you must track down every clever usage of the switch statement, and trust me this can become a real nightmare. So the thing I do sometimes is to extract the switch statement logic out into it’s own class and make it follow a command pattern. So you simply pass in an object that has the enum and a callback action and the command-class will execute it. This way you still have that multi line switch statement somewhere, but it is isolated into its own class. It’s just a necessary evil you sometimes cannot deal with in another way. Some of you might disagree with this, if you do let me know. How would you solve this particular thing?

The next topics function arguments. This is a fairly controversial topic I think. Uncle bob has some very prescriptive advice here. I’ll try to give you my most honest opinion because, some of these I simply do not agree with and I’ll explain it.

So He starts off by saying that the function you can best understand, is a function without arguments. I think we can all agree with this one. I mean, if you do not have to think about passing in arguments to the function, you just call it and be done with it. Next he talks about functions with one argument. These are very common and there are two reasons to inject an argument into a function. You’re either going to ask a question about that argument, or you might do an operation on that argument to transform it. He also says to avoid single argument functions that return a void, but to return an out argument. I mean, why would you ever do this? It makes no sense to me what so ever. A method returning void, but has an out argument? What the heck. I’m not even sure I’ve ever seen this in C#.

He also says you should avoid flag or boolean arguments as much as you can. Because, IFF you pass in a boolean to a function, it probably does more than one thing.. Right? I mean it does something in the true case, and something else in the false case. It’s kind of obvious. But, I do disagree with him on this issue. I use flag arguments for functions like SetActive-something, or Toggle-something, or Enable-something. Separating these out is just too much and, it will increase the indentation and number of lines in the calling function, right? So if you have a function enable and disable, there needs to be an if-statement somewhere that make the decision to call the right function. So sometimes just keep a boolean argument. Just make sure to remove it in functions it does not belong to like if you have a save function with that has two arguments where the first is the state of the game and the second is a boolean that indicates if the state is also supposed to be send to a backend. So setting it to false will save the game on your local machine, and true will save it in the cloud. Just, separate the functions and make a SaveLocal and a SaveOnCloud function or something. This will clarify the intend of the function far better than some random boolean argument. I can also remember a talk he did on the Clean Code, functions chapter where he talks about this and the boolean argument being tangled on. This is a talk from quite a long time ago and him being a Java programmer and me being pretty sure that Java at that time did not support default function parameters, and last I checked, it still does not. Weird right? So when you have support for default function parameters you can simply make one function that has all the defaults in there and call it with whatever you need to customize.

If the concept of default function arguments is new to you, you should definitely check it out since it will remove many unnecessary function overloads you probably do not need. I use them here and there in some cases. I can’t really quickly think of a nice example but you will probably know of some nice places you can add them if you know what this language feature brings. Let me know if you have a nice pattern or usage for this.

Next Uncle Bob talks about how to properly name a function. I think we glanced at this topic earlier but here he specifically states that functions should, contain verbs and if needed can be a combination of a verb and a keyword like writeField with an argument name.

Now that we have gotten far into the chapter of function it starts to touch on the important topics. I mean, nice names and arguments are one thing but there are some more important operational things we need to make sure we comply to in order to write proper, clean functions. And that is, we cannot have side effects in functions, unless it is absolutely clear that there are side-effects. But, what are side effects you might be thinking. Well the perfect example is the Open and close functions on a file or stream. If you call Open twice, without closing it between those calls an exception will be thrown. God forbid you forget to close the file or stream once you are done with it. And yeah, these functions do in my opinion not communicate very well that there are side effects, but this is more of a historical pattern. So if some terminology fits your domain model you can get away with short names like this. Luckily in C# we have the “using” statement that takes care of opening and closing streams or files and other kinds of classes that implement the Idisposable Interface. What using does is, it will allocate the resources to open a stream of file, then you execute your logic and do your magic, and once your code block is done it will close the stream or file automatically. Personally I find the using statement and syntax very nice, and I use it where ever it makes sense, like with HTTP requests and accessing the file system for example. Well I went off on a tangent here a bit, haha.

But yeah try to get as less functions with side-effects in your code base as possible. And I’m trying to come up with a nice example in a untiy context here but, uhm well, maybe this: imagine you are implementing some kind of merchant system in your game and once you buy something from a store, the amount must be subtracted from your game currency. The buying from the store, and subtracting the correct amount of currency from your wallet should be separate functions. Of course, these actions are highly related but the functionality should not be coupled to one another because it will confuse people.

The subject is really important too, and that is output arguments to functions. Uncle bob says that you should avoid output arguments as much as you can, and if you must change some state then you should create two functions. I simply disagree with this since I use functions with output arguments all the time. The perfect example is the TryGetValue on a dictionary. If you are implementing this kind of behaviour you just return a boolean as argument of the function itself, and return a reference of the thing you want to get as an output argument. This results in a very nice workflow in my opinion. I do agree with Uncle Bob when you have output arguments on functions that return void. That’s just useless and yeah, those should definitely be avoided. But generally, I use output arguments in a TryGet-something context.

Then he touches on the subject of command query separation. Let’s first of all explain what exactly command query separation is. Uncle bob describes it as: a function should either do something, or ask something, not both. So what he means is that a function executes some kind of action, or it should do a check for some assertion. Your function should not do both. I think a nice example of this is those one-liners you sometimes see inside of conditions of if-statements. The text-book example that I fondly remember is reading lines from a streamreader where you check if the line is null and assign it to a local variable. You can simply do this by adding some additional parenthesis. This is both a query, checking if the line is empty, and assigning the line to a local variable, the action. I bet that if you have followed some book about C# programming you have encountered this specific pattern. And I have to admit, I use this pattern sometimes as well, because it is just so common and concise. So although it’s not a proper command query separation, is still use it inside functions. But if we take it to a greater scope you should definitely try to avoid combining queries and commands. So on a function level separate out commands from queries, or actions from questions. A simple example that I can give you here from the top of my mind is the following; imagine you build some sort of pooling system. And, you have a method called GetBy-some prediate. Now, what the function does is query the objects in the pool that match the predicate you have given. Imagine that, if the object is not found, a new object is taken from the pool and flagged active plus it’s given those properties specified in the predicate. So we have two problems here, first of all, we have a function with a side effect, second, we run a query, searching for the object and an action, instantiating the object with the properties from the predicate. This is very confusing and trust me, I’ve seen solutions like this before because it is “convenient”. What do you think about command query separation, do you have any nice examples, please let me know if you do 🙂

Next up is preferring exceptions over error codes. And although, catching exceptions is easier I disagree with Uncle Bob on this one as well. As we all know, Exceptions create a lot of overhead. Generating these stack-traces etc. is very slow and in a real-time system we often cannot accept these exceptions being thrown because of it. That being said, you really need to build in a lot of sanity checks, preferable at the edges of your bounded contexts. A bounded context is a term from Domain Driven Development, which means that responsibilities are encapsulated inside the bounded context and terminology within the context has a specific meaning which is well understood, also all data that is traversing through the bounded context is deemed trusted. So it’s checked for null-refs and other kinds of corrupted data values. So in a Unity context we try to avoid throwing exceptions in parts of the code that are heavily frame dependent. So don’t throw exceptions inside an Update loop for example. This also means that that you should not throw exceptions somewhere far up the stack. Generally, do sanity checks and use exceptions only in code that does not impact the real-time system. Another piece of advice I would like to give here is to try avoid using Debug.LogError since IFF you use it you need to jump through some loops when unit-testing. I know this may sound as bad advice but most LogError statements you will see in Unity3d project are often recoverable meaning, you log some error but it’s not critical and thus execution of the code can continue. If you do use LogErrors then your unit tests will start failing on these logs. Try and come up with some proper nil or default values for your functions like empty strings, lists, arrays or just simply null. You can also make your types nullable by adding a questionmark to the type of the variable or field. So, you can make an int or boolean nullable and operatte properly on that if needed to.

Uncle bob ends this chapter with some comments about try-catch statements but we have already talked about this a little bit. His advise is to always extract the try-catch blocks into their own function since it will reduce the indentation and to clarify something potentially dangerous is going to happen. Again, my advise for this is to carefully consider this because when you extract the function out of the try-catch block, you introduce the option to call the function without the try-catch and thus introduce bugs into the system.

So that’s it for the third part of this blog. The next blog will cover the fourth chapter of the book called Comments. I hope this blogs explained the concepts around clean functions well enough. It’s quite a long read, so I hope it wasn’t too boring haha. But then again, if you reached this far into the blog, you probably didn’t think it was boring. I hope you learned something that you can start to apply immediately in your day to dat work!

Thanks for reading, and smell you next time!

#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!