|
> There is definitionally no more efficient way to improve the performance of a system than sequentially targeting each new bottleneck in its performance and nothing else. Doing so misses any state you can't hit via small iterations (you'll find a local minimum rather than global). It's easy to whack-a-mole every performance bug you can find and still miss that swapping to a columnar representation or using 32-bit keys instead of 64-bit is all you need to double performance for your program. Or that, in effect, the big ball of classes are executing something quadratic when linear solutions exist, but since that degredation isn't isolated to a small unit of code you can't identify it. Doing so, even when you _can_ iterate to the global minimum, isn't guaranteed to be the most efficient path either. Imagine, e.g., speeding up foo (the slowest thing [0]), then speeding up bar (the next slowest thing), and finding in your refactor of bar that you no longer need foo. All the optimizations that went into foo were wasted. In practice, I've had a lot of success using "lines of code deleted" as an initial north star. Rather than trying to optimize from the get-go, focus on changes which remove a bunch of code, or better yet make it easier to remove even more code in the near future. Once you've trimmed it down 5-10x [1], it's probably already faster and less buggy, but at that point the task of actually optimizing is much easier. I don't know that doing so is the most efficient solution per se, but whack-a-mole performance fixes I think are usually worse. [0] If bar calls foo, then obviously bar is actually slower than foo (ignoring mutual recursion), but you have to pick a small enough unit to optimize; it's not very helpful to note that main() is your longest-running function call. In a real refactor you very well might have the foo->bar sequencing e.g. by seeing that the majority of bar's time is spent calling foo, thus concluding that foo is the "culprit" or otherwise has some low-hanging fruit. [1] Almost all software I've seen has a tendency to accumulate cruft over time. That isn't a criticism of any individual's abilities, just an observation that the march toward new features tends to invalidate previous assumptions and degrade the project's code quality over time. Moreover, the act of running the previous version teaches things you didn't know when that previous version was written, allowing even the same author to make better informed decisions. If/when somebody decides performance is important, there's almost always an opportunity to delete a ton of code. |
When I worked in manufacturing, we distinguished between “continuous improvement,” which were these smaller improvements that will get you to a local minimum, and “radical transformation,” which will get you significant improvements and requires redesign of the entire system.