9 ms·
> Premature optimization is the root of all evil. There are few principle of software engineering that I hate more than this one, though SOLID is close. It is
by GuB-42 6mo ago
> Premature optimization is the root of all evil.
There are few principle of software engineering that I hate more than this one, though SOLID is close.
It is important to understand that it is from a 1974 paper, computing was very different back then, and so was the idea of optimization. Back then, optimizing meant writing assembly code and counting cycles. It is still done today in very specific applications, but today, performance is mostly about architectural choices, and it has to be given consideration right from the start. In 1974, these architectural choices weren't choices, the hardware didn't let you do it differently.
Focusing on the "critical 3%" (which imply profiling) is still good advice, but it will mostly help you fix "performance bugs", like an accidentally quadratic algorithms, stuff that is done in loop but doesn't need to be, etc... But once you have dealt with this problem, that's when you notice that you spend 90% of the time in abstractions and it is too late to change it now, so you add caching, parallelism, etc... making your code more complicated and still slower than if you thought about performance at the start.
Today, late optimization is just as bad as premature optimization, if not more so.
- firemelt 6mo agolol I never seen it that way its my favorit quotes premature optimization nowadays looks like choosing microservice when monolith can works just fine
- tananaev 6mo agoWith modern tools it should be pretty easy to build scalable solutions. I take premature optimization as going out of your way to optimize something that's already reasonable. Not that you should write really bad code as a starting point.
- Sammi 6mo agoThe problem is that that this term gets misused to say the opposite of what it was intended for. It's particularly the kind of people who like to say "hur hur don't prematurely optimize" that don't bother writing decent software to begin with and use the term as an excuse to write poor performing code. Instead of optimizing their code, these people end up making excuses so they can pessimize it instead.
- pydry 6mo agoIn my career Ive seen about 1000 instances of somebody trying to optimize something prematurely. Usually those people also have a good old whinge about the premature optimization quote being wrong or misinterpreted and general attitudes to software efficiency. Not once have I ever seen somebody try to derail a process of "ascertain speed is an issue that should be tackled" -> "profile" -> fix the hot path.
- Jensson 6mo ago> Not once have I ever seen somebody try to derail a process of "ascertain speed is an issue that should be tackled" -> "profile" -> fix the hot path. Many things need to be optimized before you can easily profile them, so at this stage its already too late and your software will forever be slow.
- hunterpayne 6mo ago"Not once have I ever seen somebody try to derail a process of "ascertain speed is an issue that should be tackled" -> "profile" -> fix the hot path." That's because your boss will never in a 1000 years hire the type of dev who can do that. And even if you did, there will be team members who will fight those fixes tooth and nail. And yes, I have a very cynical view of some devs but they earned that through some of the pettiest behavior I have ever seen.
- wredcoll 6mo agoMan, what are you talking about? Speed optimizations after shipping software happens constantly in everything from video games in C to ui libraries in js and everything in between. People write some code, test it, ship it, then get some ideas that its too slow and make it faster. The nice thing about doing it with shipped code is you can actually measure where time is spent insyead of guessing.
- YZF 6mo agoIn my career I've seen endless examples of hopelessly badly designed software where no amount of optimization can turn it into anything other than a piece of garbage. Slow, bloated and inefficient. Ascertain an issue is too late for bad software. The technical term is polishing a turd. Not that what you're describing doesn't happen, people trying to make something irrelevant fast, but that's not the big problem we face as an industry. The problem is bad software.
- cstoner 6mo agoYeah, I interpret "premature optimization" as taking a request that takes 500ms and focusing on saving a couple ms by refactoring logic to avoid a SQL JOIN or something. Your users are not going to notice. Sure, it's faster but it's not focused on the problem.
- austin-cheney 6mo agoThe most misunderstood statement in all of programming by a wide margin. I really encourage people to read the Donald Knuth essay that features this sentiment. Pro tip: You can skip to the very end of the article to get to this sentiment without losing context. Here ya go: https://dl.acm.org/doi/10.1145/356635.356640 https://dl.acm.org/doi/10.1145/356635.356640 Basically, don't spend unnecessary effort increasing performance in an unmeasured way before its necessary, except for those 10% of situations where you know in advance that crucial performance is absolutely necessary. That is the sentiment. I have seen people take this to some bizarre alternate insanity of their own creation as a law to never measure anything, typically because the given developer cannot measure things.
- iamflimflam1 6mo ago> I have seen people take this to some bizarre alternate insanity of their own creation as a law to never measure anything, typically because the given developer cannot measure things. Similar to the "code should be self documenting - ergo: We don't write any comments, ever"
- msla 6mo ago> Similar to the "code should be self documenting - ergo: We don't write any comments, ever" My counterpoint: Code can be self-documenting, reality isn't. You can have a perfectly clear method that does something nobody will ever understand unless you have plenty of documentation about why that specific thing needs to be done, and why it can't be simpler. Like having special-casing for DST in Arizona, which no other state seems to need: https://en.wikipedia.org/wiki/Time_in_the_United_States https://en.wikipedia.org/wiki/Time_in_the_United_States
- pc86 6mo agoThis isn't a counterpoint, it's just additional (and barely relevant) information.
- 6mo ago
- EGreg 6mo agoI would add this: https://magarshak.com/blog/perfection-is-the-enemy-of-the-good-enough/ https://magarshak.com/blog/perfection-is-the-enemy-of-the-go...
- tehjoker 6mo agoI would venture that this statement is not true for library authors. Performance is a large factor in competitive advantage, especially in domains like image analysis or processing large corpuses of text etc. In these domains, algorithm selection, and fine tuning hot spots pays off significantly. You must hit minimum speeds to make your application viable.
- cogman10 6mo agoCompletely agreed here [1]. And as I point out, what Knuth was talking about in terms of optimization was things like loop unrolling and function inlining. Not picking the right datastructure or algorithm for the problem. I mean, FFS, his entire book was about exploring and picking the right datastructures and algorithms for problems. [1] https://news.ycombinator.com/item?id=47849194 https://news.ycombinator.com/item?id=47849194
- enraged_camel 6mo ago>> Today, late optimization is just as bad as premature optimization, if not more so. You are right about the origin of and the circumstances surrounding the quote, but I disagree with the conclusion you've drawn. I've seen engineers waste days, even weeks, reaching for microservices before product-market fit is even found, adding caching layers without measuring and validating bottlenecks, adding sharding pre-emptively, adding materialized views when regular tables suffice, paying for edge-rendering for a dashboard used almost entirely by users in a single state, standing up Kubernetes for an internal application used by just two departments, or building custom in-house rate limiters and job queues when Sidekiq or similar solutions would cover the next two years. One company I consulted for designed and optimized for an order of magnitude more users than were in the total addressable market for their industry! Of that, they ultimately managed to hit only 3.5%. All of this was driven by imagined scale rather than real measurements. And every one of those choices carried a long tail: cache invalidation bugs, distributed transactions, deployment orchestration, hydration mismatches, dependency array footguns, and a codebase that became permanently harder to change. Meanwhile the actual bottlenecks were things like N+1 queries or missing indexes that nobody looked at because attention went elsewhere.
- cstoner 6mo agoThank your for posting this. I disagreed with OP but couldn't _quite_ find the words to describe why. But your post covers what i was trying to say. I was quite literally asked to implement an in-memory cache to avoid a "full table scan" caused by a join to a small DB table recently. Our architect saw "full table scans" in our database stats and assumed that must mean a performance problem. I feel like he thought he was making a data-driven profiling decision, but seemed to misunderstand that a full-table scan is faster for a small table than a lookup. That whole table is in RAM in the DB already. So now we have a complex Redis PubSub cache invalidation strategy to save maybe a ms or two. I would believe that we have performance problems in this chunk of code, and it's possible an in-memory cache may "fix" the issue, but if it does, then the root of the problem was more likely an N+1 query (that an in-memory cache bandaids over). But by focusing on this cache, suddenly we have a much more complex chunk of code that needs to be maintained than if we had just tracked down the N+1 query and fixed _that_
- 6mo ago
- xnx 6mo ago> making your code more complicated and still slower than if you thought about performance at the start. Not if your optimization for performance is some Rube Goldberg assemblage of microservices and an laundry list of AWS services.
- ghosty141 6mo agoWhat's the problem with SOLID? It's very very rare that I see a case where going against SOLID leads to better design.
- someguyiguess 6mo agoIt only applies to the object oriented programming paradigm
- marcosdumay 6mo agoThat's understating the problem. It mandates OOP. If you follow SOLID, you'll write OOP only, with always present inheritance chains, factories for everything, and no clear relation between parameters and the procedures that use them.
- Exoristos 6mo agoThis is only superficially true. Here's a fair discussion that could serve as a counterpoint: https://medium.com/@ignatovich.dm/applying-solid-principles-in-react-applications-44eda5e4b664 https://medium.com/@ignatovich.dm/applying-solid-principles-...
- mrkeen 6mo agoNegative. The only part of SOLID that is perhaps OO-only is Liskov Substitution. L is still a good idea, but without object-inheritance, there's less chance of shooting yourself in the foot.
- kortex 6mo agoI go by a philosophy that Liskov Substitution is reeeally about referential transparency. I don't care about parent/child classes, I care about interfaces and implementations, and structural subtyping. Fix that, and it's great.
- dzjkb 6mo agohere's a nice critique of SOLID principles: https://www.tedinski.com/2019/04/02/solid-critique.html https://www.tedinski.com/2019/04/02/solid-critique.html
- jollyllama 6mo agoYou ARE going to need it.
- tonymet 6mo agoThe wheel is a premature optimization to someone who never figured out how to build one.
- throwaway5752 6mo ago"Premature optimization is the root of all evil" Decades in, this is the worst of all of them. Misused by laziness or malice, and nowhere near specific enough. The graveyard of companies boxed in by past poor decisions is sprawling. And the people that made those early poor decisions bounce around field talking about their "successful track record" of globally poor and locally good architectural decisions that others have had to clean up. It touches on a real problem, though, but it should be stricken form the record and replaced with a much better principle. "Design to the problem you have today and the problems you have in 6 months if you succeed. Don't design to the problems you'll have have next year if it means you won't succeed in 6 months" doesn't roll off the tongue.
- tracker1 6mo agoOn your last bit, I definitely agree... personally I've leaned more and more into KISS above all else... simple things that are easy to replace are easily replaced only when you need to. Similarly, I also tend to push for initial implementations of many/most things in a scripted language first, mostly for flexibility/simplicity to get a process "right" before worrying about a lot of other things. One thing that came out of the no-sql/new-sql trends in the past decade and a half is that joins are the enemy of performance at scale. It really helps to know and compromise on db normalization in ways such as leaning on JSON/XML for non-critical column data as opposed to 1:1/children/joins a lot of the time. For that matter, pure performance and vertical scale have shifted a lot of options back from the brink of micro service death by a million paper cuts processes.
- jnpnj 6mo agoIt's a very interesting topic. Even when designing a system, how to modularize, it's healthy to wait until the whole context is in sight. It's a bit of a black art, too early or too late you pay some price.
- NikolaosC 6mo agoSpent 6 months last year ripping out an abstraction layer that made every request 40ms slower. We profiled, found the hot path, couldn't fix it without a rewrite. The "optimize later" school never tells you later sometimes means never
- tombert 6mo agoI'd say it usually means "never". I also find it a bit annoying is that most people just make shit up about stuff that is "faster". Instead of measuring and/or looking at the compiled bytecode/assembly, people just repeat tribal knowledge about stuff that is "faster" with no justification. I find that this is common amongst senior-level people at BigCos especially. When I was working in .NET land, someone kept telling me that "switch statements are faster" than their equivalent "if" statements, so I wrote a very straightforward test comparing both, and used dotpeek to show that they compile to the exact same thing. The person still insisted that switch is "faster", I guess because he had a professor tell him this one time (probably with more appropriate context) and took whatever the professor said as gospel.
- bluGill 6mo agoI've seen a lot of requests to obtimize code where we can measure the optimal versions saves a few nanoseconds. I just deleted some 'optimal code' that took a lot of mutexes and so was only faster when there is no contetion but in real world multi-writer situations the easy code wins. (Shared memory vs local socket for ipc)
- tombert 6mo agoI don't write a lot of super low level stuff, so maybe things are different there, but at least in the normal user space level I've found it pretty rare that explicit mutexes ever beat the performance of an (in my opinion) easier design using queues and/or something like ZeroMQ. Generally I've found that the penalty, even without contention, is pretty minimal, and it almost always wins under contention.
- davedx 6mo ago"today, performance is mostly about architectural choices, and it has to be given consideration right from the start" This doesn't make sense. Why is performance (via architectural choices) more important today than then? You can build a snappy app today by using boring technology and following some sensible best practices. You have to work pretty hard to need PREMATURE OPTIMIZATION on a project -- note the premature there
- kqr 6mo agoIn the 1970s computer systems spanned fewer orders of magnitude. Operations generally took somewhere between maybe 1 and 10^8 CPU cycles. Today, the range is closer to 10^-1 to 10^13.
- f1shy 6mo agoI agree. But I have to say, when defining the architecture, there are things known that will be terrible bottlenecks later. They should be avoided. Just as the previous comment, about defining proper indices in a database. Optimization means making something that is already “good” and correct better. There is no excuse to make a half ass, bug ridden shitty software, under the excuse “optimization is for later” that is technical debt generation: 2 very different things.
- jandrewrogers 6mo agoThe big thing that changed is that almost all software performance today is bandwidth-bound at the limit. Not computation-bound. This transition was first noticed in supercomputing around 25 years ago. Optimization of bandwidth-bound code is almost purely architectural in nature. Most of our software best practices date from a time when everything was computation-bound such that architecture could be ignored with few bad effects.
- paulddraper 6mo ago> Why is performance (via architectural choices) more important today than then? There were fewer available layers of abstraction. Whether you wrote in ASM, C, or Pascal, there was a lot less variance than writing in Rust, JavaScript, Python.
- 6mo ago
- ozim 6mo agoSounds like we agree. Bunch of stuff is done for us. Using postgres having indexes correct - is not premature optimization, just basic stuff to be covered. Having double loop is quadratic though. Parallelism is super fun because it actually might make everything slower instead of faster.
- snarfy 6mo agoI definitely hate SOLID more.
- toast0 6mo agoI only use mature optimizations, so I'm good. Thinking about the overall design, how its likely to be used, and what the performane and other requirements are before aggregating the frameworks of the day is mature optimization. Then you build things in a reasonable way and see if you need to do more for performance. It's fun to do more, but most of the time, building things with a thought about performance gets you where you need to be. The I don't need to think about performance at all camp, has a real hard time making things better later. For most things, cycle counting upfront isn't useful, but thinking about how data will be accessed and such can easily make a huge difference. Things like bulk load or one at a time load are enormous if you're loading lots of things, but if you'll never load lots of things, either works. Thinking about concurrency, parallelism, and distributed systems stuff before you build is also pretty mature. It's hard to change some of that after you've started.
- Shorel 6mo agoThat first sentence. I want it in a t-shirt. On billboards. Everywhere :)
- vanguardanon 6mo agoIs this less relevant today where if you do go down the wrong architecture it is much cheaper to rewrite everything again in something that is better?
- dec0dedab0de 6mo agoI like it as a way to remind myself to not get caught up in the minutiae.
- CyberDildonics 6mo agoUnfortunately people do keep repeating it to excuse the fact that they don't know how to optimize in the first place. Anyone who has done optimization even a little knows that it isn't very difficult, but you do need to plan and architect for it so you don't have to restructure you whole program to get it to run well. Mostly it's just rationalization, people don't know the skill so they pretend it's not worth doing and their users suffer for it. If software and website were even reasonably optimized people could just use a computer as powerful as a rasberry pi 5 (except for high res video) for most of what they do day to day.
- dorkitude 6mo agoFound the overbuilder!
- m3kw9 6mo agoIf you done enough premature optimization, you will know it’s usually wasted, detrimental and bad trade
- dartharva 6mo agoStrange, this is actually one of the most important things I learnt the hard way as an analyst having had the misfortune of being forced to do local-level data engineering after being tasked with doing extensive BI on heavy data volumes (I don't have engineering education) without cloud ETL. Had someone told me this simple statement before time it would have saved me a LOT of pain and effort.
- tombert 6mo agoThe biggest issue I have with premature optimization is stuff that really doesn't matter. For example, in Java I usually use ConcurrentHashMap, even in contexts that a regular HashMap might be ok. My reasoning for this is simple: I might want to use it in a multithreaded context eventually and the performance differences really aren't that much for most things; uncontested locks in Java are nearly free. I've gotten pull requests rejected because regular HashMaps are "faster", and then the comments on the PR ends up with people bickering about when to use it. In that case, does it actually matter? Even if HashMap is technically "faster", it's not much faster, and maybe instead we should focus on the thing that's likely to actually make a noticeable difference like the forty extra separate blocking calls to PostgreSQL or web requests? So that's the premature optimization that I think is evil. I think it's perfectly fine at the algorithm level to optimize early.
- xorcist 6mo agoI can fully understand "bickering" about someone sprinkling their favourite data type over a codebase which consistently used a standard data type before. The argument that it might be multithreaded in the futurure does not hold if the rest of the code base clearly was not writen with that in mind. That could even be counter productive, should someone get the misguided idea that it was ready for it. Make a (very) good argument, and suggest a realtistic path to change the whole codebase, but don't create inconsistency just because it is "better". It is not.
- tombert 6mo agoI don’t expose it at the boundaries, just within functions. With everything outside of the function I take a Map interface in and/or return the Map out. It makes no difference to the outside code.
- xorcist 6mo agoThat's really not much better. No function is an island, as wise man almost once said.
- kgwxd 6mo agoAll aphorisms are awful.
- theLiminator 6mo agoYeah, I hate that quote too. People take it so out of context and even ignore engineering for reasonable performance out of the box. I don't blame Knuth, he's talking about focusing on micro-optimizations, but a lot of devs nowadays don't even care to get basic performance right.
- SJC_Hacker 6mo agoMaybe its just my domain, but most perf problems I've seen relate to architechture and infrastrucutre decisions, and not really code or algorithms. Especially the "microservice" mantra, splitting out simple functions into containers, using k8s, all in the name of "scalability" then being surprised when a simple API call takes several seconds due to all that crud it has to go through.
- chrismarlow9 6mo agoA better rule is "complicate only if necessary"
- rustystump 6mo agoI have worked on projects that had 5 layers of buffer/caching all implementing complicated evictions strategies. This is all a browser client. There were 4 caching layers when i started. I added the 5th caching freq network data to disk which massively improved performance. This is too true. However, often you dont fully know the shape of the domain until you swing at it and fail.
- benrutter 6mo ago> Today, late optimization is just as bad as premature optimization, if not more so. I agree but I don't think this discredits the "premature optimisation is the root of all evil" thing, aside from the fact that it's a heavy exaggeration. The trouble is, people read it as "don't optimise" which is an incredibly bad decision. Especially in the data world though, I've seen lots of teams really struggle with problems caused by using technologies they don't need (normally spark or kubernetes or both) just because they might need them later. I think that type of pitfall is what the original quote is warning against.
- mrzhangbo 6mo agoI agree. The main reason for slow development is excessive optimization and over-design.
- pelasaco 6mo agoThe question is always, "When is it no longer premature?" Normally, it means the system is already in production, users are suffering, and maintaining and supporting it is a nightmare. Then we engineers say, "We have to spend N sprints on that to pay the technical debt."
- miki123211 6mo agoIMHO "root of all evil" sits there with YAGNI. An useful way to think about the world (overoptimizing early is often as bad as overabstracting, and just as common), but a principle which shouldn't be taken to an extreme. I think a more useful mental model is of one-way versus two-way decisions (local optimizations can be applied later., the architecture has to be right from the start), as well as expected risks and payoffs.
- konovalov-nk 6mo agoRecently I stumbled upon this crazy thing: https://github.com/anomalyco/opencode/issues/9676#issuecomment-3827198492 https://github.com/anomalyco/opencode/issues/9676#issuecomme... `ripgrep` tool call on opencode added `--follow` override, which allowed to traverse symlinks. And you can imagine what happens when symlinks point to ancestors. My 9950x3D CPU had 100% load all the time until I did a bit of research and added config to forbid this on `rg` level. So I'd refine it as "Premature optimization is the root of all evil. Blatant ignorance of it is even worse."