#begin
So next up is chapter 18 and it’s titled Code Should be obvious. Interestingly, this chapter comes after all the information about comments. This shows the importance of comments and summaries in the eyes of Prof. Ousterhout I think. He puts so much emphasis on comments in this book. I think comments deserve a lot of attention because most of them are crap so having a decent practice on how to use and write comments is good. But I think having decent coding practices is far more important than comments. But alright, it is really nice though that there’s literature like this that focuses a lot on comments.
Code should be obvious
Prof. Ousterhout says that obscurity is one of the main causes of complexity. It occurs when important information is not obvious to existing or new developers. The solution is of course to write code that is more obvious, clean code as many would call it. We have been discussing this for the past blogs now so I think we have a good grasp of what the heck clean code is. But in this chapter, Prof. Ousterhout will share some of his tips to make code more obvious.
When code is obvious someone can read it really quickly, without much thought and their guesses, or as Prof. Ousterhout puts it so nicely in this book; it increases intuition. Intuition is such a nice term to use for this I think. When code is intuitive, the reader does not have to spend much time and effort to understand the code in order to add new features, fix a bug or adapt it. It will increase their efficiency but also their effectiveness to actually be able to solve bugs. And the best thing of all, obvious or intuitive code requires less comments and documentation.
Oh, I’m so glad he finally said this and I’ll repeat it; “Obvious code needs fewer comments than
nonobvious code”. This is exactly what Uncle Bob says in the Clean Code book. And as you might have noticed from the previous blogs I gravitate more to Uncle Bob’s approach than Prof. Ousterhout’s approach. I just think that, following Uncle Bob’s practices for clean code result in a cleaner code base than large classes with long functions and lots of comments. But then again, there are some gems in this book that you cannot easily ignore. Like the mindsets while programming, deep vs. shallow modules, defining errors out of existence, comment driven development, which I still have yet to try out. So I think the combination of Clean code and A Philosophy of Software Design go hand in had pretty well. But let’s continue with the book before we drift of into another dimension entirely.
Prof. Ousterhout then also correctly says that “obvious” is in the mind of the reader, it is highly subjective; it’s easier to notice that someone else’s code is nonobvious than to see problems with your own code. John says that the best way to find out if your colleagues find you code obvious is through code reviews. And although he is right, I would argue that Pair programming or Mob Programming will be far more effective than simply code reviews. I think you should combine these practices in order to create an obvious codebase.
So let’s discuss some of the techniques Prof. Ousterhout suggests to make code more obvious. The two most important techniques have already been discussed in the previous chapters and they are choosing good names and consistency. We’ve talked about this in-depth in the previous blog so go back and read it if you haven’t yet.
But there are a few other ways to make code more obvious and that is judicious use of white space. Prof. Ousterhout says that the way code is formatted can impact how easy it is to understand the code and read it. This highly correlates to the advise given by Uncle Bob. He has an entire chapter dedicated to formatting, both horizontal and vertical formatting.
Prof. Ousterhout talks about how white spaces and newlines will increase readability of your code. In Clean Code this is referred to as horizontal and vertical openness respectively. You can use new-lines in order to separate concepts in functions, for example; if you have a guarding if statement at the top of your function, leave an empty line below the guarding statement to put more emphasis on it. And for horizontal openness we can use white-space to separate concepts from each other like adding white space between mathematical operators or logical operators in if-statements or arguments in loops. Another greatly standardized example of horizontal openness would be a white-space between arguments of a function. Luckily, our IDE’s enforce these standards by default so we don’t have to worry about these things as much.
Another practice John uses to make code more obvious is again; comments. I agree that sometimes you simply cannot express certain things in code and thus a comment is acceptable. The perfect example for this is the exclusive index in the substring function again. But let’s always remind our selves that comments are not the only way to explain the things that are not obvious from the code and they are no excuse to simply write bad code.
Next up Prof. Ousterhout lists some things that make code less obvious. He starts of with a rather interesting one, and that is Event-driven programming. He says that this kind of design or architecture is not obvious because it is hard to follow control flow of the system. Functions are never called directly, they are dependent on runtime registrations to event handlers. My personal thoughts on this are that, Event-driven architectures are a very, very strong and well used tool in your game development toolkit. Event-driven architectures allow for a really nice, decoupled way of developing your game. Think about how often you might have implemented a simple observer pattern, or even when you drag and drop an event handler on a button in the inspector. That would qualify as event-driven as well. Also, as Prof. Ousterhout said so himself, dependencies are made at runtime which is very nice since you are now able to deploy and develop independently. So in my opinion, you can use event-driven architecture as much as you want, but use it wisely since Prof. Ousterhout is right, you can create a horrible mess. I also wonder what he thinks about the current trend of microservices, these are all event based systems. But that’s not related to Unity3D so let’s continue with the book.
Prof. Ousterhout says you should add proper summaries to handlers of events that say when they are subscribed and when they are invoked. This seems like a good idea to me. I don’t do this often but it seems like a good idea so I might try this in the future.
He then raises his first red flag in a while and it says, and I quote: “If the meaning and behavior of code cannot be understood with a quick reading, it is a red flag. Often this means that there is important information that is not immediately clear to someone reading the code.” Hahah, I mean duhh. That’s been the subject of the past 17 chapters of the book. I think it is pretty funny that he put this in there, this is obvious haha.
Another thing that makes code less obvious is the use of generic containers. But what are these, well Prof. Ousterhout says that many languages provide generic classes for grouping things together like the Pair class in Java. In a C# context this could be KeyValuePairs or maybe tuples. John says that these classes are tempting to use since they make it easy to pass around multiple objects in a single variable. And he’s right! Since I’ve taken up some functional programming I use this strategy often. Although I often create value objects that represent these pairs so I can have them nicely named and they fit the domain. A value-object is a term from Domain Driven Design which is simply a data structure which does not have a unique identity but is identified by the data itself. A simple example would be an object that represents a home address. I can have two different value objects that point to the same address, which makes them equivalent. This is what we call structural equivalence. But Prof. Ousterhout is right that using a keyvaluepair as an output of a function is not really obvious since they don’t translate to your domain.
Prof. Ousterhout then has a very nice statement written in a bold font which says: Software should be designed for ease of reading, not easy of writing. And, yeah this is essentially what we have been discussing ever since the first blog about clean code. Readable code is of great importance to any stakeholder of a software system because in the end, they will all profit from it.
They next practice that makes code less obvious is really interesting as well and that is you should not use different types for declaration and allocation. The example he gives is a field that is declared as a generic list of a message class, but is initialized as a generic arraylist of a message class. So he’s using polymorphism. He says you should not do this since it makes code less obvious. And I heavily disagree here. The entire purpose of OO is to use polymorphism properly to reduce dependencies. We often declare generic lists of things based on some interface or abstract class in order to reduce the dependencies on concrete objects. It’s a bit confusing to me why Prof. Ousterhout would put this in. His argument not to put it in here goes as follows, and I quote: “The actual type may impact how the variable is used ( ArrayLists have different performance and thread-safety properties than other subclasses of List ), so it is better to match the declaration with the allocation.”
So yeah, this particular example is just a really bad use of polymorphism. But I would say in most cases polymorphism is a good practice!
And the last thing that makes code less obvious according to Prof. Ousterhout is that some code might violate reads expectations. The example he gives in the book is of a function with side-effects. So the reader will expect the function to do something, but it also does something else on the background. We’ve talked about this in the Clean Code blogs as well. Try to separate the side-effects from functions and make it abundantly clean that they are there or else you will most likely run into really tricky bug situations. Trust me, profiling your games’s memory with the memory profiler is never fun.
To wrap this chapter up, Prof. Ousterhout says the following and I quote: “To make code obvious, you must ensure that readers always have the information they need to understand it. You can do this in three ways. The best way is to reduce the amount of information that is needed, using design techniques such as abstraction and eliminating special cases. Second, you can take advantage of information that readers have already acquired in other contexts (for example, by following conventions and conforming to expectations) so readers don’t have to learn new information for your code. Third, you can present the important information to them in the code, using techniques such as good names and strategic comments.”.
#end
01010010 01110101 01100010 01100101 01101110
Recent Comments