Beyond Functionality — Part 2: Quantify Readability
This will be a follow-up to the previous “Beyond Functionality” article. The previous one explained some ways to improve code readability…
Beyond Functionality — Part 2: Quantify Readability
This will be a follow-up to the previous “Beyond Functionality” article. The previous one explained some ways to improve code readability. The next question is “How to know if it has improved?”.
“If you can’t measure it, you can’t improve it.” — Peter Drucker
Fortunately, several procedures exist to measure it, such as Cyclomatic Complexity, Cognitive Complexity, Halstead Complexity Measures, Maintainability Index, Indentation Depth, and Comment Density. It is too much to explain all of them here, so we will focus on Cyclomatic Complexity and Cognitive Complexity. Rather than choosing which one is the best, they can complement each other. Let's see the details below to better understand the pros and cons of each procedure.
Don’t worry! The tool will do the calculation. We only see the details to get a better understanding of which aspect of the code affects the complexity.
Cyclomatic Complexity
The approach of this procedure to define code complexity is by measuring the number of linearly independent paths through your code. In other words, it indicates how hard to test the code. Branching and looping contribute to the complexity.
func batchTransfer(transfers []Transfer) {
for _, transfer := range transfers { // +1
if transfer.feeType == "bonus" { // +1
if transfer.amount < 10000 { // +1
continue
} else {
transfer.feeAmount = 0
}
} else {
if transfer.feeAmount == 0 { // +1
return errors.New("fee amount can not be zero")
}
}
}
}
The score for the above snippet will be 1 (base) + 1 (for loop) + 3 (if) = 5. It clearly tells you that you need at least 5 test cases to fully cover the code. The formula is simple. The counting process only takes branch and loop into account, so it will likely work well across languages.
However, while it can represent the code complexity, it still fails to penalize some crucial aspects, such as nesting level, break, and continue.
Cognitive Complexity
Meanwhile, this procedure takes further steps to be closer to what complexity should be. It measures how hard to intuitively understand the code. This focuses on human mental effort. Nesting contributes more to the complexity.
func batchTransfer(transfers []Transfer) {
for _, transfer := range transfers { // +1
if transfer.feeType == "bonus" { // +1 (+1 for the nesting level)
if transfer.amount < 10000 { // +1 (+2 for the nesting level)
continue // +1
} else {
transfer.feeAmount = 0
}
} else {
if transfer.feeAmount == 0 { // +1 (+2 for the nesting level)
return errors.New("fee amount can not be zero")
}
}
}
}
The score is 1 (for loop) + 3 (if) + 1 (continue) + 5 (nesting penalties) = 10. It is not about counting the linear execution paths, but representing the mental efforts. It represents the code readability better than the previous procedure. However, the counting process is complicated and may differ across tools and languages.
Tooling
While there are lots of tools out there, I will use gocognit and gocyclo to measure cyclomatic and cognitive complexity respectively. The installation is simple.
# Installation
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
# Run
gocyclo .
# Installation
go install github.com/uudashr/gocognit/cmd/gocognit@latest
# Run
gocognit .
If you already use golangci-lint, it has already been included out-of-the-box. You only need to add the related config to golangci.yaml and run it as usual.
linters:
enable:
- gocyclo
- gocognit
disable:
- unused
linters-settings:
gocognit:
min-complexity: 1
gocyclo:
min-complexity: 1
# Run
golangci-lint run --config golangci.yaml
Here is the example output of golangci-lint

Red-printed text shows you which code has complexity that exceeds the min-complexity stated in the config.
The complexity score can be an indicator to start code refactoring and measure the results. No longer rely solely on feeling and instinct to know when to improve and where to place the improvement. Even better if it is integrated into the CI workflow, so you can check code complexity continuously.
Ciao! 👋
메타데이터
- post_id
- b15a72e34755
- slug
- beyond-functionality-part-2-quantify-readability-b15a72e34755
- url
- https://medium.com/@hendradanu.official/beyond-functionality-part-2-quantify-readability-b15a72e34755
- canonical_url
- https://medium.com/@hendradanu.official/beyond-functionality-part-2-quantify-readability-b15a72e34755
- author_url
- https://medium.com/@hendradanu.official
- status
- ok
- fetched_at
- 2026-06-17 16:43:20