#begin

Today we will discuss a really important topic in software design and development: Consistency. Yeah let’s go!

 

Consistency

So chapter 17 is called Consistency. Prof Ousterhout says it’s a powerful tool for reducing the complexity of a system and making the behaviour more obvious. He defines consistency as, and I quote: ”If a system is consistent, it means that similar things are done in similar ways, and dissimilar things are done in different ways.”. I think that’s a pretty good and very straightforward definition of consistency. He then also says something really interesting and that is, and I’ll quote again: “Consistency creates cognitive leverage: once you have learned how something is done in one place, you can use that knowledge to immediately understand other places that use the same approach. If a system is not implemented in a consistent fashion, developers must learn about each situation separately.”

I think this is totally correct and also such a nice way to formulate it. I mean, consistency creates cognitive leverage. I’ve never heard it said like this. But it totally makes sense and you can use that leverage to reduce the cognitive load. Prof. Ousterhout then continues by saying that consistency reduces mistakes since developers will be able to program with more intuition and based on recognition of code patterns and algorithms they have seen before.

Just by this small introductory section I think we get a good grasp of the awesome content this chapter will provide. So let’s quickly continue with the first section.

The first section is about a couple of examples on how to apply and create consistency. Prof Ousterhout starts with the obvious, something we have have talked about intensively in the previous blogs and also was an important topic in blogs about Clean Code, and that is of course… Naming. Names must be intention revealing and consistency will also greatly help with the perception of things. So don’t use terms like GameController, GameManager or GameSingleton interchangeably. Choose one suffix to rule them all, and in darkness bind them.

The next form of consistency is coding style which I think is a really great one to add. A common coding style that adheres to standards and guidelines set by the community or company is a great way to increase the understandeability of your game. Also make sure to hook up your IDE correctly to enforce most of these policies. In Uncle Bob’s Clean Code book there’s also a great chapter about formatting code. He talks a lot about how to properly do horizontal and vertical formatting. He explains concepts like density and openness. Which refers to code that related code should be close to each other in a file, so don’t spread conditions in if-statements over multiple lines. Openness refers to using additional white-space or new-lines to create separation between things that a re separate. So use white-spaces between mathematical or logical operators in formulas or conditions, or use white-spaces between function arguments. And use new-lines to separate functions and fields for example. And Yeah, luckily our IDE’s do a lot of this out of the box already but sometimes you need to tweak some settings to fit your personal, or company preferences.

The next form of consistency is implementation of interfaces. So if an interface has multiple implementations, that is a form of consistency and will improve the unstandeability of your game. Once you understand one implementation of the interface, you will understand other implementations as well. Maybe not their nitty ritty details, but you will understand it in an abstract matter, which is certainly nice. So if you see another implementation of that interface in the code, you will probably be find it easy to find out what it does on a high level.

Next up are design patterns which are generally-accepted solutions to certain common problems. Such as the model-view-controller pattern or the dreaded singleton your will definitely find in Unity3D projects. If you use patterns like these in your code they will be easy to understand plus you can raise the abstraction level while talking about the implementation. So instead of explaining some difficult setup and dependencies between classes, you can just tell your colleague you used the observer pattern, and move on. Just make sure you don’t overdo it. Don’t use design pattern for everything in your game. You will build a very flexible system this way, but it will also be overly complicated. Oh and then I want to throw another thing in here and that is you should not use design pattern names for things that are not related or do not implement the pattern. So for example, don’t call your class PlayerSingleton, when it does not implement the singleton patter. These names have become such common practice that, you use them, people will have certain expectations about them. They have become so accustomed to these design pattern names that reading them will instantly create recognition. But if you use them in code, that does not implement the actual pattern, they are a great source of confusion.

And the last example of consistency is invariants. An invariant is a property of a variable or structure that is always true. Prof. Ousterhout gives the example that in a data structure that stores lines of text, every line is terminated by a newline character. These kinds of properties will ensure consistency in your game. I think this a particularly interesting type of consistency and one I don’t think of often myself.

But how do we ensure that there is any kind of consistency in our code? Consistency is hard to maintain, especially when many people work on a project over a long time. Sometimes rules and guidelines will be violated unintentionally. For example, by newcomers. So next up, Prof. Ousterhout will give some tips on how to maintain consistency:

And his first tip is to make sure the conventions, style guides and guidelines are documented somewhere. He proposes to use some kind of wiki for this and you should encourage people to actually read these docs. Also make sure to keep your rules and style guides timely since these can get out of date. For example, when new programming language features are introduced, the style guides and conventions can change. For example, in Unity3D we cannot use Records but these are available in the language. Maybe in the future, we are able to use them in Unity3D and then we might be needed to update the guidelines. Or maybe when the ECS finally reaches somewhat of a stable state, you might need to update the guidelines to include the ECS.

Ousterhout’s next tip is to enforce the rules and conventions. And here I totally agree and I think almost everyone will. Our IDE’s support enforcement of rules and conventions out of the box. Even so, when you first open your IDE there is probable some enforced formatting applied automatically. Try to follow the C# coding conventions here as much as you can btw. I follow the C# conventions used I our community but I admit I made some small modifications to them like; my constant variables are in SCREAMING_SNAKE_CASE instead of just UpperCamelCase, this makes my constants just pop out a little more. And I’ve made comments in my code a bright red color, as if they were errors; so if the comment is not useful or when it is outdated or misleading I’ll delete that giant red fluorescent comment from the file. And I think I’ve talked about this before but with Jetbrains Rider you are able to setup a dedicated git repository to host these kinds of settings, so I did. We share this repo among team members and thus we ALL have the same rules. You can also just export these rules into a zip and import them. I suppose other IDE’s support this feature as well. It’s really easy and straightforward. And the best part is that, when you do this, the entire team uses the same rules for formatting and code style, plus if the rules need changing, you edit the settings in the gitrepo and everyone’s settings are updated. It’s such a nice collaborative feature. You can also extend your CI/CD pipeline with linters and other kinds of checking and formatting tooling. That’s a great idea as well btw.

The last tip by Prof. Ousterhout to help with consistency is to well, do what others do. You should check out and study files to find out what the rules and conventions are. I think in open-source projects this can indeed be a good way to study the coding conventions and styles. But in a team inside a company, you really want these rules to be enforced. But this also goes a little further. For example; you might need to implement some feature and you can check out how similar features are implemented and do it exactly the same way. A simple example would be, if in all the existing code some AbstractFactory design pattern is used for object construction, you should not implement your feature using a decorator pattern. You should take the approach that is most obvious which is to align your code with the existing one and implement it with an AbstractFActory. Now is this always the case? Well, no I don’t think so. Especially when you are working with legacy code, you might intentionally divert from previous design decisions because you want to improve the structure of the code and make it more testable. But you still need to be carefull. Prof. Ousterhout says that you should not just change existing conventions. Having a “better” idea is not a sufficient excuse to introduce inconsistencies. He’s totally right here. I’ve fell into this trap myself before where I would introduce some new way of doing things when refactoring. But this did not align with the current state of the code.

Prof. Ousterhout then also explains you can take consistency too far. When you become overzealous about consistency and try to force dissimilar things into the same approach, such as by using the same variable name for things that are really different or using an existing design pattern for a task that doesn’t fit the pattern, you’ll create complexity and confusion. And I guess he’s right, especially with the part about design patterns. I think we will encounter this more than once in our careers when some developer sprinkled design patterns all over the codebase for no apparent logical reason other than he wanted to use as much design patterns as possible. But this makes the code overly complicated and most importantly, it probably wont fit the domain. In your domain there might be no singleton, visitor or observer. These are programming jargon.

Concluding argument for this chapter are that consistency is part of the strategic mind and an investment mindset. Take just a bit more work to ensure consistency. Work to decide on conventions, work to create automated checkers, work to look for similar situations to mimic in new code, and work in code reviews to educate the team. The return on this investment is that your code will be more obvious. Developers will be able to understand the code’s behavior more quickly and accurately, and this will allow them to work faster, with fewer bugs.

This is all very true and I certainly think Uncle Bob would agree with everything in this chapter. This is not particularly controversial advise. I think the advise in this chapter was mostly, well, common sense. But I suppose, if you don’t know about how to enforce conventions you will run into inconsistency problems. So, setup your IDE settings and share them among your team and also make sure to document design decisions somewhere so other developers align their code with the existing design and not work against it.

 

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