Avoid Excessively Nested Code and be Loved

Tags: Clean Code

Nesting for birds is great, but nesting your code is not.

In this post we will consider two types of excessive nesting that should be avoided: statement nesting and method nesting.

Statement Nesting

Nesting if-else statements and or loop statements can lead to hard to read code. Uncle Bob, author of Clean Code: A Handbook of Agile Software Craftsmanship, tells us that more than two levels of  if-else nesting is too much. I agree! Same thing for loops. Nesting more than three loops should be avoided. Let’s take a look at an example.

Hard to Read Nested Code


public bool NestedFind(IList list, string element)
{
	bool found = false;
	if (list != null)
	{
		if (element.Length != 0)
			foreach (var item in list)
			{
				if (!string.IsNullOrEmpty(item))
				{
					if (item == element) found = true;
				}
			}
	}
	return found;
}

Did you count the nesting? Five levels deep! Excessive nesting is hard to follow because your mind tries to remember each level as you traverse down the nest. That’s mental burden which causes stress possibly leading to people disliking you.

Reducing Nesting


public bool Find(IList list, string element)
{
	bool found = false;
	if (list == null) return found;
	if (element.Length == 0) return found;

	foreach (var item in list)
	{
		if (!string.IsNullOrEmpty(item)) continue;
		if (item == element) found = true;
	}

	return found;
}

This example shows the same method with the amount of nesting reduced to only two levels. It’s much easier to read and understand. It frees the mind, reduces stress and makes people like you.

Method Nesting

Method nesting is when one method calls another method which then calls a different method and so on.
Let’s see an example of multiple layers deep method nesting and how to refactor it to make readable.

Api Call Example

Lets imagine a scenario where we are making an api call and saving the data we get back to a database. There are several steps in between to prepare the api request and prepare the api response for saving.

Nested


public class MethodNest
{

	public void ProcessTask()
	{
		SaveToDatabase();
	}

	public string GetRequestData() { return "data"; }
	public string GetCredentials() { return "creds"; }

	public string BuildApiRequest()
	{
		string data = GetRequestData();
		//manipulate data here...
		ValidateRequest(data);
		return "request";
	}

	public void ValidateRequest(string req) { }


	public string CallApi() {
		string req  = BuildApiRequest();

		// call the api here...
		string parsedResponse = ParseResponse("api response");
		return parsedResponse;
	}

	public string ParseResponse(string resp) 
	{ 
		// do parsing...
		return "parsed response";
	}

	public void SaveToDatabase() {
		string data = CallApi();
		// save to db here...
	}
}

Our first example shows that we’ve broken out our logic into small methods. Great! The top level method ProcessTask simply calls one method SaveToDatabase. Looks clean. Then we see that SaveToDatabase calls another method which in turn calls two methods one of which calls two other methods. It is difficult to understand the flow of this process, this may cause aggravation, and may lead to your collegues hating you.  

Non Nested


public class MethodNonNest
{


	public void ProcessTask()
	{
		string requetData = GetRequestData();
		string apiRequest = BuildApiRequest(requetData);
		ValidateRequest(apiRequest);
		string creds = GetCredentials();
		string response = CallApi(apiRequest, creds);
		string parsedResponse = ParseResponse(response);
		SaveToDatabase(parsedResponse);
	}

	public string GetRequestData() { return "data"; }
	public string GetCredentials() { return "creds"; }

	public string BuildApiRequest(string data)
	{
		//manipulate data here...
		return "request";
	}

	public void ValidateRequest(string req) { }


	public string CallApi(string apiRequest, string creds)
	{
		// call the api here...
		return "api response";
	}

	public string ParseResponse(string resp)
	{
		// do parsing...
		return "parsed response";
	}

	public void SaveToDatabase(string data)
	{
		// save to db here...
	}
}

In the refactored example we have removed all nesting. The ProcessTask method orchestrates the entire process and you can read through code an easily follow the steps in the flow. No method calls another. And each method can now be tested independently by feeding in a mocked input. This leads to joy and puts smiles on developers faces.  You will be loved.

No Comments

Add a Comment