Code is one of the most important things when making a game, almost anything you play on Roblox wouldn’t have existed without good ol’ coding. From making a part change color to advanced frameworks, code helps us create things we otherwise couldn’t do. But with all that power comes a problem some developers face, coherency. Coherency is a term used to describe something that is intelligible, meaning something that people can easily understand. In some scripts I have seen by seen by Developers and or other scripters in other places, I’ve seen that they were unintelligible, making it hard to figure out issues with the script when it had to be debugged.
This guide/tutorial will serve as a way to teach developers suffering with issues due to incoherency in their scripts, teaching them ways on how to improve legibility and help out other developers when they have to look at their scripts so they can easily understand everything that the script is meant to do
With the introduction out of the way, let’s begin with the guide
Proper naming of Variables and Functions
Note: A lot of this can be boiled down to personal preference. If you already have code that can be understood without following the naming conventions in this section, you can skip over it
It’s begin with a simple thing that some developers make when they script, when naming a variable or a function, it’s best to make the name of it match the use case that it will use for. Proper naming can also help get rid of certain comments that explain what it does when proper naming can act as a comment itself. This same principle can also work for naming Instances as well
Take this example
local x = {"Apples","Pears","Bananas"}
Here we see an array of fruit, we understand it through reading the contents of the variable, but not from the name of variable itself. The issue comes when you have to use that table and see x[1]
in your code for example, what does the variable x
contain? To remedy this, as a rule of thumb, the names should be what the variable contains or its use case, the names should be self-documenting
local fruits = {"Apples","Pears","Bananas"}
Tip: If you have 2 or more words in your variable, camelCase can help to make those words be understood easily. canthroworjump
is not as legible as canThrowOrJump
.
With this simple change, we can now easily know what the variable contains inside it as it is named accordingly. There are other naming conventions you should try when naming variables, examples
In pairs loop
This is something I see many people do, even I myself is victim of this. The thing I’m referring to is when we use the standard i
and v
for in pairs loops, this can be confusing, especially if you have many in pairs loops or when you have one nested inside of another, this for example
for i,v in pairs(workspace:GetChildren()) do
if v:IsA("BasePart") then
v.Transparency = 1
end
end
Sure this may not be difficult to understand, but what if you have this,
for i,v in pairs(workspace:GetChildren()) do
if v:IsA("BasePart") then
for i,vv in pairs(v:GetChildren()) do
print(vv.Name)
end
end
end
This is even more confusing as we’re not properly naming our variables, meaning we are not sure as to what is going on in those two loops. But if we properly name them,
for _,part in pairs(workspace:GetChildren()) do
if part:IsA("BasePart") then
for _,partChild in pairs(part:GetChildren()) do
print(partChild.Name)
end
end
end
We have already improve the code without even adding more code into our script. Proper naming is key.
Tip: If you have a variable that you get by force (such as the index in pairs loop), it’s good t o set that as an underscore _
to help show that it’s an unused variable, meaning you didn’t use it for what you needed
Functions
Typically when naming a function, its name should reflect on what it is used for, and should typically be constructed by a Verb followed by a Noun, such as addNums
or setSpeed
. Here’s an example
local function Calculate(x,y)
return x + y
end
Technically we’re calculating 2 numbers, but it’s a bit misleading since its only function is to add 2 numbers, a more descriptive name would be
local function Add2Numbers(x,y)
return x + y
end
Already we can understand what the function does just by the name alone.
There are many more ways to use naming conventions but I talked about it longer it would make this post longer than it should be, I recommend reading The Art Of Naming Variables as it describes naming conventions not touched upon in this post
Commenting
Sometimes there can be cases where proper naming won’t or barely helps readers understand the code, this is where comments come in. Comments can be made by typing --
followed by words that describe what you need to describe. Here’s an example
local fruits = {"Apples","Pears","Bananas"}
print(fruits[math.random(#fruits)])
For an intermediate to experienced developer, this code is simple, print a random value from the fruits
table, but what if someone doesn’t know that’s what it does? Sure they can just test and see that it prints a random value, but to help our reader even more, a comment should be placed
local fruits = {"Apples","Pears","Bananas"}
--Get a random value/fruit from the fruits table and print it
print(fruits[math.random(#fruits)])
With that simple print, first time readers will be able to understand that line of code if they have never seen it before. It’s a bit of a silly example as most people already know how getting a random value from a table works, but it’s to show the power of commenting. I could mention more examples, but from one example you probably already know what I mean by commenting your code, just remember not to write comments on obvious code that you can understand by reading it, even if you’re a new scripter
Guard Clauses
Now some of you may be in this section and be confused as to what a guard clause is, I don’t blame you, first time I saw it used I had to google it to know what it meant. A guard clause is a condition that must be true before continuing on with the next lines. Now you may ask “Isn’t that an if statement?”, guard clauses do use if statements, but the way they’re structured is different and should generally be used when if statements can harm readability. Here’s an example of code without guard clauses
Part.Touched:Connect(function(hit)
local hum = hit.Parent:FindFirstChild("Humanoid")
if hum then
if not deb then
if hit.Name ~= "Left Leg" then
deb = true
print("Conditions met!")
wait(1)
deb = false
end
end
end
end)
This code will work as it should, but its readability is a bit flawed since there’s 3 if statements and a variable that doesn’t nothing but check a condition. Here is the same code with guard clauses
Part.Touched:Connect(function(hit)
local hum = hit.Parent:FindFirstChild("Humanoid")
if not hum and hit.Name == "Left Leg" and deb then return end
deb = true
print("Conditions met!")
wait(1)
deb = false
end)
With guard clauses, the code is much shorter and easy to understand what is going on because each statement is now condensed into a single if statement that has more readability, showing easily what stops the function from continuing rather than the if statements as shown before
The same principle can apply in loops as well, but instead of return
, you write continue
, example
Before guard clause
for _,part in pairs(workspace:GetChildren()) do
if part:IsA("BasePart") then
print(part.Name .. " is a basepart!")
end
end
After guard clause
for _,part in pairs(workspace:GetChildren()) do
if not part:IsA("BasePart") then continue end
print(part.Name .. " is a basepart!")
end
You can also use this to break a loop if needed, but the most common are either going to be return
clauses and continue
clauses
Indentation
This one is going to be a short section since Roblox automatically indents code when needed, but sometimes mess ups can occur and accidentally mess up the indentation. Indentation is when a line is tabbed in a certain amount of times
This line is indented by 3 tabs!
“But Embat, why are you making this section if Roblox does it for us!” - I’m making this section to highlight the importance indentation has if you accidentally have some lines not indented properly
Here’s a huge example of that
part.BrickColor = BrickColor.Random()
if part.BrickColor = BrickColor.Red() then
print("Red!")
part.Transparency = 0.5
end
part.CanCollide = not part.CanCollide
part.Anchored = not part.Anchored
print("Done!")
As you can see, without indentation, it can be quite a hassle to figure out what is happening, what lines are in the if statement for example. Sure it’s not difficult to notice, but it takes more time to find it without indentation. With indentation on the other hand
part.BrickColor = BrickColor.Random()
if part.BrickColor = BrickColor.Red() then
print("Red!")
part.Transparency = 0.5
end
part.CanCollide = not part.CanCollide
part.Anchored = not part.Anchored
print("Done!")
It becomes much clearer to us that those two lines are in the if statement, because they stand out more than without.
Or alternatively to fix indentation quickly, just press Format Document
Conclusion
There definititely more ways to improve code coherency, such as the D.R.Y (Don’t Repeat Yourself) and K.Y.S.S (Keep Your Statements Simple) principles, but they should be easy to understand just by their name alone, but if you’re still confused, you can read the articles I posted below or you could do your own research to figure out these principles
Here are some articles related to the topic of coherency of code, I recommend you also read these as they feature principles that I did not touch over in my post. Be warned that some points in some articles may not work for Roblox
Five Rules to Improve Code Readability by RayRay, features the DRY principle
Three ways to make your code more readable, I used this for some of the points
If there’s something you would like point out or add, please send a reply on this topic!