Writing Clear and Concise Code: 11 Guidelines for C# Developers
Tags: csharp, dotnet, programming, cleancode
Published: 2023-06-28 21:33:46

Writing clear and concise code is a fundamental skill that we developers should strive to master. Clean code is not only easier to read and understand but also promotes **_maintainability, collaboration, and efficient_** debugging.

> _I could list all of the qualities that I notice in clean code, but there is one overarching quality that leads to all of them. Clean code always looks like it was written by someone who cares. There is nothing obvious that you can do to make it better. All of those things were thought about by the code’s author, and if you try to imagine improvements, you’re led back to where you are, sitting in appreciation of the code someone left for you — code left by someone who cares deeply about the craft. **Michael Feathers, author of Working Effectively with Legacy Code**_

---
Let’s look at some examples:

## Overcomplicating Code

_Bad way_
```
public string GetFormattedName(string firstName, string middleName)
{
   string formattedName = string.Empty;
  
   if (!string.IsNullOrEmpty(firstName))
   {
      formattedName += firstName.Trim();
   }
  
   if (!string.IsNullOrEmpty(middleName))
   {
      if (!string.IsNullOrEmpty(formattedName))
      {
         formattedName += " ";
      }
    
      formattedName += middleName.Trim();
   }
  
   return formattedName;
}
```
_Good way_

```
public string GetFormattedName(string firstName, string middleName)
 => string.Join(" ", firstName?.Trim(), middleName?.Trim()).Trim();
```

In the simplified code, the **string.Join** method is used to concatenate the names with spaces, and the **?. null-conditional** operator is used to handle potential null values. The code is more concise, easier to read, and achieves the same functionality without unnecessary complexity.

Overcomplicating code can lead to increased cognitive load, reduced maintainability, and higher chances of introducing bugs. It’s important to strive for simplicity and readability in code whenever possible. Let's take a look at another example.

_Bad way_

```
bool isEven = (number % 2 == 0) ? true : false;

```
_Good way_

```
bool isEven = number % 2 == 0;

```

## Loops Instead of LINQ
90% of cases loops can be substituted with a LINQ query. It might be my personal viewpoint, but I believe LINQ query is much more comprehensible than a significantly larger for-loop.

_Bad way_

```
public List<int> GetEvenNumbers(List<int> numbers)
{
   List<int> evenNumbers = new List<int>();
  
   foreach (int number in numbers)
   {
      if (number % 2 == 0)
      {
         evenNumbers.Add(number);
      }
   }
  
   return evenNumbers;
}
```
_Good way_

```
public List<int> GetEvenNumbers(List<int> numbers) 
 => numbers.Where(number => number % 2 == 0).ToList();

```

## Complex IF Condition

A complex if condition refers to a conditional statement that involves multiple logical operations, conditions, or an expression that might be difficult to read and maintain.

_Bad way_

```
if (number % 2 == 0)
{
   // Do something
}
```
_Better way_

```
private bool IsEven(int number) => number % 2 == 0;

if (IsEven(number))
   {
     // Do something
   }
}
```
This practice helps in reducing code duplication, improving code organization, and enhancing code maintainability.

## Deep Nesting
In the example below, the code is 3-level nested and this can make the code harder to understand and maintain. Deep nesting can also increase the risk of introducing logical errors and make code modifications more challenging.

_Bad way_

```
if (condition1)
{
    if (condition2)
    {
        if (condition3)
        {
            // Do something
        }
    }
}
```

_Good way_

```
if (condition1 && condition2 && condition3)
{
    // Do something
}
```

Just ensure that the conditions are logically correct and properly grouped. Also, it might be a perfect time to refactor and extract them into methods as we did in the previous example **IsEven**.

## String Concatenation
The **GenerateGreeting** method concatenates multiple strings using the + operator. While this code may work correctly, it can become problematic when dealing with more complex scenarios or a large number of concatenated strings

_Bad way_

```
public string GenerateGreeting(string name)
{ 
   return "Hello, " + name + "! " + "How are you today?";
}
```

_Good way_

```
public string GenerateGreeting(string name)
{ 
   return $"Hello, {name}! How are you today?";
}
```

## Magic Numbers
Avoid using magic numbers. Assign meaningful constants or enumerations to such values to improve code clarity and maintainability.

_Bad way_

```
if (status == 2)
{
    // Do something
}
```

_Good way_

```
const int InProgressStatus = 2;

if (status == InProgressStatus)
{
    // Do something
}
```

## Long Methods
Break down long methods into smaller, focused methods. This improves code readability, reusability, and maintainability.

_Bad way_

```
public void ProcessData()
{
    // Several hundred lines of code
}
```

_Good way_

```
public void ProcessData()
{
    ValidateInput();
    CalculateValues();
    SaveData();
}
```

## Poor Naming Conventions
Using meaningful and descriptive names for variables, methods, and classes improves code readability and helps others understand our code.

_Bad way_

```
var dt = DateTime.Now.ToString("YYYY/MM/DD");
```

_Good way_

```
var currentDate = DateTime.Now.ToString("YYYY/MM/DD");
```

## Inconsistent Formatting
Consistent and properly indented code enhances readability and reduces confusion.

_Bad way_

```
public void PrintNumbers()
{
for (int i = 0;i < 10; i++)
{
Console.WriteLine(i);
}
}
```

_Good way_

```
public void PrintNumbers()
{
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(i);
    }
}
```

## Excessive Comments
Avoid commenting on obvious code. Comments should be used to explain complex logic or clarify code that may be unclear.

_Bad way_

```
// Increment counter by 1
counter++;
```

_Good way_

```
counter++;
```

## File-Scoped Nested Namespaces
File-scoped namespaces were introduced in C# 10.0 and allow us to define namespaces directly at the file level without enclosing them in a traditional namespace block

_Ok_

```
// File-scoped nested namespace declaration
namespace MyApplication.Utilities
{
    public static class Helper
    {
    }
}
```

_Better way_

```
namespace MyApplication.Utilities;
    
public static class Helper
{
}
```

---

## Final Thoughts
By avoiding these bad practices and adopting good coding practices, we can significantly improve the readability, maintainability, and overall quality of our C# code.

---

## Thanks for reading!
Through my articles, I share Tips & Experiences on web development, career, and the latest tech trends. Join me as we explore these exciting topics together. Let’s learn, grow, and create together!

➕More article about [Programming, Careers, and Tech Trends.](https://medium.com/@andytechdev)

🔔 Follow me on [Medium](https://medium.com/@andytechdev) | [Twitter ](https://twitter.com/andytechdev)