This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.
The following blog post, unless otherwise noted, was written by a member of Gamasutras community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.
Here’s one simple but (sadly) often ignored principle in software development: SRP.
That reads: Single Responsibility Principle.
And that means: every class, every function should have one and only one responsibility.
Some examples:
Class PlayerProfile. This class should only contain data related to the player (level, name) and functions directly related to reading/writing them.
The PlayerProfile class should NOT show level-up popups nor grant xp-related achievements.
Function int CalculateGainedExperience(int level). This function should just calculate how much experience you gain when you beat a level.
It should NOT grant xp to the player, nor write any data in the player profile. In fact, it should have no side effects. Ninguno.
This is a common mistake that violates SRP:
class Player
{
void LevelUp()
{
Backend.Instance.SendLevelUp();
}
}
You see that Backend.Instance access?
This access violates the Single-Responsibility Principle.
The LevelUp function should just do a level up. It is not part of its job description to find a reference to a backend system (in this case, the singleton).
So this function should just invoke the SendLevelUp function through a backend reference that someone passed it.
This is why breaking SRP in this manner is a problem:
The next time you change your specific backend implementation, gl hf changing all references.
Creating unit tests that mock the backend is hard, as you can’t easily change the references
Getting references makes your code messier and harder to read for everyone
More typical examples of SRP violation:
FindObjectOfType<Backend>()
GetComponent<Backend>()
I can sum it up this way: finding a reference to an object is not your class/function’s problem.
So, whose problem is it then?
Finding object references is the Dependency Injector’s problem.
What is Dependency Injection (DI)?
To keep it short, a DI system does two things:
Keep track of your main project objects, e.g. Backend, VO, Localization, Logger
Assign/Inject references into your objects as they require
Think of a DI system as the table of contents of a book. A ToC with a list of chapters ( Backend) and their page/location (0x123123).