Following the widespread adoption of the object-oriented programming paradigm in the 1990s, Meilir Page-Jones introduced the Connascence model to extend the analysis of coupling and interdependencies to object-oriented design. The word connascence comes from Latin and means “having been born together.” Two components are said to be born together if a change in one necessitates a corresponding change in another, or if a reasonable change can be postulated that would affect both components.
Compared to module coupling, connascence enables a more detailed discussion of design choices. It defines nearly twice as many levels, each describing a more nuanced kind of relationship. The levels of the model are categorized into two types: static and dynamic. Static connascence describes compile-time relationships, while dynamic connascence focuses on runtime dependencies.
Static Connascence
Compile-time relationships described by static connascence can be identified by examining the source code and reflect the information required for components to communicate.
Connascence of Name
Connascence of name is the lowest level of connascence. It implies that connected components must agree on a name, such as the name of a variable or a method.
Connascence of Type
More often than not, agreeing on a name is not enough; components must also be aware of the type—whether it’s a class, primitive, method signature, or another construct. This dependency makes the components connascent by type.
Connascence of Meaning
Connascence of meaning occurs when special meaning is assigned to values passed between components. For example, consider statusId = 7
—what does the number 7 represent? The knowledge of its meaning must be shared across integrated components.
Connascence of Algorithm
Connascence of algorithm describes a situation in which integrated components must agree on an algorithm for proper communication. For example, two components exchanging encrypted data must agree on the encryption algorithm. If different encryption algorithms are used, communication becomes impossible.
Connascence of Position
With connascence of position, a meaning is attributed to values based on their position. For example, consider the method: SendEmail(string[] values)
. This method sends an email and expects the sender and recipient addresses, subject, and body as an array of strings. The meaning of each value is determined by its position in the array.
This integration method is implicit and prone to errors that may go unnoticed by the compiler. That’s why connascence of position is considered the strongest form of static connascence.
Dynamic Connascence
The levels of dynamic connascence describe runtime dependencies between components, often representing functional rules and invariants that must be maintained to ensure system correctness. As a result, even the lowest level of dynamic connascence signifies a stronger interdependence than the highest level of static connascence.
Connascence of Execution
The lowest level of dynamic connascence is connascence of execution. It describes situations where operations must occur in a specific order. For example, a database transaction must be committed or rolled back only after it has been opened.
Connascence of Timing
Connascence of timing extends the previous level by introducing an explicit time constraint between executions. For instance, after opening a database connection, if no operations are executed for 60 seconds, the connection times out. The fixed time span (60 seconds) makes the open and timeout actions connascent by timing.
Connascence of Value
Connascence of value describes a transactional relationship between multiple values, meaning they must change together to maintain system integrity. For example, if edgeA, edgeB, and edgeC represent the edges of a triangle, all three values must be updated simultaneously to preserve mathematical correctness. Changing just one will result in an invalid triangle.
Connascence of Identity
The highest level of dynamic connascence (and connascence overall) is connascence of identity. It describes scenarios where two components must reference the same instance of a third component to function correctly. Examples include reading/writing to shared memory, relying on a common database, or sharing a unit of work.
Connascence vs. Module Coupling
Connascence and module coupling describe different levels of detail, each with blind spots that the other model addresses. It is natural to attempt to draw parallels between them. For example, common coupling and external coupling can be seen as special cases of connascence of identity.
However, the two models reflect different aspects of cross-component relationships and cannot be merged into a single scale. This distinction is best illustrated by the use of reflection to update the value of a private variable. Since the variable is private and not intended for integration, this is the highest level of module coupling: content coupling. However, the use of reflection requires the knowledge of the variable’s name and type, corresponding to the lowest levels of connascence: connascence of name and type.
Connascence and Integration Strength
The integration strength model doesn’t favor one approach over another but combines them into a single framework that provides a coherent picture of how knowledge is shared across component boundaries. The model adapts the levels of module coupling to describe the four types of knowledge that can be shared for integration. It then applies the levels of static and dynamic connascence to describe the degrees of functional, model, and contract coupling.
Additionally, the integration strength model addresses blind spots present in both module coupling and connascence: duplicated functionalities implemented in multiple components.