10 Tips On Writing Perfect Clear Code

Clear Code Main Logo

10 Tips On Writing Perfect Clear Code

Hello! Today I want to share tips on writing perfect clear code, taken from the book by Peter Goodleaf “Craft programmer//Practice of writing good code.”

Of course, it would be nice to read this entertaining book to anyone who writes code, but for particularly lazy, but willing to stop torturing less and introduce colleagues to confusion (have a conscience).

1. Write a simple code with good formatting

The presentation format has a huge impact on the ease of understanding the code. A sensible representation conveys the structure of the code: functions, loops, and conditional statements become clearer.

int fibonacci(int position)
{
if (position < 2)
{
return 1;
}
int previousButOne = 1;
int previous = 1;
int answer = 2;

for (int n = 2; n < position; ++n)
{
previousButOne = previous;
previous = answer;
answer = previous + previousButOne;
}
return answer;
}

  • Try to make the normal execution of your code obvious. Error handling should not detract from the normal execution sequence. Conditional if-then-else constructs should have a uniform branch order (for example, always put a branch of “normal” code in front of the “error handling” branch, or vice versa).
  • Avoid a large number of levels of nested statements. Otherwise, the code becomes complicated and requires lengthy explanations. It is considered that each function should have only one exit point; this is known as the code Single Entry, Single Exit (SESE, one input – one output). But usually, this restriction makes it difficult to read the code and increases the number of nesting levels. I like the above version of the Fibonacci function more than the following SESE style version:

int fibonacci(int position)
{
int answer = 1;
if (position >= 2)
{
int previousButOne = 1;
int previous = 1;

for (int n = 2; n < position; ++n)
{
previousButOne = previous;
previous = answer;
answer = previous + previousButOne;
}
}
return answer;
}

I would have refused such unnecessary nesting in favor of the additional operator return – it became much more difficult to read the function. The expediency of hiding a return somewhere in the depth of a function is quite doubtful, but simple abbreviated calculations at its beginning make it very easy to read.

  • Beware of optimizing the code as a result of which the clarity of the basic algorithm is lost. Optimize the code only when it becomes clear that it interferes with the acceptable work of the program. When optimizing, make clear comments on the operation of this code segment.

2. Choose meaningful names

The names of all variables, types, files and functions should be meaningful and not misleading. The name must correctly describe what it is. If you can not find a meaningful name, then there is a doubt that you understand the work of your code.

The naming system should be consistent and not cause unpleasant surprises. Make sure that the variable is always used only for the purpose its name implies.

A good choice of names is probably the best way to avoid unnecessary comments. Names best allow you to bring the code closer to the expressiveness of natural languages.

3. Break the code into independent functions

How you break the code into functions and what names you give them can make the code understandable or completely incomprehensible.

One function, one action

Minimize any unexpected side effects, however helpful they may seem. They will require additional documentation.
Write short functions. They are easier to understand. You can orient yourself in a complex algorithm if it is broken into small fragments with meaningful names, but this cannot be done in a shapeless mass of code.

4. Choose meaningful type names

As far as possible, describe the constraints or behavior using the available language features. For example:

  • Defining a value that will not change, assign a constant type for it (use const in C).
  • If the variable should not take negative values, use the unsigned type (if available in the language).
  • Use enumerations to describe the associated dataset.
  • Choose the type of variables correctly. In C / C ++, write the size to variables of type size_t, and the results of arithmetic operations with pointers to variables of type ptrdiff_t.

5. Use named constants

A code like if (counter == 76) is puzzling. What is the magic value of the number 76? What is the meaning of this test? Practicing magical numbers is flawed. They obscure the meaning of the code. It is much better to write this:

const size_t bananas_per_cake = 76;
...
if (count == bananas_per_cake)
{
// bake a banana cake
}

If the code often contains the banner, it is an additional advantage to replace the number 76, which is fraught with errors.

This applies not only to numbers but also to constant strings. Take a closer look, especially if they occur multiple times. Wouldn’t it be better to use named constants instead?

6. Highlight important code snippets

Try the highlight. The attention of the reader. For this, there are a number of techniques. For example:

  • Reasonably place your ads in the classroom. First, it should be informed about open objects. It is less interesting to most readers.
  • If possible, hide all non-essential information. Do not leave unnecessary garbage in the global namespace. In C++, there is a simple idiom that allows you to hide it. (Meyers 97).
  • Do not hide the important code. And make this operator simple. It is difficult to read such statements. Avoid them.
  • Limit the nesting depth of conditional statements. Otherwise, it is important to understand the case.

7. Combine related data

All related information should be in one place. Otherwise, you will not only be able to jump through the hoops, but you also need to use the ESP. API for each component must be represented by a single file. If there is too much-interconnected information, it should be revised.

If possible, combine objects using language constructs. In C++ and C#, you can combine the elements within the same namespace. In Java, a means of combining is the package mechanism. Can be defined in the enumeration.

8. File Headers

This is a list of comments. This does not require much work. This is an idea of ​​what they are dealing with. This is a copyright statement. Usually, file headers look like this:

/*********************************************************
* File: Foo.java
* Purpose: Foo class implementation
* Notice: (c) 1066 Foo industries. All rights reserved.
********************************************************/

9. Correctly handle errors

Place all error handling in the most appropriate context. If there is a read/write disk problem, it must be processed in the code that deals with disk access. To handle this error, you may need to generate another error (such as the exception “I can not download the file”), passing it to a higher level. This means that at each level of the program the error should be an exact description of the problem in its context. It makes no sense to handle the error associated with a disk failure in the user interface code.

The self-documenting code helps the reader to understand where the error occurred, what it means and what its implications are for the program at the moment.

10. Write meaningful comments

So, we tried to avoid writing comments using other indirect methods of documenting code. But after you have made every effort to write clear code, everything else needs to be provided with comments. To make the code easy to understand, you need to add the appropriate amount of comments. What exactly?

  • First, try other tricks. For example, check whether the code can be made clearer by changing the name or creating a helper function, and thus avoid commenting.

I am sure that already after introducing several of these principles into the habit you will make one programmer happier. And you will be this happy programmer. When? At the time of returning to work on his code of six months ago.