What is the hybrid class-component anti-pattern in EK9?
← Code Quality · Ref: Q959
When a class uses 'by' delegation AND has 3 or more additional service fields (trait/abstract typed), it is mixing class and component responsibilities. E11024 triggers.
WHY THIS MATTERS
A class using 'by' delegation is extending behavior through composition (a class pattern). Having 3+ service fields means it is also coordinating multiple services (a component pattern). Mixing these patterns creates maintenance problems.
THRESHOLD
- Must have at least 1 'by' delegation
- Must have 3 or more additional service-type fields (not counting 'by' delegate fields)
THIS EXAMPLE
DocumentManager uses 'by' delegation for Storable trait and has 2 additional service fields (formatter and encoder). With only 2 service fields, this is under the threshold of 3.
The typicalError mutation adds a third service field, hitting the threshold and triggering E11024.
See Q314 for cohesion and coupling. See Q111 for component basics.
Example
defines module qa.quality.excessiveservicefields defines trait Storable store() abstract retrieve() abstract Formatter formatContent() abstract Encoder encodeContent() abstract Compressor compress() abstract defines class StorableImpl with trait of Storable override store() require true override retrieve() require true PlainFormatter with trait of Formatter override formatContent() require true SimpleEncoder with trait of Encoder override encodeContent() require true BasicCompressor with trait of Compressor override compress() require true defines class <?- DocumentManager uses 'by' delegation for Storable and has 2 additional service fields (under threshold of 3). Adding a 3rd service field would trigger E11024. -?> DocumentManager with trait of Storable by persistence persistence Storable: StorableImpl() formatter Formatter: PlainFormatter() encoder Encoder: SimpleEncoder() title as String: "untitled" processDocument() formatter.formatContent() encoder.encodeContent() persistence.store() default operator ? defines program ExcessiveServiceFieldsDemo() stdout <- Stdout() stdout.println("DocumentManager has 1 by-delegation and 2 service fields") stdout.println("Under the threshold of 3 additional services")
Common mistakes
E11024 — Adding a third service field (compressor) to a class with 'by' delegation triggers E11024 (3 >= threshold of 3). Split into a component for service coordination. See ek9 -h E11024 for details.
Incorrect:
formatter Formatter: PlainFormatter() encoder Encoder: SimpleEncoder() compressor Compressor: BasicCompressor()
Correct:
formatter Formatter: PlainFormatter() encoder Encoder: SimpleEncoder()
Other ways to ask this
- What triggers E11024 HYBRID_CLASS_COMPONENT?
- Why does EK9 reject classes with delegation and many service fields?
- How many service fields can a class with 'by' delegation have?
Coming from another language?
Java: no 'by' delegation, no construct distinction. Spring beans mix data and services freely. C#: no built-in delegation detection. Go: no class vs component distinction. EK9: detects hybrid patterns at compile time.
Keywords: service, threshold, field, component, class, quality, by, E11024, hybrid, delegation