Scripting with Module Scripts OR one big script

So many of my games have been scripted in one script, which has made it easier to reference many modules within the same script. It also allows me to not redefine services over and over again in each different module script. There are many downsides to it, but I would like to hear the input from other coders.

How do you guys organize your scripts? How do your module scripts interface with each other? Any feedback would be very helpful.

16 Likes

Scripting with one big script is, in my opinion, the worst thing anyone could do when programming. Nobody does it in the real world for large projects, why should you do it with Roblox projects? Your code becomes a cluttered mess of trying to use comments to organize sections of code instead of just splitting them up. Employ the Unix philosophy; your scripts should do one thing and do it well. This, in turn, means I never have scripts with over 300-400 lines, and at that point it’s a red flag.

I have plenty of short scripts, some 10-20 lines long, to follow this philosophy and I’m a strong believer that everyone else should too. If that script breaks, it’s no big deal. If a “main” script breaks, it can be very dangerous.

You don’t even have to have everything be a ModuleScript to implement this, I have more Scripts and LocalScripts than I do ModuleScripts.

28 Likes

Some people think it’s cool or impressive to have big scripts that do everything. Then they have to maintain and debug them. Organize your code and don’t try to centralize everything into one big script. It’ll do you more harm than good.

7 Likes

I agree with a lot of what @Kampfkarren said, except I disagree with the last part.

I am of the seemingly common philosophy of keeping Script and LocalScript instances to a minimum.

I think that every script should do one job, and do it very well. I believe each one should act as just an API, essentially, very similarly to Roblox objects. I do use an OOP system, but I do not think OOP is the only way to do things.

Here are some examples of ModuleScripts I have:

  • SharedConstants is a common module script I have that is literally just a table of constant values that I share across the server and client. It is not OOP, per se, as it is just a regular table.
  • CurrencyService is a service (modeled after Roblox services like HttpService or MarketplaceService) that I have on the server-side that manages player’s currency. It’s job is to simply save currency, load currency, allow currency to be added, and to allow currency to be deducted. For deductions, it can return false if it would result in a negative value.

Those are just a couple examples.

I think the biggest pro to this is that I don’t have to scroll for ages and all of my variable names can be well understood in their given context. It also helps me to organize my code such that separate entities stay separate, making future updates much easier.

Using one (or just a couple) script seems like a horrible decision to me. You’re now packing thousands of lines of code into one place, meaning that you’re likely to have a large number of scoping issues with variable names. It will also likely make Studio take longer to open the script, parse it, and do its syntax highlighting (I’m not sure how large a script must be for this to be a meaningful difference). But, worst of all, it just feels horribly unorganized.

12 Likes

I agree with both @Kampfkarren and @ProbableAI

While organising the hell out of something is always a good idea, Roblox is not designed like other languages which benefit from having millions of separate classes (e.g. Java?).

The Roblox engine encourages you to put a number of functionalities into one script.

Luckily, to deal with this, there are ways you can organise your code within your scripts, though.
Recently I’ve started using do blocks:

local NameGetter = {} do
    -- pointless method really but /shrug
    function NameGetter:GetName(Object)
        return Object.Name
    end
end

do -- not really useful for such small code but you'll appreciate it in bigger scripts
 print(NameGetter:GetName(SomeRandomObject))
end

You can extend this to literally everything in your script. Think of it like making psuedo-classes (Lua doesn’t have proper classes) for everything.
Even things that aren’t classes can be put into a do block to organise your code.

Additionally it encourages good use of scope-relevant variables (hopefully lowering the memory your script uses and making your code generally better).

I highly recommend you read the book ‘Clean Code’. It has a lot of the stuff I’ve said in here, and more.

10 Likes

I personally have One Big Script in ServerScriptService, One LocalScript on the Client running Guis and other Client Stuff & 1 Module in Replicated Storage + 1 inside the ServerScript; I even have 1 RemoteEvent & RemoteFunction for the Entire game!

So a total of 4.


I agree with @Kampfkarren @EmeraldSlash & @ProbableAI ,but hear me out.

I started scripting since last year so I have been scripting for about a Year and 2 months.

When I first started I had 1 Script for everything and it has annoying actually:

I had like 1 Script for everything that needed a Script like a GuiButton and it has annoying to me because I thought to myself “Why do I need to Write Code for all of these there should be a way to do less” & so I found

For i , v in pairs() do end

Which I use all the time because it’s not okay for me to Write more Code and I have to

Which lead to using Tables and OPP


Advantages of using fewer Scripts for everything are:

You can use the same Vars, same Tables (Yeah I know you can use BindableObjs or _G)

If something breaks you know which Script is broken because there is Only a few

When you need to copy or move the game to another place you don’t need to copy everything just a few scripts that you have.

Handling Remote Objs & Marketplace Service is easier if you have 1 Script everything you need is in one place.

An Exploiter might try to Destroy() one of your scripts to take Advantage of the game but if you have only 1 Script running everything on the Client they won’t be able to do much.


Disadvantages

If you aren’t careful you might run into a problem with having to many “Local” Variables

I think the limit is 250 or 200 can’t remember but you can Write Code in a way that having 1000 or more “Local” Variables wouldn’t matter.

When 1 line of Code Errors, if it’s not an Event or Function it could stop the whole Script which is not what Anybody wants but that’s why we Debug our Scripts and make sure that they are working perfectly.


There are exceptions tho, if the script is doing a Heavy Task then you should Create a Separate Script.

If you have a Toy Store with one Employee you pay less than having many Employees; the decision you have to make is “Is one Employee enough to run your store?” If it’s too much work load then Hire a second Employee, or more.

As you can see more Employees means you need to manage more people and pay more.
If only 1 Employee can run the Business then you only need 1.


Also @EmeraldSlash is this the Audio Book of Clean Code?


Edit I found this Video

9 Likes

Nope, it’s got code examples in it too so that would probably be a bad idea. It’s by Robert C. Martin.

Also nice mention stack chain! :wink:

4 Likes

I like many of your points. But this one…I don’t know that you understand module scripts. You can use the same vars, tables, functions, etc. using module scripts.

…Not actually sure I agree.

EVERYTHING on the client is always susceptible to some level of exploit. Having one script vs. having 1,000 scripts is not going to help that. What helps it is to use FilteringEnabled and to make sure all your client-side code is non-critical to the rest of the players.

I understand where you’re coming from here…And I sort of agree. But I also like to think, what tools would that employee need? Probably a cash register. Probably a mop. Probably a label maker. Each of those should probably be their own scripts, as well. And, likewise, every individual task/tool/separable entity should likely get its own script.


I know I disagreed on a lot of points here, but I do want to say I like that you have really considered a lot of points here. But I think you missed a big one, and honestly I also missed it in my original post. Collaboration is much easier when you use a lot of scripts. Not just because TeamCreate requires it, but because it’s much easier to have two people working on different parts of the game if they don’t have to worry about stepping on the other person’s toes. Admittedly, collaborative programming is rare in Roblox, but I think that the day where that will change will come eventually and I think it is smart to prepare for such a future.

4 Likes

I do use Modules so of course I understand how they work, I’m talking about stuff that can’t be stored in a Module.

I’m talking about stuff like getting the Player Obj and use it inside one script VS sending the Player Obj to another script with BindableObjs or _G

like this kind of Data

PlayerData[PlayerObj].Data

Just so you can understand my perspective:
My usage of a ModuleScript is Storing Data that both Client & Server has to see but other than that I some times Run Scripts or have a few Functions in a ModuleScript, however 95% of Functions , Vars & Scripts are in a Script or LocalScript as I mentioned I mostly use a ModuleScript to Store Data(it has 3K lines of code so yeah I don’t want to scroll through all of that while working on Scripts).


I know it’s not more difficult in some cases however mine is because I store Data in one script which means if I want to do something with the Player’s Data I would have to do more to get the same results if I used another Script instead of one.


Of course Filtering Enabled is always on for me so it’s not even worth mentioning that but what I meant was

If you had something that will detect if a player is cheating and it’s in the same script as a Gun script if they delete that they would be able to cheat but not use the Gun.

I know that you have to assume that your game will be taken advantage of on the Client Side, Stealing a script, assets, whatever an Exploiter will do.


Yes, but to me these (a cash register, a mop, a label maker) are Functions.


True but I script alone which is why I neglected this point.

I know there are so many Scripts in many programs or games, different people work on different stuff and that’s fine.

You can’t deny that using too many ModuleScripts like how the Default Chat Script uses it is a pain, it’s so confusing and it’s like a web you have to get to this and then to that and this and that it’s not a good experience.

I’m not saying that you can’t use many ModuleScripts, it’s best when done right, it’s just that in the case above I think it could be a lot better than it is currently.


All in all do what you have to do, if you need to use math.huge Scritps then do it, I just like to put everything in one place, it’s just Preference.

2 Likes

With my most recent project, I’ve begun messing around with the idea of using only one Script, one LocalScript, and then many ModuleScripts to accomplish what I want. The two scripts act as managers for the modules.

When they start running, they get passed a Scope argument in a function called getModules(). The function gets all the descendants of that scope, loops through them, determines which ones are modules, and then adds them to a table after they have been require()'d. That table is then distributed to all of the accessed modules, and the modules are allowed to start running.

I don’t know how great this setup is in terms of memory, but it makes adding new stuff extremely easy. If I want to access a certain function from the Inventory script, for example, all I have to type is Modules["Inventory"]. This setup also solves a problem that I’ve had where modules can become cyclic, which happens when two modules directly require each other.

Just for show, this is how the server-side is set up in my newest project:
image
One main script, then a lot of Modules to make the game work. All modules have freedom to access eachother without the risk of becoming cyclic.

  • PS: I got the idea of this from @berezaa. He did something similar to it on one of his streams and I wanted to try it out myself. It took a lot of fine tuning but it works very well.
23 Likes

Do you the link for that video? I’d be interested to have a go at this myself too.

Thanks.

1 Like

I’ve kinda always done it under 1 ‘Core/Main’ server script, that runs through the game, with a few other scripts to do separate things. Only really used ModuleScripts for say gamemodes tbh, or storing dictionaries. Not entirely sure how to go abouts just using ModuleScripts however.

3 Likes