The Architecture Reference

Fnd components · Foundations · Intermediate

Connascence

A precise vocabulary for HOW two components are coupled — static vs dynamic connascence — and the three properties that guide refactoring toward weaker forms.

Fnd components Intermediate ⏱ 4 min read Complete

🧬 Analogy

Connascence — literally ‘having been born together’ — is like the shared dependencies in a recipe. If two cooks merely agree on the name of an ingredient, either can swap brands freely. If they must agree on the exact order steps happen, or the precise timing, changing one forces the other to change too. The tighter the agreement, the harder either can move alone.

What connascence adds to coupling

Plain afferent/efferent coupling tells you that two components depend on each other; connascence (Meilir Page-Jones) tells you how. The definition: two components are connascent if a change in one would require the other to be modified to maintain overall correctness. It splits into two families.

graph TD
C["Connascence"] --> S["Static<br/>(source-level, analysable)"]
C --> D["Dynamic<br/>(runtime, harder to detect)"]
S --> SN["Name (weakest)"]
S --> ST["Type"]
S --> SM["Meaning / Convention"]
S --> SP["Position"]
S --> SA["Algorithm (strongest static)"]
D --> DE["Execution (order)"]
D --> DT["Timing"]
D --> DV["Value"]
D --> DI["Identity"]

Static connascence (weakest to strongest)

Discoverable by static analysis, ordered from easiest to hardest to refactor:

  • Name (CoN) — agree on a name (most desirable; renames are easy).
  • Type (CoT) — agree on a type.
  • Meaning / Convention (CoM) — agree on a value’s meaning (magic numbers).
  • Position (CoP) — agree on order (parameter order).
  • Algorithm (CoA) — agree on an algorithm (a client and server computing the same hash).

Dynamic connascence (runtime)

Harder to detect because it only appears when the system runs:

  • Execution (CoE) — order matters (set fields before sending).
  • Timing (CoT) — timing matters (race conditions).
  • Value (CoV) — related values must change together (a value spread across databases; distributed transactions).
  • Identity (CoI) — must reference the same entity (a shared distributed queue).

The three properties that guide refactoring

Connascence is judged on three axes:

  • Strength — how easy it is to refactor. Prefer static over dynamic, and refactor toward weaker forms.
  • Locality — how close the connascent code is. Proximal code tolerates stronger connascence; distant code should be weakly coupled.
  • Degree — the size of the impact (a few modules vs many).

Weirich’s rules crystallise this: the Rule of Degree — convert strong connascence to weaker forms; the Rule of Locality — as distance increases, use weaker connascence. Page-Jones’s guidelines: minimise overall connascence by encapsulating, minimise connascence that crosses encapsulation boundaries, and maximise connascence within a boundary.

graph LR
S["Strong & distant<br/>(Algorithm across services)"] -->|"Rule of Degree:<br/>weaken the form"| W["Weaker form<br/>(toward Name)"]
S -->|"Rule of Locality:<br/>pull it closer"| L["Same module<br/>(local & encapsulated)"]
W --> G["Weak & local = safe"]
L --> G

⚠️ The 1990s blind spot

Classic connascence is low-level code hygiene and originally said nothing about the modern key decision: synchronous vs asynchronous communication in distributed systems. The Hard Parts and Building Evolutionary Architectures extend it with communication connascence (sync = stronger, async = weaker), which feeds directly into the architecture quantum.

Connascence and bounded contexts

Building Evolutionary Architectures notes that connascence locality (1993) and DDD’s bounded context (2003) express the same anti-brittleness principle: never expose implementation details — especially database schemas — across a boundary.

💡 Key insight

When you must couple two things, ask: can I make this Name connascence instead of Position or Algorithm, and can I keep it local? Weak-and-local beats strong-and-distant every time.

See also

When to use it — and when not

✅ Reach for it when

  • When you need to reason precisely about why a change in one place forces a change elsewhere
  • When refactoring to weaken coupling between modules or services
  • When deciding what may safely cross an encapsulation boundary

⛔ Think twice when

  • When the coupling is trivial and a simple afferent/efferent count suffices
  • When you treat connascence as only a code-hygiene concern and ignore communication coupling

Check your understanding

Score: 0 / 4

1. What is the definition of connascence?

Page-Jones: connascence describes when changing one component forces a change in another to preserve overall correctness.

2. Which is the most desirable (weakest) form of static connascence?

Name is the weakest and easiest to refactor; refactor strong forms toward Name where possible.

3. Dynamic connascence differs from static connascence because it…

Static connascence is discoverable by static analysis; dynamic forms (execution order, timing, values, identity) appear only at runtime.

4. What do Weirich's Rule of Degree and Rule of Locality advise?

Rule of Degree: convert strong to weak. Rule of Locality: the farther apart, the weaker the connascence should be.

Comments

Sign in with GitHub to join the discussion.