Connascence is a model that classifies dependencies between software elements more finely than simply calling them 'coupling'. What are its three axes, and how does it make the goal of low coupling actionable?
answer
- Con-nascent = must change together
- Axes: strength, degree, locality
- Static: name → type → meaning → position → algorithm
- Dynamic: execution order → timing → value → identity
- Strong is OK if local; distance demands weakness
basics
~20 sConnascence means two pieces of code must change together to stay correct. It grades each dependency by strength (how hard it is to spot and fix), degree (how many places are involved) and locality (how far apart they are). Reduce strength, degree, or distance.
solid answer
~50 sMeilir Page-Jones's connascence gives coupling three measurable axes. **Strength** — a ranked ladder from static/compiler-visible forms (name, type, meaning/convention, position/argument order, algorithm) to dynamic/runtime forms (execution order, timing, value, identity); higher forms are harder to detect and to change safely. **Degree** — how many elements share the connascence; ten call sites depending on argument order is worse than two. **Locality** — how far apart the connascent elements are; strong connascence *inside* one small class is fine, the same connascence across two services is dangerous. That last axis is the key insight and yields the working rules: **strong connascence is acceptable when it is local; the greater the distance, the weaker the connascence must be**, and you improve a design by lowering strength, reducing degree, or increasing locality. Compared to the classic coupling scale it names *why* something is coupled and gives a concrete refactoring target.
code
pseudocode · 11 lines// Connascence of Meaning (magic value), degree = every call site
if (user.status == 3) { ... }
// downgraded to Connascence of Name via a shared enum
if (user.status == Status.CANCELLED) { ... }
// Connascence of Position: caller must know argument order
createUser("Ada", "Lovelace", true, false)
// downgraded: named fields carry the meaning
createUser(firstName = "Ada", lastName = "Lovelace", isAdmin = true, isLocked = false)go deeper
Explain the core idea — two pieces of code that must be changed together — and give one concrete example, such as a magic number whose meaning is duplicated at many call sites.
Name the three axes, list several strength levels with a refactoring for each (magic value → enum, positional args → named parameters), and connect it to ordinary code smells.
Present the full static/dynamic ladder, state the locality rule precisely, and use the vocabulary to give concrete review feedback with a named downgrade target.
Use the locality axis to justify architectural boundaries — bounded contexts, versioned published contracts, team ownership — and argue that a boundary is only worth drawing where connascence across it is already weak.
## What connascence means Two software elements are **connascent** if a change to one requires a change to the other for the system to remain correct. Meilir Page-Jones coined the term (from Latin *con-* "together" + *nasci* "to be born") in the early 1990s to give the vague word "coupling" a measurable structure. It has been popularised again through the work of Jim Weirich and Kevin Rutherford. It is language-agnostic: the axes apply to functions, classes, modules, and services alike. ## Axis 1 — Strength (the ladder) Strength = how hard it is to *find* the connascent partners and *change* them safely. Static forms are detectable by reading code or by a compiler; dynamic forms only manifest at runtime. **Static (weaker → stronger):** 1. **Connascence of Name (CoN)** — both must agree on a name (calling a method by its name). Weakest and unavoidable; renaming tools handle it. 2. **Connascence of Type (CoT)** — both must agree on a type. 3. **Connascence of Meaning / Convention (CoM)** — both must agree on the *interpretation* of a value: `status = 3` meaning "cancelled", `-1` meaning "not found", an empty string meaning "absent". Cure: named constants or enums, which downgrades it to Connascence of Name. 4. **Connascence of Position (CoP)** — both must agree on *order*: positional arguments, tuple element order, CSV column order. Cure: named parameters, or a value object with named fields. 5. **Connascence of Algorithm (CoA)** — both must implement the *same algorithm*: two ends independently hashing a password, computing a checksum, or formatting a date. Cure: extract the algorithm to one shared place. **Dynamic (weaker → stronger), only visible at runtime:** 6. **Connascence of Execution Order (CoE)** — B must be called after A (`open()` before `write()`). Cure: make the API impossible to misuse — combined operations, builders, or types that only exist once the precondition holds. 7. **Connascence of Timing (CoTiming)** — correctness depends on *when* or how fast something happens (races, timeouts, sleeps in tests). 8. **Connascence of Value (CoV)** — several values must change together to stay consistent (a total field and its line items; a start date that must precede an end date spread across objects). Cure: put the invariant inside one object that enforces it — this is exactly what a domain-driven-design aggregate is for. 9. **Connascence of Identity (CoI)** — two elements must reference the *same instance* (a shared mutable buffer, a specific singleton). Strongest and hardest to reason about. (Some presentations also list *Contranascence*: two elements must differ — e.g. names that must not collide across modules.) ## Axis 2 — Degree How many elements participate. A convention shared by 3 call sites is a cheap fix; the same convention baked into 300 call sites is a project. Degree is what turns a mild smell into a migration. ## Axis 3 — Locality How close the connascent elements sit: same function → same class → same module → same codebase → across a network/service/team/organisation boundary. **This axis is the reason connascence is more useful than a flat coupling scale.** Strong connascence *inside* a small, private scope is perfectly acceptable — two lines of one method sharing execution order are trivially changeable together. The *same* connascence between two services owned by two teams is a coordination nightmare, because you cannot change both atomically. ## The three working rules 1. **Rule of Degree** — convert strong forms into weaker forms. 2. **Rule of Locality** — as distance between elements increases, the acceptable strength of connascence decreases. Conversely, strong connascence is fine when local. 3. **Minimise overall connascence** by making the parts more encapsulated: pull connascent things *closer together* (increase locality) or eliminate them. So there are three legitimate moves for any bad dependency, not one: **weaken** it, **shrink its degree**, or **move the participants closer together**. That third move is regularly overlooked — sometimes the right answer to "these two things always change together" is not an abstraction but *merging them into one module*. ## Why this improves on the classic ladder The classic Constantine scale (content/common/control/stamp/data) classifies a *call's* shape. Connascence classifies *any* required-co-change relationship, including duplicated algorithms and ordering rules that involve no call at all, and it explicitly prices distance. In practice it gives review comments a precise vocabulary: instead of "this feels coupled", you say *"this is connascence of meaning at degree 12 across a module boundary — replace the magic number with a shared enum, which downgrades it to connascence of name."* ## Relation to GRASP Low Coupling GRASP's Low Coupling says "prefer the assignment with fewer/weaker dependencies" but leaves "weaker" undefined. Connascence supplies the definition and, crucially, the locality axis that explains why coupling budgets differ inside a class versus across a service boundary — which is precisely the reasoning behind bounded contexts, published-language contracts, and versioned APIs. ## Caveats - The full nine-level taxonomy is more detail than many teams will adopt; the durable takeaways are the three axes and the locality rule. - Not all connascence should be removed — connascence of name is unavoidable and harmless. - Watch for the trap of "decoupling" by adding distance: splitting connascent code across a network boundary keeps the connascence and makes it far more expensive.
- Two classes in the same file share strong connascence of execution order. Is that necessarily a defect worth fixing?Not necessarily. Locality is an axis of the model: strong connascence in a small, local, single-owner scope is cheap because both sides change together in one atomic edit. The rule is that acceptable strength falls as distance rises — so the same ordering requirement spanning two services would demand attention.
- How does connascence explain why domain-driven-design aggregates exist?An aggregate encapsulates fields whose values must change together — connascence of value. By placing that invariant inside one object with one entry point, you raise locality to its maximum and let the object enforce the rule, rather than scattering value connascence across several classes that could drift apart.
- Besides weakening a dependency, what other move does connascence legitimise?Increasing locality — moving the connascent elements closer together, up to merging them into one module. If two things always change together, co-locating them can be strictly better than inserting an abstraction between them, which would preserve the co-change while adding indirection.
Two dancers performing a lift are strongly connascent — timing and position must match exactly. That is fine when they are in the same studio rehearsing daily (high locality). Ask them to perform the same lift from separate buildings and the strength that was harmless becomes impossible. Distance is what turns acceptable coupling into a coordination failure.
saying these in an interview costs you the question
- Thinking all connascence must be eliminated — connascence of name is unavoidable and harmless.
- Ignoring the locality axis and flagging strong-but-local connascence as a defect.
- "Decoupling" by pushing connascent code across a network or team boundary, which keeps the co-change requirement and makes it far more expensive to satisfy.
- Confusing degree (how many participants) with strength (how hard to detect and change).
- Treating connascence as a replacement for cohesion reasoning rather than a sharper lens on coupling.