I was examining a localization system recently, and I noticed it had implemented a very nice approach. The strings were stored in a JSON-like file, simple and easy to manage. Something like this:

{
  "welcome": "Welcome!",
  "goodbye": "Goodbye!"
}

Then there was a code generator that generated code files from those strings:

public static class Strings
{
    public const string Welcome = "Welcome!";
    public const string Goodbye = "Goodbye!";
}

Now, instead of manually accessing a raw string by its key, you could simply write:

var text = Strings.Welcome;

The benefit of this system is that it allows you to avoid hacky ways of accessing raw input. A compiler or code generator takes your strings and turns them into usable code, so you can simply import and use them in your files while taking advantage of IntelliSense without missing a beat. If you know about the typed-css-modules package in Node.js, you know what I'm talking about. It can generate .css.d.ts files, allowing you to import from CSS files without losing the benefits of autocomplete.

This mindset was also something I recently read about in The Pragmatic Programmer. I remembered the authors talking about writing code that writes code. They spoke so fondly about the idea that I found myself thinking, "Maybe they love it because this book is old and they didn't have many ready-made options back then." But now I realize what they were talking about.

So I started questioning my previous choices. I thought, maybe it would've been much better if I had used this mindset when implementing the localization system in my Unity game. Why didn't I? The first issue that came to mind was that I mostly assigned text through the GUI, so maybe I would have needed to come up with an enum generator as well. Then a bigger issue came up: compiling code in Unity takes a long time.

I wanted to implement a simple, pragmatic method that was supposed to make my job easier, but there was this big wall, my so-called "tool", that I also had to get past. Maybe my tool wasn't appropriate for the job. Maybe it'll be fixed in the future updates, but the point is not "Unity" specifically. It's this big dependency that we add to our projects.

I realized that this is one of the problems with abstraction. Unity abstracts away a huge amount of lower-level code. That can be good in some ways, but it can also change your struggle into, "How do I work most effectively with Unity?" That is also why specialists in these fields are valuable. Understanding the ins and outs of an engine requires a lot of time and energy. And even then, you probably won't understand most of it and with each update you might be given a whole new program. Unity doesn't optimize for your team, it optimizes for the average team.

So, is it even worth it? These frameworks and layers of abstraction save you time in the moment, but over time, you also have to account for the hours you spend learning your engine, a black box whose internals you might not even have access to. Are you really sure that, in the long run, building your own engine or using a lower-level framework would take more time than learning and working around the limitations of Unity or Unreal?

This is similar to writing code faster. You could hypothetically write programs twice as fast (by hand), but if doing so creates twice as many bugs, it might not be worth it anymore. Is abstraction really helping you?

I have to say that I'm not against abstraction in general. I think it's great for the people who create these abstractions, and it's certainly great for other people from time to time. I definitely wouldn't go write C code for a web development commission. But we have to be mindful: to what degree should we accept abstraction?

Sometimes, if not most of the time, it's easier to understand how something works than to learn how a reworked version of that thing works. Imagine you need to drive somewhere. You can learn the basic rules of driving, or you can use a highly automated car that does everything for you, but first, you have to learn all of its buttons, modes, warnings, and strange behaviors. The automation may still be useful, but sometimes learning the underlying thing is actually simpler than learning the system built to hide it.

The question here is about trade-offs. Does the automated tool you're using actually benefit you in the long run? Is it worth learning all this jargon just to conserve a little more energy? You can ask other people as well, but beware: the sunk cost fallacy can strongly influence these discussions. Someone might say, "Yeah, it's awesome," simply because they've already invested so much time and energy into that thing that they don't want to start from scratch.

Sometimes, the trade-off isn't really calculable. So, do you want to risk spending your time learning something that might pay off in the future, or something that might ultimately waste even more of your time in the long run?

While this article is not related to AI, I want to end it by mentioning how much of absraction has AI added to our development cycles. Abstractions back then were just things we didn't know, not things that nobody knew. Unity has a lot of developers who create the stuff that's there. they make very precise documentations on how the engine works under the hood and how to optimize it in great details. you don't learn Unity by just throwing words at it and see how it reacts, to find some patterns. But we do that with AI. A real black box whose output has some element of randomnessand you can only learn it by trial and error. It might make your life easier now, but the technical debt it adds to your project is something you can't ignore forever. Even though I'm practically doing "AI Engineering" for work, it's a really scary tool for development and I'm yet unsure what's the actual good usage of it except for doing very mundane tasks like renaming some variables or such refactoring processes.