What is code coupling?
Code coupling refers to how intertwined your code is. In other words, how strong the connections between different modules are.
Typically, loose coupling (weaker connections between modules) is considered good design. However, strong coupling is considered bad design.
Why use signals?
The reason for using signal modules is that they promote loose coupling and, in turn, good design.
Example
Here’s an example of code that doesn’t use signals versus code that does:
Without Signals
PlayerDataHandler.lua
local PlayerDataHandler = {
Coins = 100
}
function PlayerDataHandler:SetCoins(NewValue)
self.Coins = NewValue
CoinGui.Coins.Text = NewValue
Character.Overhead.Coins.Text = NewValue
end
...
This example allows us to set our coins to whatever we want. However, because we’re not using signals, we’re forced to add unrelated code into the PlayerDataHandler module that is purely meant for storing player data.
On the topic of coupling, this would be referred to as a strong connection between the PlayerDataHandler and the Overhead system. This isn’t ideal as, if you wanted to use your PlayerDataHandler system in another game, you would have to manually go in and edit it for each game.
Say later down the line we have another chunk of code that needs to know when coins change. Because we’re not using signals, we’ll either need to setup a loop to detect when coins change, or we’ll have to add more unrelated code into the PlayerDataHandler module.
With Signals
PlayerDataHandler.lua
local PlayerDataHandler = {
Coins = 100,
CoinsChanged = Signal.new()
}
function PlayerDataHandler:SetCoins(NewValue)
self.Coins = NewValue
self.CoinsChanged:Fire(NewValue)
end
HudHandler.lua
local function UpdateCoinsLabel(NewValue)
CoinGui.Coins.Text = NewValue
end
PlayerDataHandler.CoinsChanged:Connect(UpdateCoinsLabel)
...
OverheadHandler.lua
local function UpdateOverheadCoinCount(NewValue)
Character.Overhead.Coins.Text = NewValue
end
PlayerDataHandler.CoinsChanged:Connect(UpdateOverheadCoinCount)
...
This would then allow you to copy your PlayerDataHandler module into another project if needed, without needing to modify it.