ModuleScripts Discussion

According to ROBLOX developer wiki, you can write all of your functions in one script and use it everywhere.

“ModuleScripts are essential objects for adhering to the don’t-repeat-yourself (DRY) principle. When you write a function, write it only once and use it everywhere.”

This begs the question, why do we need regular scripts then?

I understand that ModuleScripts require a normal script to run them, but then why aren’t all scripts able to share code?

Because ModuleScripts are meant to represent Lua modules. Modules can be required using the typical require. Read more on that here:

Regular scripts are usually functioning like a bootstrapper, while the modules are the libraries that are being used. To avoid ‘reinventing the wheel’, you simply use the modules necessary for a certain functionality, that you don’t want to rewrite every single time.

Because each script is running their own ‘code environment’, they cannot share variables across unless they used the true global scope of _G(which I don’t really use).

Some common repetitive practice that is avoided is the ‘one script per model’ concept. You have a model that works in a certain way, which includes a script inside. However, you want to change or update the code and that would be tedious. That is why modules should be considered. Alternatively, a different paradigm should be considered which works equally well.

1 Like

I rarely use ModuleScripts is that bad? I also seen someone script with about >90% of scripts were ModuleScripts, but the game worked greatly.

I need to understand the functionality and practical uses of them in order for me to learn…

1 Like

Lack of module scripts only means difficulty in organization, especially when it comes to debugging. Also if you used multiple regular scripts, race conditions may occur, meaning one script may be ahead of the other.

2 Likes

I am still greatly confused how this person made a working game with mostly ModuleScripts.

Is it perfectly fine to only use ModuleScripts when you have code you don’t want to rewrite?

You still need a bootstrapper to execute those ModuleScripts. It is advisable to treat modules as libraries for specific functionalities. That said, it is perfectly fine but you need to convert some part of the original code to work with that.

Also some of my previous frameworks utilized the concept of ‘one script’ only, backed by multiple modules.

1 Like

Here’s an example of how I use ModuleScripts.

In all my scripts, I tween values. If I wanted a part’s transparency to gradually decrease, instead of making a tween function, I have a ModuleScript that has this function:

function module.tweenValue(value1, value2, changeTime)
    local tweenService = game:GetService("TweenService")
    local tweenInfo = TweenInfo.new(changeTime)
    local tween = tweenService:Create(value1, tweenInfo, value2)
    tween:Play()
end

Here are some examples of what I use it for:
https://gyazo.com/f05d43ac20a222724f5f72c40ba4abde Gradually tweening the transparency of these models
https://gyazo.com/e5c2520f3b1d493570e319757cec3423 Gradually tweening the blur and colorcorrection for this UI, as well as tweening the transparency for the UI elements.

This specific ModuleScript function is super useful because I don’t have to rewrite the function whenever I use it, and can be used in multiple scripts! It’s not necessarily bad if you don’t use Modules but it helps to keep your code organized without violating the DRY (Do not Repeat Yourself) principle.

If you don’t use ModuleScripts I would highly recommend it as it saves you on time and effort!

2 Likes

I can provide an example of a previous module that I have been working on, its version is currently 2.22.1, and still needs some extra work put into it. This time, it’s metatable-based.

-- Functions
function Clock.new(length, clockMethod, clockDisplayType, clockDisplayTypeProperties)
	return setmetatable({
		Completed = true;

		CurrentTime = 0;
		StartTime = 0;
		Length = type(length) == "number" and length or 10;

		ClockMethod = findClockMethod(clockMethod);
		ClockDisplayType = findDisplayType(clockDisplayType);
		ClockDisplayTypeProperties = getDigitalSettings(clockDisplayTypeProperties);
	}, {__index = Clock})
end

function Clock:Read()
	return rawget(self, "Completed")
end

function Clock:GetCurrentTime(displayType, overrideProperties)
	return getDisplayFromDisplayType(
		rawget(self, "CurrentTime"), 
		displayType or rawget(self, "ClockDisplayType"), 
		overrideProperties or rawget(self, "ClockDisplayTypeProperties")
	)
end

Note: Clock is a table that is returned in the end of the code, I cut this snippet to demonstrate that modules can house objects.

1 Like

ModuleScripts are important in a game loop action, when using a server script with requiring a module script, the module will have like functions to help you the game loop so for better readability.

1 Like

Module scripts are important so other scripts can require it easily, and if you’re just making big functions in a server script, other scripts can’t get the functions, besides copy and pasting to make your code unprofessional.

1 Like

A more simple example in my opinion would be, let’s say a permissions module responsible for returning whether or not the player you pass is above a specific rank in the group. We’re also going to assume that that the required rank is predefined in your module.

You might be asking, why can’t you just check their rank in the script instead of going through all this module nonsense? Well, let’s say you want to change the required rank in the future. You don’t want to have to go through every single script that checks a player’s rank, and instead you can just change it in your module.

1 Like