Software Development: Hegel & Stendhal, Caffeine, Hacks & Dirt
The struggle between beautiful designs and messy reality in software development
Alejandro López Correa
10/15/20243 min read
Today I want to talk to you about one of those eternal battles: idealism versus reality. That battle between the beautiful diagrams in PowerPoint and the spaghetti code with patches and hacks, between the perfect architecture on paper and the real life code, with its tangles, patches, and scars. Between Hegel’s ideas and the stubborn resistance of the world. Basically, what could be called “theory crashes against the wall of implementation.”
Everything starts well; the world is beautiful and clean when there are only plans, plans of such beauty that they captivate the imagination of the developer, swept away by the Stendhal effect and an excessive consumption of caffeine. You make your flowchart, your modular architecture, your standard processes. But then it’s time to implement. And that’s where the devil sticks his paw in. What you thought of as something elegant and pristine turns into a Frankenstein full of hacks, dirt, tech debt, and, what the heck, the indecipherable arcane.
Let’s use an example, one of my favorites: video games. Let’s say you’re developing a game. At first, you make your engine. You have support for rendering graphics, animating characters, making that satisfying BOOM sound. The engine is the elegant part. But it turns out that to make the game fun, you have to add a thousand exceptions. The animation needs to be a bit faster in that scene, that character has to do a somersault just because, or that action has to break the physics to make the player feel powerful. Engines are there to support gameplay, but gameplay is fickle and doesn’t care about your precious architecture or your performant engine: it seeks fun, art.
The same happens in every other corner of the software world (and probably well beyond, any place where science, engineering, and craftsmanship collide with the messy unpredictability of the real world). Think of a search engine, like Google’s. Back in the 2000s, it was all PageRank and pure algorithms. How nice and simple. But over time, every user wants something different. Don’t show me the string ‘32*9’, give me the result, I don’t have all day! Or detect that I’m looking for flights and show me the most relevant options directly, or if I’m searching for a recipe, show me the ingredients and calories in a special tabular format. It’s these special cases that, after so many patches, turn that simple and elegant code into a formless monster with hundreds of thousands of lines of code (if not millions), full of systems and languages, but that ultimately provides a much better service to users.
And you know what? That’s normal. As you put your design into the real world, you start to discover its flaws, its limitations, the corners that never fit. Then, you stretch it, twist it, and end up with the dreaded “tech debt.” That technical debt doesn’t always come from laziness or rushing. Sometimes, quite commonly I’d say, the cause is that the original design was too Hegelian, it wanted to be perfect and neat, but the reality is that complexity is wild, and PowerPoints, diagrams, and top-down design alone can’t handle it.
Based on my extensive experience in software development, and from what I see in artificial intelligence, it’s exactly the same there. Beautiful designs, models that process enormous amounts of data with a relatively simple algorithm and achieve surprising emergent results. But something is always missing. To make something truly useful, a product with real intelligence, you have to get your hands dirty. You have to add those details, all those special cases, figure out ways to overcome the model’s weaknesses, you have to make it robust to the user’s little quirks and the circumstances of the environment.
And that’s where the true intelligence of a product is forged. Not in the theoretical potential of a brilliant algorithm, nor in the immense amount of processed data or model parameters, but in the meticulous work of adjusting it to real life to provide a useful service. That’s what turns an AI engine into a product: that ability to withstand and react to the unexpected, to have gameplay that feels alive. You have to write prompts, define information flows, manage errors, conduct internal reflection, consider latencies and user experience, select and combine a palette of models considering their ability and cost, provide fast and useful interfaces, implement specific procedures to handle common use cases, and even deal with the boredom of trolls or the malice of hackers.
And to conclude, a general piece of advice for any paper design: think about the flow of information through the system. Sooner or later, it will be necessary to make new information travel through part or all of that flow, often breaking encapsulation and establishing ugly interdependencies. A simple string field carried around with the flow of information through the system, able to store unstructured JSON data, can make the difference between needing a massive refactor at the worst moment or just a simple hack that doesn’t break the architecture too much.