How to organize your project correctly

This tutorial will help you structure your projects in Roblox Studio to improve readability, maintainability, and scalability.
Keep in mind that I am by no means saying that this structure is perfect. But it is the most readable of all that I have used.

1. Code Organization

The key to success - modularity. Break your script into modules and one+ main sxripts, independent modules, each of which is responsible for a specific task. This improves readability, simplifies debugging, and allows code to be reused in other projects.

  • a) Modules:
    –each module must be a separate class, utility, function, or regular singleton (a class that will be used once. For example, any Service in luau is a singleton). In short, a module is not necessarily just a table, and it is important for you to remember this. In fact A module is just a value that we return at the end of the code, usually it is a table.

  • b) Classes
    –Each class is a separate module, even if it consists of only 2 fields. The file name must match exactly the class name (ZoneManager, BlasterClass) as far as I know, the module itself is usually returned when creating a class, however, until roblox fixes its TypeChecker (We’ve been waiting for this for a long time… Does it take 4 years?) you should use typing, and in my opinion, instead of returning the module table, return the constructor itself.

  • c) Naming Conventions
    camelCase For variables and functions (for example, playerPosition, calculateDamage). The first word is written with a lowercase letter, each subsequent one is capitalized.
    PascalCase For classes (for example, PlayerCharacter, InventoryManager). The first letter of each word is capitalized.
    UPPER_SNAKE_CASE For constants (for example, MAX_HEALTH, PLAYER_SPEED). All letters are uppercase, words are separated by underscores.
    –By the way, you should declare each service at the beginning of the code. Variables also, but in a reasonable sense (only those that are needed in the entire script, as an example - constants), with modules and classes as well as with variables

  • d) Folders
    ReplicatedStorage : The code is stored here, accessible by both the client and the server.
    —Remotes : Scripts for RemoteEvents, RemoteFunctions (Bindables? Really idk)
    —Client : I think u alr know
    — (Keep in mind that in order for the local script to run, you need to use the regular one with the RunContext change.)
    —Services : Classes and services that implement logic. InventoryService, ShopService.
    —Utils : Utils. (function GetZone() return Zone end) ... return GetZone)
    —Constants : A module with constants (UPPER_SNAKE_CASE!)
    –
    image
    –
    ServerScriptService : Scripts that run only on the server are hosted here.
    Don’t overload it

  • e) Singletons: Use singletons to control access to unique objects or resources. Create them directly in the module, avoiding global variables (roblox singleton is a… Like a service)
    (Don’t forget that globals and getfenv disable optimization.)

  • f) Tags and Attributes
    As far as I know, you can create private and public values in unity. This is also implemented in luau (I’m not talking about the possibility of creating a privateValue table in a class, etc.), in roblox studio it is also possible, but this is done through attributes. (in the code, instead of knowing, you write obj:GetAttribute(“idk”)). In cooperation with classes, this creates a very cool logic. Also, you should use tags for better organization. In the code, you can write CollectionService:GetTagged(“idk”) and get a table of all instances with this tag at once

I’ll write the next part tomorrow. Good Luck

(Sorry for my bad English, I used translator)

8 Likes

You are very mistaken that the organization does not matter, and I am ready to give you a hundred examples of why you are wrong. striving for it is the same as for clean code, of course, everything has a limit… The minimum organization must be present.
You’re right about the server folder.

1 Like

He is absolutely right—organizing code is important, especially for optimizing large games. We all know how questionable Roblox’s default optimization system is.

1 Like

MuTaNtCaSe is underrated.
a) Modules: Indexing and storing a value, even if done 1 thousand times, will end up being a better practice than “Balkanizing” your Module Scripts.

b) Classes: Not really a good practice to create module scripts for everything; “To confuse your enemy, you must confuse yourself” tip. Also, it would not really be that good for potato players having to download so much data with 1MB/S internet.

c) Naming Conventions are not really a thing relevant in Luau. For example, in Java people use camelCase because of class methods; in C++ people use underscore for easier navigation and auto-completion, and all of that is not relevant when it comes to Luau. I personally prefer using PascalCase and SNAKE_CASE but I don’t see people getting confused and lost working as a team in Luau for just naming conventions.

d) Folders
It’s honestly a very good tip if you work in a team; but other than that, it’s a preference.
Hower once again, why would you use ReplicatedStorage for a Client/Server only modules?

2 Likes

Roblox’s Optimization system is not questionable.
The other way arround here.It already does everything for you mostly and yet there still people who do some warcrimes like:

local table_insert = table.insert

Want to note that if you do some --!optimize 0 work such as getfenv/setfenv then yes doing that is revelant but that the only exeption

2 Likes

Creating one server script and one local script for each player for the entire game is also more effective than the devil. You’re absolutely right, I won’t argue with you, because it’s the same as being the devil’s advocate. About variable names: let me ask a counter question, how do names of the same type help in coding? Why is it written that way in language x? You have to understand what I mean. And yes, you’re right about the other scripts in replicated storage, I do it myself, I just didn’t update the post.