In this article, we want to talk a little about simple code quality rules. We use them in practice: the minimum of lines of code and the same nesting structure of equivalent operations. These principles lead to good results.
Let’s look at a small example. The task of the code fragment, having received the URL and serialized data for the request as input, make an HTTP call to the service, hiding the entire transport layer from the client. The code contains only 17 lines. Now let’s look at one of the structural criteria for the complexity of a function – the amount of indentation. In line 12, we see the nesting of the 3rd level. If you remember what they write about such functions in the book Clean Code, you can set a goal to change the code to a simpler one. Here’s one, for example:
Of course, the above example is not the only possible case. But it shows one interesting feature: without changing the logic of the code, now instead of 17 lines of code, we have 26. More similar examples are described in the hooks guide.
How is it that we use the practice of simplifying the code, and in the end, we get its structural complexity?
Let’s take a closer look at this phenomenon and recall the KISS rule: in the code, we used the C # language construct – Extensions, added a separate class, and introduced an unknown function into our project. Agree, this is clearly a little more difficult than just writing a call to several framework native methods, and this can be considered not a very good solution. But, on the other hand, we simplified the reading of the original function by reducing its nesting, which can be counted as a plus.
Comparing such pros and cons, we have repeatedly concluded that it is rather difficult to derive objective indicators in each specific example. Therefore, as a rule, we use the principle of minimality of the final code to solve the problem.
Logic blocks of comparable size within the same function
This is the second rule that helps you evaluate the structure of your code. Let’s see how to achieve this with our example. First, let’s see if the original function adds value between operations 1 and 2. The answer is no, it just calls system constructs without any transformation or data processing. Therefore, we will immediately move the logic of writing data to a request into the function of creating a request.
Now we have reduced the number of actions in the function:
- Create an HTTP request with data;
- Receiving a response and writing it to a file.
But we still have a problem: the first and second operations are reflected by different code structures (nesting). Let’s recall how we solved the problem of reading string data in the first example and move the request-a processing procedure into the same Extension class.
However, let’s go back to our example and see what the original function became. There are only two operations left, and now they have the same structural complexity. If before combining the formation of a request and writing data to it, we see the structural difference between the Get and Post methods, then after that we see the same structural complexity of these functions, and this is good. After these operations, the total file size decreased by 17 lines, which confirms the principle of improving the code by reducing its size. After a more detailed examination of the resulting code, the algorithmic similarity is noticeable, which already suggests the idea of using DRY for further improvement.
The considered criteria for the minimality of lines of common code and the same complexity of internal structures are not scientific. They make it easy to find places for optimization in practice. Here are a few things to watch out for when writing code:
Don’t make premature abstractions. Always consider the context and complete structure of the code you write, not the local piece. Use code assessment criteria that are easy to measure and monitor.