Improve your C# code even further with these tips

According to the Coding Guru Robert C. Martin, clean code is not too well defined, however, the results of clean code are pretty clear. You do want the code to be readable as a good book, easy to maintain, and easy to extend. Bugs should be easily spottable, or even avoided by design. A clean code will keep productivity high, and the costs of maintaining low.
One of the quotations from the book Clean Code goes like this:
“Clean code can be read, and enhanced by a developer other than its original author.” (Dave Thomas on Clean Code)
In my opinion, this is one of the most important points of clean code. If not only you can maintain a code, but also any other developer, that has an experience level close to you, a code will automatically fulfill most of the requirements of Clean Code. Of course, it may not be 100% clean, but clean enough, that the results are close to the ones mentioned above.
For other developers to maintain your code, it should be extremely easy to read and understand. Your goal, when writing any line of code should always be readability. Even one line could confuse another developer enough, that he might waste precious minutes understanding your code, and it is your fault!
So what makes a code more readable by other developers?
In this article, I will not focus on the methods of checking, that are mentioned in the book Clean Code, as I can recommend them out by yourself. However I am focusing on specific guidelines, I learned from my experience as a .NET developer over the last 8 years.
These guidelines are supposed to make code as short and/or readable as possible. They do not replace any methods of clean coding, but they are complementary to those of Clean Code.
Let’s not waste any more time and jump straight to the guidelines. These are the principles, my colleague Jan Donnermayer and I figured out by ourselves during the last 8 years of programming.
1. Avoid “Else”
The first principle is, to simply avoid else
. Nearly every time, you are using else
in the code, it is very easily avoidable and makes the code more readable. Have a look at the following examples:
The first example is also known as early returns. You should always clarily state, what you expect from the arguments in the first few lines of code.
The second example shows a fairly new way of switching statements in C#, the so-called pattern matching. You can clearly see what happens when some explicit case was passed, and what function is handling the case. Here also another guideline was applied: Create an extra function for each sub logic, that is well named.
2. Avoid high Cyclomatic Complexity
Another principle for this matter is, that you also should try to avoid a higher number of cyclomatic complexity. This means, that your method should have the least possible amount of side logic, that may be executed, when some certain state is present. You may for example realize this, by implementing interfaces to classes and implement the separate logic in each class:
3. Avoid too much identification-levels
In the example in avoid_else.cs
you can also see another difference, that avoiding else
makes. You avoid one indentation level in your method. A good guideline to make your code more readable is, to simply avoid too many indentation levels. I found, that a maximum of three to four indentation levels is a good rule to stick to. However, those should be really necessary indentations.
For instance, you should never put an if
clause inside another if
clause! Actually, you should avoid if
clauses anywhere, if feasible.
Nearly the only case, where I use more than one indentation level, is when I use Linq-Queries. More on this topic comes in the next guideline.
4. Avoid Loops by Mastering Linq
You probably have seen code like this:
Ask yourself the question: Is your loop replaceable by a Linq-Query? And I guarantee you in over 90% of cases it is! It may be my personal opinion, but I think a good Linq-Query is way easier to understand than a way bigger for-loop.
Mostly, when you are using a for-loop, you want to transform one or more enumerable to a result. Linq has everything, you need, to apply checks, transformations, and actions on an IEnumerable<T>
. If you have not yet worked with Linq, I highly recommend, you do so now!
In Linq, you have the choice of Query Syntax or Method Syntax. Personally, I prefer the Method Syntax, but you are free to choose. You can find all extension methods for IEnumerables
here.
5. Extract and name your methods
Extracting methods and giving them a readable name also drastically increases the readability.
Imagine you have a more complicated logic in your Where()
or Select()
methods, then in this example.
If you are the author of this function, you may know what is supposed to happen there, but another developer may struggle to understand. So why not just extract the method and give it a good name? The intention gets clear and the next developer will know what this code is supposed to do.
6. Break and Indent your code
Another way of creating more readable code is by correctly breaking and indenting your lines. Visual Studio will help you with most of the indentation, however, it is still far from perfect.
A few good rules of thumb, what to break and indent are:
- A line of code should not exceed half the screen. This makes it easier to read and you can have two files open in a split-screen, without missing some code.
- Indentation-Level of opening and closing brackets should match. I know it takes a few more seconds, but breaking the closing bracket after your method calls makes it easier to read and edit. (See 2nd example)
- Break before a point or after a comma. This way you could delete the whole line to remove the code part.
- Each Lambda Function gets a new indentation level.
By the way, your IDE will do the work for you here. Check out my article on shortcuts and refactorings for Visual Studio and VSCode. There you will learn how to quickly reshape your code with the help of your IDE.
7. Use short syntax
I admit, you can argue, whether it is good or bad to use short syntax. However, if you are getting used to it, I think it improves the readability, by removing unnecessary code noise.
C# is constantly updated and many new features are getting added each year. Oftentimes a new version will feature a shorter way of coding some things you already use daily. For C# 10 some of them are listed here:
- Most readable String Interpolation, in my opinion:
- Pattern matching. A bit complicated at first, but most readable case differentiation mechanism:
- Expression Bodies. Best for one-liner functions or properties:
This list contains some of the short syntaxes, I use daily. As I mentioned, this represents my personal opinion. Some of you might find it harder to read at first, but from my experience, it becomes easier to read, when there are fewer characters.
8. Global Usings and File-Scoped Namespaces
In C# 10 you now have the possibility to use file-scoped namespaces and global uses.
File-scoped namespaces will remove one indentation level from your whole code file, which in my opinion (see 3.) makes the code a little bit more readable. When adding new classes or methods to your code, you will have one less closing bracket }
that could mess with you.
Global uses are project-scoped and will save you a lot of space on the top of your files. However, you should use global uses carefully, as some uses are very helpful for another developer, to understand what packages and namespaces you are referencing in your code. Only add global uses for namespaces, that is very frequently used throughout your project.
The usings
in this example are also importable by firing implicit usings
in your project.