How Do You Write Appealing Code?

Hi guys!

I’ve been creating a roleplay-oriented game that I often write code for but eventually end up disliking. I’ve been writing a lot of frameworks recently independently to see what conventions I do and don’t like and incorporate the good parts into my roleplay game’s framework; however, I still am never content with specifically the organization of my code.

Therefore, I’m curious about what your guys’ scripting preferences/idiosyncrasies are.

  1. What casing convention do you use? camelCase, LOUD_SNAKE_CASE, PascalCase, or something else – and when?
  2. Do you have code you write one day and end up disliking? How do you deal with it? Do you continue writing off of it?
  3. How do you set up your scripts? Do you use a lot of modules? How do you assemble them all together (if a LocalScript, what do you put in your central script? User input?)
  4. How lengthy are your server and client scripts?
  5. Do you use an organizational technique with your functions? Do you put all of your functions into a table and use the “self” argument? Do you create a table and then write your functions outside of it?

I’m on a quest to improve my code-writing by getting outside feedback. Help me out if you can!

7 Likes

Something you may be interested in looking into is the idea of having a system architecture. I don’t have any good examples of it off-hand, but it’s something where you plan out the design of your system before going into it and it can help you to keep it all to a specific standard (so you’re more comfortable in it long-term).

As to the actual questions:

  1. For coding conventions, I’ve just found that consistency is key. Pick one you like and stick to it.
  2. Sometimes it actually is better just to throw something away and redo it. Don’t overdo it but sometimes it’s worth doing.
  3. I like modules but there’s definitely different ways of doing it. This is where the system architecture would really play into it, though, so look into that.
  4. I like to keep them small but have had larger ones. The main idea for me is that everything sticks to one purpose; but again, the system architecture thing would help here.
  5. I like that style in general, but I’ve found cases where it applies really well and cases where it doesn’t so much. So it really depends on what you’re doing with it. But for the most part, I do like it as a style and there’s definitely benefits to it.

You can also go to Google for this; if you google how to write clean code, there’s a lot of people that talk about that. It’s a pretty broad topic.

3 Likes

The convention for writing variables is the first one, first work in lowercase and rest with first letter capitalised.

I find organised code the most satisfying to write, and I include spaces almost everywhere. E.g. 1 + 1 not 1+1

I also predefined my variables to make it neater.

3 Likes

I follow, and suggest you follow, Roblox’s own Lua styleguide

https://roblox.github.io/lua-style-guide/

This is (obv) used in all of Roblox’s Lua code.

10 Likes

I tend to keep my code well organized. I also use the comment function -- like this to keep track of what is what. I also put in proper indents and possibly spacing to space out different ideas in a script, or different functions. Yes, sometimes it is better to redo it, but most of the time you should try to debug it first and ask the forum before you redo something(unless it’s very short)

Edit: Apparently I conform to the Roblox style guide in pretty much every way and I didn’t even know they had a style guide :smile:

I primarily use PascalCase. I definitely have days where I end up disliking code. I usually end up trying to adapt my important code to a better format.

I use a ton of modules. Pretty much all code I write is in module form besides the code to actually load the modules. For my local and server code I usually have a folder called “StarterModules” which each have init, preinit, etc functions. Outside of there I keep utility, library, “service-like” code, etc outside of the StarterModules folder and keep them in their own CentralModules folder which get required individually at the start of the game.

I try to keep as much of my code categorized as I can. Player related stuff goes in one file. Save related stuff in another. This means some scripts can get really long, especially the main ones like Players, but it also gets really small. And I make sure everything is organized. If I can create submodules I’ll do it whenever possible if it means easier to navigate code.

The main problem I run into with this style is that despite trying to keep things organized I sometimes don’t do a great job and have to scrap some code. The good thing is eventually I’ve been getting better with writing good code and if it’s organized well I know exactly what I need down to dependent modules.

In my code I always no matter what kind of project keep services at the top of my script. I keep primary variables, requires etc, at the top too. This way I can at a glance see what stuff the script uses.

I also tend to keep modules into one table (including internal code). It’s not worth the hassle imo to create separate internal code which may be used by other modules in the future.

4 Likes
  1. I often mix together with PascalCase and camelCase, but this doesn’t really affect anything. I know I should just try sticking with one, but they both suit me. I also don’t like LOUD_SNAKE_CASE.

  2. If there are possible ways around, I usually try fixing it up and stuff, but when everything is running awful and I can’t figure it out, I usually just redo. This probably happened to me several times while trying to develop a specific game.

  3. Generally, I don’t use modules. I have a bunch of variables here and there that I name, and can find easily. When it’s client-sided, I often write user input stuff in local scripts. Well, I have created a few modules for quick and easy personal use (like whenever i need to convert an RGB value to Color3.new())

  4. Well, most of my scripts aren’t that lengthy at all, unless I am developing on plugins and such.

  5. I don’t use Object-Oriented Programming. Currently it’s too confusing. Most player variables are stored in a folder called PlayerData, parented inside each and every player. That way I can keep track of multiple things (e.g. does the player have key 1, does he/she have a screwdriver, is the player carrying a crate)

2 Likes

My codebase is made up essentially by a bunch of “Managers”. For example: TrasnactionManager, PlayerDataManager and MarketplaceManager. Each script has its own set of events so other scripts can interact with it like getting playerdata for example or checking if someone has purchased a gamepass.

I generally just use PascalCase for everything, i don’t know about you but anything but looks extremely odd to me.

The only thing i used modules for is for databases (team databases, item databases) and for simple functions (Math module, string module, table module).

The thing about programming in general is you really are constantly learning. This means i usually end up dislike code ive written a lot, not because it looks unorganized but because i just learned a better way to do things.

I’m not one to really favor the “One script architecture”, each server script for example has its own purpose. Makes things more organized for me as opposed to scrolling through thousands of lines of code just to edit one small portion. Just a preference though.

I use OOP for simple things like basic lists and groups to name a couple.

All the module scripts, RemoteEvents and RemoteFunctions i use are grabbed through Quenty’s NevermoreEngine. I found this helps me with organization a lot. https://github.com/Quenty/NevermoreEngine

2 Likes

I’ve seen that before and attempted to follow Roblox’s styleguide; however, when it comes to things like the client, there are certain discrepancies that make me inclined to break those rules, such as the following:

-- just to reiterate: this is on the client
local Players = game:GetService("Players") -- okay, services at the top

local ThisModule = require(Players.LocalPlayer.PlayerScripts.ThisModule) -- this module would be theoretically stored inside of StarterPlayerScripts.
local OtherModule = require(Players.LocalPlayer.PlayerScripts.OtherModule) -- so is this one
local FinalModule = require(Players.LocalPlayer.PlayerScripts.FinalModule) -- etc.

local localPlayer = Players.LocalPlayer
local playerScripts = localPlayer:WaitForChild("PlayerScripts")

Is this the kind of declaration hierarchy that the styleguide encourages? The styleguide, for me, is perfectly viable within server scripts, but how should I adapt the styleguide to look appealing on the client?

I appreciate the feedback! It’s interesting to see the differences in how everyone writes code.

I used to use PascalCase, but I started to follow the official Roblox styleguide and it changed how I write code entirely. I’m not sure if this is a good or bad thing, uniformity isn’t always the answer, but I’ve also found that the styleguide is one of the reasons why I don’t entirely like my client-side code.

If you use modules, where do you place them in your script? Somewhere near the beginning, or just before the point when you reference them in application?

Basically all important things go at the beginning

Nevermore allows me to handle modules like this.

1 Like

I think sticking to a certain style is the best approach, but I’ve experimented and have still found difficulty finding a style that I approve of. Maybe it’s because I’m being too hasty when switching from one style to another in hopes that it’ll solve my discontent with the appearance of my code.

Of the three conventions I mentioned prior, camelCase, LOUD_SNAKE_CASE, and PascalCase, what do you use? I’m curious as to which you use and, if you know, why.

Thanks for the insight. Much appreciated.

That’s a very neat approach. Mine is similar, but I don’t use Nevermore to handle my imports/requires; I’ll surely look into using Nevermore later.

Thanks!

In terms of setting up scripts, I would look into Aero Game Framework by Crazyman32. Amazing framework. Never going back to anything else.

2 Likes

I use a mix of all casing conventions.
camelCase for statically typed variables where the lower case part represents the type:
classClassName
listListName
PacalCase for important dynamically typed variables and snake case for less important ones.

I often end up reusing old code which runs efficiently by hiding it behind a module or a block that I can fold later on. You can also label a block with a comment right after “do” which will still appear even when folded.

I use 1 script and multiple module scripts. The script itself doesn’t contain any game-related logic and is only for loading the modules in a constant order. Every module returns a function with 1 argument being the global environment so that they can interact with each other.

The modules themselves range from only 10 lines to 1k as it all depends on what they do. The most important part is to use blocks so that you can fold any part of the script you don’t currently need to view.

It is a good idea to reuse the same function for every object of a class. There is no reason to create a new function every time that does the same as the previous.

1 Like

Alright, so when it comes to number two on the list, I’d have to say I love the feeling of taking an old script which code I no longer like because It was probably less efficient and requires more lines than needed, and scrapping it, rewriting it, and see the end product with usually much less lines, more features, and usually a lot quicker.

1 Like

The only issue is when you have no idea how it does what it does and yet it works perfectly. I have around 60 lines in my pathfinding function which add +1 to the neighboring nodes on a row-major order while checking for sector bounds, but I have no idea how to rewrite them without breaking the entire thing. It takes around 0.1 seconds for it to complete a 200x200 grid so I won’t even try.

I use PascalCase for methods and class names because it coincides with how Roblox does it. For properties, local variables, and stuff like that, I use camelCase because that’s what I’m used to (basically it was how my profs have done it so I learned from them).

But honestly, Roblox has their own conventions so maybe you’d like to look at that? This is how admins do it:
https://roblox.github.io/lua-style-guide/

2 Likes

Over-complication is bad. Pseudo-code is good. Think before you code.

Reuse. Reuse. Reuse.

1 Like

PascalCase for everything. Nothing worse than missing a capital somewhere and not being able to find it.

I like my code. I write it out in layman’s terms first. A flow chart of a piece, describing how things work together. They become my notes. Often I’ll find it’s getting messy and too complicated so then I look for ways to simplify.

How do you set up your scripts?
I try to have 1 script for each type of thing, and where there are many similar duplicates, I clone them and then have then get information from the parent to be able to function.

Do you use a lot of modules?
What are they?.. Joking aside. I hate them. The only reason I have them is in my zombie AI for pathfinding and targeting etc. If I can avoid them, I will. I hate anything complicated. The simpler the code, the easier it is to follow.

How lengthy are your server and client scripts?
Client scripts are almost non existent. Gui operation and remote firing the end result so the server can do the work. The client just informs the game of desires. The game then does the work. I do believe this helps to stop hackers. And I am assuming that anything inside the player is client side, and anything in workspace or server storage etc is server side.

Do you use an organizational technique with your functions?
I rarely use functions. Often I write the function, and then realize I might as well just move it to the place where it’s called and stop it from being a function.

Do you put all of your functions into a table and use the “self” argument? Do you create a table and then write your functions outside of it?

Yeah no idea what this means. I basically never use tables. I rarely need to. I don’t have lists much and if I do, I just have them as a list of locals and them use them when ever I want and then when the work is done, I send my output to an IntVariable for anything else to use when it’s required.

So really, No tables, No functions, No modules, No client side scripts, and no _G globals. And anything else that’s more fancy than a for loop and finding first child… not interested.

1 Like