Keeping methods small

While programming clean and readable code, it is important to keep the methods small. Preferably, in the C# world, it is best to keep methods under 10 lines long. The perfect length is no more than 4 lines. A good way to keep methods small is to consider if you should be trapping for errors or bubbling them further up the call stack. With defensive programming, you can become a little too defensive, and this can add to the amount of code you find yourself writing. Besides, methods that trap errors will be longer than methods that don't.

Let's consider the following code, which can throw an ArgumentNullException:

        public UpdateView(MyEntities context, DataItem dataItem)
{
InitializeComponent();
try
{
DataContext = this;
_dataItem = dataItem;
_context = context;
nameTextBox.Text = _dataItem.Name;
DescriptionTextBox.Text = _dataItem.Description;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
throw;
}
}

In the preceding code, we can clearly see that there are two locations where an ArgumentNullException may be raised. The first line of code to potentially raise an ArgumentNullException is nameTextBox.Text = _dataItem.Name;; the second line of code that may potentially raise the same exception is DescriptionTextBox.Text = _dataItem.Description;. We can see that the exception handler catches the exception when it occurs, writes it to the console, and then simply throws it back up the stack.

Notice that, from a human reading perspective, there are 8 lines of code that form the try/catch block.

You can completely replace the try/catch exception handling with a single line of text by writing your own argument validator. To explain this, we will provide an example.

Let's start by looking at the ArgumentValidator class. The purpose of this class is to throw an ArgumentNullException with the name of the method that contains the null argument:

using System;
namespace CH04.Validators
{
internal static class ArgumentValidator
{
public static void NotNull(
string name,
[ValidatedNotNull] object value
)
{
if (value == null)
throw new ArgumentNullException(name);
}
}

[AttributeUsage(
AttributeTargets.All,
Inherited = false,
AllowMultiple = true)
]
internal sealed class ValidatedNotNullAttribute : Attribute
{
}
}

Now that we have our null validation class, we can perform the new way of validating parameters for null values in our methods. So, let's look at a simple example:

public ItemsUpdateView(
Entities context,
ItemsView itemView
)
{
InitializeComponent();
ArgumentValidator.NotNull("ItemsUpdateView", itemView);
// ### implementation omitted ###
}

As you can clearly see, we have replaced the whole of the try catch block with a one-liner at the top of the method. When this validation detects a null argument, an ArgumentNullException is thrown, preventing the code from continuing. This makes the code much easier to read, and also helps with debugging.

Now, we'll look at formatting functions with indentation so that they are easy to read.

Indenting code

A very long method is hard to read and follow at the best of times, especially when you have to scroll through the method many times to get to the bottom of it. But having to do that with methods that are not properly formatted with the correct levels of indentation can be a real nightmare.

If you ever encounter any method code that is poorly formatted, then make it your own responsibility, as a professional coder, to tidy the code up before you do anything else. Any code between braces is known as a code block. Code within a code block should be indented by one level. Code blocks within code blocks should also be indented by one level, as shown in the following example:

public Student Find(List<Student> list, int id) 
{
Student r = null;foreach (var i in list)
{
if (i.Id == id)
r = i; } return r;
}

The preceding example demonstrates bad indentation and also bad loop programming. Here, you can see that a list of students is being searched in order to find and return a student with the specified ID that was passed in as a parameter. What annoys some programmers and reduces the performance of the application is that the loop in the preceding code continues, even when the student has been found. We can improve the indentation and the performance of the preceding code as follows:

public Student Find(List<Student> list, int id) 
{
Student r = null;
foreach (var i in list)
{
if (i.Id == id)
{
r = i;
break;
}
}
return r;
}

In the preceding code, we have improved the formatting and made sure that the code is properly indented. We've added a break to the for loop so that the foreach loop is terminated when a match is found.

Not only is the code now more readable, but it also performs much better. Imagine that the code is being run against a university with 73,000 students on campus and via distance learning. Consider that if the student matches the ID is the first in the list, then without the break statement, the code would have to run 72,999 unnecessary computations. You can see how much of a difference the break statement makes to the performance of the preceding code.

We have left the return value in its original location as the compiler can complain that not all code paths return a value. This is also why we added the break statement. It is clear that proper indentation improves the readability of the code, thus aiding the programmer's understanding of it. This enables the programmer to make any changes that they deem necessary.