How does EK9 detect code smells?
← Code Quality · Ref: Q313
EK9 detects several categories of code smell at compile time and rejects code that exhibits them.
RESPONSIBILITY SMELLS (E11022-E11025)
E11022 Class should be component: When a class has too many injected dependencies, it should be restructured as a component.
E11023 God class: A class with too many methods and fields is doing too much. Split into smaller, focused classes.
E11024 Missing delegation: A class implements a trait but does not use 'by' delegation. Manual forwarding is error-prone.
E11025 Hybrid aggregate: A type mixes data storage and complex behaviour. Separate into a record (data) and a class (behaviour).
DATA CLUMPS (E11053)
When the same group of parameters appears together in multiple function signatures, extract them into a record. Records give the group a name and make the code self-documenting.
LAW OF DEMETER (E11054)
Chained method calls like a.getB().getC().doSomething() violate the Law of Demeter. Each object should only talk to its immediate collaborators. EK9 detects excessive chaining and flags it.
STRING CONCATENATION (E11068)
Using the + operator to build strings with three or more parts should use string interpolation instead. Interpolation is clearer, faster, and avoids intermediate string allocations.
NAMED ARGUMENTS (E11061-E11062)
Calls with many positional arguments are hard to read. EK9 requires named arguments beyond a threshold to prevent parameter order mistakes.
See Q311 for the full quality checks catalog. See Q312 for complexity metrics. See Q314 for cohesion and coupling. See Q109 for composition patterns. See Q267 for anti-patterns including god classes.
Example
defines module qa.codequality.smells defines record <?- Extract related fields into a record to avoid data clumps. Instead of passing street, city, postcode separately everywhere, group them into an Address record. -?> Address street as String: String() city as String: String() postcode as String: String() Address() -> street as String city as String postcode as String this.street :=? street this.city :=? city this.postcode :=? postcode override operator ? as pure <- rtn as Boolean: street? and city? and postcode? operator $ as pure <- rtn as String: `${street}, ${city} ${postcode}` defines function <?- Uses the Address record instead of three separate parameters. This eliminates the data clump smell. -?> formatMailingLabel() as pure -> recipientName as String recipientAddress as Address <- label as String: `${recipientName}\n${recipientAddress}` defines program CodeSmellsDemo() stdout <- Stdout() homeAddress <- Address("10 High Street", "London", "SW1A 1AA") mailingLabel <- formatMailingLabel("Jane Smith", homeAddress) stdout.println(mailingLabel)
Common mistakes
E11068 — Building a String from three or more parts with + should use interpolation; `recipientName + "\n" + $recipientAddress` triggers E11068 - use a backtick `${...}` template. See ek9 -h E11068 for details.
Incorrect:
label as String: recipientName + "\n" + $recipientAddress
Correct:
label as String: `${recipientName}\n${recipientAddress}`
E50001 — Renaming the variable means later references to 'mailingLabel' become unresolved, triggering E50001. See ek9 -h E50001 for details.
Incorrect:
mailingLabelXYZ <- formatMailingLabel("Jane Smith", homeAddress)
Correct:
mailingLabel <- formatMailingLabel("Jane Smith", homeAddress)
Other ways to ask this
- What code smells does EK9 catch?
- How does EK9 detect god classes and data clumps?
- Does EK9 enforce the Law of Demeter?
Coming from another language?
Java: SonarQube detects god classes, data clumps, and feature envy but as optional warnings. PMD has GodClass and LawOfDemeter rules but configurable. Rust: clippy has no code smell detection beyond simple patterns. Go: no code smell detection built-in. Python: pylint detects some smells but all optional. EK9: code smell detection built into the compiler as mandatory errors.
Keywords: god, delegation, clump, responsibility, quality, smell, metric, hybrid, E11068, class, E11053, interpolation, clean-code, demeter, E11022