DEV Community

Artur Serra
Artur Serra

Posted on

Rustlings #1 (Or The Power of Comments in Programming)

The first Rustling challenge shows us how comments are an essential part of programming, bringing - in one way or another - numerous benefits to developers and teams. They serve as a form of documentation that makes it easier for developers to understand the code by providing context, clarity, and explanations of how the code works, helping developers to save time and effort by reducing the need to decipher code and allowing them to focus on the actual problem-solving.

(Original post on - https://www.therustyco.de/post/rustlings-1-or-the-power-of-comments-in-programming)

I. Introduction

Comments are an essential and often overlooked part of programming, especially in complex projects where there can be a lot of code to navigate. They serve as a form of documentation that makes it easier for developers to understand the code by providing context, clarity, and explanations of how the code works. This helps developers to save time and effort by reducing the need to decipher code and allowing them to focus on the actual problem solving. In addition, comments can also help to identify potential issues, highlight tricky code, and provide insights into why certain decisions were made during the development process.

In this blog post, we will explore the importance of commenting code and the benefits that it can bring to developers in more detail. We will delve deeper into the different types of comments, such as single-line and multi-line comments, and provide examples of how they can be used effectively. We will also discuss self-documented code, which is code that is written in a way that is easy to read and understand, even without comments. By understanding the importance of self-documented code, you can write code that is not only functional but also easy to understand.

Furthermore, we will cover the best practices for commenting code. By following these methods, you can ensure that your comments are consistent, easy to read and effective. Then, we’ll take a look on some examples of tricky code, and how commenting can be important to make code understandable in this scenario.

By following these best practices, you can write code that is well-documented, easy to understand, and maintainable for years to come. With comments, you can ensure that your code is readable and maintainable by others (or the future you). This is especially important when working on a team, as it can lead to better collaboration and more efficient development. By the end of this post, you will have a deeper understanding of how comments can benefit your development process and how to write efficient code with comments.

In the first Rustling challenge, we face a simple task for most experienced programmers, but it may not be so simple for beginners: Remove a comment from the code. However, even more experienced programmers don’t fully understand all the implications and strategies to comment their code, which can be prejudicial for their collaborative work with their teammates.

// intro1.rs

// About this `I AM NOT DONE` thing:
// We sometimes encourage you to keep trying things on a given exercise, even
// after you already figured it out. If you got everything working and feel
// ready for the next exercise, remove the `I AM NOT DONE` comment below.
// Execute `rustlings hint intro1` or use the `hint` watch subcommand for a hint.
//
// If you're running this using `rustlings watch`: The exercise file will be reloaded
// when you change one of the lines below! Try adding a `println!` line, or try changing
// what it outputs in your terminal. Try removing a semicolon and see what happens!

// I AM NOT DONE
Enter fullscreen mode Exit fullscreen mode

To complete this challenge, simply remove the whole line that states //I AM NOT DONE, and you should be good to go. Quite simple, right? More or less. Commenting code can be a bit more challenging than that, and that’’s what I will explain to you in this post!

II. Comment the Method

Why is it important?

Documenting code is an essential part of programming, as it allows developers to understand the functionality and purpose of the code. However, simply commenting the code inside a method may not be enough to provide a complete understanding of the method's purpose and functionality. This is why it is important to also comment the method itself, providing context and a higher-level overview of its purpose within the codebase.

By commenting both the method and the code inside it, developers can gain a profound understanding of its purpose and how it contributes to the overall functionality of the codebase. This information can help other developers understand how it fits into the larger codebase and how they can use it in their own code. In addition, a method comment can also provide information about any of its potential issues or limitations, which can be useful when debugging or modifying the code.

Commenting just the code inside a method can be helpful for understanding how the code works, but it may not provide a complete understanding of the the purpose and functionality it provides. Without a method comment, other developers may have to spend more time deciphering what the method actually does, and less time fixing or improving it. By adding comments above and inside the method, developers can save time and effort by quickly understanding what the method does and how it contributes to the overall functionality of the code.

But commenting can also help with code maintenance. If a developer needs to modify or update the codebase, they can use the method comments to quickly understand the purpose of the method and any potential implications of modifying it. This can help prevent unintended consequences and make the modification process more efficient, ensuring that the codebase remains maintainable and understandable, even as it is updated and modified over time.

Best practices for commenting the method

Good method comments use clear and concise language that describes the method's purpose and functionality. They should include information about the inputs and outputs of the method, as well as any potential issues or limitations. Method comments should also be consistent with the formatting and style used throughout the codebase. This can help to make the codebase more maintainable and easier to understand for other developers. Additionally, adding examples that demonstrate how to use the method can be very helpful, especially for developers who are new to the codebase.

Bad method comments, on the other hand, are vague and may not provide enough information about the method's purpose and functionality. They may also use abbreviated or unclear names for the method, which can make it harder for other developers to understand what the method actually does. Comments that are too long or irrelevant can also be unhelpful, especially if they don't provide any useful information about the method's purpose or functionality.

When commenting a method in Rust programming, it is important to use clear and concise language that describes the method's purpose and functionality. The following are examples of good and bad method comments:

Good Example

// This is the main function. It will print a sentence in the console.
// The code should not take any arguments, it  will simply run the
// print in line - println! - macro. 
fn main() {
// Statements here are executed when the compiled binary is called.

    // Print text to the console.
    println!("Hello World!");
}
Enter fullscreen mode Exit fullscreen mode

Here we have an example of the simplest code you could write in Rust, probably. A simple Hello World being printed to the console. But in this case, we added some documentation for other developers to understand what is actually going on in this method, and what we expect it to do.

Bad Example

// This prints text
fn main() {
    println!("Hello World")
}
Enter fullscreen mode Exit fullscreen mode

In this other method, the comment is too vague and does not provide enough information about the method's purpose and functionality. It prints something in the console? In an actual printer? In the screen? It also does not include any information about the inputs or outputs of the method, if it should take anything or what it should return.

Good Example

/// Returns the average of a vector of integers.
///
/// # Arguments
///
/// * `numbers` - A vector of 32-bit integers.
///
/// # Examples
///
/// let numbers = vec![1, 2, 3, 4, 5];
/// let result = calculate_average(numbers);
/// assert_eq!(result, 3);
fn calculate_average(numbers: Vec<i32>) -> i32 {
    let sum = numbers.iter().sum::<i32>();
    let count = numbers.len() as i32;
    let average = sum / count;

    return average;
}

Enter fullscreen mode Exit fullscreen mode

In this other case, we have a detailed set of instructions, explaining in details the functionality of this method. It also adds what arguments should be passed, what should be expected to be returned, and even some usage examples.

Bad Example

/// Calculates the average of a vector.
fn avg(numbers: Vec<i32>) -> i32 {
    let sum = numbers.iter().sum::<i32>();
    let count = numbers.len() as i32;
    let avg = sum / count;

    return avg;
}
Enter fullscreen mode Exit fullscreen mode

For this method, everything looks like a mess! Abbreviation (which is even worse in the next subject, Self-Documenting Code), a vague description and no clue at all of what is being passed and what we should expect to see being returned.

III. Self-Documenting Code

What is self-documenting code?

We’ve been talking a lot about displaying the functionalities of the code in the comments, right? The self-documenting code is a concept that refers to writing code in a way that conveys its purpose and functionality without the need for additional comments. This is achieved by using descriptive variable and function names, breaking up complex code into smaller, more manageable pieces, and using consistent formatting and indentation. When code is self-documenting, it becomes easier for other developers to read and understand, reducing the need for comments and making the codebase more maintainable.

Writing self-documenting code has many advantages that can make developer’s lives easier. For one, it makes the code effortless to read and understand. When code is written with descriptive names for variables and functions, it becomes the process to understand what each part of the code does is straightforward and painless. This can lead to faster development times since developers can more quickly and easily get the gist of the codebase. Additionally, self-documenting code can reduce the need for comments. Comments can be helpful, but they can also become outdated or misleading if the code they describe is changed. Let’s say you update a method for something else, but forget to update its comments. This way, the next developer who touches the codebase will find a piece of “lying” code that can slow down their process. With self-documenting code, the code itself becomes the documentation, making it easier for other developers to understand and modify the code without the need for any additional comments. When code is self-documenting, developers can spend less time writing and updating comments and more time focusing on writing high-quality, maintainable code, which can lead to better and more efficient workflows. When code is written in a clear and concise way, it becomes easier for new developers to get up to speed and start contributing to the project, from junior to senior levels!

What are the best practices for writing self-documenting code?

When writing self-documenting code, there are several best practices that can help to make the code easier to read and understand. These include:

  • Using meaningful variable and function names: Variable and function names should be descriptive and convey their purpose and functionality. Avoid using names that are too short or unclear, as this can make the code harder to understand.
  • Avoiding abbreviations and acronyms: While abbreviations and acronyms can be useful for saving space, they can also be confusing to other developers who may not be familiar with them. Where possible, use full and descriptive names for variables and functions.
  • Breaking up complex code into smaller, more manageable pieces: Complex code can be difficult to read and understand, especially if it is all contained in a single function or method. To make the code easier to read, consider breaking it up into smaller, more manageable pieces. This can also make the code easier to test and debug.
  • Using consistent formatting and indentation: Consistent formatting and indentation can make the code easier to read and understand, especially when working with a team of developers. Use a consistent style for variable and function names, as well as for indentation and line breaks.

Examples of self-documenting code

Good Example

fn calculate_average(numbers: &[i32]) -> i32 {
    let sum = numbers.iter().sum();
    let count = numbers.len() as i32;
    let average = sum / count;
    average
}
Enter fullscreen mode Exit fullscreen mode

In this example, we have a simple function that calculates the average of a vector. The function name calculate_average is descriptive and conveys its purpose. The function takes a slice of integers as an argument, which is also a explanatory name. The function also uses &[i32] instead of Vec as it's input parameter, making it more efficient and readable. The variable names within the function are also descriptive and easy to understand, making it clear what each variable represents. The return statement is also clear and concise.

Good Example

fn is_valid_name(name: &str) -> bool {
    name.chars().all(|c| c.is_ascii_alphabetic() || c == ' ')
}
Enter fullscreen mode Exit fullscreen mode

This function checks whether a given string is a valid name. The function name is_valid_name effectively communicates the function's intended purpose. It takes a string slice as an argument, which is also a descriptive name. The function uses the chars method to iterate over each character in the string, and the all method to check if every character meets a certain condition. The condition is notably comprehensible and straightforward to grasp.

Good Example

let sentence = "The quick brown fox jumps over the lazy dog.";
let words: Vec<&str> = sentence.split(' ').collect();
Enter fullscreen mode Exit fullscreen mode

In this example, we have a simple code that splits a sentence **_into _words**. The variable names sentence and words convey the meaning behind the variables through a quite descriptive naming. The _*split *_method is used to split the sentence into words at every space character, and the resulting words are collected into a vector. The code is clear and concise, making it easy to understand what is happening.

Bad Example

fn f(x: i32, y: i32) -> i32 {
    let a = x * y;
    let b = a / 2;
    return b;
}
Enter fullscreen mode Exit fullscreen mode

In this instance, we encounter a function that computes the area of a rectangle. The name of the function, "f," fails to sufficiently indicate its intended operation. Furthermore, the names of the variables, "a" and "b," fail to provide any insight into their intended use. Additionally, the code within the function lacks self-documentation, thereby obfuscating the specific calculation being performed.

IV. Commenting Tricky Stuff

Why it is important to comment tricky or non-obvious parts of the code

Tricky or non-obvious parts of the code can make it difficult for other developers to understand how the code works. These parts of the code may be essential to the functionality of the program, but without proper comments, they can be difficult to decipher.

For instance, let's say you've developed a program that has a complex algorithm that performs a specific task. It may be difficult for another developer to understand how this algorithm works just by reading the code, even if it has a self-documented approach. By commenting each step of the algorithm, you can help other developers understand how it works, and they can modify or debug the code more efficiently. This will save them time and avoid unnecessary confusion.

Best practices for commenting tricky code

One of the most important aspects of writing clean and maintainable code is adding comments to explain the thought process behind it. One best practice to achieve this is to use inline comments. Inline comments can be placed directly next to the code they are commenting on, providing context and explanations for that piece.

Additionally, another best practice is to add comments to explain unusual or unexpected behavior. This can help other developers understand why certain decisions were made during the development process and how they might impact the codebase. It is important to keep in mind that not all developers are familiar with the same programming concepts or methodologies, so adding comments can make it easier for everyone to understand the code.

Highlighting any potential pitfalls or edge cases is also important, as it can help other developers avoid common mistakes and errors. By providing clear explanations and examples of what can go wrong, developers can be better equipped to handle any issues that may arise during the development process.

In summary, adding comments to explain the thought process behind the code, including inline comments, comments to explain unusual or unexpected behavior, and highlighting potential pitfalls or edge cases, is crucial for writing maintainable and understandable code.

Examples of tricky code and how to comment it effectively

One example of tricky code is code that uses recursion. Recursion can be difficult to understand and may require additional comments to explain how the recursive function works. Adding comments that explain the recursion logic, the base case, and the exit conditions can help other developers understand how the function works and how it contributes to the overall functionality of the codebase.

Another example of tricky code is code that involves complex algorithms or data structures. In these cases, it can be helpful to add comments that explain how the algorithm or data structure works, as well as any potential issues or limitations. This can help other developers understand how the code works and how they can modify it to fit their needs.

Code that involves external libraries or frameworks can also be tricky to understand. In these cases, adding comments that explain how the code integrates with the library or framework can be helpful. This can help other developers understand how the code works and how it interacts with the external codebase.

Finally, code that uses unusual or unexpected syntax or language features can also be tricky to understand. In these cases, adding comments that explain the syntax or features can be helpful. This can help other developers understand how the code works and how it contributes to the overall functionality of the codebase.

By following these best practices, you can ensure that tricky or non-obvious parts of the code are well-documented and easy to understand. This can help other developers modify and debug the code more efficiently and effectively, leading to a more maintainable and understandable codebase.

VI. Conclusion

In conclusion, commenting code is an essential part of programming that can bring numerous benefits to developers and teams. By providing context, clarity, and explanations of how the code works, comments can save time and effort by reducing the need to decipher code and allowing developers to focus on problem-solving. Comments can also help to identify potential issues, highlight tricky code, and provide insights into why certain decisions were made during the development process.

In this blog post, we explored the importance of commenting code and the benefits of doing so. We delved deeper into the different types of comments and provided examples of how they can be used effectively. We also discussed self-documented code and best practices for commenting code, including commenting the method, writing self-documenting code, and commenting tricky code.

We hope that this post has been helpful in encouraging you to start commenting your code more effectively. By following the best practices outlined in this post, you can ensure that your code is well-documented, easy to understand, and maintainable for years to come. Remember to use clear and concise language, avoid abbreviations and acronyms, break up complex code, and use consistent formatting and indentation.

In order to improve the maintainability and understandability of our codebases, it's important to adopt a more effective commenting strategy. By commenting our code more thoroughly, we can provide valuable guidance to other developers who may need to work with our code in the future. This can help to prevent confusion and errors, ultimately saving time and resources. Additionally, effective commenting can make our codebases more accessible to developers who may not be familiar with the specific technologies or design patterns we're working with. By explaining our thought processes and providing clear explanations of complex concepts, we can help ensure that our code can be understood and maintained by a wider range of developers. So, let's prioritize effective commenting as a key part of our development process moving forward!

Top comments (0)