How do you make a design easy to understand?
A lot of people probably think that in order for something to be easily understandable, it needs to be simple. And sure, while simplicity is always nice, I don’t think it’s required for understanding your software designs. This episode describes two other factors I think will serve you much better, familiarity and consistency.
the next time you come up with a wildly new design, ask yourself if it’s really worth it. Because anytime you introduce something new, you risk confusing a lot of people. Sometimes the change is worth it. Especially when the new design catches on and becomes widely adopted. It then becomes familiar. But if it’s a new design with limited use either in scope or in time, then it may not be worth it. Stick with a design that is common.
A long time ago, light switches used to be two push buttons. I remember when my grandparents moved into an old house and the fun I used to have pushing the buttons on the walls. At some point, this style of switch went out of favor and a toggle switch became normal that flipped up or down. And then not too long ago, more houses started using flat toggle switches that while still toggle up and down actually have a lot in common with the old double push buttons. My point is that what’s common and familiar can and will change. It also takes a huge effort to change major trends. This is just something to keep in mind because it can have a major impact on whether or not your software designs are understandable.
The other factor is consistency. This is different than being familiar and works to help your designs be more understandable in the short term. Don’t make other developers keep track of special cases. Keep everything consistent and you’ll find even if your design is complex, it’s a lot more understandable.
Listen to the full episode or you can also read the full transcript below.
Okay on to the question this week. There’s no single answer to this type of question. I’ll give you some tips and guidance that have worked well over the years.
The first thing to understand is that you want your designs to be as simple as possible but not overly simple. Sometimes, things are going to be complicated and if you try to make something too simple, it starts looking more like a toy. Focusing on simplicity alone won’t make your designs easy to understand. It can sometimes make them unusable. And if a design is unusable, then it doesn’t matter if it’s understandable or not.
Instead of simplicity, I like to focus on two other aspects when designing software, familiarity and consistency.
Let’s consider familiarity first. For the last several weeks in this podcast, I’ve been explaining design patterns. And I’ll continue explaining design patterns. We’re not done yet. They’re super important and directly relate to this question about how to make your designs easy to understand.
Think about your first spoken language. The language you speak most often. It’s said that some languages are harder to learn than others. But it doesn’t matter with your first language. It comes easy to all of us. Why is that? Well, I’m not a language researcher but to me it seems likely because we’re so familiar with it. It’s part of who we are. It forms our very thoughts. We can easily understand another person no matter how fast that other person speaks whenever our first language is involved.
Over time, familiarity becomes the dominating factor in how understandable something is. It’s like the Big-O notation of understandability. You can listen to episodes 37 and 38 for more information about Big-O notation and how to use it to describe the complexity of an algorithm. It seems to me that familiarity when taken to the limit becomes the most important factor.
I’m sure you’ve met people who are experts in their field and who can jump right in to a debate about their field and quickly take charge of the entire conversation. How did this person reach this level of expertise? Usually through many long years of hard work. This has the side effect of making a person very familiar with a topic.
Based on this, any design you create has the potential to be understandable given enough time and effort. The only problem is that’s not what we really mean when deciding if something is understandable. We want to know if something is understandable now.
The best way to accomplish this is to make sure that your designs follow what’s already been done. Because this builds on existing familiarity.
A person completely new to programming is going to find everything unfamiliar. There’s still something you can do to help even a new person understand your designs and that’s the other aspect, consistency, that I’ll describe in just a moment.
As a new person learns one topic, if the next topic resembles the first in some ways, then it’ll naturally be more understandable. The more similarities you can adopt and the more common practices you can follow, the more understandable your designs will be. This is where design patterns help you the most. They provide a means for you to design your software so that it’s familiar to other developers. And even yourself too.
This is why for the previous episode about double-buffering, I decided to introduce the pattern as a behavioral design pattern instead of the new category that the author used called a sequencing pattern. Does double-buffering have to do with time and sequences? Yes. But creating a new category for just three patterns, to me, breaks the familiarity guideline.
There’s always a proper time and place to introduce a new concept or some radical new design that breaks familiarity with everything else. My advice is that you should strongly consider if your design will be better served by being unique or by being familiar.
I’ll describe the next focus, consistency, right after this message from our sponsor.
( Message from Sponsor )
If familiarity leads to long term understandability, then I think consistency is the best thing you can focus on for short term understandability. When something is consistent, then it becomes expected. And when that expectation matches reality, it’s as if you’ve spent years becoming familiar with it.
I mentioned languages earlier. Think about how many inconsistent words are in your language. Special case words that don’t follow the normal patterns. Sometimes these are called sight words for early readers because they have to just learn them by sight and not by how they should look if the words better resembled the normal words. After spending years working with a language, these words become expected but not because of their consistency.
It follows then that a language that’s more consistent should be easier to learn because you don’t need to spend so long becoming familiar with strange words that don’t follow the rules.
When creating your own software designs, being consistent is like an invisible quality that we can’t always point to, but is sure appreciated when it’s there.
Let’s say that you need to call some operating system API in one of your class methods and this API returns an error code. Well, unless you’re already using similar error codes in the rest of your application, the easy and inconsistent way to handle this is to just declare your class method to also return a similar error code. This is called exposing your implementation because you let your class interface be determined by whatever means was used to implement the interface.
If the rest of your application uses exceptions, then a better and more consistent way to deal with this API is to check the error code yourself inside the method and throw an exception in the case of an error. This way, other developers know to use exceptions when dealing with your code. You’re consistent and this leads to code that’s easier to understand.
You should also pay attention to the order of your method parameters. If you have a bunch of methods that need an A type and then a B type to call the method, then keep them in that order. And when you need to create a new method that also needs a C type, then put the C type at the end. This will keep the first two parameters consistent even though this new method now needs three parameters.
And the last thing I’ll mention about consistency has to do with naming patterns. Don’t abbreviate some words in your method and class names while spelling out others. The only time you really should abbreviate anything or use an acronym is when most people already know and expect something to be abbreviated or expect an acronym. For example, you probably should change a method called getHypertextTransferProtocolAddress to just getHTTPAddress. This is because spelling out such a common acronym could cause more confusion than just using the acronym.
Oh, and let me talk about something that always makes me cringe. It’s common in programming to need to identify something. So a lot of method names will be something like getID. And the developer will capitalize both the I and the D in id. The only time you should do this is for acronyms. Just to be clear, an acronym is a series of single letters usually from the first letter of several words. Well, Id is not an acronym, it’s an abbreviation of the word identity. So to be consistent with other abbreviations, only the first letter I should be capitalized.
A lot of people think that C# is easier to learn than C++. As far as the language itself goes, I’d be tempted to say that C# is actually more complicated than C++. But learning a programming language involves more than just the language syntax. The bigger learning curve for me anyway has always been learning the libraries and frameworks that come with the language. This is where C# really shines. If there’s one area that I think Microsoft truly did an outstanding job, it has to be the consistency of the .Net Framework. It used to be that I could look at several Microsoft APIs and easily group them together based on different patterns. Some used error codes. Some set lastError. Some followed strange naming conventions. Etc. Not anymore. With the .Net Framework, Microsoft really has a consistent design applied to almost everything. I think this is the biggest reason for making C# easier to understand.
Take a suggestion from Microsoft and put some extra thought into making your designs more consistent and familiar and you’ll find your designs too are easier to understand.