E11020: combined complexity and size exceeds maintainability threshold
What went wrong
While complexity and statement count individually pass their limits, the COMBINATION exceeds the maintainability threshold. Both metrics are borderline high, creating compound risk.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1339 (Why does EK9 reject a function whose complexity and si...)
Rationale
- Formula: (complexity/maxComplexity) × (statements/maxStatements)
- Statements are counted as for E11012: declarations, assignments, control flow, throw, calls, increments, streams, and require / assert / assertThrows / assertDoesNotThrow / assertPanic
- Threshold: 0.50 (e.g., 69% × 71% = 0.49 passes, 71% × 72% = 0.51 fails)
- Based on NASA SATC research on module reliability: modules with both high complexity and large size have the lowest reliability (Rosenberg, Hammer & Shaw, "Software Metrics and Reliability", ISSRE 1998)
Example scenario
How to fix it
- Extract helper functions (reduces statements, may reduce complexity)
- Simplify conditional logic (reduces complexity)
- Use polymorphism instead of switch/if chains (reduces both)
- TARGET: Both metrics below 70% of limits → combined ≤0.49
Common causes
- Function accumulated both logic and size over time
- Multiple responsibilities merged into single function
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E11020: combined complexity and size exceeds maintainability threshold
#!ek9 defines module error.e11020.bad defines function combinedTooHigh() -> counter1 as Integer counter2 as Integer counter3 as Integer counter4 as Integer counter5 as Integer <- rtn as Integer: 0 //90 variable declarations (each counts as 1 statement) v1 <- 1 v2 <- v1 + 1 v3 <- v2 + 1 v4 <- v3 + 1 v5 <- v4 + 1 v6 <- v5 + 1 v7 <- v6 + 1 v8 <- v7 + 1 v9 <- v8 + 1 v10 <- v9 + 1 v11 <- v10 + 1 v12 <- v11 + 1 v13 <- v12 + 1 v14 <- v13 + 1 v15 <- v14 + 1 v16 <- v15 + 1 v17 <- v16 + 1 v18 <- v17 + 1 v19 <- v18 + 1 v20 <- v19 + 1 v21 <- v20 + 1 v22 <- v21 + 1 v23 <- v22 + 1 v24 <- v23 + 1 v25 <- v24 + 1 v26 <- v25 + 1 v27 <- v26 + 1 v28 <- v27 + 1 v29 <- v28 + 1 v30 <- v29 + 1 v31 <- v30 + 1 v32 <- v31 + 1 v33 <- v32 + 1 v34 <- v33 + 1 v35 <- v34 + 1 v36 <- v35 + 1 v37 <- v36 + 1 v38 <- v37 + 1 v39 <- v38 + 1 v40 <- v39 + 1 v41 <- v40 + 1 v42 <- v41 + 1 v43 <- v42 + 1 v44 <- v43 + 1 v45 <- v44 + 1 v46 <- v45 + 1 v47 <- v46 + 1 v48 <- v47 + 1 v49 <- v48 + 1 v50 <- v49 + 1 v51 <- v50 + 1 v52 <- v51 + 1 v53 <- v52 + 1 v54 <- v53 + 1 v55 <- v54 + 1 v56 <- v55 + 1 v57 <- v56 + 1 v58 <- v57 + 1 v59 <- v58 + 1 v60 <- v59 + 1 v61 <- v60 + 1 v62 <- v61 + 1 v63 <- v62 + 1 v64 <- v63 + 1 v65 <- v64 + 1 v66 <- v65 + 1 v67 <- v66 + 1 v68 <- v67 + 1 v69 <- v68 + 1 v70 <- v69 + 1 v71 <- v70 + 1 v72 <- v71 + 1 v73 <- v72 + 1 v74 <- v73 + 1 v75 <- v74 + 1 v76 <- v75 + 1 v77 <- v76 + 1 v78 <- v77 + 1 v79 <- v78 + 1 v80 <- v79 + 1 v81 <- v80 + 1 v82 <- v81 + 1 v83 <- v82 + 1 v84 <- v83 + 1 v85 <- v84 + 1 v86 <- v85 + 1 v87 <- v86 + 1 v88 <- v87 + 1 v89 <- v88 + 1 v90 <- v89 + 1 //18 if statements with comparisons (each if adds +1 complexity, each > adds +1 complexity) //Each if is also a statement if counter1 > 0 v1 := v1 + 1 if counter2 > 0 v2 := v2 + 1 if counter3 > 0 v3 := v3 + 1 if counter4 > 0 v4 := v4 + 1 if counter5 > 0 v5 := v5 + 1 if v1 > v2 v6 := v6 + 1 if v2 > v3 v7 := v7 + 1 if v3 > v4 v8 := v8 + 1 if v4 > v5 v9 := v9 + 1 if v5 > v6 v10 := v10 + 1 if v6 > v7 v11 := v11 + 1 if v7 > v8 v12 := v12 + 1 if v8 > v9 v13 := v13 + 1 if v9 > v10 v14 := v14 + 1 if v10 > v11 v15 := v15 + 1 if v11 > v12 v16 := v16 + 1 if v12 > v13 v17 := v17 + 1 if v13 > v14 v18 := v18 + 1 //Final assignment reads the eighteen updated above; the rest feed one another up to v90 rtn := v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14 + v15 + v16 + v17 + v18 + v90
Fixed: Split a long, branching function into focused steps
#!ek9 defines module error.e11020.good defines function validated() -> first as Integer second as Integer <- rtn as Boolean: first > 0 and second > 0 combined() -> first as Integer second as Integer <- rtn as Integer: first + second combinedWithinLimits() -> first as Integer second as Integer <- rtn as Integer: 0 if validated(first, second) rtn: combined(first, second)