Help with Code flow?

im basically at a stage where i can make any individual system easily and efficiently. I understand the fundamentals of roblox studio and know stuff like functional and oo programming. I also know and use stuff like events and promises. But the issue is my code flow management whenever i try to make a game i always make the first few modules properly but once a few modules add up with different classes and stuff my entire code flow break down. So im asking for tips and maybe how u guys manage codeflow in your games. Im used to java and with stuff like inheritance hard to implement here using oop what should i do? I have tried using composition but i really don’t get the hang of it can someone help me. I’m completely self thought with around 1 yr of coding experience i learnt java mainly to understand the concepts of oop but now im questioning myself if i learnt anything :joy:

From my experience with both the languages, Java seems to be more verbose and more focused on OOP and its principles (inheritance, polymorphism, encapsulation, and abstraction), so much so that there is dedicated syntax for them (for the most part that is true), while Lua’s OOP is not that strict as compared to that of Java’s (since Luau is a Prototype Based Language).

In Lua, you can come up with your own way of implementing these principles:

Inheritance

--// Example-Inheritance.lua
type FirstClass = {
    Data: string;
};

--// Using the `&` operator, we can intersect (combine) types
type InheritedClass = FirstClass & {
    MoreData: string;
};

--// ExampleScript.server.lua
local myClass: InheritedClass = {};

myClass.Data --// Valid
myClass.MoreData --// Also valid

Polymorphism

--// Example-Poly.lua
--// Using the `&` operator again, we can combine function types, which will cause it to be overloaded
type OverloadedFunction =
    () -> () &
    (data: string) -> ();

--// We define the function now
local ExampleFunction: OverloadedFunction;
ExampleFunction = function(data: string?): ()
    if (data) then
        --// ...
    end;
end;

--// Another way of doing this
function ExampleFunction(data: string?): ()
end :: OverloadedFunction;
--  ^^ means type assertion

Encapsulation

Encapsulation is pretty easy to do in ModuleScripts.

--// Example-Encap.lua
function private(): ()
    --// ...
end;

function public(): ()
    --// ...
end;

return {
    PublicFunction = public;
};

Encapsulation for Classes

local Public = {};
local Private = {};

function Public.new(): ()
    Private.Something = "Something should go here";
end;

function Public:DoSomething(): ()
    --// We can only access private variables in this ModuleScript/Class
    print("[Private Scope]: Something = "..Private.Something);
end;

return Public;

Be vary that the some examples which I provided use Luau’s static typing, so make sure you get your feet wet with Luau’s type system and how it works to understand.

Keep these things in mind while using OOP in Luau, only use it when it is absolutely necessary and not everything needs to be in a module. (which could be said for a lot of things).
Only use modules when you are creating multiple objects of a class.
For example, you could be making an AI module for creating and handling multiple AIs.
Using a normal server script or local script may not be fit for such scenarios like that.
An example of an AI module is AIEngine.

I hope you learned something useful from this post, I’m glad to have helped!

Cheers :clinking_glasses: