Write a code that endures endless business requirements: Part-1 On Software Code Quality Metrics!
Here I am back after a long vacation (one month and a half!) in my home country, Sudan. It was an amazing vacation where I met many old friends, relatives and enjoyed our local food!
Returning to blogging. I discussed why you should aggressively invest in your coding skills in Part-1 and Part-2. I hope that I made a clear case and convinced you that writing good code is not a luxury but rather a necessity in a world full of coding cowboys.
Now, I will shift the focus from the problem to the solution. We will take a three parts series that will give some insights on how to write better code. In the first post, we will learn how we can measure our code complexity. In the second post, we will learn how can we design a proper greenfield solution. Finally, in the last part, we will learn how to refactor a brownfield solution.
Ready? Let us start our storytelling in the first part.
Oops, it is another incident!
Usually, you start your day as a developer with a cup of coffee after having your standup meeting. Then, you run into your computer fully energized and ready to implement a new future the business requested. But unfortunately, it does not always go smoothly!
You get an email from an operation manager that there is a critical application feature that is down and he requests your urgent intervention to fix it. There is no other option, as this critical system is a money cow for the company and the incident is affecting thousands of users who pay your collogues payroll! You are asked straight away to prioritize new developments down and focus on this incident. Even worse, the feature has been developed by a friend who left the company years ago in a codebase you are not familiar with 😊 Sounds familiar, huh?
The curse is coming …
You got the heat and decided to navigate the codebase and understand what is going on. You open your Visual Studio (Read IntelliJ, PyCharm, whatever!). You found the code area that you suspect is the root cause of the issue and decide to troubleshoot. And here is how it looks.
Trrrrra!!! This ladder-style coding is well recognized for us since the early days we started learning how to program. It is called Spaghetti Code; it is a horrible, disgusting, foolish and terrible coding style!
You curse the developer who wrote the code as you are receiving huge pressure from the project manager and the business stakeholders to fix the issue and restore the normal application operation.
Away from the emotional reaction towards a spaghetti code, let us try and analyze the objective disasters with it:
- Would you feel safe modifying this code?
- Can you make it readable?
- Can you write unit tests against this code?
- Do you think it would be flexible against future business requirements?
For an organization, such code means:
- Low time to Market
- High maintenance cost
- Lower system availability
- Less business agility
Thus, Decreased overall organization competitiveness. Therefore, such a coding style is a business threat, and we should have the proper forensic measures to deal with it.
Introducing Code Complexity Metrics
What gets measured gets done
Fortunately, our understanding of software development methodologies has developed to the extent that it made us develop some objective metrics to measure the code quality. These metrics serve as a vehicle to assess different aspects of code quality, such as:
- Depth of Inheritance: This metric tells us how deep a certain class goes in the inheritance tree.
- Cyclomatic Complexity (CC): My favorite metric! It tells us how difficult it is to test our code; it relies mainly on measuring the number of branching we have on our code. Industry recommendations are to make it below 10; it only matters on the method level.
Refer to this academic paper for a more in-depth analysis of Cyclomatic Complexity.
- Maintainability Index: A percentage indicating how difficult it is to maintain a certain piece of code.
- Class Coupling: According to MSDN, “Measures the coupling to unique classes through parameters, local variables, return types, method calls, generic or template instantiations, base classes, interface implementations, fields defined on external types, and attribute decoration.” This metric works best to assess the code from an OOP point of view.
- Cognitive Complexity: A new measure introduced by Sonar Source in their White Paper. Unlike the Cyclomatic Complexity, which aims to tell how difficult the code is to test, cognitive complexity aims to tell how difficult the code is to understand. However, not many tools support cognitive complexity.
Depth of Inheritance, Cyclomatic Complexity, Class Coupling, and Maintainability index are the most common metrics in the industry.
Why do we have very bad programming experience?
If we look at the code quality metrics in Visual Studio (Click to learn how to do it), we will end up with the image shown above. The arrows point clearly on the metrics for the method “VeryComplexCode” we see that it has Maintainability Index of 60 and Cyclomatic Complexity of 8. The numbers tell us we have some problematic parts in the code. Such metrics are extremely useful to quickly analyze big projects and decide on critical parts, which, if fixed, will result in the greatest ROI on the project.
So, the conclusion I would like to draw here is:
The more nesting we have in our code, the more complex it will be. Therefore, we should strive to minimize nesting.
More reads around improving Cyclomatic Complexity
Attaining the skill to write an excellent code takes time, effort and education. However, it is a long term strategic skill I would highly recommend learning. Here are some resources I would recommend based on my experience.
15 Articles series by Zoran Horvat on how to reduce Cyclomatic Complexity: An extremely useful blog posts series by Zoran Horvat on how to improve code complexity, he starts from a dirty, ugly code and reasons towards better-refactored design. Useful post to understand the thought process behind design patterns.
Design Patterns Library: A must to have skill for any decently developed code is the proper usage of design patterns. Pluralsight has an extensive course that covers a wide range of design patterns by many world-class authors.
Aggregate Complexity: Cyclomatic Complexity has certain limitations when it comes to large codebases, Steve Smith, has developed a unique metric called aggregate complexity to overcome that; it will be interesting to read on that.
If the guy who developed the previously presented problematic code has read the previous courses and applied them, the business application would be in better shape in terms of agility, maintainability, and stability! Your life as a succeeding developer will be easier too!
No matter how good and recent your platform/infrastructure stack is (e.g., Kubernetes, clustering, HA, etc.), bad code will always beat good hardware.
A bad code for me is like a careless student you sent to MIT (1st world-ranked engineering school), they will never learn, not because of MIT, but because of the student. Good code is like a hardworking student from very underprivileged school; he succeeds at the end (e.g., Google CEO)Mohammed Osman