---
title: Connascence as a vocabulary to discuss Coupling
teaser: 'How Connascence can make discussions around Coupling easier and more productive.

  '
tags: coupling,connascence,ruby,refactor
author: Matheus Sales
published_on: 2022-06-20
---

As software engineers, we often discuss complex concepts that might lead to nebulous and endless discussions.
[Coupling] is one of these complex concepts that raise common questions. How harmful is coupling? 
How can we measure coupling? What are the different types of coupling?
[Connascence] introduces a shared vocabulary for determining different types and the severity of the coupling
in our systems, answering these questions, and making discussions around coupling
less nebulous and goal-oriented.

[Coupling]: https://thoughtbot.com/blog/types-of-coupling
[Connascence]: https://connascence.io/

## What is Connascence

Let's define the concept of Connascence:

> Two pieces of software share connascence when a change in one requires a corresponding change in the other.

Connascence allows us to go beyond the binary of "coupled" and "not coupled", serving
as a tool to measure coupling and describe how bad it is under different levels
and kinds.

## How we measure the Connascence

1. **Strength**: Stronger connascences are harder to discover, and/or harder to refactor.
2. **Degree**: Describes how many components are coupled. Components with a large number
   of connascent entities are a more significant issue than just a few connascent entities.
3. **Locality**: Describes how close the coupled components are. A high locality is
   better and means coupled components are in the same module.

`Connascence = Strength x Degree / Locality`

<aside class="info">
This article, will use an emoji scale from one to five 
to provide better visualization.<br>
Strength -> 💪 <br>
Degree -> 📈 <br>
Locality -> 📍
</aside>

## Types of Connascence

Connascence comes in many forms. Below are three of the most common that appear in
Rails applications and how to avoid them. They are listed from weakest connascence
to strongest, so it is worthwhile to refactor from one of the later forms on the list
to one of the earlier forms.

### Connascence of Name (CoN)

Connascence of name happens when multiple components must agree on the name of an entity.
Constants and object names are an example of this form of connascence: if the name of an
object changes, every reference to that object needs to change. It's
the weakest form of connascence and almost always unavoidable.

```ruby
class Order
  def Order.most_recent
    ...
  end
end

Strength -> 💪 (weakest form of connascence)
Degree -> 📈 (only one component)
Locality -> 📍📍📍📍📍 (inside same model)
```

This code has an explicit dependency between our `Order` class name 
and how we defined our `Order.most_recent` class method. Ruby provides 
a way to refactor this code and remove the CoN (Connascence of Name).

```ruby
class Order
  def self.most_recent
    ...
  end
end

Strength -> (zero connascence)
Degree -> 📈 (only one component)
Locality -> 📍📍📍📍📍 (inside same model)
```

Even though **CoN** is often harmless and expected to exist, it should
be eliminated when possible so this was a nice refactor.

### Connascence of Position (CoP)

Connascence of Position happens when multiple components must agree on the position/order of
their values. Let's see an example to explain this type of connascence better.

```ruby
class Order
  # Always add a new status to be the last element of the array
  enum status: [:pending, :published, :delivered]
end

Strength -> 💪💪 (stronger than connascence of name)
Degree -> 📈📈📈 (model and database are coupled)
Locality -> 📍📍📍 (models are distant from the database)
```

This example is one of the most common **CoP** in Rails codebases and it has a low Locality because it's
coupled to a distant database. Declarations like that often come with a comment, explaining that the position
of the [enum] items matter -- but fortunately, it has an easy fix: it is possible to use a hash instead of 
an array, which would explicitly map the enum values instead of relying on their implicit position within the array.
This refactoring changes from CoP to CoN, thus reducing the **Strength** of the connascence.

[enum]: https://apidock.com/rails/ActiveRecord/Enum

```ruby
class Order
  enum status: { pending: 0, published: 1, delivered: 2 }
end

Strength -> 💪 (connascence of name)
Degree -> 📈📈 (model and database are coupled)
Locality -> 📍📍📍 (models are distant from the database)
```

### Connascence of Meaning (CoM)

Connascence of Meaning happens when multiple components must agree on the meaning of particular
values. In its most basic form, it's all about [magic values].

[magic values]: https://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad

```ruby
class Order
  def deliver!
    if self.type == '001'
      ...
    else
      ...
    end
  end
end

Strength -> 💪💪💪 (connascence of meaning)
Degree -> 📈📈📈 (multiple models checking this condition or using this value)
Locality -> 📍📍 (multiple models, database)
```

The meaning of `type == '001'` is unclear, and such a conditional tends to be repeated
throughout our codebase, leading to increased **Locality**. If that value changes in one place,
it must also change in another.

**CoM** can be improved to **CoN** by moving magic values to named constants and creating convenient methods to be used
externally. However, in doing so, we have increased the amount of **CoN** but again lowered the Strength of connascence.

```ruby
class Order
  B2C_TYPE = '001'

  def b2c?
    type == B2C_TYPE
  end

  def deliver!
    if b2c?
      ...
    else
      ...
    end
  end
end

Strength -> 💪 (connascence of name)
Degree -> 📈 (single method to check)
Locality -> 📍📍📍📍
```

### In Summary

Connascence's arguably most important benefit is to give developers a common vocabulary to talk about different types of coupling
and DRY principles in a less abstract way, allowing software engineers to easily share experiences by referring to a standard set of nouns,
resulting in productive discussions on code reviews and pull requests.
