Writing Better Code
Posted: Fri Sep 30, 2016 10:28 pm
If you've clicked into this thread you want to write better code. What is good code? Good code is easily maintained, easy to update, and easy to read and understand. This will be as general as possible to cover as many scripting situations as possible, and will be updated as I see things come up in this forum that need to be covered.
Starting with questions you should ask yourself to consider code quality:
Can I easily explain what is going on with this part of my code?
If you can't easily explain what is going on, it will be hard for people to understand your scripts. Also, it will be harder for you to debug your own scripts if you are unable to identify where in your code you went wrong. It will be much harder to continue working on your script after taking a break from it, so it is best to make lines shorter and straight forward. Ask yourself this frequently. Lastly, if you can explain it then do it. You can insert comments into your code by adding a double dash (--) before a line to describe what is going on. You don't have to go into detail for every single line, but comment as much as possible. Descriptive variable names are always a benefit too.
If a fellow programmer was reading this code, how long would it take for them to understand what it does?
It would be much to ask to make your code understandable by a novice, however you should make your code be able to be interpreted by those at your same skill level. To answer this, share your code as you write it with others and see how well they're able to interpret it. If people start getting confused, try going back and seeing if you can make any edits to make your code clear. Helpful insight can come from this so don't be afraid to share unfinished work, or even broken code. You'll be able to write better code in the future this way and learn to solve problems on your own the more you ask early on.
Are any parts of my code repetitive, or recurring with only slight changes?
If yes, this is a sign of inefficiency. Try identifying where the slight change is, and reducing your code to a single chunk with that bit as a variable. Here's an example in pseudo code:
Bad
Good
As you can see, the only thing changing in the first code was the second number, so instead of making a long if chain that checks the frame constantly, it can be reduced to one line of code that will always be accurate without checking. Look for patterns, like the number increasing by 32 for each frame in this example, to see where you can fit a variable like this. One line of code is easier to update if need be rather than x amount of lines. Less is more.
Does my code work under specific circumstances, or universally?
The more you can reuse code the better. Code that can only be used in specific circumstances can be easy to lose track of and leaves you with bloated blocks that quickly turn into spaghetti code. Always assume an error will be thrown so make the code robust to handle anything that's thrown at it. If a negative number will break everything, just slap a math.abs() on the variable to knock that out as an example. If you have to be careful with what you send to your functions like that and make different blocks of code for different situations then try going back and revising instead of adding new code.
Is there a more efficient way of doing this?
This is similar to the repetitive code question and the example used. The math library can help knock out a lot of unneeded guess work when it comes to numbers. Most of the time you will be working with numbers so learn what you can do and take advantage of it. Doing the math can make your code more accurate than it is, and more universal as well. Take this code as an example:
Doing the math leaves you with this:
This example comes from Prado's water timer. There isn't an exact pattern with the code here, other than repetitive if blocks, so you'll have to pay attention to what you're looking for and see if you can make a math function that gives you the right value every time.
Am I using good practices? -credit to Hoeloe
Optimization is one thing, but there's actually another element to this too: standards and good practice.
There's actually a lot to this, but effectively there are certain standard ways things are done when programming. By no means are they the only way to achieve an effect, but they are standard because they have some benefit over other methods.
Code repetition is a good example. Doing something like this:
isn't inefficient, but it does have a problem. Here, you're repeating the same pattern of code 3 times. Now, what happens if you want to change that to this?
You COULD go around replacing every instance, but what if it's not all together like this, and instead dotted around a 2000 line file? It's quite likely you'll miss one, and then, at best things will not work as intended, at worst there will be some subtle bug that you won't notice right away.
To solve this, it's good practice to minimize repetition where possible. This isn't the same as optimizing the code - it doesn't make it run faster - it just allows less room for error when modifying the code later. Ideally, you'd do something like this:
Now, notice that if I want to change what the function does, I only have to edit one location in the code, rather than several at once.
Also note that I've put brackets around the equation. Again, this does not make it run faster, but it removes potential ambiguity in expressions, and makes it clearer what the code is doing.
Basically, optimization is a huge and important step, but good code practice is just as important. I've rewritten programs a lot of times, not because they ran slowly, but because they were difficult to read and understand, so I wrote them with better coding practice.
Also, where the function of some code isn't immediately obvious, comments are your friend.
Any more advice is welcome.
Starting with questions you should ask yourself to consider code quality:
- Can I easily explain what is going on with this part of my code?
- If a fellow programmer was reading this code, how long would it take for them to understand what it does?
- Are any parts of my code repetitive, or recurring with only slight changes?
- Does my code work under specific circumstances, or universally?
- Is there a more efficient way of doing this?
- Am I using good practices?
Can I easily explain what is going on with this part of my code?
If you can't easily explain what is going on, it will be hard for people to understand your scripts. Also, it will be harder for you to debug your own scripts if you are unable to identify where in your code you went wrong. It will be much harder to continue working on your script after taking a break from it, so it is best to make lines shorter and straight forward. Ask yourself this frequently. Lastly, if you can explain it then do it. You can insert comments into your code by adding a double dash (--) before a line to describe what is going on. You don't have to go into detail for every single line, but comment as much as possible. Descriptive variable names are always a benefit too.
If a fellow programmer was reading this code, how long would it take for them to understand what it does?
It would be much to ask to make your code understandable by a novice, however you should make your code be able to be interpreted by those at your same skill level. To answer this, share your code as you write it with others and see how well they're able to interpret it. If people start getting confused, try going back and seeing if you can make any edits to make your code clear. Helpful insight can come from this so don't be afraid to share unfinished work, or even broken code. You'll be able to write better code in the future this way and learn to solve problems on your own the more you ask early on.
Are any parts of my code repetitive, or recurring with only slight changes?
If yes, this is a sign of inefficiency. Try identifying where the slight change is, and reducing your code to a single chunk with that bit as a variable. Here's an example in pseudo code:
Bad
Code: Select all
if frame = 0 then
drawimage(x, 0, 32, 32)
elseif frame = 1
drawimage(x, 32, 32, 32)
elseif frame = 2
drawimage(x, 64, 32, 32)
elseif frame = 3
drawimage(x, 96, 32, 32)
elseif frame = 4
drawimage(x, 128, 32, 32)
...
end
Code: Select all
drawimage(x, frame * 32, 32, 32)
Does my code work under specific circumstances, or universally?
The more you can reuse code the better. Code that can only be used in specific circumstances can be easy to lose track of and leaves you with bloated blocks that quickly turn into spaghetti code. Always assume an error will be thrown so make the code robust to handle anything that's thrown at it. If a negative number will break everything, just slap a math.abs() on the variable to knock that out as an example. If you have to be careful with what you send to your functions like that and make different blocks of code for different situations then try going back and revising instead of adding new code.
Is there a more efficient way of doing this?
This is similar to the repetitive code question and the example used. The math library can help knock out a lot of unneeded guess work when it comes to numbers. Most of the time you will be working with numbers so learn what you can do and take advantage of it. Doing the math can make your code more accurate than it is, and more universal as well. Take this code as an example:
Code: Select all
function updateOxygen(timer)
if((timer < 1956) and (timer > 1755)) then
oxygen = 10;
end
if((timer <= 1755) and (timer > 1560)) then
oxygen = 9;
end
if((timer <= 1560) and (timer > 1365)) then
oxygen = 8;
end
if((timer <= 1365) and (timer > 1170)) then
oxygen = 7;
end
if((timer <= 1170) and (timer > 975)) then
oxygen = 6;
end
if((timer <= 975) and (timer > 780)) then
oxygen = 5;
end
if((timer <= 780) and (timer > 585)) then
oxygen = 4;
end
if((timer <= 585) and (timer > 390)) then
oxygen = 3;
end
if((timer <= 390) and (timer > 195)) then
oxygen = 2;
end
if((timer <= 195) and (timer > 0)) then
oxygen = 1;
end
if(timer <= 0 ) then
oxygen = 0;
end
end
Code: Select all
function updateOxygen(timer)
oxygen = math.abs(math.ceil((timer / 65) / 3))
end
Am I using good practices? -credit to Hoeloe
Optimization is one thing, but there's actually another element to this too: standards and good practice.
There's actually a lot to this, but effectively there are certain standard ways things are done when programming. By no means are they the only way to achieve an effect, but they are standard because they have some benefit over other methods.
Code repetition is a good example. Doing something like this:
Code: Select all
local x = 5;
local y = x*4+3;
local z = y*4+3;
local w = z*4+3;
Code: Select all
local x = 5;
local y = x*5+7;
local z = y*5+7;
local w = z*5+7;
To solve this, it's good practice to minimize repetition where possible. This isn't the same as optimizing the code - it doesn't make it run faster - it just allows less room for error when modifying the code later. Ideally, you'd do something like this:
Code: Select all
local function myfunc(val)
return (val*4)+3;
end
local x = 5;
local y = myfunc(x);
local z = myfunc(y);
local w = myfunc(z);
Also note that I've put brackets around the equation. Again, this does not make it run faster, but it removes potential ambiguity in expressions, and makes it clearer what the code is doing.
Basically, optimization is a huge and important step, but good code practice is just as important. I've rewritten programs a lot of times, not because they ran slowly, but because they were difficult to read and understand, so I wrote them with better coding practice.
Also, where the function of some code isn't immediately obvious, comments are your friend.
Any more advice is welcome.