Recently, I’ve taken to utilizing 1 function as a global so I can use it without having to paste it around or require a module for it. I found this to be extremely helpful but I have always known to not use globals & instead utilize module scripts, which I agree. When I decided to use my global, I was a bit nervous since this stigma is so large in the Roblox community. Do you use globals? If so, how do you utilize them? If you have in the past but no longer use them, why did you move away from them?
I don’t, and the reason is just readability of knowing where things are defined and preventing any race conditions between its definition and its use.
If it’s just you on your own and you’re happy it isn’t racing then fair enough.
Personally, I use a microservice architecture with an integrated module loader. This allows me to call modules like this:
local SomeModule = self:GetModule("ModuleName")
local RunningService = self:GetService("SomeRunningGameService")
The framework loads modules (which can later be accessed anywhere by
Framework:GetModule() ) and exposes them through the global
GetModule() method. This makes it easy for any game system to make use of a module without having to worry about:
- The physical path/location of the module in the game’s datamodel
- Whether or not the module has been initialized or replicated to the client yet
- What dependencies said module might have, since its dependencies are automatically resolved by the framework
A given microservice usually controls 1 game system, and does not worry about other game systems - it only worries about interacting with the interfaces of other game systems or modules. A microservice’s methods are exposed globally via the framework, and can be accessed via
GetService() - similiar to how modules are exposed to the global environment.
My modules (be it a regular util module, class module, or a microservice module) follow the SOC (seperation of concerns) principles - a module should do one thing, and do it well (see also : the unix philosophy). This makes for an extremely robust and modular software project - I can quite literally gut & replace any given game system, and nothing else cares as long as the interfaces remain the same. It’s easy to extend, change, and maintain game-specific code without needing to reason about everything at once.
TL;DR : I have global methods for accessing modules & game systems.
If you’re curious, you can check out my framework at https://github.com/NobleDraconian/Dragon-Engine.
I use a bunch of microservice (server) and controller (client) modules to organize my codebase, but I still get tired of typing
local Load = require(game:GetService("ReplicatedStorage"):WaitForChild("EnCore")).load
every time I create a new module and need to require library modules. I have _G.Load defined in my server and client bootstrapper scripts as well as _G.Server and _G.Client for the server and client tables respectively. This way I can access any of my services/controllers from any module easily. I just create a local reference to each global variable at the top of my modules so that I don’t have to type _G every time.
I do not!
- Hurts readability
- Cannot compose or reuse modules
- Creates race conditions