Cleaner Code — The Structure (Code Nesting)

Sakhawat Ali
4 min readJun 19, 2024

As a seasoned programmer, I always like readable code, not to discount the performance.

And to have a readable code — one of the most important thing is the structure of the code.

This might sound odd at first, but it has transformed the way I write and structure my code. The first and foremost important aspect of code structure is code nesting. You might be wondering, what exactly is code nesting? Let’s dive into this concept, its benefits, and how you can apply it to your coding practices with some concrete examples.

What is a Code Nesting?

Code nesting refers to the practice of placing one or more control structures (like loops, conditionals, or functions) inside another control structure. The more nesting you have in your code, the more difficult it can be to read and maintain.

For example, if you have a function like the one below, it is 1 level nesting.

function calculate(value1: number, value2: number): number {
return value1 + value2;
}

But if you add an if-condition, it will become 2 levels nesting e.g.

function calculate(values: number[]): number {
let result: number;
if(values.length == 1) {
result = values[0];
}
else if(values.length == 2){
result = values[0] + values[1]
}
return result;
}

Now let’s take it a bit further and add a for-loop. Now it becomes 3 levels nesting

function calculate(values: number[]): number {
let result: number;
if(values != null) {
for(value in values) {
result += value;
}
}
return result;
}

Each level of nesting adds a layer of complexity, requiring the programmer to keep track of multiple contexts simultaneously.

A function that goes beyond three levels of nesting starts to become problematic.

The Problem with Deep Nesting

Deeply nested code can be hard to follow. Each additional level of nesting increases the cognitive load on the programmer, making it more difficult to understand the logic at a glance. For example, consider the following deeply nested function:

function processData(data: Item[]): void {
for (const item of data) {
if (item.isValid()) {
if (item.needsProcessing()) {
processItem(item);
if (item.requiresNotification()) {
notifyUser(item);
}
else {
logItem(item);
}
}
}
else {
discardItem(item);
}
}
}

This function is challenging to read quickly. Let’s look at how we can improve it using two key strategies: extraction and inversion.

Method 1: Extraction

Extraction involves pulling out parts of the function into their own dedicated functions. This reduces the complexity of the original function and improves readability.

function processData(data: Item[]): void {
for (const item of data) {
if (item.isValid()) {
processValidItem(item);
}
else {
discardItem(item);
}
}
}

function processValidItem(item: Item): void {
if (item.needsProcessing()) {
processItem(item);
handleNotification(item);
}
}

function handleNotification(item: Item): void {
if (item.requiresNotification()) {
notifyUser(item);
}
else {
logItem(item);
}
}

Method 2: Inversion

Inversion is about flipping conditions and using early returns to avoid deep nesting. This approach helps keep the code flat and easier to follow.

function processData(data: Item[]): void {
for (const item of data) {
if (!item.isValid()) {
discardItem(item);
continue;
}
if (!item.needsProcessing()) {
continue;
}
processItem(item);
if (item.requiresNotification()) {
notifyUser(item);
}
else {
logItem(item);
}
}
}

A Practical Example: Download Manager

Let’s take a more complex example — a download manager that handles multiple downloads simultaneously. Here’s the initial code:

function runDownloadManager(downloads: Download[]): void {  
for (const download of downloads) {
if (download.state == 'Pending') {
startDownload(download);
}
else if (download.state == 'InProgress') {
const result = processDownload(download);
if (result == 'Complete') {
markComplete(download);
}
else if (result == 'Error') {
if (download.retryCount < MAX_RETRIES) {
retryDownload(download);
}
else {
failDownload(download);
}
}
}
else if (download.state == 'Complete') {
finalizeDownload(download);
}
}
}

This code is functional but can quickly become unwieldy. Applying extraction and inversion can make it much cleaner:

function runDownloadManager(downloads: Download[]): void {  
processPendingDownloads(downloads.filter(d => d.state == 'Pending'));
processInProgressDownloads(downloads.filter(d => d.state == 'InProgress'));
finalizeCompletedDownloads(downloads.filter(d => d.state == 'Complete'));
}

function processPendingDownloads(pendingDownloads: Download[]): void {
for (const download of pendingDownloads) {
startDownload(download);
}
}

function processInProgressDownloads(inprogressDownloads: Download[]): void {
for (const download of inprogressDownloads) {
handleInProgressDownload(download);
}
}

function finalizeCompletedDownloads(completedDownloads: Download[]): void {
for (const download of completedDownloads) {
finalizeDownload(download);
}
}

function handleInProgressDownload(download: Download): void {
const result = processDownload(download);
if (result == 'Complete') {
markComplete(download);
}
else if (result == 'Error') {
handleDownloadError(download);
}
}

function handleDownloadError(download: Download): void {
if (download.retryCount < MAX_RETRIES) {
retryDownload(download);
}
else {
failDownload(download);
}
}

Conclusion

Adopting this philosophy encourages writing cleaner, more maintainable code by limiting the levels of nesting. By using extraction and inversion, you can reduce complexity and improve readability, making your code easier to understand and maintain. As a bonus, you’ll likely find that your code’s quality improves, and debugging becomes less of a headache. So, give it a try — your future self will thank you!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response