A module is a unit of code with a defined boundary: a public interface through which other modules interact with it, and private internals that no other module can see or depend on. Modules exist at every scale — a function, a class, a package, a service. The principle is the same at each scale: hide what can change, expose what must be stable.
The import graph makes the module structure visible. Every import statement is a directed edge from the importing module to the imported module. Cycles in the import graph are architectural problems: if module A imports B and B imports A, neither can be understood, tested, or deployed independently. The cycle has created a single entangled unit masquerading as two.
Connascence is a vocabulary for measuring the degree of coupling between modules. Two components are connascent if a change in one requires a change in the other. The types, ordered from weakest to strongest:
Connascence of Name — two components agree on an
identifier. Module B calls module_a.process(). If A renames
process, B breaks. This is the weakest form — renaming is
mechanical.
Connascence of Type — two components agree on the type of a value. A passes an integer; B expects an integer. Changing to a float breaks the contract.
Connascence of Meaning — two components agree on
what a value means. A passes status = 1 to mean “active”. B
treats status = 1 as “pending”. This coupling is invisible
to the type system and can be silent for months.
Connascence of Position — two components agree on
the order of values. process(user_id, account_id) vs
process(account_id, user_id) — positional connascence
produces silent bugs when arguments are transposed.
Connascence of Execution — two components agree on
the order of operations. initialize() must be called before
process(). Violating the order causes runtime failures, not
compile-time errors.
Connascence of Timing — two components depend on relative timing. Service A must write before Service B reads. This is the hardest to detect and the most expensive to violate.
The progression from weak to strong corresponds to increasing cost of change. Connascence of Name is tolerable and addressable with refactoring tools. Connascence of Timing is a distributed systems problem.