Short summary on stopping to use frameworks

This post will be controversial for many of you

Most of the developers with experience above 1-2 years begin to use pre-built frameworks for convenience purposes. While it can be convenient, you really should reconsider using them if you rely on them instead of them assisting you. You’ll be able to acquire the skill of building your own reusable code with the assistance of this post. With the main idea of this post being taken away. Let me bring my points across multiple sections:

  1. Why not to use frameworks
  2. When to use frameworks

The Blame Game

What I mean by this is that a lot of devs use these frameworks to solve the problem easily, and in case it still doesn’t work, just blame the framework or Roblox itself (“This is a Roblox problem” devs say hello).

This is not the right way. Programming was never easy, no matter what CEOs or some motivators say. Programming was always about critical thinking and making the best of the current situation. Using someone else’s code to solve your problem is almost like saying, “Solve this for me”. It is extremely disrespectful to your inner C programmer.

Sometimes you really just have to stop and think: “Maybe it is worth a shot to solve it.”. I’m no coding guru, and professionally speaking, I only got into programming recently. That quote comes from my parents. Which I rely on in every activity I do.


Simplicity: Performance’s best friend

No matter what the framework states:
"

:zap:BLAZINGLY FAST™

"

or :
“Ultra fast [fancy term]-based solution”

or even sometimes:
“Native compiled framework”

IN NO WAY will any framework be faster and more efficient in terms of execution speed except the code that does exactly what you wanted to do. You want to pack data in a buffer? In no way will any replication library make it more efficient than you hardcoding it yourself. You want to make functional UIs? In no way will having a whole framework outperform a single local script managing the UI it was designed for.

Personally speaking, some of my code was able to outperform native compiled code without much trouble. While also being a lot easier to read


Bloatware and boilerplating

Unless you have a huge project with a huge team, and that being a maybe too, you are not going to use every tool of the framework. I can’t provide exact examples. But if you catch yourself thinking, “I think I could implement it a lot more easily”, you might work in a bloated framework.

Think practically: each framework has to do some other job before actually doing the work you wanted it to do. That level of bloat can range from “It’s just a convenience factor” to “Why does your code require at least 10 modules to work?”.

That would’ve been fine if that job was hidden under framework. But most of the time it is exposed to the programmer itself writing the code in the framework. Which leads to a bunch of boilerplate before actually doing any job


Simplicity: Programmer’s best friend

We begin to tackle the second section. It is that most of the frameworks are not simple. Both in terms of back-end and front-end. That leads to issues with debugging, with teaching newcomers, with memory, and with reading. And that’s what I named. Writing your own framework-independent code allows you to know what your code is actually doing. Frameworks hide that simplicity in their layer of abstraction for you to blame the framework for not doing the job properly.

For example, let’s compare 2 codes doing the exact same job, 1 being my own “Framework” HierarchyBuilder, and a formatted code:

HierarchyBuilder:

local build = require("./HierarchyBuilder")

local example1 = build{ Type = "Folder";
	Parent = workspace;
	
	Name = "Example1";
	
	{ Type = "Configuration";
		{ Name = "That is";
			Type = "Folder";
			{ Type = "Part";
				Name = "Nested";
			}
		}
	};
	
	{ Type = "Part";
		_count = 10;
		Size = Vector3.one;
		
		_init = function(self:Part,id:number)
			self.Name = tostring(id)
			self.Position = Vector3.new(id*2,0,0)
		end;
	};
}

Default organization:

local example2:Folder do
	example2 = Instance.new("Folder")
	example2.Name = "Example2"
	
	local Configuration:Configuration do
		Configuration = Instance.new("Configuration")
		
		local ThatIs:Folder do
			ThatIs = Instance.new("Folder")
			ThatIs.Name = "That is"
			
			local Nested:Part do
				Nested = Instance.new("Part")
				Nested.Name = "Nested"
				
				Nested.Parent = ThatIs
			end
			
			ThatIs.Parent = Configuration
		end
		
		Configuration.Parent = example2
	end
	
	for i = 1,10 do
		local Part = Instance.new("Part")
		Part.Name = tostring(i)
		Part.Position = Vector3.new(i*2,0,0)
		Part.Size = Vector3.one
		Part.Parent = example2
	end
	
	example2.Parent = workspace
end

Which of them could you understand quicker? Both do the same code; both are decently organized. But in one you know exactly what is happening. And the other only leaves you to guess what the hell is going on under the hood of HierarchyBuilder. That example was with an extremely easy example. If we scale it up to UI or other stuff, it becomes almost impossible to understand what the hell is actually going on without reading the documentation.


The Good Uses

There are some pre-built frameworks that are actually doing what you told them to do. These are the ones you might actually keep in your import list. In the end we do not want to go into full reimplementation, AKA “rewritten in Rust” syndrome. If something already does the job extremely well and is proven to be stable. Why not to keep it?

The best example I could think of is actually ProfileStore. It does exactly 1 thing: providing a reliable way of saving your player’s data as well as providing fallbacks. It doesn’t hide complexity; it embraces the complexity of safely saving data


Making reusable code yourself

If you are 1% of framework users that actually decided to rewrite your project. You might still want to reconsider due to the huge amount of work required. It’s not as simple as replacing an existing framework with a rewritten one.

For example, you are using a [buffer-based and schema-based native compiled custom replication with AES encryption] framework. It already established you in setting up both client and server to use certain protocols in order to communicate with each other. Replacing it with a simple luau data to buffer is not viable. It will literally require you to rewrite all of your existing code.

If you are the 25% of that 1% who decided to just rewrite the entire project. You need to first question why you used the framework in the first place. Is it for convenient buffer write? Is it for convenient communication with the client and server? Or is it for a false sense of security of AES encryption? Once you decide what you actually used the framework for. You design code that does exactly what you loved about the framework. If you loved simple buffer write. Make a module that automatically moves to the next [data size] bytes in your buffer implementation. That way you just do:

Buffer:WriteNumber(1212) -- automatically pushes write position by 8
Buffer:WriteF32(12131) -- automatically pushes write position by 4

And then do anything you actually wanted with that buffer. Simple and exactly what you wanted with way less bloat.


Answering common arguments

  1. Arg: “Hey, but it keeps my code organized”
    Ans: Learn to organize your code yourself instead of relying on a framework to do it for you.

  2. Arg: “This is not bloat; those are tools. You are just inexperienced and can’t use them efficiently”
    Ans: Personally, I’ve never seen a single person be able to use all of the tools of framework in a single project.

  3. Arg: “My code that’s based off the framework is more performant than my code that’s not based off it”
    Ans: Learn to optimize your code then.

  4. Arg: “My code keeps the complex job look quite simple”
    Ans: You might want to look into that “Simple” implementation of the function you use. You might be surprised to see that it adds even more complexity to an already complex problem. That’s called hidden complexity

  5. Arg: “I can prototype a lot faster with frameworks than without them”
    Ans: No one denies you from balancing between development speed and quality manually. Frameworks only make it automatically

6 Likes

Roblox: The global De-frameworkitisation

Before time had a name… First C optimization codder-

Great tutorial!
I find that how most people who are coming from High level languages ALWAYS seeking ways to make Luau look like their first programming language, Mainly being JavaScript, TypeScript, and sometimes Java and C#.
It gets only weirder that most of them start learning these kinds of frameworks during the “basic learning” phase, Likely in attempts to forge “Luau” into their environment, aka absolute ignorance towards our dear Luau.

It is always interesting that people coming from Mid-level languages like C/C++ ALWAYS get integrated into the community seamlessly and never use any kind of frameworks :rofl:

Skill issues JavaScripters

1 Like

Not everyone has an inner C inside of them. I am basing this reply on this youtube video, which has a really interesting discussion about the goals of different programmers. TL;DR is that craft based programmers are the ones that tend to build the tools that are then used by result based programmers. And these programmers definitely prefer using someone else’s code, to reach their goal faster. These programmers tend to prefer front end development, which I’m glad because I don’t want to be the one doing it lol

I’m saying this as someone who likes to make everything myself

You are putting too much importance on performance. I don’t use frameworks (or very rarely), but I still end up making my own frameworks/modules anyway for a simple reason, hardcoding everything is not sustainable. It might be easier to read it if the script is small, but when it grows, it’s waayyy harder to read. When making large scale projects you need to abstract away the complexity of this or that system or your project will become very hard to build upon. I absolutely believe that one should know as much as possible of how everything works, but at some point it’s too much, and it needs to be hidden away

I always try to build my module scripts (which I usually use to abstract code) in such a way as to abstract without limiting what is possible (usually by having methods take functions as arguments). I also try to build my modules in such a way where someone hopefully can understand what the method does without having to look into the module
Abstraction is a balance between complexity and limitation. Usually, when reducing complexity you make the system more limited in what it can do

Software as a whole is built on abstraction. Computers are extremely complicated if you look at them as a whole, but all the layers of abstraction built on top of each other is what makes all this madness possible

1 Like

Tbh I agree with you 50/50
I personally believe that the effect of horse-shoe applies to abstraction as well.
It’s good to keep great balance to not end up being “01001000 01100101 01101100 01101100 01101111 00100000 01100011 01101111 01101101 01110000 01110101 01110100 01100101 01110010”
and yet not end up piling a bunch of layers of deprecation on your “OOP” that, in the end, turns into some kind of sandwich with half of its code being deprecated methods.

1 Like

I can’t find any mention to our pricey friend? ( Time )

Some don’t build their own stuff simply because they can’t or don’t have the time or can’t care about every part of their game so the can finish it ( especially solo devs )

Yes simple stuff can and should be done by you.

don’t forget that a game is not one part, and programmers mostly specialize ( or prefer ) one thing be it : data stores, linking Animations and Sounds and Effects, building tools, game mechanics, everything else that require math.
It’s rare to find someone that says they love programming and want to learn everything about programming games

1 Like

Wraping is a traping - Don’t Trap yourself :rofl:
I think OP explained your excuses pretty clear:

As I understood, OP means that it’s fine using them, but you must consider it being only temporary and it being a delay for disaster.

Imagine that you are a doctor. You have a very ill patient (code). Feeding it “Frameworks” will only delay its misery, but the only true cure is an operation “Adaptation of manual code/Lightweight frameworks” for your needs.

My personal temporary solution for you would be the “debloating” framework you are using.

Try making it run in strict code; Remove unneeded/badly implemented features.

Brotha you need to lock in on learning if you don’t know the basics.

I may be slow but after reading this maybe i am a lot slower than i imagined ( i don’t understand your reply but i’ll try )

Yeah i thought so too before posting but didn’t find anything, can you point out where exactly?

Yeah… Sorry but i don’t think me writing the code will be considered an “operation”, coding a solution for a problem or using an already proven fix are the same ( you will face bugs anyway ) the difference is when using a framework you can put the blame on someone else ( imo you should know or have a general idea of what the tool is doing if you have time of course)

Let me just say ( and question ) what you said.
How is Knowing every field in a profession considered the basics?

I dislike your analogy, because you don’t use frameworks after the fact, you use them as building blocks. When you are making a project, it is your responsibility to ensure the code doesn’t become sick, and if it does become sick, then you can refactor, or restructure, … . Frameworks are a tool available to everyone, to speed up development more often (if we are talking about projectile module, datastore modules, etc), in which case, they are tools for development, and don’t really affect the structure of your game, or they can be full on global frameworks for your whole game, in which case, they are used for the organization of the game as a whole, and they probably help?

This is a perfect example of the craft based programmers versus result based,

These are craft based programmers, which is what I’m more of. I love the process of programming itself, rather than doing programming for the result. It is an important distinction to make, because there isn’t one way of doing that applies to everyone.
Result based developers will tend to prefer work that is less focused on math, such as front end web development

2 Likes

To explain this a bit more
data stores are easy to learn until it’s not, if you want to save and load the player coins man that’s easy.
But if you want to ensure there is no lost data, save more complicated data, season locking, share data between games. Man you are gonna have a harder time.

linking Animations and Sounds and Effects ensuring that everything happens at the same time without losing quality.

building tools not game tools but developer tools ( plugins )

everything else that require math rendering engines or things that change the player position in a different way ( Wall stick/Gravity Controller by EgoMoose )

And Network programmers or making multi-player games

As in someone who is only programming to learn and enjoy the process?

Yeah i was one of those until I found out that time is money and if i am not making any then i’m losing

2 Likes

Data stores are fairly straightforward once you consider all the things you need to do, and if you are really not up for the grind, modules exist for it.

Reusing is not to be confused with using a framework.

OP likely means abusing the hell out of stuff like metatables unnecessarily.

I myself come mostly from a C# background before I got into Luau, and even then it is 10x easier to simply throw functions at the problem than waste time trying to understand OOP to then realise you’re just slowing your code down a bunch while also opening inheritance when it is not necessary.

People LOVE metatables; sure, go for them. However, metatables are like virtual calls, slow as hell in comparison to what you could do otherwise had you changed your design.

Of course, some bits are OBVIOUSLY just plain better using virtual function calls (in Luau you can find them as simply using the __index metamethod), but using this on every class is, simply put, unnecessary and a waste of resources.

If you did not design something for inheritance, opening it to it by allowing the user to just openly do .new() and then getting the metatable of it, again, is not particularly useful nor good. It is an unnecessary cost you’re taking for something that you realistically wouldn’t be taking originally.


I do not consider myself a ‘craft-based programmer,’ because that’s simply not the case. But even I know how to distinguish between a money-hungry one and someone who knows what they are doing.

Having been an exploiter and opened games, I have seen stuff so badly programmed and so poorly written that, quite honestly, it is bizarre, and those were from people who looked to have done everything from scratch.

Frameworks are good; if used properly, you cannot just throw them at every problem and refuse to learn design. This is why back then we used to first learn C or a low-level language before jumping to a higher abstraction because then we were knowledgeable on the cost of what we were doing to a certain extent; now we just jump directly to the high level, ignoring everything else sometimes, taking shortcuts to proper design, and just overall making something that is not good with excuses like “It is too little pay” or “I did not have enough time!” If I know I don’t have enough time, I drop it or drive myself a bit more than usual because otherwise I know that I will end up under-delivering. I may have myself not liked certain specific things, like libraries that just make really bizarre things to achieve extra performance, but put to think of it, we need to get performance back, because on top of all this bad, unnecessary abstraction we have built, there are only daemons ahead.


In short, because I’m 99.99% sure NO ONE will read the content above:

Frameworks are good if you are short on time. If you cannot do something properly without the assistance of a library, either lower your ego or just pour more time into it. Having seen horrible works of art, such as a game whose rebirth remote just rebirths you without validation another one that grants network ownership of a player from just a remote, I can guarantee you, even as an ex-exploiter, that all those issues are simply inexperienced scripters who have had an ego, refusing to use external libraries or asking around for help during development while also doing lacklustre testing. There are many safeguards in place if you choose a framework, so it is preferable to a certain extent that you do so if you cannot guarantee good code.

We have also taken absurd methods to get back performance lost as a product of metatable abuse, using bizarre methods to obtain and reuse thread objects that really aren’t that well explained. This also comes from the fact that everyone likes to set a metatable to everything, even if it is not required, for, say, a singleton object or something that will not have any inheritors in an OOP aspect.

In short of the short:

  • Frameworks are good if you’re short on time, preventing *horrible, terrible, and bizarre design decisions that would have not been a problem should you have used known code and not invented something out of thin air, for lack of a better term.
  • We have created bizarre solutions to try and get the performance we lost due to our own daemons.
  • People have grown accustomed to using metatables without really considering their cost.
  • We should first take a step back and look at the reasons we do some things; that way, we can value, apply, and improve those.

Programming is designing a solution to a problem, shortcuts to a solution given that we know some things already are OK. Reinventing those ‘shortcuts’ will not aid you and likely harm you. We think, therefore we are, and knowing how to ‘code’ is not enough; the thing that actually matters is using that ability well, and if you really are after solutions, you have to doubt what you’re doing at least once.

Ok, cheerio, I don’t believe anyone will read my yap though; I took some inspiration on the last bit from the great René Descartes. I believe my message and what I tried to convey is clear, and I hope this post finds whoever reads it, at whichever time, good, :slight_smile:

5 Likes

This is one of the best things I ever read, it’s detailed, grammatically correct, the details are amazing it is very easy to read now I understand how to code, thank you

1 Like

Singleton part is so real bro :skull::skull::skull:
People just should lower ego and at least learn basics of C or any mid level language at least

1 Like

That’s an interesting set of replies. I definitely forgot to mention the time argument. I will edit the post right after posting this message. But basically in projects with tight deadlines or just wanting to push the first prototype. Frameworks are great. They cut some of the redundant code. While also keeping the maintainability. It also applies to teaching newcomers. Developers that are already familiar with any established framework like React will quickly learn how the project is built and will right away begin adding their code to the project.

While with a custom-built solution, they would probably have to spend weeks or months understanding the established code (probably more if the established code is horrendous). That’s the neat part about properly organizing your code. As compared in the main post, both solutions can be extremely easy to read as well as providing a good abstraction. No one denied you can’t balance between speed and quality. Frameworks just do it for you automatically.

2 Likes

Frameworks kinda broke me, especially when it comes to SSA and OOP. I’ve made my own one, but quickly returned to just using scripts and more primitive ways to code a game.
I still do use stuff like Jecs for ECS/Data Oriented Design, Blink/Zap for efficient networking and Fusion for declarative UI (if necessary).
Things got easier to work with after no longer constraining myself to that.

Yeah same, I have run into the issue even with my own frameworks where I make them but only realise later in line that im just making a complex problem even more complex.

I eventually now strted making my own framework that can be used for organized code but also keep things that dont need a framework be built to rely on themself. At the end of the day as much as you try things will eventually have to look messy or complex to function. And that is fine you just have to find ways to explain the complex system in an efficient way or atleast make it really versatile so it is easy to add new mechanics and stuff in the future! ( This is my own opinion and interpertation of the topic so whatever I say isnt a statement its just me talking about my experience and thoughts :>. )

used frameworks like Knit and Aero for years because I thought it was the thing to do until I realized they were all basically completely useless outside of the utility modules they come with lol