Best practices on writing clean, compartmentalized code?

Hi all -

After a few months of practice, I feel I’m starting to reach the point where I can put something resembling an incremental 2D clicker game together.

However, I noticed that these days I quickly become overwhelmed by the sheer number of components I have to work with. For example, I have a GameController object that stores key variables such as food, wood, population etc. I then have scripts attached to buttons (such as buttons to build houses, to hire workers, etc) that reach into the GameController script to check and update their variables. I then have buttons for manually gathering food and wood, each with its own script which also reaches into GameController to impact the variables. I then have scripts that enable and disable buttons based on the contents of GameController variables. I have scripts that instantiate things. I have scripts that check for instantiated things. Given enough skill, I’d probably have scripts that wrote scripts.

In short, the longer I code, the more I feel I’m producing spaghetti code of sorts - something I can only make sense of while “in the flow” and probably would not know what to do with the next day! After a while, I feel defeated not by the complexity of the task, but by the sheer amount of variables and scripts that I’ve got to keep track of. Surely there’s got to be a better way?

Do you have any resources / references on how to code “cleaner”, for lack of a better word? Something that would help me keep things compartmentalized, manageable, and make it possible to only deal with isolated “chunks” of code when implementing a feature? For instance, should I have as many discrete scripts as possible each containing only a few functions that are closely related to what the script is trying to do? Or should I have a monster script (e.g., ButtonController) that is assigned to the OnClick of dozens of buttons across the UI?

After all, a 2D clicker game is clearly a very low-complexity project compared to professional AAA work - so if I’m struggling to handle what I built now, then I’m clearly doing something wrong.

Don’t know if the question makes sense, really - finding it quite hard to even describe the problem, other than the sense of looking at the code and going “Oh my God, this is overwhelming - and surely there’s got to be a sort of conceptual architecture of sorts out there to avoid this?”

George

Try to make methods all black boxes which don’t use any variables in the class where possible, this will cut down the amount of free radical variables, which cuts down the amount of spaghetti.

1 Like

Yeah, there’s no one simple answer to this — you’ve conjured up the demon of Complexity, which is indeed the biggest obstacle in software engineering. Many a project has been slain by it.

So, basically, all of software engineering is weapons in your arsenal against this monster. From object-oriented programming to component architecture, and hundreds of more specific techniques like encapsulation, data hiding, various design patterns, etc., are all ways to reduce complexity, or at least hide it under the rug while you’re working on the drapes. (Hmm, I think I’ve slipped into a mixed metaphor there.)

But cheer up! You’re better off than most beginners, who have never felt the pain of Complexity in their own projects. So as you learn about new techniques now, you will probably have that “oh!” moment that makes it really clear to you when and where that is useful. Somebody who’s never wrestled the demon themselves may learn the rules of good programming, but not really understand why they’re valuable (and so won’t know, for example, when the rules should be broken).

2 Likes

Part of the struggle is remembering the tip when you’ve got to the tail. So whatever you design, you know it’s the right one when you haven’t forgotten how it works by the time you finished it.

2 Likes

Thanks all!

I took another look through my code and recognized that one of the things lacking in my approach was consistency. I did not just have a metric ton of scripts - these scripts varied from managing a specific functionality, to a bunch of functionalities, to serving as an intermediary to enable a functionality.

This what the light bulb moment for me. I went through my code and realized that the number of the scripts wasn’t the problem - inability to tell, at a glance, what each one did, was. So, instead of looking for ways to consolidate scripts (and potentially make things even more confusing), I instead decide to focus on mini-scripts, each one responsible for a very specific part of the code.

For example, I ended up with the following scripts:

  • Script that instantiates a menu prefub
  • Script that manages the buttons for the addition of each resource (of which there are four) within than menu
  • Script that manages the buttons for the substitution of each resource within than menu
  • Script that manages the labels showing how much of each resource is allocated (again, x4)

Is it a lot of scripts and could they probably be consolidated into something more generic? Sure - but, right now, I feel I’d end up adding more complexity and making my own project less comprehensible if I tried to refactor the code here and now.

Thanks a bunch, everyone, for your replies - much appreciated!

1 Like

I think one of the things you can strive to do is separate game logic from your display/client logic. So for your clicker game, all of that data for upgrades, items, food, etc shouldn’t be tied to a component / monobehavior. Then for your client side, you need to display the data onto the screen, so you create components to read your data. Using your example, you wouldn’t need to have the 4 different scripts then. The substitution / addition and even the updating of all the buttons/labels will just correspond to what your data shows. So you would just need a script to update your UI based on the current state of the data. For example, if your building gains 4 resources, it can show those, if it loses 2, it can update the UI using the same exact script. The same applies for labels, etc.