Tips/tutorials on project organization with OOP/module scripts

Hello everyone,

I have been coding and doing stuff on roblox for quite a few years and have a very good understanding of coding.
My goal right now is to enter the top and become a “”“professional”“” so that I can also work for big groups and generally work on bigger projects.

Mainly my point that I have to master is the project/code structure, I sometimes see snippets of the explorer or of some code and I see many modulescripts in folders and in the code they use classes and everything connects.

The questions is now, does anyone have any tips, tutorials regarding my goal?

1 Like

I would recommend looking at other projects on Github and see how they wrre able to componentalize large scripts into individual readable pieces.

That is also what I wanted to do but I cant find such sripts

The best way to start off is by practicing a clean code-base that you believe would be readable from the perspective of another programmer who has no idea what your code is trying to achieve.

There are several factors behind what makes a code “clean”, one of the more important factors is efficiency—the question of whether your block of code can achieve its intended result efficiently and quick without an unreasonable amount of resources. Another is format and syntax, like indentation & spacing, or consistent naming conventions, which just makes it easier to read each variable and function. The most common programming naming convention used on Roblox is the Pascal Case, but I personally prefer the Camel Case due to my history with programming languages for Java for example.

The names of variables should especially have meaning. One mistake I see here and there is that people just name their variables anything—sometimes it’d just be one letter, sometimes it’d have no correlation with what the variable is supposed to store. For example:

local function roll(a)
    local b = 1;
    return Random.new(os.time()):NextInteger(b, a);
end

A technical, intermediate or experienced programmer would definitely have an idea of what the variables a and b connotate, but that’s because this is just a pretty simple example and the function isn’t too complex that it doesn’t take much to piece two and two together. But for more complex functions, it’ll be especially recommended that your variables have meaning.

Fixed code with updated variable names

Giving the variables actual meanings in their names just makes it easier to comprehend the purpose of the function and also helps you find that one part of the code in case you need to go back.

local function rollDice(max)
    local min = 1;
    return Random.new(os.time()):NextInteger(min, max); -- return a random value between 1 and the provided maximum
end

Additionally, comments help, too. They’re there for a reason, and they exist—whether to serve as a reminder, or to add credits to a part of a code, or to let another programmer or even future you know what this part of the code does; all of that will definitely help with project organization as you asked. When making functions, you should also focus on allowing a reusability factor for them.

Single-Responsibility-Principle

I figured I should add this as well considering you included OOP (Object-Oriented Programming) within your inquiry. The single-responsiblity-principle (SRP) is a core concept within OOP, and it should be something that you always keep in mind when creating new modules & especially functions. A function or object method for example should only have one, well-defined responsibility or purpose. You shouldn’t merge several functions into one, what if you end up having to re-use them later? Then it’d be inconvenient and also an unnecessary addition of lines to the code by re-pasting or re-typing them.

This also partly applies to modules; if you’ve had experience with other programming languages before, such as Java, then in Object-Oriented Programming, you could think of module scripts as classes. And the principle dictates that each class should have only one responsibility or purpose. This means that, for example, if you have a module script that handles the serialisation of certain values, that shouldn’t be handling data saving as well. Have a separate module script that handles the data.

1 Like

thanks you very much for the tips :happy2:

1 Like

In fact, advice about this can be given endlessly.

  1. Separation of Concerns
    Try to divide the logic of the game into separate, independent modules, each of which is responsible for its specific task
  • For example: the script for a custom death screen should be divided into a script of a pair of modules, DeadHandler and DeadUIcomponent with different methods. In DeadHandler, you create an OnStart function in which you specify the logic for creating a UI at death(I mean, you don’t create it in the same script, it’s done by DeadUIComponent, from which you require everything.). In the same module, you return the OnStart function. Well, then I personally create the core of the project. which simply require all modules and uses the OnStart function
    image
    Core script:
    image
    Client loader script:
    image
    Modules structure:
    image
    But, you don’t have to repeat after me, I just decided to share.
  • Using folders for organization. The choice of style is yours. Organizing your game

Design Patterns:
the most used ones are singletons and factories. The former will help you set up objects quickly, and the latter… Pretty useless, just a special case of OOP

Singleton: Ensures that the class has only one instance. Useful for managers who need to be globally accessible.
Observer: Defines a one-to-many relationship between objects. Useful for events and notifications.
Factory: Used to create objects without specifying a specific class. It is useful for abstracting the process of creating objects.
State: Allows an object to change its behavior depending on its internal state. Useful for managing player states, AI, etc.

** Coding Style:** Adhere to a consistent coding style. Use clear names for variables and functions. Write comments explaining the logic of your code.

Use modules! This is the “basis” for creating reusable code.
As for the reusable code, you should definitely use a utilitarian style. Just create utilities. For example, MathUtils can contain functions like Lerp, etc.
In the end, I advise you to document the function(before declaring it. Thanks to this, when you use it, you will immediately see this comment in the hint), and the code itself - only if it is an “important point”.
And also about functions, be sure to type at least its arguments and output.
Bad practice:

local function lerp(a, b, t)
	return a + (b - a) * t
end

Good practice:

--Linear interpolation between the initial and final values.
local function Lerp(startValue: number, endValue: number, alpha: number): number
	return startValue + (endValue - startValue) * alpha
end

although, to be honest, I’m not sure, most likely no one will mind a,b,t, because it is very often used, however, I am more than sure that a beginner will not understand anything if you show him this function without saying its name.

P.S. STUPID TRANSLATOR😣

2 Likes

hi, thanks for the response.
I have an example I need help with.
I want to make a train track generation system, I have different structures in a folder.

now theoretically I could have a modulescript with a function like: append(structure_to_append, appending_to_structure) and I just pass the model of the structure and the models have start and end points.

OR

I could make a class which is responsible for structures and have a new structure created with structure = Structures.new(“underground_tunnel”) and then I could append it using structure:append(to_structure)

Which one is better, should I make it “complicated” and use classes or just use normal functions which seems more convenient.

But aside from that I still need a script (loop) to actually generate the structures, like 1/10 of the structure are going to be curved roads 1/20 bridges, and there can’t be a ground rail when the last one was a bridge without a connection to the ground, basically just the algorithm.
where do I keep this script now?

What is an example code structure for what I just explained?

If you plan to edit the script after you’ve written it, of course it’s better to write a class.

  • Where to store the generation script?
    If you’re talking about the module, then it should be stored somewhere in the ServerScriptService.Gameplay.Packages or by type
1 Like