Mike was telling me about some advice for programmers, which is that premature abstraction is as bad as premature optimization. The idea is that abstracting too soon (i.e. before you know how to solve your problem) can cause problems later on when your assumptions change. Which is the same thing that you see in premature optimization. On the face of it, it sounds like simple advice, but there are some cultural reasons why it's not.
Abstraction and optimization act as opposing forces in software design. Optimization is always trying to push your algorithm closer to the metal, closer to the silicon. Optimization rejoices at side effects and arcane trickery. Abstraction is trying to push your algorithm away from the silicon. The mindset of abstraction is to make sure you never have to worry about those messy details. Abstraction rejoices at eliminating your algorithm completely by delegating it to a lower level. So abstraction allows a large group of developers to work on a vast project without slowing eachother down. Optimization on the other hand, allows code to run fast enough to be useful.
For academic applications, abstraction is more important. (If your code is slow you just come back in the morning.) So, that's why they teach you abstraction in school.* But for games, optimization is king. Generally, the optimization mind-set is not taught. You have to seek it out, you have to believe in it.
My belief, as a games programmer, is that abstraction is only permissible as long as it doesn't get in the way of necessary optimization. I currently am in the middle of a battle with a culture that seems to believe in abstraction as an inherent good, as a higher order value than optimization. I find that frustrating.
*There are lots of good reasons to teach abstraction, it's a difficult and important skill and it can color the way you think for the rest of your life. Optimization on the other hand is by nature tied to the specific technology that you're working with, it's far less generally applicable and it tends to be full of tricks, instead of full of insight.
Well put. There's no simple solution.
ReplyDeleteContrary to what you wrote:
> The idea is that abstracting too soon (i.e. before you know how to solve your problem) can cause problems later on when your assumptions change.
I find that abstraction done right makes changes very easy. For example, just change code in one place to pass the parameter you need (out of thin air, as it were), re-compile, find and change each place that needs to pass the data, and then when no errors occur, you're done; you've made the smallest opening in the abstraction armor possible, and you get the data you need from this part of the program way over here and make it accessible over there. (This only works in statically compiled languages, which is why I find them to be more flexible and easier to make changes to than dynamic languages like Python, JavaScript, which require you to constantly run and test each change, and think really hard about where old code might break.)
You're absolutely right that optimization tends to break down abstractions and sort of merges their multiple functions into one, more optimized, hairy algorithm. That's the constant battle in building large (or medium sized) systems.
In an ideal world, programmers could build hairy but optimized prototypes like only performance mattered, and then refactor, cleaning up and adding proper abstractions. Or they could start with pure abstractions and then fix performance with a rewrite. As you mentioned, they usually pick the latter when neither extreme is really preferable if a rewrite is required; sometimes rewrites cannot be avoided without the post hoc knowledge gained from writing the slow or hairy code.