Hello, I’ve been an on and off developer for a while. I find that every time I take a break longer than a week I just get completely confused by my own code, and take a few days just delving into a single 550 line script because it is so poorly organized. I was hoping to get some tips to help me with this.
Give us an example of code you’ve written which is unorganized.
honestly i’ve been finding myself doing the same thing, id like some tips on this as well.
edit: not trying to hijack your thread or anything lol just pointing out that your not the only one in that boat
If your code is not clear, then add comments! In the comments describe exactly why you created the variable, what it’s supposed to solve, and any other relavant thoughts about it.
Poor code, you must read more code to determine what this means:
var hitPoints = 5;
Good code, you can easily find out what hitPoints means by reading comments:
// Hit points starts at some arbitrary, positive number and can only go down.
// Once the variable hits 0, then a detonation occurs and the Die() method is invoked.
// You are not supposed to modify this variable directly, instead call ApplyDamage()
var hitPoints = 5;
Again, don’t be afraid to add a lot of comments. I don’t care if you have to write a whole book on one int variable
Hmm, yeah I suppose I could add more comments. My current problem isn’t understanding my code though, it’s organizing it. A great example:
I’m writing a part of my character script to handle the character’s combat. Later, I decide it’s inefficient, comment it out (incase the new method doesn’t work, so at least I have a working way of doing combat), but forget to delete it. This is an actual example from today. Came back to my project after months, realized I had turned off the combat system when trying to develop some AI. When I finished the AI today, I went to turn the combat on and had to figure out which of the 3 or so versions of combat I actually wanted.
Any tips to avoiding this sort of thing (Obviously “avoid it”, but any tips for actually…doing it?)
I can’t say I’ve ever experienced that kind of problem…
I recomend to read ‘Domain Driven Design Online’ - it is free and enough short book (about 100 pages), there are lot of good advices and examples of best practices and code organisation. For example, one of them could help you to make your code more readable and understandable - extract conditions - replace most difficult and unreadable conditions with special methonds.
Instead of such code:
if(player.tranform.position = finishPoint.transform.position & playerRank == 1)
{
...
}
Recomended to write this one:
if(IsPlayerFinishedFirst())
{
...
}
/// returns true if player comes to finish ranked first
bool IsPlayerFinishedFirst()
{
return player.tranform.position = finishPoint.transform.position & playerRank == 1;
}
Good luck
i have experienced the exact same situation he just described, i use comments quite often to remove temporarily some parts of my code to test different ideas without removing what i tried before as i might want to look at it again. one thing i do is i add some white space, like a couple empty lines between each version to separate them, then i make a specific comment just saying which one it is, and describing the problem(s) with that specific version. that way i can atleast tell which part is which without having to go line by line trying to remember what i did the night before specifically.
If you need lots of comments to explain what you’re doing then chances are your design isn’t particularly elegant. I like the idea of “self-documenting code”, which is basically code where its structure and naming tells you what it does without needing (much) extra information.
That doesn’t mean “don’t write comments”. It means that you should think about making your design and implementation as reasonably comprehensible on its own, and then add comments to fill the gaps.
There are downsides to the “lots of comments” approach. First of all, in a real world working environment there’s plenty of cases where you or someone else won’t have time to update the comments in tandem with the code. What’s worse than no comments? Incorrect comments! People will rely on them, then get led into a back alley and clobbered, before having to undo whatever they tried and then starting to read the code. If the incorrect comments weren’t there they’d have started with that and saved some time.
Anyway, to get my design nice I typically think about things in terms of roles and responsibilities. Each thing (class, function or variable) should only have one role, and as few responsibilities as possible as a part of that role. If you find yourself cramming multiple roles or too many responsibilities into one thing… split it up. If you’re doing this, any competent coder should be able to look at any part of your code and from the class, function and variable names alone tell you what its role is and what responsibilities make up that role. Also, if you described the role and responsibilities to any competent coder they should be able to code it up in a reasonably straightforward manner - if they can’t then your definitions aren’t clear enough.
This typically leads to clean, relatively compartmentalised, and easily understandable units of code. It takes practice to get the roles and responsibilities thing down, but it’s definitely worth it.
Thanks for the advice guys. It’s crazy late for me, so no time to try them out, but after reading them I can see how they’d be helpful. Will try to implement them asap.
All games need global variables(score, player, gameActive, etc …). For this, create a Base class derived from MonoBehaviour, for example Game class
public abstract class Game : MonoBehaviour{
protected static int Private_Global_Static_Int = 0;
public static int Public__Global_Static_Int = 0;
}
Abstract class doesn’t instantiate(you need derive it) and doesn’t appear in Component menu.
All other classes must be derived from that type.
Important, organize your scripts or derived classes by elements (GUI, control, particles) using [AddComponentMenu(“Scripts/TypeElement/nameClass”)]
If you don’t want include the script in Component menu, add in the header [AddComponentMenu(“”)]. Abstract or Static class, or personal classes(don’t derive from MonoBehaviour) don’t appear in Component menu.
Sometimes it helps, sometimes it leads to higher coupling.
What you will do when you will need to change some logic in base class? You will have to test all inherited classes to be sure if it still works
I have to disagree.
Comments clutter up your code and take your attention away from the most important thing in code… the code!
Good code is self explanatory, and rarely needs comments.
The fact that you explain in the comment that hitPoints can only go down is not a very good idea, what if later on you implement a HP-Potions which restores your hitPoints, you will also have to revisit a unnessacary comment.
int hitPoints; is in itself explanatory, the name tells you what it does.
I suggest you to get a copy of the book “Clean Code” by Robert C. Martin and read it from time to time. It contains many tips and advices to write code that other developers and yourself will understand better. You may find a collection of the most important tips around the web but the book also explains the reason why to use it.
There is also a “community” around it here: http://www.clean-code-developer.com/
Anyway, writing good code is not a matter of lack of tips but often a lack of experience and discipline. It is hard work to obey these tips in day to day work because often we want it quick and dirty (deadlines, ideas). Thats why clean code is not written in the code the first time it is refactored into it countless times you read it again. So you find a method you don’t understand any more and you work on it and change some variable names, extract a method or a new type etc… So you should always leave the code in a better state than you find it, especially when you see it is not readable by yourself.
From my point of view this is a pretty bad example since the purpose of a variable should NOT be defined by a 3 line comment. Comments have the tendency to “rot” faster than the code since code gets moved around and comments get invalid over time. Only the code is valid and it should speak more or less for itself.
Let version control handle it. Check in a working version, modify the code and if it does not work retrieve to a previous state. If you want to experiment create a branch.
If you comment out code put a tag and or explanation in the comment why it is there. In most IDE’s you can search for such tags (like todo, hack) and navigate to them.
Putting your code under source control can help a lot in cases like your example above. If you had your code under source control then you would have been able code and experiment mercilessly since you would always be able to go back in time to where your code worked.
im going to have to look into source control, that sounds wonderful
-
Break down your code into single-action or single-idea methods. Methods should usually not go over 10-20 lines of code. Sure, there’s always some case where you will get a big ugly block of a hundred line of code, such as drawing GUI, but it should be an exception, and you should try to break it down into smaller manageable chunks.
-
Break down your method into smaller “paragraph”. You have empty line for a reason, to group of logical sub-action with each other. Consider a novel; if someone didn’t use chapters, paragraphs and tabulation, reading it would be one major pain. Don’t care about “packing more” in your screen, it just makes it unreadable.
-
Name everything with a meaningful name. It doesn’t matter if that member has a looooong name. It should be self-explanatory. If you need a comment to explain what a variable does, this variable is not properly named or properly designed.
-
Comment every public, accessible member with something SHORT and meaningful. Comment are NOT for writing a novel, they are there to explain what your very short methods does that the name couldn’t fully cover, like what the parameters should be or any edge-case. If you build a library, export the damn comment XML! (you know, what Unity doesn’t do…)
-
Keep in-code comment to a minimum. If everything is named and structured properly, you should almost never have to.
// If it's true, we should exit this method
if (value)
return;
ಠ_ಠ Don’t do that.
Actually GUI can be split in small chunks as well :
this.drawEnergyBars();
this.drawLeftMenu();
this.drawMiniMap();
etc…
I wouldn’t write “this.” when you call internal members. It just adds characters for no reason.
And yes, GUI can be split, but something you can’t… I have in mind a class that handles customization of character, and it bakes the new character into a single mesh.
While I have many methods that handles specific job, there’s a method that goes
List<GameObject> parts = new List<GameObject>();
List<Texture> partTextures = new List<Texture>();
GameObject go = ProcessPart(headPrefab);
parts.Add(go);
partTexture.Add(GetTexture(go));
go = ProcessPart(shoulderPrefab);
parts.Add(go);
partTexture.Add(GetTexture(go));
go = ProcessPart(torsoPrefab);
parts.Add(go);
partTexture.Add(GetTexture(go));
if (headExtraPrefab != null)
{
go = ProcessPart(headExtraPrefab );
parts.Add(go);
partTexture.Add(GetTexture(go));
}
// etc for every single parts that makes a character
// ...
// ...
GameObject merged = MergeParts(parts);
Texture texture = MergeTexture(partTextures);
Shader shader = GetShader();
SetMaterial(merged, shader, texture);
SetAnimator(merged);
SetSkeletton(merged);
// and so on
It’s a list of method call. It could be broken down into smaller method, but each of those method would be meaningless and make it very hard to manage properly. I call those method “shopping list”, because they are just that, a list of thing to do. They don’t do anything on their own, but tell everybody else what to do.
You could have a simple enum+class that store the type + prefab, and instead of variables for each part you make an editor script that allows you to set one item per enum value in an array, then instead of repeating the processing code you could loop through the list of parts… But I’m being picky