E11027: too many constructs in module - split into focused modules

Category: E11xxx Code quality and IR analysis · Reported in phase: PRE_IR_CHECKS · Classification: EXCESSIVE_MODULE_SIZE · All error codes

What went wrong

This module declares more than 250 constructs. A module of that size has almost certainly accumulated several unrelated responsibilities, and every reader of it pays for that: the whole module is the unit you must hold in your head to know what a name refers to.

250 is deliberately generous - it is a backstop for a god-module, not a design nudge. For calibration it is roughly the 99th percentile of real-world Java packages; the JDK's own hand-written packages top out around 160, and the largest module in EK9's own corpus is 158. If you are hitting it, the module is an outlier.

Note

Only constructs YOU declare are counted. Auto-generated monomorphised parameterised types ('List of String' and friends) are created in the module that declares the GENERIC, not the module that uses it - so they are excluded. A module exporting a generic is never penalised for how heavily other code instantiates it.

Common causes

  • A single 'app' or 'model' module that every new type gets added to by default
  • Porting a flat package layout from a language with no module-level quality gates
  • Generated or transcribed data types (protocol messages, table rows) declared in one module

How to fix it

Split the module along the seams of what its constructs actually reference. The compiler can point at those seams: E11017 (low module cohesion) reports how many DISCONNECTED groups the module has, and each group is a candidate module. If E11017 is silent, the module is at least connected - look for the sub-clusters that only touch each other and lift those out first.

See also

  • E11017: Low module cohesion - constructs share little commonality (the design signal)
  • E11016: Excessive module coupling - references too many external modules
  • E11014: LCOM4 cohesion within a single construct

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E11027: too many constructs in module - split into focused modules

#!ek9
defines module error.e11027.bad

  // 260 classes in one module: over the 250-construct cap, so E11027 is reported at the module.
  // Every class extends BaseType, so the module is perfectly cohesive - E11017 stays silent. A module can be
  // cohesive and still be too big: the size cap catches that on its own merit.
  defines class

    BaseType as open
      identify()
        <- rtn as Boolean: true

    DerivedNumber0000 extends BaseType
      describeNumber0000()
        <- rtn as Boolean: true

    DerivedNumber0001 extends BaseType
      describeNumber0001()
        <- rtn as Boolean: true

    DerivedNumber0002 extends BaseType
      describeNumber0002()
        <- rtn as Boolean: true

    // ... derived-classes

    DerivedNumber0257 extends BaseType
      describeNumber0257()
        <- rtn as Boolean: true

    DerivedNumber0258 extends BaseType
      describeNumber0258()
        <- rtn as Boolean: true

Fixed: Keep a module to the constructs that belong together

#!ek9
defines module error.e11027.good

  // A module of the constructs that genuinely belong together is far under the 250-construct cap.
  // When a module grows past it, split along the seams of what its constructs reference.
  defines class

    BaseType as open
      identify()
        <- rtn as Boolean: true

    DerivedNumber0000 extends BaseType
      describeNumber0000()
        <- rtn as Boolean: true

    DerivedNumber0001 extends BaseType
      describeNumber0001()
        <- rtn as Boolean: true