What is the combined complexity-size check and when does it trigger?
← Code Quality · Ref: Q733
EK9 checks that functions are not both moderately complex AND moderately large at the same time. A function can be somewhat complex OR somewhat long, but not both.
FORMULA
(complexity / maxComplexity) x (statements / maxStatements) must be 0.50 or less
For functions: maxComplexity = 45, maxStatements = 150
For methods: maxComplexity = 45, maxStatements = 100
For operators: maxComplexity = 45, maxStatements = 50
WHY THIS CHECK EXISTS
Individual complexity and statement count checks catch extreme cases. But a function can pass both individually while still being a maintenance problem:
- 30 complexity (passes: under 45) + 120 statements (passes: under 150)
- Combined: (30/45) x (120/150) = 0.67 x 0.80 = 0.53 (FAILS: over 0.50)
THIS IS A DESIGN INSIGHT
A function that is 67% of max complexity AND 80% of max size is carrying too much responsibility. Neither metric alone triggers a violation, but together they reveal a function that needs decomposition.
HOW TO FIX
Decompose into smaller functions. Reducing EITHER complexity (fewer branches) OR size (fewer statements) brings the combined ratio under the threshold.
THIS EXAMPLE
The analyzeMetrics function below has moderate complexity and moderate size, but the combined ratio stays well under 0.50 because the logic is decomposed into helper functions. A function that triggers E11020 would need 30+ branches AND 100+ statements simultaneously, which is too large for a concise example but exactly the kind of monolithic function this check prevents.
See Q696 for complexity limits. See Q310 for code quality overview. See Q322 for quality enforcement.
Example
defines module qa.codequality.combinedcomplexityboundary defines constant THRESHOLD_LOW <- 25 THRESHOLD_MEDIUM <- 50 THRESHOLD_HIGH <- 75 THRESHOLD_EXCELLENT <- 90 defines function <?- Classifies a numeric score into a category. Small, focused function: low complexity, few statements. -?> classifyLevel() as pure -> scoreValue as Integer <- scoreLevel as String: "unknown" if scoreValue < THRESHOLD_LOW scoreLevel: "low" else if scoreValue < THRESHOLD_MEDIUM scoreLevel: "medium" else if scoreValue < THRESHOLD_HIGH scoreLevel: "high" else scoreLevel: "excellent" <?- Generates a description from a classified level. Separate function keeps both complexity and size low. -?> describeLevel() as pure -> scoreLevel as String <- classification as String: "unclassified" if scoreLevel == "low" classification: "needs improvement" else if scoreLevel == "medium" classification: "average performer" else if scoreLevel == "high" classification: "strong performer" else if scoreLevel == "excellent" classification: "outstanding" <?- Analyzes metrics by composing small focused functions. Combined complexity-size stays well under 0.50 because logic is decomposed into classifyLevel and describeLevel. -?> analyzeMetrics() as pure -> scoreValue as Integer <- report as String: "" scoreLevel <- classifyLevel(scoreValue) classification <- describeLevel(scoreLevel) passed <- scoreValue >= THRESHOLD_MEDIUM if passed report: `${classification} (${scoreLevel}) PASS` else report: `${classification} (${scoreLevel}) FAIL` defines program CombinedComplexityBoundaryDemo() stdout <- Stdout() scores <- [15, 42, 78, 95] for scoreValue in scores stdout.println(analyzeMetrics(scoreValue))
Common mistakes
E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.
Incorrect:
stdout.println(analyzeMetrics(scoreValue).toUpperCase())
Correct:
stdout.println(analyzeMetrics(scoreValue))
E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.
Incorrect:
classification <- describeLevel(scoreLevel).toUpperCase()
Correct:
classification <- describeLevel(scoreLevel)
Other ways to ask this
- What triggers E11020 combined complexity size?
- How do complexity and size interact in EK9?
- What is the combined complexity threshold?
- Why does EK9 check both complexity and size together?
Coming from another language?
Java: no combined check (SonarQube checks complexity and length separately). Python: no combined check. C++: no combined check. Rust: no combined check. Go: no combined check. EK9: multiplicative combined check catches functions that pass individual limits but are still too complex for their size.
Keywords: decompose, size, formula, metric, E11020, threshold, statements, limit, boundary, combined, complexity, quality, clean-code