DEV Community

Xavier Abelaira Rueda
Xavier Abelaira Rueda

Posted on

To comment, or not to comment

πŸ“ƒ Introduction

Yes, that's one of the less exciting but most over-discussed topic about code maintenance, I would like to say in every language and framework.

But I recently saw a post on Bluesky from Nick Cosentino asking about it and it reminded me that the topic was a good candidate to feed this series with another episode, where every developer has their own point of view and experience, whether being a Junior, or a Senior Software Developer Advocate in a big tech company.

So, let's try to gather some information about the topic and, as always, I'll try to give my point of view at the end with some reasons about why.

But bear in mind, as I always repeat, that in the end, it is just a matter of preference, and it never deserves long discussions. Hence, I encourage everybody reading it to be respectful and polite with other points of view or preferences.

πŸ” The context

From very early on in the learning path of a developer, each of us has received recommendations about how to comment code, including our formative stage. Without going any further, during my time as a student, one of the evaluation criteria was having comments in code. I clearly remember discussing what was the standard when adding documentation to JavaScript files, because we were 'forced' to add documentation in code in different ways, depending on the teacher, and to a lesser extent, the technology or subject they taught. I even remember another requesting us to add a comment above each line explaining the intention of the line below.

More than a complaint, this is an example that this topic has lacked cohesion and even pragmatism since the very beginning in each of us as developers. These discrepancies have continued depending mainly on the developers' preferences in each project.

But I think that nothing has provided better alignment in our developer's path on this subject than Clean Code. Clean code, despite the years and even controversies around it, especially around Uncle Bob, has been part of our path and guided us through a more pragmatic orientation, and it is part of the usual bibliography of almost any developer.

Clean code makes some claims that are, to some extent, part of many of our code comment orientations.

Sometimes you see comments that are nothing but noise. They restate the obvious and provide no new information.

using System;

public class Calculator
{
    // This creates a new calculator instance
    public Calculator()
    {
        // Constructor does nothing
    }

    // This method adds two numbers
    public int Add(int a, int b)
    {
        // Adding a and b
        return a + b; // Return the sum
    }

    // This method subtracts two numbers
    public int Subtract(int a, int b)
    {
        // Subtracting b from a
        return a - b; // Return the difference
    }

    // This method multiplies two numbers
    public int Multiply(int a, int b)
    {
        // Multiplying a and b
        return a * b; // Return the product
    }

    // This method divides two numbers
    public int Divide(int a, int b)
    {
        // Dividing a by b
        return a / b; // Return the quotient
    }
}

public class Program
{
    // This is the main method
    public static void Main(string[] args)
    {
        // Creating an instance of Calculator
        Calculator calc = new Calculator();

        // Performing addition
        int sum = calc.Add(10, 5); // 10 + 5
        Console.WriteLine("Sum: " + sum); // Print the sum

        // Performing subtraction
        int difference = calc.Subtract(10, 5); // 10 - 5
        Console.WriteLine("Difference: " + difference); // Print the difference

        // Performing multiplication
        int product = calc.Multiply(10, 5); // 10 * 5
        Console.WriteLine("Product: " + product); // Print the product

        // Performing division
        int quotient = calc.Divide(10, 5); // 10 / 5
        Console.WriteLine("Quotient: " + quotient); // Print the quotient
    }
}

Enter fullscreen mode Exit fullscreen mode

Staying within the context of Clean Code, another important sentence written in stone for most of us is the following:

The purpose of a comment is to explain code that does not explain itself. It is a pity when a comment needs its own explanation

This very important sentence states something obvious on paper, but that is not always applied perfectly.

public static class BubbleSortSample
{
    // This method sorts an array using bubble sort algorithm
    public static void SortArray(this int[] arr)
    {
        int n = arr.Length; // Get the length of the array
        for (int i = 0; i < n - 1; i++) // Loop through the array
        {
            for (int j = 0; j < n - i - 1; j++) // Loop through the array up to the unsorted part
            {
                if (arr[j] > arr[j + 1]) // Compare adjacent elements
                {
                    // Swap the elements if they are in the wrong order
                    int temp = arr[j]; // Store the value of arr[j] in a temporary variable
                    arr[j] = arr[j + 1]; // Assign the value of arr[j + 1] to arr[j]
                    arr[j + 1] = temp; // Assign the value of temp to arr[j + 1]
                }
            }
        }
    }
}

public class Program
{

    // This is the main method
    public static void Main(string[] args)
    {
        int[] myArray = { 54, 33, 25, 10, 105, 16, 22, 11, 93 }; // Initialize an array with unsorted elements
        myArray.SortArray(); // Call the bubble sort method to sort the array
        Console.WriteLine("Sorted array:"); // Print a message indicating the array is sorted
        foreach (int item in myArray) // Loop through the sorted array
        { 
            Console.Write(item + " "); // Print each element of the sorted array
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

At first sight, we might think that we have enough information to understand the intention of the code, nonetheless, there are a few questions, discrepancies or unnecessary elements.

So, the important question is: Do we understand this code more easily and quickly because of the comments that we see? Is there any other way to make it clearer and faster?

public static class BubbleSortSample
{
    public static void SortArray(this int[] numbers)
    {
        int length = numbers.Length;
        for (int pass = 0; pass < length - 1; pass++)
        {
            for (int index = 0; index < length - pass - 1; index++)
            {
                if (ShouldSwap(numbers, index))
                {
                    Swap(numbers, index);
                }
            }
        }
    }

    private static Boolean ShouldSwap(int[] numbers, int index)
    {
        return numbers[index] > numbers[index + 1];
    }

    private static void Swap(int[] array, int index)
    {
        int temp = array[index];
        array[index] = array[index + 1];
        array[index + 1] = temp;
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        int[] numbers = { 54, 33, 25, 10, 105, 16, 22, 11, 93 };
        numbers.SortArray();

        Console.WriteLine("Sorted array:");
        foreach (int number in numbers)
        {
            Console.Write(number + " ");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

I'm pretty sure that if look at the codebase of the projects that we work on, we will find tons of examples or scenarios where we can simply follow basic rules to improve readability, and most of the times, if not always, we will remove the need for comments explaining the intention.

In the example above, (and again, you might find much better examples), it's at least simple enough to understand than just by following basic techniques of refactoring, isolating certain actions in specific methods, and giving proper names to the variables that are used, we make the code clear and self-explanatory enough to avoid all the comments.

But comments in code don't lie just in a few explanatory lines. As .NET developers, we are familiar with the OpenAPI specification and generators such as Swashbuckle that are capable of reading some standard XML documentation from endpoints and models exposed externally and adding it to the OpenAPI definition of that REST API.

So, we can see that, even though we can refactor the code with the aim of having the most readable code with the fewest or no comment in code, there are a few scenarios that deserve their own specific chapter.

⭐ My preference

Having reached this point, my opinion on the matter is that I must agree with the general recommendations written in Clean Code, therefore I tend to name variables, properties, methods and classes as concretely as possible, easing the readability of the code and removing the need for unnecessary comments mixed with code making noise.

However, considering the entire context in mind, I would like to say that there are a few situations where some comments can be useful, if not almost mandatory.

  • XML Documentation for publicly exposed elements:

    Whether you are developing a NuGet package or a REST API, these elements are useful for document generators and even for developers that consume that API if it's properly documented.

You can find a few samples of OpenAPI in .NET apps here

Sample method from an MVC controller with XML documentation:

 /// <summary>
 /// Authenticates the user and creates a new session.
 /// </summary>
 /// <param name="credentials">The user's credentials.</param>
 /// <returns>
 /// An <see cref="IActionResult"/> containing the session information if authentication is successful;
 /// otherwise, an <see cref="IActionResult"/> indicating the failure reason.
 /// </returns>
 /// <response code="200">Returns the session information if authentication is successful.</response>
 /// <response code="400">Returns the validation errors if the model state is invalid.</response>
 /// <response code="401">Returns if the authentication fails.</response>
 [AllowAnonymous]
 [HttpPost("login")]
 public async Task<IActionResult> LoginAsync([FromBody] Credentials credentials)
 {
     if (ModelState.IsValid)
     {
         var session = await _sessionService.AuthenticateAsync(credentials);

         if (session is not null)
             return Ok(session);
         else
             return Unauthorized();
     }
     else
     {
         return BadRequest(ModelState);
     }
 }
Enter fullscreen mode Exit fullscreen mode

Sample of a Minimal API endpoint with OpenAPI documentation support through extension methods:

app.MapGet("/hello/{name}", 
        ([Description("The name of the person to greet.")] string name) => $"Hello, {name}!")
    .WithSummary("Get a personalized greeting")
    .WithDescription("This endpoint returns a personalized greeting.")
    .WithTags("GET");
Enter fullscreen mode Exit fullscreen mode

Sample of an extension method registering services from a Nuget package:

 /// <summary>
 /// Configures library main functionalities
 /// </summary>
 /// <param name="services">Services container</param>
 /// <returns>ICustomConfigurationBuilder, allowing fluent syntax to its own builder</returns>
 public static ICustomConfigurationBuilder AddReleasy(this IServiceCollection services)
 {
     var configurationBuilder = new CustomConfigurationBuilder(services);

     configurationBuilder.Services.AddTransient<ICustomService, ImplementedService>();

     return configurationBuilder;
 }
Enter fullscreen mode Exit fullscreen mode
  • Pending changes:
    In this particular scenario, we can distinguish two different situations:

    • A TO-DO: Sometimes, especially when the project is in an early stage of its conception, or during the development of new features that require a few iterations to be completed, we might have things pending to improve or change and are in a preliminary stage. To-Do comments play an important role here, helping to remind specific changes to apply in the near future.
    • Temporary requests from business It might be possible that anyone from business requires a specific change, sometimes temporary, sometimes implying another change that requires more effort to have it properly implemented, but the urgency forces the team to deploy a quick change/fix as soon as possible. In such circumstances, it's really useful to remark the reason that forced it to be like this, and if possible, the planned action to revert this To-Do.

In both cases, a To-Do comment becomes really handy. Furthermore, IDEs such as Visual Studio, JetBrain IDEs among others have support for these comments in code, adding tasks to a task view that eases the life of every developer.

public record UserDto(int Id, string Email);

public class SampleService
{
    public Task<UserDto> GetAsync(int id)
    {
         //TODO: Infrastructure layer to be implemented in the incoming sprint.
         return Task.FromResult(
            new UserDto(1, "sample-user-1@email.com")
            );
    }
}
Enter fullscreen mode Exit fullscreen mode

Visual Studio's Task List view

Visual Studio's Task List view screenshot

JetBrain's Rider TO DO view
JetBrain's Rider TO DO view image

I hope you liked this article, so please feel free to share your thoughts, opinions and/or experiences in the comments section below.

Happy coding! πŸ’»

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more