/ PROGRAMMING, TYPESCRIPT, TECH, VSCODE

Code Metrics - A red flag for overly complex code

When you are writing code your main focus should be solving the problem at hand - creating code that works. However this is only a very short term view of your codebase. In a very short time this can lead to so complicated code that nobody understands how it works. You can try to explain the code in comments, however those can become outdated very quickly.

When you are tasked with fixing bugs, or maintaining the code it can become a nightmare to figure out what you should do.

The best thing what you can do during the initial development of the code is to try to write simple code and as soon as your code gets complicated break it down into smaller functions.

By doing it this way, you are forced to name the function explaining what this piece of code is actually doing.

However the question is what is (objectively) complicated code?

Calculating Code Complexity

Human Approach

The most naive way to figure out if code is getting complicated is to simply count the lines of code. The more lines => the more complicated the code. You could then set a limit for your team to say: ok 10 lines of code and then you refactor the function into smaller functions.

When you do that however developers tend to be ‘smart’ by using every trick in the book to create unreadable code. Shorthand Syntax, less whitespace, meaningless variable names etc.

Example 1: A totally useless function

foo(b){
  return (b < 2) ? 1 : 2;
}

As you can see a metric like lines of code can lead to bad results.

Example 2: A readable function

const calcNewIncrement = (value) => {
  const MAX_VALUE = 2;
  const STANDARD_INCREMENT = 1;
  const DOUBLE_INCREMENT = 2;

  let increment;
  if (value < MAX_VALUE){
    increment = STANDARD_INCREMENT;
  } else {
    increment = DOUBLE_INCREMENT;
  }

  return increment;
}

This function essentially does the same as the previous function. However When another human reads this function he can understands what is going on.

(If you are concerned about the amount of data you are transmitting to the client, you should add a minifier into your build pipeline, that will probably convert this nto the shortform of Example 1)

IDE Assisted

A much more meaningful way of calculating complexity would be to take a look at the AST-Tree generated by your code and then count the number of expressions needed. You then would assign values for various statements (assigning a variable = 0, return statement = 1, etc.). By analysing the AST Tree all of the ‘cleverness’ of the developer by using shorthand is eliminated and you can get a consistent value for your code.

VS Code: Code Metrics

For Visual Studio Code there is this awesome Plugin Code Metrics For JavaScript or TypeScript is simply adds a little flag on top of the function - warning you that your code complexity is getting out of hand.

Example 3: Exending with a random function

Back to our example, we got a very specific request from users, that anyone not named alfred should get a bonus increment. Now the code has to deal with it. (A common situation during development.)

Code Metrics Warning

The plugin will now display a warning that your Complexity has reached 7 and you should start refactoring.

Final Refactored Code

const MAX_VALUE = 2;
const STANDARD_INCREMENT = 1;
const DOUBLE_INCREMENT = 2;


const calcNewIncrement = (value, name) {
  const adjustedValue = adjustValueForSpecialUser(value, name);
  if (adjustedValue < MAX_VALUE){
    return STANDARD_INCREMENT;
  } else {
    return DOUBLE_INCREMENT;
  }
}

/**
 * Adjustment for Special User Privileges
 * Alfred gets a 120 point bonus.
 *
 * For all other users Default Values 0 and 2 are returned.
 *
 * @param {number} value
 * @param {string} name
 * @returns number
 */
const adjustValueForSpecialUser = (value, name) => {
  if (name === 'alfred'){
    return value + 120;
  } else {
    if (value > MAX_VALUE){
      return 0;
    } else {
      return 2;
    }
  }
}

It is not obvious why we are treating alfred as something special, thus a JSDoc comment was added. In the hope that the next developer can understand the reason that this function exists.

Conclusion

While my code example was a little contrived I wanted to show the benefit of readable code - it is still wierd code but you can quickly understand what is going on.

The smaller functions are now easier to maintain and easier to write tests for them.

CodeMetrics really is just a small indicator that your code is probably going to be difficult to understand and reminds you to refactor complicated functions into smaller more manageable functions.

The goal is not to have purely simple code - some problems are by nature just more complicated. But you should think about it if the problems are really that complicated or if you can refactor it to be more simple.