Comments

5 Tips for Junior C# Developers to Write Cleaner C# Code

Many students of my C# Basics course submit their code in the discussion area, and when I get a chance, I review their code and give them hints to improve their code. I’ve noticed quite a few common patterns in the code submitted by junior C# developers. In this post, I’m going to explore these areas and share a few tips to write cleaner and more maintainable code.

1. Validate the input “first”!

Look at this code snippet:

public void Draw(Shape shape)
{
   if (shape != null)
   {
      Console.WriteLine("Drawing " + shape.ToString()); 
      Console.WriteLine("---");     
   }
   else 
   {
      throw new ArgumentNullException("shape");
   }

We have to read all this code to find the last line that throws an exception if the argument is null. By convention, we often validate the input first. This tells the reader of the code how a given method should be used.

So, let’s reverse the order of if and else here:

public void Draw(Shape shape)
{
   if (shape == null)
   {
      throw new ArgumentNullException("shape");
   }
   else    
   {
      Console.WriteLine("Drawing " + shape.ToString()); 
      Console.WriteLine("---");     
   }

Now, you can immediately tell what is a valid argument for this method. You don’t have to scroll down to the end of the body of the method to figure that out.

2. You don’t always need an “else”!

Continuing from the last example, if shape is null, we throw an exception and the rest of the method will not be executed. So, there is really no need to add that “else” block, which increases the indentation of the code. Here is a cleaner way to write this code:

public void Draw(Shape shape)
{
   if (shape == null)
   {
      throw new ArgumentNullException("shape");
   }
      
   Console.WriteLine("Drawing " + shape.ToString());
   Console.WriteLine("---");
}

Note that the rest of the code after the “if” statement is not indented.

3. Curly braces?

This one is subjective. Some developers love their curly braces, some don’t. I’ve gone through different phases. There is really no right or wrong here. Do your own judgment when looking at the code. Let’s remove the curly braces in the precious code and see what it looks like:

public void Draw(Shape shape)
{
   if (shape == null)
      throw new ArgumentNullException("shape");
 
   Console.WriteLine("Drawing " + shape.ToString());
   Console.WriteLine("---");
}

I think this code is cleaner. What do you think?

4. Pay attention to the name of your identifiers

Name of your identifiers is as important as the name of your children. I’m dead serious. No one wants to read someone else’s code with the following identifiers:

  • od: What is od? Oh Damn? Obsessive Disorder? Overdue Days?
  • Button1_Click(): What is Button1? How is it different from Button2?
  • thisAs: What’s that even supposed to mean?!

Use a name that clearly communicates the intent.

5. Avoid unnecessary variables

Back in 80s, programming books used to teach use to declare a variable for nearly everything! Look at this piece of code that reads two numbers from the console and prints the maximum:

var firstInput = Console.ReadLine();
var firstNumber = Convert.ToInt32(firstInput);
var secondInput = Console.Readline();
var secondNumber = Convert.ToInt32(secondInput);
var max = (firstNumber > secondNumber) ? firstNumber : secondNumber;
Console.WriteLine(max);

My eyes are popping out as I’m declaring all these variables! What is the focus of this code? Two numbers and their maximum. So, firstInput and secondInput, which are strings read from the input, are not the focus of the code. All we care about is a number read from the console. The temporary string we receive from the console is not the focus here. So, these two variables are not adding any value to this code in terms of readability. They’re just creating noise in the code.

We can read an input from the console and convert it to a number in one line:

var firstNumber = Convert.ToInt32(Console.ReadLine());
var secondNumber = Convert.ToInt32(Console.Readline());
var max = (firstNumber > secondNumber) ? firstNumber : secondNumber;
Console.WriteLine(max);

So, avoid declaring unnecessary variables. Use variables to increase the readability of the code.

If you enjoyed this post, please drop a comment and also share it with your peers. If you’d like to learn more tips for writing cleaner code, check out my course: “Clean Code: The Art of Writing Beautiful C# Code”.

Related Posts

Tags: , ,

28 responses to “5 Tips for Junior C# Developers to Write Cleaner C# Code”

  1. Sam says:

    IMO, these are not good tips. Especially the removal of brackets xD

    • Elton says:

      I see what you mean. However, the aim is to eliminate unnecessary clutter from code.

    • Temi says:

      You are one of the developers that love their curly braces.

      • Teo says:

        The lack of brackets is dangerous because if someone else does not pay attension when modifying your code, following may happen:
        – let’s assume he finds a reason to commend-out the line of code with “throw” (could be anything, does not matter if it is a throw)
        – he comments-out only the statement and not the “if”, because he did not pay attention
        – with brackets everything remains fine
        – without brackets, the “if” is “jumping” to the next statement – and therefore wrongly conditioning it

        This is not a scenario invented by me for having a counter-argument, but a mistake I’ve seen very often done by unexperienced deveolpers.

  2. Abdisamad says:

    I know conditional operator, but what does “(firstNumber > secondNumber)” mean?

    Thanks

  3. Angus says:

    Great tips, thanks Mosh

  4. Shane says:

    Thank you for taking the time to do this. I am guilty of doing what you describe above. Thank you for helping me become a better programmer. I enjoy all the tips and am in the middle of “Clean Code”

  5. Shaun says:

    Love best practice insights like these. Being short and to the point, they’re much easier to digest and start applying. Thank you Mosh!

  6. Wafi says:

    Useful tips. Thank you mosh

  7. Omar says:

    thanks man it’s v. helpful 🙂 🙂

  8. TSDP says:

    THanks Mosh for the preciouse tips

  9. Temi says:

    Good tips Mosh

  10. Gregg says:

    When you are writing code that receives input from a programatic action (as opposed to a parameter), you should consider abstractions which allow you to test as well as change how that input is gathered. As a general rule of thumb, good code structure involves only one “leg” of code that orchestrates anything. All the input actions and calculation actions should be in functions so that you can replace their implementation later. And you should even think about putting them into a separate class so that you must have an object to reference them with so that this becomes an “injection” point for testing or changing how things work later, without having to change the actual code, only the orchestration code.

    Don’t be afraid to start with something as flexible as the following. This will provide you ample opportunity to write less code later, and to provide reusable functions that simplify your exploration and learning experience with any programming language.

    public interface NumberReader {
    public int ReadInt();
    public long ReadLong();
    public double ReadDouble();
    }

    public class NumberConsoleReader : NumberReader {
    public NumberConsoleReader( ) {
    }
    public int ReadInt() {
    return Convert.ToInt32( Console.ReadLine() );
    }
    public long ReadLong() {
    return Convert.ToInt32( Console.ReadLine() );
    }
    public double ReadDouble() {
    return Convert.ToInt32( Console.ReadLine() );
    }
    }

    public class NumberStreamReader : NumberReader {
    private StreamReader input;
    public NumberStreamReader( StreamReader input ) {
    this.input = input;
    }
    public int ReadInt() {
    return Convert.ToInt32( input.ReadLine() );
    }
    public long ReadLong() {
    return Convert.ToInt32( input.ReadLine() );
    }
    public double ReadDouble() {
    return Convert.ToInt32( input.ReadLine() );
    }
    }

    NumberReader rdr = new NumberConsoleReader();
    var firstNumber = rdr.ReadInt();
    var secondNumber = rdr.ReadInt();

    var max = firstNumber;
    if (firstNumber < secondNumber)
    max = secondNumber;

    Console.WriteLine(max);

    So now, if you want to read from a file next, you just need to change what you construct and assign to "rdr" to be a NumberStreamReader instance instead, and your software continues to work as it did with the Console while you were exploring.

    • admin says:

      Hi Gregg, this article is for “junior” developers as the title suggests. Plus, interfaces are not for writing cleaner code. They’re used for testability and extensibility, and again, both are intermediate/advanced level topics.

  11. Hisss says:

    I disagree with removing the brackets. Brackets after the if statement should be mandatory. There was already so much evil in the world because of missing brackets. Maybe one exception can be input validation (as you mentioned above), but dont teach juniors to not use brackets!!!

    Remove unnecessary variables?
    Unecessary variables are great for debugging. Imagine you are stepping though the code and try to see, what the hell was read from the input? Hmm I need to wait for the exception from convert to be able to see it.

    Developpers Please, use as many well named temporary variables as possible, it will pay you back during the maintainance.

    • admin says:

      I wouldn’t clutter my code by declaring all sorts of temporary variables because ONE day I may need to debug a given method. Have you ever used the watch and immediate windows during debugging? I guess not. Nonetheless, if you prefer to declare temporary variables because they would ease up debugging, you can do it only when required. No need to clutter the code that others have to read.

      Also, you mentioned there was so much evil in the world because of missing brackets. I’ve never heard of that story. Can you give us one example?

  12. Merrick Sapsford says:

    surely the original is still best because of the performance gains due to branch prediction?

    public void Draw(Shape shape)
    {
    if (shape != null)
    {
    Console.WriteLine(“Drawing ” + shape.ToString());
    Console.WriteLine(“—“);
    }
    else
    {
    throw new ArgumentNullException(“shape”);
    }

    • admin says:

      Can you explain how much performance you gain here?:)

      • Merrick Sapsford says:

        When a branch instruction is executed, its address and that of the next instruction executed (the chosen destination of the branch) are stored in the Branch Target Buffer. This information is used to predict which way the instruction will branch the next time it is executed so that instruction prefetch can continue. When the prediction is correct (and it is over 90% of the time), executing a branch does not cause a pipeline break.

        you need to put the MOST COMMON taken branch in the if statement.
        which is:

        Console.WriteLine(“Drawing ” + shape.ToString());
        Console.WriteLine(“—“);

  13. name_required says:

    What a stupudity i just read. There is no point to test on null and then throw ArgumentNullException, because, surprise surprise — you get same exception automatically. There is very simple golden rule: if you can not do anything sane at the point of wrinting code – you should not test the error case, becasue if you do – you MUST do sane thing. This testing should be left for those who call you method and if the know how to handle an error – they do so. How hard is that?

    • admin says:

      Oh, really? I never knew ArgumentNullException and NullReferenceException are the same thing! Thanks for sharing a brilliant tip! 🙂

  14. teotite says:

    The lack of brackets is dangerous because if someone else does not pay attension when modifying your code, following may happen:
    – let’s assume he finds a reason to commend-out the line of code with “throw” (could be anything, does not matter if it is a throw)
    – he comments-out only the statement and not the “if”, because he did not pay attention
    – with brackets everything remains fine
    – without brackets, the “if” is “jumping” to the next statement – and therefore wrongly conditioning it

    This is not a scenario invented by me for having a counter-argument, but a mistake I’ve seen very often done by unexperienced deveolpers.

  15. Renee says:

    My team requires brackets on all if statement blocks. I personally like the cleaner look, but I think it is required for a good reason.

Leave a Reply