Clean Code in C# Part 2 Methods
Caio Cesar
Posted on December 4, 2021
Introduction
Methods, Functions, Routines or whatever you intend to call them are usually highly used on any program. In this section we will review some key points in keeping them more clean in the C# programming language.
Sizing
When you implement a method, it is important to think about its main goal. Giving too much responsibility to one single method can cause confusion when others or yourself need to maintain that method. It is better to keep methods small and with single responsibility.
Small Methods
Just as writing this post is divided into various sections, methods should also be small. Creating small methods is better for maintenance and understanding of its purpose. It is also beneficial for reuse. If we write methods that have too much responsibility it might be harder to reuse it in other places that does the same thing. According to Uncle Bob [1] a method should have at most 20 lines of code, it should do only one thing, do it good, and dot it well.
Adjusting Methods Size
Analyze the code written bellow in .NET 6:
Example 1:
int[] array = { 10, 5, 1, 7, 2 };
Console.WriteLine("Array:");
foreach (int p in array)
Console.WriteLine(p + " ");
Console.WriteLine("Sorted Array:");
foreach (int p in BubleSort(array))
Console.WriteLine(p + " ");
Console.Read();
int[] BubbleSort(int[] arr)
{
int temp;
for (int j = 0; j < arr.Length - 1; j++)
{
for (int i = 0; i < arr.Length - 1; i++)
{
if (arr[i] > arr[i + 1])
{
temp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = temp;
}
}
}
return arr;
}
Example 2:
int[] array = { 10, 5, 1, 7, 2 };
PrintArray(array, "Array:");
PrintArray(BubleSort(array), "Sorted Array:");
Console.Read();
int[] BubbleSort(int[] arr)
{
for (int j = 0; j < arr.Length - 1; j++)
{
for (int i = 0; i < arr.Length - 1; i++)
{
if (arr[i] > arr[i + 1])
{
arr = SwapArrayIndex(arr, i, i + 1);
}
}
}
return arr;
}
void PrintArray(int[] arr, string title)
{
Console.WriteLine($"{title}");
foreach (int p in array)
Console.WriteLine($"{p} ");
}
int[] SwapArrayIndex(int[] arr, int beginIndex, int endIndex)
{
int temp = arr[endIndex];
arr[endIndex] = arr[beginIndex];
arr[beginIndex] = temp;
return arr;
}
Example 2 has more methods than example 1. The first change was the PrintArray method that removes code duplicity. The SwapArrayIndex was also created because this swapping could be reused on other sorting algorithms. Creating methods might add more lines of code to the solution, but when working on large codebases it improves maintenance and readability of code.
Parameters
The ideal number of parameters in any method is zero. However since that is not always possible, one should aim to keep a low number of parameters and not exceeding 3. If more than 3 parameters are needed, consider refactoring your code. Maintaining a low number of parameters makes for better testing and maintainability of code.
The example below shows how to reduce the number of parameters in the BubbleSort algorithm.
Main Method:
int[] array = { 10, 5, 1, 7, 2 };
var bubbleSort = new BubbleSort(array);
Console.WriteLine(bubbleSort.GetArrayDetail("Array:"));
bubbleSort.SortArray();
Console.WriteLine(bubbleSort.GetArrayDetail("Sorted Array:"));
Console.Read();
BubleSort Class:
public class BubbleSort
{
private readonly int[] Array;
public BubbleSort(int[] array)
{
Array = array;
}
private void SwapArrayIndex(int index)
{
if (Array[index] > Array[index + 1])
{
int temp = Array[index + 1];
Array[index + 1] = Array[index];
Array[index] = temp;
}
}
private string GetArrayValues()
{
string arrayValues = string.Empty;
foreach (int p in Array)
arrayValues += $"{p} ";
return arrayValues;
}
public void SortArray()
{
for (int j = 0; j < Array.Length - 1; j++)
{
for (int i = 0; i < Array.Length - 1; i++)
{
SwapArrayIndex(i);
}
}
}
public string GetArrayDetail(string title)
{
return $"{title}{Environment.NewLine}{GetArrayValues()}";
}
}
This time the swap had logic in it since we now have a Bubblesort class that has its own scope.
Parameters Tips
- Indenting: When working with keywords such as if, else, while, for, etc.. it is important to try to keep a low number of indentation. The amount of indentation within a method should be at max 2 with a focus on 1. This means if you have 3 conditional statements within each other your code will be hard to maintain.
- Logical Parameters: It is better to have two methods than one method with a boolean value as a parameter. As shown in the example bellow.
Method with boolean:
public string GetArray(bool showDetail)
{
if (showDetail)
return $"Details: {GetArrayValues()}";
return $"{GetArrayValues()}";
}
Methods without boolean:
public string GetArrayDetail() => $"Details: {GetArrayValues()}";
To get the array without detail one could just call the GetArrayValues() Method.
- Objects Parameters: Sometimes you need parameters that represents a collection of information such as an Address with the fields: Number, ZipCode, etc. It is wise to use an object as an parameter and not each field as single parameter.
- Separate Responsibilities: If a method name is GetAddress then don't update the address inside that method. This might seem obvious but it happens more than often.
- Exceptions: Try not to return an error code. Instead throw exceptions that might contain error codes. When you return an error code the method caller will have to interpret the error.
- Code duplication: Don't repeat yourself. If something is done twice in the same context, you probably need a methods for it.
Conclusion
Writing clean method might not be as straight forward as some might think it is. It is important to always think about your work so that someone else including yourself in the future will interpret the code without much effort. Uncle bob cites in his book that writing code should be like telling a story, so make sure you tell it well.
References
- Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.
Posted on December 4, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.