DEV Community

Ali S. Topuz
Ali S. Topuz

Posted on

Complexity: An unwished experience in scaling and maturity phases

Complexity: An unwished experience in scaling and maturity phases

Introduction

I’m sharing my notes on “Complexity”, a concept we often come across when developing applications and products.

SOLID principles, Domain driven Design, Test driven Development, KISS, DRY, YAGNI, etc.. When questioning concepts and principles like these, the principle of “Cohesion”, which is one of the intersections of almost all concepts and principles, hang behind. I’ll try to elaborate on “Cohesion” principle.

Principles in Coding

Let’s try to remember some principles of coding and make them connected with “complexity” topic:

  • Keep It Simple, Stupid
  • Write DRY Code
  • Separation of Concerns
  • You Aren’t Going to Need It
  • Document Your Code
  • SOLID principles

And it should be noted that when these principles are evaluated together within the framework of their own rules, they find a few common points. One of these points is “Avoiding complexity”.

KISS: Unnecessary complexity should be avoided
DRY: Avoids knowledge duplication
Separation of Concerns: Instructs to avoid writing long complex functions.
YAGNI: Avoids rework and decrease the complexity

What can “complexity” cause?

Basically, Complexity can lead to “get lost” in any journey.

**Tightly Coupled code base
**Works but not easily maintainable code lines, limited flexibility (or no flexibility) on code. Too much dependency between features/modules and this also leads blind alley.

**Making irreversible decisions
**To sustain productivity and be able deliver things, hack all day.. Also leads to increase bugs and waste.

**Poor readability
**Unclear indications, duplicated business rules, multiplied/duplicated business logics, occasionally hearing “it is available in documentation but works different in app”, not consistent behavior based on what it read.

What is Cohesion and Coupling? Why “High Cohesion, Low coupling” matters?

Cohesion is a measure of the degree to which the elements of the module/component are functionally related. It is the degree to which all elements directed towards performing a single task are contained in the module/component.

Coupling is a measure of the degree of interdependence between component/modules. Good software has low coupling.

The best scenario would be:

Wikipedia pic: Low Coupling High Cohesion example view within modules

High Cohesion

High cohesion is a software engineering concept that expresses how closely all the members or all the code in a class supports a central purpose of module/component/functionality. It can be taken into account that the SoC is implemented very strongly. Classes with strongly related functions are defined as having a high level of compatibility; the heuristic goal is to make cohesion as high as possible.

Low Coupling

Modules should be as independent as possible from other modules. This interdependency brings flexibility and don’t make big impact other components/modules. With this manner, Low Coupling would be the best approach for the code base to sustain qualified deliveries.

How can we measure coding complexity?

  • Not having a coding architecture does not mean “High complexity”.

  • At first glance, incomprehensible folder structure does not mean “High complexity”.

  • Absence of Unit tests or Integration tests does not mean “High complexity”.

  • Complexity should be evaluated within the framework of concrete values. It is not a parameter that can be evaluated for partial or the whole application with prediction and assumption.

Cyclomatic Complexity

Cyclomatic Complexity is a source code complexity measurement. It is a software metric used to indicate the complexity of a program. It is computed using the Control Flow Graph of the program.

Example flow graph representations

For example, if source code contains no control flow statement then its cyclomatic complexity will be 1 and source code contains a single path in it. Similarly, if the source code contains one if condition then cyclomatic complexity will be 2 because there will be two paths one for true and the other for false.

And with this measurement way, there is already some calculation methods within functions and some characteristics:

M = E-N+2P

E = the number of edges in the control flow graph
N = the number of nodes in the control flow graph
P = the number of connected components

On the other hand, there are tools to measure this or closer to this such as Visual Studio Calculate Code Metrics, VS Code CodeMetrics (Not exactly CC algorithm but very close to that algorithm) etc.

Categorisation to interpret cyclomatic complexity

In this presentation, Tom McCabe introduces the following categorisation to interpret cyclomatic complexity:

  • Between 1 and 10: Simple procedure: little risk

  • Between 11 and 20 More complex: moderate risk

  • Between 21 and 50 Complex: high risk

  • 50 and Higher: Untestable code: very high risk

We can also get benefit of tools to see some warnings on our functions in editor. An example view of the complexity on a function and suggestions is as follows.

With VsCode CodeMetrics Extension, A view of Cyclomatic Complexity value

An example of list of suggestions to reduce Cyclomatic Complexity:

With VsCode CodeMetrics Extension, A view of suggestions to reduce Cyclomatic Complexity

Conclusion

  • Consider to track Cyclomatic complexity.

  • At least for critical functions, keep Cyclomatic complexity reduced as much as possible

  • Stop being nice about postponing things

  • Feed backlog for refactoring relevant items with relevant tag such as reducing complexity.

  • From your point of view, If any principle brings more complexity on a solution/feature/module or whole application, make some brainstorming with your team.

  • Kicking-off a new feature in short time doesn’t mean to deliver bad code.

Cheers!

Top comments (0)