Originating from the Latin word ‘connascere’, meaning ‘born together’, connascence is a term used in software development to describe the interdependence of software components — a property often referred to as ‘coupling’. It is a measure of how much two or more software components are dependent on each other, with respect to a particular reason for change. Excessive connascence in our software means that the system is hard to change and hard to maintain.
Two elements are connascent if a change to one element would also force a change to the other in order for the program to be correct.
One of the most important benefits of connascence is that it gives developers a vocabulary to talk about different types of coupling. Connascence codifies what many experienced engineers have learned by trial and error: Having a common set of nouns to refer to different types of coupling allows us to share that experience more easily.
Reasoning about the amount of interdependence between software components is tricky, as it is not a binary property. Components can be interdependent in various ways, and to various degrees. To make reasoning about coupling of components more manageable, the connascence metric has been broken down into several different facets. Software components can be evaluated for their connascence based on the following criteria:
There are many different types of connascence, each with its own particularities. Broadly speaking, we can distinguish between two categories of connascence: Static and Dynamic connascence. The distinction between these two categories is based on the time at which the connascence is established. Static connascence is established at compile time, while dynamic connascence is established at runtime. While both types of connascence can be problematic, certain forms of static connascence are considered more problematic because they introduce tighter coupling at compile time, reducing flexibility.
warning: The different types of connascence are not mutually exclusive, i.e. a single piece of code can exhibit multiple types of connascence at the same time. Reading through these different types of connascence, you might find them overly detailed or even redundant. The main goal is to offer an overview and general understanding of the different ways elements in a system can become interdependent.
Static connascence is established at compile time, meaning that the dependencies between components are determined before the program is run. This type of connascence is often associated with strong coupling, as it can lead to a more rigid and inflexible system. Static connascence can be further divided into several subtypes:
user_role
with value admin
is used to indicate administrative privileges, the code that checks for this value must change if the meaning of the admin
value changes. Other examples include the use of specific identifiers to denote test versions, the meaning of column names in a database, or the meaning of currency codes in a financial system.Dynamic connascence is established at runtime, meaning that the dependencies between components are determined while the program is running. This type of connascence is often associated with weak coupling, as it can lead to a more flexible and adaptable system. Dynamic connascence can be further divided into several subtypes:
WARN
in a hardcoded, implicit way.These dynamic types of connascence are typically challenging to detect and manage, as they do not show themselves until the system is running. They can be mitigated through careful design and testing practices. Using shared interfaces, common libraries, and well-defined APIs can help make these dependencies more explicit — and therefore easier to manage.
The term connascence comes from the Latin connascentia, derived from con- (“together”) and nasci (“to be born”), meaning “born together” or “originating together.” In general English usage, the word is rare and mostly used in literary or biological contexts to describe things that grow or emerge together from a common origin.
In software design, the term was popularised by Meilir Page-Jones in the early 1990s as a way to describe the interdependence between software components. Unlike the broader and sometimes ambiguous term coupling, connascence breaks down these relationships into concrete types and levels, giving developers a more precise vocabulary for reasoning about change impact and design quality. The concept provides a structured way to discuss not only whether components are coupled, but also how, how strongly, and how many components are involved.
Connascence helps experienced developers and technical leads reason more effectively about design quality and system maintenance. It is particularly useful when:
tip: Use connascence to explain why a refactor or rewrite is needed, not just that it is required. For example, instead of saying “we need to decouple this module”, you can say “this module has high connascence of name and type with several other modules, which makes it hard to change without breaking things. We should refactor it to reduce that coupling.”
At first glance, connascence and orthogonality may appear similar—they both deal with how parts of a system relate to each other, but they differ in focus, granularity, and intent. The table below summarizes the key differences:
Aspect | Orthogonality | Connascence |
---|---|---|
Focus | Design independence—how isolated responsibilities are. | Degree and nature of coupling—how changes in one part affect another. |
Perspective | Encourages separation of concerns and minimal overlap. | Classifies the strength and type of dependencies. |
Granularity | Typically applied at the module or system design level. | Often applied at the code level: functions, arguments, naming. |
Intent | Promote composability, clarity, and modifiability. | Evaluate and reduce harmful coupling to improve maintainability. |
In simple terms:
While both concepts aim to reduce unnecessary entanglement, orthogonality is a design principle, whereas connascence is a diagnostic lens. Orthogonality helps you prevent entanglement, connascence helps you detect and classify it.
tip: Connascence is not a silver bullet. It is a tool for reasoning about design quality, but it does not replace the need for good design principles, testing practices, and team communication. Use it as part of a broader toolkit for building maintainable systems.
A team deploys a new version of a microservice that exposes an internal API to several downstream services. The deployment passes CI/CD checks, and all services start up correctly in staging and production — everything seems fine. However, within minutes, logs begin to show erratic failures in related services.
The problem? The development team made what seemed like a harmless change: they reordered the parameters of a JSON payload in a request object (static connascence of position), renamed a status field (connascence of name), and refined a timeout behaviour that slightly delays a response under certain conditions (dynamic connascence of timing).
Although the schema wasn’t formally versioned, other services were implicitly relying on field names, order, and response timing. These dependencies weren’t enforced by any compiler or test suite — they only showed up when the system was live. The result was a cascade of subtle failures, including retries, dropped messages, and incorrect status reporting. Fixing the issue required careful rollback and a clearer contract definition between services.
An engineering team updates a backend service that reads from a shared customer database. As part of a schema cleanup, they remove a legacy status_code
field that was deemed unused, and refactor the created_at
field from a string
to a proper timestamp
format in the database.
The application’s unit tests pass, and the deployment succeeds — but hours later, support tickets start rolling in. A different internal tool, maintained by another team, had been silently depending on the status_code
field to filter active accounts. Worse, a nightly reporting job fails because it attempts to parse the created_at
field as a string, causing the entire pipeline to break.
In this case, the system exhibited:
status_code
meant.string
where a timestamp
was now stored.status_code
values (e.g. “active”, “pending”) were hardcoded elsewhere.These kinds of issues are difficult to detect ahead of time because the coupling is not visible at the API level. It hides in the database schema and in informal agreements between teams. The lack of an explicit contract or shared data ownership policy made it easy for one change to have far-reaching, unintended effects.