Never Burn Money

Discovery

Your project has been running for years. It’s been through so many hands that nobody understands the whole thing. It is just too big. But it’s also too big to start over, too much has been invested in it. Unfortunately, the code was not well designed and is just getting worse with each new desired feature. We made a coding standard for all new code going forward, so why is it that things seem to be getting worse and not better? How can we fix this mess of spagetti?

The reason nothing is getting better is that nobody knows where to start from when adding a new feature. The code is so large that when you want to add something new, you don’t know what to build it on top of. There are no layers of the original app, because it’s grown over with the vines of so many special cases that were added by the coders before you. So everyone reinvents the wheel each time, making the project even larger.

But all is not lost! There is still a path to redemption!

What is really wrong is an issue of discovery. The project is so big that nobody knows the ‘best practice’ for this project to do any given task. “I want to make a scrolling list of UI items.” There’s a whole lot of ways to do that, and because this project is so big, there’s lots of examples. But none of them do quite what you need, or it could be more efficient. So you make your own version which does it better. And the next person comes along and knows _nothing_ about what you wrote, so they do it all over again.

The solution is actually very simple: an index document that lists generic tasks and points to specific examples of code that solve those tasks. In the Index, you’d search for “scrolling list of UI”, and it points to an exact file that demonstrates that task. Or it could get even more specific, like “for a few elements” and “for many many elements” and “with group headers”, all pointing to different examples in the code. With each entry it lists a one sentence blurb that clarifies what makes that example different from the others in the category.

One of the bonuses of an index document is that it can be searched easily, as there should not be a large amount of content for each kind of task.

Homework

A couple months go by. There are finally some good examples of doing several things in the project. The index document is pretty stable these days. But the project is still getting bigger somehow. What’s going on here?

We’ve started creating these ‘clean’ examples, but nobody is making them re-usable! They’re only doing copypasta!

The failure is that the app is not being designed in layers. When a new feature is requested, the code is being copied from the template instead of refactoring the template to provide shared code for both the template and the new feature. New rule: to add a feature you must add a layer, not modify existing code. You can refactor existing code to make that new layer, as long as you support the original with its own layer on you refactored base.

This sounds like a heavy burden in such a large codebase, but that will only happen when first starting out. It should happen less and less often, once we start doing it in earnest. This is because the more layers we add, the less special cases will be needed.

RAM

So that fixes that. Right? Not quite. This entire process change is a new coding standard. And if we’re doing our job, the coding standard will continue to improve, covering new situations that we haven’t handled before. Now we have an index file that’s pointing at the old examples, which don’t match the new standard. It’s still a better situation than we started with, true. But how can we tell that the examples are all following the latest standard? We can’t.

Yet again, there is a simple solution to this problem too. We ‘version’ the standard. With human understandable numbers, like ‘2.0.’ As we update code to adhere to a new standard, we simply comment the source file with a header mentioning “Code Standard 2.0.” The rule would then be: if you don’t see a coding standard tag, you’re not allowed to use it. If you see a tag but it’s old, verify that it still meets the latest standard and update the tag.

For ‘core’ objects that is used by many things like UIController, one tag for the header isn’t really enough – instead it gets included in specific method definitions. The idea is the same.

We can even extend this to best practices in our prefabs! A simple single MonoBehavior component that stores an enum of a coding standard version. Along with the Note component for commenting, it will clearly identify that the GameObject and children of that hierarchy are correctly following a given standard, and is therefore safe to use as a starting point for a new UI or system.

And there we have it. A way to untangle the mess without losing your hair.