Cyclomatic complexity is a tool. As with any other tool, it may be inappropriate in some cases. This truism is neither an excuse for fallacies in reasoning about the tool, nor a permission to ignore what the tool indicates.
Cyclomatic complexity isn’t a proxy variable, which was chosen merely because somebody noticed a correlation with the value of interest.(1) CC has been constructed as a mathematical formulation of the measured value itself. This gives it a strong theoretical foundation. As a result of deductive reasoning it can only be challenged in limited number of ways. Even if the arguments make sense. Much less if they are in the form of “there exist corner cases, therefore it is wrong” or “I constructed a synthetic and obviously inadequate case,(2) therefore wrong”.
It has shortcomings. There are corner cases, where it performs poorly. But corner cases are rare and can’t be used to explain a large number of functions having high CC. As I mentioned earlier, automated evaluators may not be able to “understand” some patterns: for example multiple execution paths are equivalent from program’s logic perspective. But these patterns are objectively recognizable. “I wrote this code” is not one of them. Neither is “this tool I stupid and can’t understand my genius”. CC assumes mutual independence of edges and it will overestimate, if this condition is not met. But if you have a big function with many edges and they are highly dependent on each other, it is very often an indication of a larger problem. Finally, cyclomatic complexity does not make statements about some arbitrarily chosen interpretation of code quality. It tells something about testability and maintainability. Yes, highly optimized code segments may have high CC. But guess what: they are also testability and maintainability nightmare. They may be neccessary evil, but they remain evil.
Code metrics are misused by management. This alone does not make them invalid. If that was the case, we would need to reject all maths beyond basic arithmetic. “My boss uses a screwdriver to hit nails, so I will not use it for screws” seems to me like a poor choice. I think it is smarter to understand the tool and make the best use of it.
Even if this means accepting, that our code is not as amazing as we might have thought it is.
(1) In opposition to — for example — LoC.
(2) Expressing data as code.