upvote
Huh, I've always understood that quote very differently, with emphasis on "premature" ... not as in, "don't optimize" but more as in "don't optimize before you've understood the problem" ... or, as a CS professor of mine said "Make it work first, THEN make it work fast" ...
reply
And if you know in advance that a function will be in the critical path, and it needs to perform some operation on N items, and N will be large, it’s not premature to consider the speed of that loop.
reply
Another thought: many (most?) of these "rules" were before widespread distributed computing. I don't think Knuth had in mind a loop that is reading from a database at 100ms each time.

I've seen people write some really head shaking code that makes remote calls in a loop that don't actually depend on each other. I wonder to what extend they are thinking "don't bother with optimization / speed for now"

reply
First, I agree with what you're saying.

But second, I'd remove "optimization" from considering here. The code you're describing isn't slow, it's bad code that also happens to be slow. Don't write bad code, ever, if you can knowingly avoid it.

It's OK to write good, clear, slow code when correctness and understandability is more important that optimizing that particular bit. It's not OK to write boneheaded code.

(Exception: After you've written the working program, it turns out that you have all the information to make the query once in one part of the broader program, but don't have all the information to make it a second time until flow reaches another, decoupled part of the program. It may be the lesser evil to do that than rearrange the entire thing to pass all the necessary state around, although you're making a deal with the devil and pinky swearing never to add a 3rd call, then a 4th, then a 5th, then...)

reply
If you really have a loop that is reading from a database at 100ms each time, that's not because of not having optimized it prematurely, that's just stupid.
reply
Reminds me of this quote which I recently found and like:

> look, I'm sorry, but the rule is simple: if you made something 2x faster, you might have done something smart if you made something 100x faster, you definitely just stopped doing something stupid

https://x.com/rygorous/status/1271296834439282690

reply
Got it. What about initiating a 800mb image on a CPU limited virtual machine that THEN hits a database, before responding to a user request on a 300ms roundtrip? I think we need a new word to describe the average experience, stupidity doesn't fit.
reply
And yet... :)

I think there is just a current (I've seen it mostly in Jr engineers) that you should just ignore any aspect of performance until "later"

reply
and, I guess, context does matter. If you need to make 10 calls to gather up some info to generate something, but you only need to do this once a day, or hour, and if the whole process takes a few seconds that's fine, I could see the argument that just doing the calls one at a time linearly is simpler write/read/maintain.
reply
Just remember Rob Pike's 1st rule: don't assume where bottlenecks will occur, but verify it.
reply
I've worked on optimizing modern slow code. Once you optimize a few bottlenecks it turns out it's very hard to optimize because the rest of the time is spread out over the whole code without any small bottlenecks and it's all written in a slow language with no thought for performance.
reply
From my understanding you still need to care care about the algorithms and architecture. If N is sufficiently large, you should pick O(N) algorithm over O(N^2). But usually there is a tradeoff, simple code (or hiding something behind some abstraction) might be easier to understand and maintain, but it might work slower with large input data and vice versa. I would rather write code that will be easier to optimize if there is some bottleneck than to optimize it overagressivelly. Also, different code needs different kind of optimization. Sometimes the code might be more IO heavy (disk / DB or network), for this type of code, the IO operation planning and caching is more critical than the optimization of the raw CPU time. Sometimes the input is too small to have any significant performance effects, and, what's paradoxical, choosing smarter algorithms might even hurt performance (alongside the maintanability). For example, for 10 - 100 items a simple linear scan in an array might be faster than using a O(log n) binary search tree. It's also well known that faster executable code (regardless of being hand written, machine generated, high level or machine code) usually has larger size (mostly because it's more "unrolled", duplicated and more complex when advanced algorithms are used). If you optimize the speed everywhere, the binary size tends to increase, causing more cache misses, which might hurt the performance more than improve. This is why some profiling is often needed for large software than simply passing O3.
reply
We will optimize it later, we don't have time for that right now, it seems it works fast enough for our needs right now.

"Later" never comes and all critical performance issues are either ignored, hot-patched externally with caches of various quality or just with more expensive hardware.

reply
My favourite quote for that is:

Broken gets fixed, but crappy stays forever

reply
While what you say is often true, it is a different problem and does not change the fact of the prior posters.
reply
Plenty of people seem to understand it as, "don't even think about performance until someone has made a strong enough business case that the performance is sufficiently bad as to impact profits".
reply
well you see, in corporate (atleast in big tech), this is usually used as a justification to merge inefficient code (we will optimize it later). That later never comes, either the developers/management moves on or the work item never gets prioritized. That is until the bad software either causes outages or customer churn. Then it is fixed and shown as high impact in your next promo packet.
reply
IDK if it can be applied in all situations.

Sometimes, especially when it comes to distributed systems, going from working solution to fast working solution requires full blown up redesign from scratch.

reply
I agree with you. "Premature" is the keyword. Bloated software is the result of not having the intention to optimize it at all.
reply
> Make it work first, THEN make it work fast

1. I have seen too many "make it work first" that ended up absolute shitshow that was notoriously difficult to do anything with. You can build the software right the first time

2. The "fast" part is what I think too many people are focusing on and in my experience the "THEN" part is always missing resources utilization and other types of inefficiency that are not necessarily related to speed. I have seen absolute messes of software that work really fast

reply
Ditto here
reply
Another one from my personal experience: apply DRY principles (don't repeat yourself) the third time you need something. Or in other words: you're allowed to copy-and-paste the same piece of code in two different places.

Far too often we generalise a piece of logic that we need in one or two places, making things more complicated for ourselves whenever they inevitably start to differ. And chances are very slim we will actually need it more than twice.

Premature generalisation is the most common mistake that separates a junior developer from an experienced one.

reply
The rule of 3 is awful because it focuses on the wrong thing. If two instances of the same logic represent the same concept, they should be shared. If 10 instances of the same logic represent unrelated concepts, they should be duplicated.

The goal is to have code that corresponds to a coherent conceptual model for whatever you are doing, and the resulting codebase should clearly reflect the design of the system. Once I started thinking about code in these terms, I realized that questions like "DRY vs YAGNI" were not meaningful.

reply
Of course, the rule of 3 is saying that you often _can't tell_ what the shared concept between different instances is until you have at least 3 examples.

It's not about copying identical code twice, it's about refactoring similar code into a shared function once you have enough examples to be able to see what the shared core is.

reply
But don’t let the rule of 3 be an excuse for you to not critically assess the abstract concepts that your program is operating upon and within.

I too often see junior engineers (and senior data scientists…) write code procedurally, with giant functions and many, many if statements, presumably because in their brain they’re thinking about “1st I do this if this, 2nd I do that if that, etc”.

reply
3 just seems arbitrary in practice though. In my job we share code when it makes sense and don’t when it doesn’t, and that serves us just fine
reply
I agree. And I think this also distills down to Rob Pike’s rule 5, or something quite like it. If your design prioritizes modeling the domain’s data, shaping algorithms around that model, it’s usually trivial to determine how likely some “duplication” is operating on shared concepts, versus merely following a similar pattern. It may even help you refine the data model itself when confronted with the question.
reply
Agreed. DRY is a compression algorithm. The rule of 3 is a bad compression algorithm. Good abstraction is not compression at all.
reply
The devil’s in the details, as usual. No rule should be followed to the letter, which is what the top comment was initially complaining about.

Yet again, understanding when to follow a rule of thumb or not is another thing that separates the junior from the senior.

reply
> If two instances of the same logic represent the same concept, they should be shared. If 10 instances of the same logic represent unrelated concepts, they should be duplicated.

Exactly.

reply
I think we should not even generalize it down to a rule of three, because then you're outsourcing your critical thinking to a rule rather than doing the thinking yourself.

Instead, I tend to ask: if I change this code here, will I always also need to change it over there?

Copy-paste is good as long as I'm just repeating patterns. A for loop is a pattern. I use for loops in many places. That doesn't mean I need to somehow abstract out for loops because I'm repeating myself.

But if I have logic that says that button_b.x = button_a.x + button_a.w + padding, then I should make sure that I only write that information down once, so that it stays consistent throughout the program.

reply
The reason for the rule of thumb is because you don't know whether you will need to change this code here when you change it there until you've written several instances of the pattern. Oftentimes different generalizations become appropriate for N=1, N=2, N>=3 && N <= 10, N>=10 && N<=100, and N>=100.

Your example is a pretty good one. In most practical applications, you do not want to be setting button x coordinates manually. You want to use a layout manager, like CSS Flexbox or Jetpack Compose's Row or Java Swing's FlowLayout, which takes in a padding and a direction for a collection of elements and automatically figures out where they should be placed. But if you only have one button, this is overkill. If you only have two buttons, this is overkill. If you have 3 buttons, you should start to realize this is the pattern and reach for the right abstraction. If you get to 10 buttons, you'll realize that you need to arrange them in 2D as well and handle how they grow & shrink as you resize the window, and there's a good chance you need a more powerful abstraction.

reply
> Instead, I tend to ask: if I change this code here, will I always also need to change it over there?

IMO, this is the exact (and arguably only) question to ask.

reply
Critical thinkers understand that rules aren't written for critical thinkers; that they are written for beginners who don't yet have the necessary experience to be able to think critically.
reply
IMO, the right way to think about DRY is to consider why a given piece of code would ever change.

If you have two copies of some piece of code, and you can reasonably say that if you ever want to update one copy then you will almost certainly want to update the other copy as well, then it's probably a good idea to try to merge them and keep that logic in some centralized place.

On the other hand, if you have three copies of the same piece of code, but they kind of just "happen to" be identical and it's completely plausible that any one of the copies will be modified in the future for reasons which won't affect the other copies, maybe keeping them separate is a good idea.

And of course, it's sometimes worth it to keep two or more different copies which do share the same "reason to change". This is especially clear when you have the copies in different repositories, where making the code "DRY" would mean introducing dependencies between repositories which has its own costs.

reply
I really like Casey Muratori's "[Semantic] Compression-oriented programming" - which is the philosophical backing of "WET" (Write Everything Twice) counterpart to DRY.

https://caseymuratori.com/blog_0015

reply
It’s not how many times, it’s what you do about it. DRY doesn’t mean you have to make abstractions for everything. It means you don’t repeat yourself. That is, if two pieces of code are identical, chances are one of them shouldn’t exist. There are a lot of simple ways you might be able to address that, starting from the most obvious one, which is to just literally delete one of them. Abstraction should be about the last tool you reach for, but for most people it’s unfortunately the first.
reply
This is so true. I have been burned by this more times than I can count. You see two functions that look similar, you extract a shared utility, and then six months later one of them needs a slightly different behavior and now you are fighting your own abstraction instead of just changing one line in a copy. The rule of three is a good default. Let the pattern prove itself before you try to generalize it.
reply
I had a situation where we need to implement a protocol. The spec was fairly decent but the public implementations of the other end were slightly non compliant which necessitated special casing. Plus multiple versions etc.

An expensive consultant suggested creating pristine implementation and then writing a rule layer that would modify things as needed and deploying the whole thing as a pile of lamdba functions.

I copy pasted the protocol consumer file per producer and made all the necessary changes with proper documentation and mocks. Got it working quickly and we could add new ones without affecting.

If I'd try to keep it DRY, i think it would be a leaky mess.

reply
The instances should be based on the context. For example we had a few different API providers for the same thing, and someone refactored the separate classes into a single one that treats all of the APIs the same.

Well, turns out that 3 of the APIs changed the way they return the data, so instead of separating the logic, someone kept adding a bunch of if statements into a single function in order to avoid repeating the code in multiple places. It was a nightmare to maintain and I ended up completely refactoring it, and even tho some of the code was repeated, it was much easier to maintain and accommodate to the API changes.

reply
I think this is a reasonable rule of thumb, but there are also times that the code you are about to write a second time is extremely portable and can easily be made reusable (say less than 5 minutes of extra time to make the abstraction). In these cases I think it's worth it to go ahead and do it.

Having identical logic in multiple places (even only 2) is a big contributor to technical debt, since if you're searching for something and you find it and fix it /once/ we often thing of the job as done. Then the "there is still a bug and I already fixed that" confusion is avoided by staying DRY.

reply
The D stands for "dependency", the R stands for "regret" and I'm not sure what the Y stands for yet.
reply
Yelling... it stands for yelling...

Mostly at the massive switch statements and 1000 line's of flow control logic that end up embedded someplace where they really dont belong in the worst cases.

reply
You say that, but I've created plenty of production bugs because two different implementations diverge. Easier to avoid such bugs if we just share the implementation.
reply
I've also seen a lot of production bugs because two things that appeared to be a copy/paste where actually conceptually different and making them common made the whole much more complex trying to get common code to handle things that diverged even though they started from the same place.
reply
DRY follows WET (Write Everything Twice).
reply
Agreed, I think even Carmack advocates this rule
reply
deleted
reply
My rule of thumb is “when I have to make changes to this later, how annoying is it going to be to make the same change in multiple places?”

Sometimes four or five doesn’t seem too bad, sometimes two is too many

reply
“Once, twice, automate/abstract” is a good general rule but you have to understand that the thing you’re counting isn’t appearances in the source code, it’s repetitions of the same logic in the same context. It’s gotta mean the same, not just look the same.
reply
More critical in my mind is investigating the "inevitably start to differ" option.

If two pieces of code use the same functionality by coincidence but could possibly evolve differently then don't refactor. Don't even refactor if this happens three, four, or five times. Because even if the code may be identical today the features are not actually identical.

But if you have two uses of code that actually semantically identical and will assuredly evolve together then go ahead and refactor to remove duplication.

reply
Depends on length and complexity, imho. If it's more than a line or two of procedure? Or involves anything counterintuitive? DRY at 2.

Extract a method or object if it's something that feels conceptually a "thing" even if it has only one use. Most tools to DRY your code also help by providing a bit of encapsulation that do a great job of tidying things up to force you to think about "should I be letting this out of domain stuff leak in here?"

reply
Ehh, people who are really excited about DRY write unreadable convoluted code, where the bulk of the code is abstractions invented to avoid rewriting a small amount of code and unless you're very familiar with the codebase reasoning about what it actually does is a mystery because related pieces of functionality are very far away from each other.
reply
DRY is not to avoid writing code (of any amount). DRY is a maintainability feature. "Unless you're very familiar with the code" you probably won't remember that you have to make this change in two places instead of one. DRY makes life easier for future you, and anyone else unfortunate to encounter (y)our mess.
reply
You are confusing DRY done as intended vs what DRY looks like in the real world to many people.
reply
deleted
reply
Making maintainable code is a good goal.

DRY is one step removed from that goal and people use it to make very unmaintainable code because they confuse any repeated code with unmaintainability. (or their theory that some day we might want to repeat this code so we might as well pre-DRY it)

The result is often a horrendous complex mess. Imagine a cookbook with a cookie recipe that resided on 47 different pages (40 of which were pointers on where to find other pointers on where to find other pointers on where to find a step) in attempts to never write the same step twice in the whole book or your planned sequels in a 20 volume set.

reply
It's almost like there's a "reasonable person" type of standard that's impossible to nail down in a general rule...
reply
If you can describe a rule in one sentence it'll probably lead to as much trouble as it fixes.

The problem is zealots. Zealotry doesn't work for indeterminate things that require judgement like "code quality" or "maintainability", but a simple rule like "don't repeat yourself" is easy for a zeal. They take a rule and shut down any argument with "because the rule!"

If you're arguing about code quality and maintainability without one sentence rules then you actually have to make arguments. If the rule is your argument there's no discussion only dogma.

As a result? Easy to distill rules spread fast, breed zealots, and result in bad code.

reply
> and the missing context is essential.

Oh yes, I'd recommend everyone who uses the phrase reads the rest of the paper to see the kinds of optimisations that Knuth considers justified. For example, optimising memory accesses in quicksort.

reply
This shows how hard it is to create a generalized and simple rule regarding programming. Context is everything and a lot is relative and subjective.

Tips like "don't try to write smart code" are often repeated but useless (not to mention that "smart" here means over-engineered or overly complex, not smart).

reply
I dunno, Ive seen people try to violate "dont prematurely optimize" probably a thousand times (no exaggeration) and never ONCE seen this happen:

1. Somebody verifies with the users that speed is actually one of the most burning problems.

2. They profile the code and discover a bottleneck.

3. Somebody says "no, but we shouldnt fix that, that's premature optimization!"

Ive heard all sorts of people like OP moan that "this is why pieces of shit like slack are bloated and slow" (it isnt) when advocating skipping steps 1 and 2 though.

I dont think they misunderstand the rule, either, they just dont agree with it.

Did pike really have to specify explicitly that you have to identify that a problem is a problem before solving it?

reply
>1. Somebody verifies with the users that speed is actually one of the most burning problems.

Sometimes this is too late.

C++98 introduce `std::set` and `std::map`. The public interface means that they are effectively constrained to being red-black trees, with poor cache locality and suboptimal lookup. It took until C++11 for `std::unordered_map` and `std::unordered_set`, which brought with them the adage that you should probably use them unless you know you want ordering. Now since C++23 we finally have `std::flat_set` and `std::flat_map`, with contiguous memory layouts. 25 years to half-solve an optimisation problem and naive developers will still be using the wrong thing.

As soon as the interface made contact with the public, the opportunity to follow Rob Pike's Rule 5 was lost. If you create something where you're expected to uphold a certain behaviour, you need to consider if the performance of data structures could be a functional constraint.

At this point, the rule becomes cyclical and nonsensical: it's not premature if it's the right time to do it. It's not optimisation if it's functional.

reply
> the opportunity to follow Rob Pike's Rule 5 was lost.

std::set/std::map got into trouble because they chose the algorithm first and then made the data model match. Rule 5 suggests choosing the right data model first, indicating that it is most important.

reply
You've inadvertently made an argument for deprecation, not ignoring rob's rule.

When building interfaces you are bound to make mistakes which end users will end up depending on (not just regarding optimization).

The correct lesson to learn from this is not "just dont make mistakes" but to try and minimize migration costs to prevent these mistakes from getting tightly locked in and try to detect these mistakes earlier on in the design process with more coordinated experimentation.

C++ seems pretty bad at both. It's not unusual, either - migration and upgrade paths are often the most neglected part of a product.

reply
How would you have minimised migration costs for std::map?
reply
Exactly!

I wish Knuth would come out and publicly chastise the many decades of abuse this quote has enabled.

reply
To be fair, I think human nature is probably a bigger culprit here than the quote. Yes, it was one of the first things told to me as a new programmer. No, I don't think it influenced very heavily how I approach my work. It's just another small (probably reasonable) voice in the back of my head.
reply
Yep. If one is implementing quicksort for a library where it will be used and relied on, I'd sure hope they're optimizing it as much as they can.
reply
I was a bit worried you are paraphrasing Rob Pike, but no, he actually agrees with that Knuth quote.

I am almost certain that people building bloated software are not willfully misunderstanding this quote; it's likely they never heard about it. Let's not ignore the relevance of this half a century old advice just because many programmers do not care about efficiency or do not understand how computers work. Premature optimization is exactly that, the fact that is premature makes it wrong, regardless if it's about GOTO statements in the 70s or a some modern equivalent where in the name of craft or fun people make their apps a lot more complex than they should be. I wouldn't be surprised if some of the brutally inefficient code you mention was so because people optimized prematurely for web-scale and their app never ever needed those abstractions and extra components. The advice applies both to hackers doing micro-optimizations and architecture astronauts dreaming too big IMHO.

reply
No I've definitely heard plenty of people use this as some kind of inarguable excuse to not care about performance. Especially if they're writing something in Python that should really be not super slow. "It's fine! Premature optimisation and all that. We'll optimise it later."

And then of course later is too late; you can't optimise most Python.

reply
Ignoring optimization opportunities until you see the profile only works when you actually profile!

Profiling never achieved its place in most developers’ core loop the way that compiling, linting, or unit testing did.

How many real CI/CD pipelines spit out flame graphs alongside test results?

reply
I usually defer this until a PM does the research to highlight that speed is a burning issue.

I find 98% of the time that users are clamoring to get something implemented or fixed which isnt speed related so I work on that instead.

When I do drill down what I tend to find in the flame graphs is that your scope for making performance improvements a user will actually notice is bottlenecked primarily by I/O not by code efficiency.

Meanwhile my less experienced coworkers will spot a nested loop that will never take more than a couple of milliseconds and demand it be "optimised".

reply
Even at Google, the tendency is (or was when I was there), to only profile things that we know are consuming a lot of resources (or for sure will), or are hurting overall latency.

Also the rule (quote?) says "speed hack", I don't think he is saying ignore runtime complexity totally, just don't go crazy with really complex stuff until you are sure you need it.

reply
That depends on which part of Google. I worked in the hot path of the search queries and there speed was extremely important for everything, they want to do so much there every single query and latency isn't allowed to go up.
reply
The problem with ignoring performance is that you'll always end up with slow software that is awful to use but ticks all the feature boxes. As soon as someone comes along that is fast and nice people will switch to that.

People don't ask for software to be fast and usable because it obviously should be. Why would they ask? They might complain when it's unusably slow. But that doesn't mean they don't want it to be fast.

reply
I don't think the quote itself is responsible for any of that.

It's true that premature optimization (that is, optimization before you've measured the software and determined whether the optimization is going to make any real-world difference) is bad.

The reality, though, is that most programmers aren't grappling with whether their optimizations are premature, they're grappling with whether to optimize at all. At most companies, once the code works, it ships. There's little, if any, time given for an extra "optimization" pass.

It's only after customers start complaining about performance (or higher-ups start complaining about compute costs) that programmers are given any time to go through and optimize things. By which point refactoring the code is now much harder than it wouldn've been originally.

reply
Totally agree. I’ve see that quote used to justify wilfully ignoring basic performance techniques. Then people are surprised when the app is creaking exactly due to the lack of care taken earlier. I would tend to argue the other way most of the time: a little performance consideration goes a long way!

Maybe I’ve had an unrepresentative career, but I’ve never worked anywhere where there’s much time to fiddle with performance optimisations, let alone those that make the code/system significantly harder to understand. I expect that’s true of most people working in mainstream tech companies of the last twenty years or so. And so that quote is basically never applicable.

reply
Slow code is more of a project management problem. Features are important and visible on the roadmap. Performance usually isn't until it hits "unacceptable", which may take a while to feed back. That's all it is.

(AI will probably make this worse as well, having a bloat tendency all of its own)

reply
> generations of programmers have now been raised to believe that brutally inefficient, bloated, and slow software is just fine.

I believe people don't think about Knuth when they choose to write app in Electron. Some other forces might be at play here.

reply
I wish we lived in a world where quotes could be that powerful. But I'm afraid in reality this quote, like any other, is just used as a justification after the fact.

Actually, I do not believe devs are to blame, or that CS education is to blame; I believe that's an unfortunate law of society that complexity piles up faster than we can manage it. Of course the economic system rewards shiping today at the expense of tomorrow's maintenance, and also rewards splitting systems in seemingly independent subsystems that are simpler in isolation but results in a more complex machinery (cloud, microservices...)

I'm even wondering if it's not a more fundamental law than that, because adding complexity is always simpler than removing it, right? Kind of a second law of termodynamic for code.

reply
This discussion kind of irks me. I just read these posts as: "The quote saying A is bad. Actually it said A all along!"

It's just complaining about others making a different value judgement for what is a worthwhile optimization. Hiding behind the 'true meaning of the quote' is pointless.

reply
A lot of developers get enamored by fetishes. Just one example, because it's one i always struggle to vanquish in any of my teams.

Devs are obsessed with introducing functional-style constructs everywhere, just for the sake of it. FP is great for some classes of software, but baseline crufty for anything that requires responsiveness (front-ends basically), let alone anything at real interactive speeds (games, geo-software, ...)

The "premature optimization" quote is then always used as a way to ignore that entire code paths will be spamming the heap with hundreds of thousands of temporary junk, useless lexical scopes, and so forth. Writing it lean the first time is never considered, because of adherence to these fetishes (mutability is bad, oo is bad, loops lead to off-by-one errors, ...). It's absolutely exhausting to have these conversations, it's always starting from the ground up and these quotes like "premature optimization is the root of all evil" are only used as invocations to ward of criticism.

reply
> Multiple generations of programmers have now been raised to believe that brutally inefficient, bloated, and slow software is just fine

100%

reply
> From his 1974 paper, "Structured Programming with go to Statements":

> He was talking about using GOTO statements in C.

I don’t think he was talking about C. That paper is from December 1974, and (early) C is from 1972, and “The UNIX Time-Sharing System” (https://dsf.berkeley.edu/cs262/unix.pdf) is from July 1974, so time wise, he could have known C, but AFAICT that paper doesn’t mention C, and the examples are PL/I or (what to me looks like) pseudocode, using ‘:=’ for assignment, ‘if…fi’ and ‘while…repeat’ for block, ‘go to’ and not C’s ‘goto’, etc.

reply
I agree. Faster hardware or horizontal scaling on distributed cloud environments can mask the problem; but it certainly doesn't solve the problem of bloated, inefficient software.

While it might not be necessary to spend hours fine-tuning every function; code optimization should be the mindset of every programmer no matter what they are coding.

How many fewer data centers would we need if all that software running in them was more efficient?

https://didgets.substack.com/p/finding-and-fixing-a-billion-...

reply
I think the bigger problem is that "Premature optimization is the root of all evil" is a statement made by software engineers to feel more comfortable in their shortcomings.

That's not to bemoan the engineer with shortcomings. Even the most experienced and educated engineer might find themself outside their comfort zone, implementing code without the ability to anticipate the performance characteristics under the hood. A mental model of computation can only go so far.

Articulated more succinctly, one might say "Use the profiler, and use it often."

reply
Picking the starting point is very important. "optimization" is the process of going from that starting point to a more performant point.

If you don't know enough to pick good starting points you probably won't know enough to optimize well. So don't optimize prematurely.

If you are experienced enough to pick good starting points, still don't optimize prematurely.

If you see a bad starting point picked by someone else, by all means, point it out if it will be problematic now or in the foreseeable future, because that's a bug.

reply
I hear you, friend!

While you were seeing those problems with Java at Google, I saw seeing it with Python.

So many levels of indirection. Holy cow! So many unneeded superclasses and mixins! You can’t reason about code if the indirection is deeper than the human mind can grasp.

There was also a belief that list comprehensions were magically better somehow and would expand to 10-line monstrosities of unreadable code when a nested for loop would have been more readable and just as fast but because list comprehensions were fetishized nobody would stop at their natural readability limits. The result was like reading the run-on sentence you just suffered through.

reply
Don't confuse premature pessimization for the warnings against premature optimization.

I can write bubble sort, it is simple and I have confidence it will work. I wrote quicksort for class once - I turned in something that mostly worked but there were bugs I couldn't fix in time (but I could if I spent more time - I think...)

However writing bubble sort is wrong because any good language has a sort in the standard library (likely timsort or something else than quicksort in the real world)

reply
Anyone else feel like bloat is usually not an algorithmic problem, but rather a library or environment issue most of the time?
reply
Totally agree. Out of this context, the word "premature" can mean too many things.
reply
I always point out the operational word is "premature".
reply
As someone currently writing 16-18 tables all with common definition, and crud, Id like some abstraction
reply
deleted
reply
> Multiple generations of programmers have now been raised to believe that brutally inefficient, bloated, and slow software is just fine. There is no limit to the amount of boilerplate and indirection a computer can be forced to execute. There is no ceiling to the crystalline abstractions emerging from these geniuses. There is no amount of time too long for a JVM to spend starting.

I think that's due to people doing premature optimization! If people took the quote to heart, they would be less inclined to increasing the amount of boilerplate and indirection.

reply
The boilerplate and indirection isn't done for performance
reply
At least before the LLM world you would have to trade money (aka more compute) for time to market. What is the point of spending a single second optimizing a query when your database has 10 users?

Of course today this has changed. You can have multiple agents working on micro optimizing everything and have the pie and eat it too.

reply
I too learned this the hard way, via a supposedly concurrent priority queue that did quadratic-time work while holding a lock over the entire thing. I was told that "premature optimization is the root of all evil."

Sorry, folks, but that's just an excuse to make dumb choices. Premature _micro_optimization is the root of all evil.

EDIT: It was great training for when I started working on browser performance, though!

reply
And if I may add a corollary: Measurement doesn't need to be held off until the end of the project! Start doing it as soon as you can!
reply
In all honesty, this is one of the less abused quotes, and I have seen more benefit from it than harm.

Like you, I've seen people produce a lot of slow code, but it's mostly been from people who would have a really hard time writing faster code that's less wrong.

I hate slow software, but I'd pick it anytime over bogus software. Also, generally, it's easier to fix performance problems than incorrect behavior, especially so when the error has created data that's stored somewhere we might not have access to. But even more so, when the harm has reached the real world.

reply
I don't believe there is any tension at all between fast and simple software.

We can and should have both.

This is a fraud, made up by midwits to justify their leaning towers of abstraction.

reply
User-facing, sure, nothing stopping us from doing "simple and fast" software. But when it comes to the code, design and architecture, "simple" is often at odds with "fast", and also "secure". Once you need something to be fast and secure, it often leads to a less simple design, because now you care about more things, it's kind of hard to avoid.
reply
IME doing application servers and firmware my whole career, simple and fast are usually the same thing, and "simple secure" is usually better security posture than "complex secure".
reply
Interesting, never done firmware, but plenty of backends and frontends. Besides the whole "do less and things get faster", I can't think of a single case where "simple" and "fast" is the same thing.

And I'd agree that "simple secure" is better than "complex secure" but you're kind of side-stepping what I said, what about "not secure at all", wouldn't that lead to simpler code? Usually does for me, especially if you have to pile it on top of something that is already not so secure, but even when taking it into account when designing from ground up.

reply
Not really. `return 0` is the simplest program you could write, but it's not terribly useful. There's an underlying assumption that there's some purpose/requirement for the program to exist. Through that lens "secure" is just assumed as a requirement, and the simplest way to meet your requirements will usually still give you the fastest program too.

"Do less and things get faster" is a very wide class of fixes. e.g. you could do tons of per-packet decision making millions of times per second for routing and security policies, or you could realize the answer changes slowly in time, and move that to upfront work, separating your control vs data processing, and generally making it easier to understand. Or you could build your logic into your addressing/subnets and turn it into a simple mask and small table lookup. So your entire logic gets boiled down to a table (incidentally why I can't understand why people say ipv6 is complex. Try using ipv4! Having more bits for addresses is awesome!).

reply
> "simple" is often at odds with "fast"

Sort of. But if you keep the software simple, then it is easier to optimize the bottlenecks. You don't really need to make everything complicated to make it faster, just a few well selected places need to be refactored.

reply
> I have seen more benefit from it than harm.

Same. I, too, am sick of bloated code. But I use the quote as a reminder to myself: "look, the fact that you could spend the rest of the workday making this function run in linear instead of quadratic time doesn't mean you should – you have so many other tasks to tackle that it's better that you leave the suboptimal-but-obviously-correct implementation of this one little piece as-is for now, and return to it later if you need to".

reply
So you're saying people have misunderstood "premature optimisation is the root of all evil" as "optimisation is the root of all evil"?

I don't think you can blame this phrase if people are going to drop an entire word out of an eight word sentence. The very first word, no less.

reply
This is the sort of pontifical statement that old guys like me tend to make which is strictly wrong but also contains a lot of wisdom.

Yes, software is bloated, full of useless abstractions and bad design. You kids(well, anyone programming post 1980, so myself included) should be ashamed. Also let's not forget that those abstractions helped us solve problems and our friends in silicon valley(ok that no longer makes sense but imagine if SillyValley still just made HW) covered our mistakes. But yeah, we write crap a lot of the time.

But as other folks have said, it doesn't mean "don't optimize."

I've always used my own version of the phrase, which is: "Don't be stupid." As in, don't do dumb, expensive things unless you need to for a prototype. Don't start with a design that is far from optimal and slow. After profiling, fix the slow things. I'm pretty sure that's what most folks do on some level.

reply
> I have lived the absolute nightmares that evolve from the willful misunderstanding of this quote.

how do you know which code was written using this quote in mind.

reply
He doesn't know, but that quote makes for a cool talking point. Software is slow or bloated because of budget, deadlines, and skill levels - not because of a quote.
reply
It has less to do with a quote and more to do with CS education (and the market) rewarding minimal functionality over performance, security, fault-tolerance, etc.

The average university CS student in USA (and India I presume) is taught to "hack it" at any cost, and we see the results.

reply
> I have lived the absolute nightmares that evolve from the willful misunderstanding of this quote.

Then the quote wasn’t the problem. The wilful misunderstanding was the problem.

reply