See all glossary terms

Coupling

We talk about coupling when two pieces of code depend on each other, and changing one piece will cause errors or bugs in the other. Coupling describes how dependent pieces of code are on one another.
Part of a developer's job is to keep coupling in check and avoid making too many parts of the program interdependent, as this makes the code difficult to change or add features to.
We generally talk about coupling when the connections happen between different objects or modules in the program. For example, if the user interface directly accesses data in the player character, we can say that the UI is tightly coupled to the player character because changing the player data may cause errors in the UI code.
Generally, you can think that whenever you call a function on another object or access its properties, you increase coupling with this object.

Loose coupling

Not all ways to interact with other code create the same level of coupling. We talk about loose coupling when two pieces of code use each other but indirectly. For example, you can use signals to communicate between two objects. This way, the two objects don't know about each other, and you can change one without affecting the other.
With signal connections, when one object gets freed from memory, the signal connection automatically disconnects, and nothing breaks.
Other ways to achieve loose coupling include all sorts of ways to create a nice API: public methods, abstract classes, using interfaces, and signals, as mentioned above. Using aggregation, a form of composition where objects can operate independently of each other is another way to achieve loose coupling promoted by Godot's node system.
Note that:
  • Loose coupling doesn't mean no coupling and doesn't guarantee bug-free code. It means that the interdependence between pieces of code is kept in check and that the two pieces of code can change independently of each other.
  • Tight coupling, the opposite of loose coupling, can be perfectly fine. For example, if a piece of user interface is always present and only exists to show data from the player character, like the player Heads-Up Display (HUD), it's okay to make it part of the player scene and update the HUD directly from the player script.
Reducing coupling can come at the cost of making the code more abstract and complex, so it's a trade-off you have to make depending on the context rather than a rule to follow systematically.
How do I know when to reduce coupling?
If not all coupling is problematic, how do you know when to reduce it? Here are a couple of guidelines to help you decide:
  • When you change a piece of code and something unexpected breaks changes in another part of the codebase, it's a smell. Distant parts of the code should keep working the same when you change something unrelated.
  • When you have to change the code in many places to introduce a change or new feature, you may have a coupling problem.
  • When one game entity only exists to serve another, it can be okay if they are tightly coupled. For example, if a mob has a unique laser attack that only it uses, it's fine to write the laser attack code in the mob script. You can always extract it if you need to reuse it elsewhere later.
In general, you can think of coupling as lines connecting different code parts. In an ideal codebase, you want the lines to form a mind map or branching structure where lines don't cross. If the connections look like a spider web... good luck!
In practice, the connections are always somewhere between a neat tree and a spider web. Especially in games, where entities want to know about each other to interact, you have to manage quite a bit of coupling.
Identifying when coupling is problematic is a skill that comes with experience. The more you work on complex projects, the more you'll get a feel for when it's inevitable, when