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.
The reason for using signal modules is that they promote loose coupling and, in turn, good design.
Here’s an example of code that uses signals versus code that doesn’t:
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.
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.