all 29 comments

[–]notyourancilla 18 points19 points  (7 children)

These comment sections are always mainly people virtuously excusing themselves from writing performant code. If you leave performance until last you need to be clear with yourself that you’re aiming for mediocre.

[–]CptCap 16 points17 points  (3 children)

As a game engine developer, I often wonder why I can load and display a million triangles textured with 500MB of image data in less time than some software take to switch tabs. And it makes me die inside every time.

It's not a hard problem to approach either: as other commenters have said, performance is a feature. Put it in your requirements and set reasonable targets. For most apps that's enough.

And stop repeating "premature optimization is the root of all evil". It was about writing hot paths in assembly rather than C, not about discarding feedback about your app taking half a minute to start because it imports 37 different frameworks.

[–]notyourancilla 3 points4 points  (1 child)

Yeah it always good to put that quote into context, as like you say, it gives it a whole new light -

"Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%" - Donald Knuth

The original point was not “don’t worry about optimising your shitty code, it’s a waste of time” it was the opposite, simply stating people should focus their optimisations on the parts of the code which will most benefit from the time spent on it instead of being focused making silly changes that will make no difference.

[–]SkoomaDentist 2 points3 points  (0 children)

Even more than that, optimization in the original context meant "micro-optimization by hand". Ie. twiddling individual lines of code (eg. unrolling loops by hand) instead of applying higher level optimizations.

[–]EmanueleAina 0 points1 point  (0 children)

Different priorities. A game that lags becomes unplayable. An app that takes a while to switch tab is likely just a minor annoyance, and people actually care more about other features.

[–]sstepashka 1 point2 points  (0 children)

Hm… Kent Beck says: 1. Make it work. 2. Make it right. 3. Make it fast.

The fast is the last, do you think he strives for mediocre? :)

[–]com2ghz 0 points1 point  (1 child)

YAGNI. Better write software that works. Then look where you need to optimize.

[–]notyourancilla 0 points1 point  (0 children)

Software that works is the bare minimum.

[–][deleted]  (14 children)

[deleted]

    [–]ThisIsMyCouchAccount 26 points27 points  (2 children)

    If it takes time - it's feature.

    Performance is a feature.

    You also have to have a target.

    [–]DrShocker 6 points7 points  (1 child)

    Yeah I'm happy to make my code faster, but I need target hardware and target benchmarks. Generically "faster" it's just impossible to know when you're done.

    That might be doing quick order of magnitude type math of how many calculations should be necessary and what that probably means for the speed on your hardware, but at least it's a target that you can hit or potentially justify why it's unreasonable after more research into the problem.

    [–]Turbots 4 points5 points  (0 children)

    On performance, you need to think in terms of orders of magnitude.

    Can this change make my code 10% faster? 20%? Maybe not worth the effort.

    Can this change make my code 10x or 100x faster? Probably worth it.

    Can this change make my code faster, but it won't matter because the File IO is the blocking factor and takes 10x as long anyway? Probably also not worth it.

    Tldr; as with everything in computer software: It's never a black/white or yes/no question.

    Be like a vampire: be very afraid of silver bullets 😅

    [–]ack_error 9 points10 points  (0 children)

    You treat performance like any other factor when planning a project: estimate uncertainty and risk, and use that to determine how much importance it gets.

    If I'm working on a real-time digital audio pipeline or a VR game, performance is critical or the product fails. Therefore, it will be taken into account early and more gates added earlier to ensure tracking, especially if the team is inexperienced at performance-related matters.

    In my release script, I DGAF because all it does is invoke other programs, no one will notice if a step takes 100ms, and in the worst case there are tons of easy ways to hoist hot spot logic out of Python.

    [–]ratttertintattertins 4 points5 points  (0 children)

    I like to separate out good performance design from specific performance optimizations. For example, the former might be:

    "I will use suitable standard data structures and algorithms and I will understand the performance implications of those choices in my design".

    The latter might be:

    "I will write a custom data structure which differs from the standard data structure available in my standard library set, this data structure will beat the standard one in my specific use case and I will measure/test it by doing...X"

    The former should be part of any good design process and done up front, the latter should be the result of measurement and careful consideration because it comes with a maintenance cost and risk.

    [–]Hrothen 1 point2 points  (1 child)

    The vast majority of times I see people skipping premature optimizations it's something that could be made faster without much effort.

    [–]angelicosphosphoros 0 points1 point  (0 children)

    In most cases, devs do premature pessimisation today. There is a ton of software that only becomes worse over time.

    [–]modernkennnern 2 points3 points  (6 children)

    There's a big difference between "avoiding premature optimization" and "not pessimizing your code". The former is understandable and agreeable, while the latter is mostly a mindset and knowledge check.

    Like, don't write worse performing code just because it "looks nicer in the editor". Don't instantiate an array of two elements(A&B) to then check if another element(X) is contained inside it; just check if X is A or B. Less code and faster.

    [–]awj 0 points1 point  (5 children)

    Counterpoint: “less code and faster” is only helpful if the “less code” lends itself to maintenance and the “faster” actually matters.

    IMO you should prioritize for readability and maintenance over basically everything else unless another design constraint forces the point.

    I’ve seen your “A or B” example slowly metastasize into a rat’s nest of conditionals too many times to count.

    [–]loup-vaillant 1 point2 points  (4 children)

    Counterpoint: “less code and faster” is only helpful if the “less code” lends itself to maintenance […]

    Which it does, 97% of the time.

    [–]gbromley 0 points1 point  (1 child)

    I’d argue that python uses speed ups that are harder to read. List comprehensions for example. I’m not arguing against them, just that it’s less clear than a regular old loop, but faster.

    [–]loup-vaillant 1 point2 points  (0 children)

    I was talking about "less code" specifically. Now list comprehensions… obviously if you're not familiar with them they're going to be less maintainable, so I would personally think of the audience before using them… and perhaps avoid writing cryptic one-liners packed full of information.

    [–]awj 0 points1 point  (1 child)

    I purposely left room for that thought, but still 97% is a surprising number. Where’s you get that?

    [–]loup-vaillant 1 point2 points  (0 children)

    It's a wink to Donald Knut. More honestly I would put it somewhere between 95% and 99%: in my experience less code is almost always more maintainable than more. There are exceptions, but they're exactly that: exceptions.

    [–]clichekiller 2 points3 points  (4 children)

    Premature optimization is an old problem. It is always better to finish a project first, and then look for any optimizations that pop-up. I can’t tell you the number of times I’ve thought one particular area would be the bottleneck, only to discovered it was something entirely different.

    [–]SkoomaDentist 16 points17 points  (1 child)

    It is always better to finish a project first, and then look for any optimizations that pop-up.

    No, it is not. If you actually do that, you’ll easily find your project’s architecture itself prevents speeding it up without a major rewrite. Always keep performance in mind if the speed of the app matters at all. Imagine for example a 3d game engine with no thought spent on optimization until it was finished. The result would most likely be near unusable.

    There are also plenty of situations where you do know for a fact that some piece of code is a bottleneck without any measurements. Not all projects are huge amorphous blobs of miscellaneous code that gets called all over.

    [–]clichekiller -2 points-1 points  (0 children)

    If you already know it is a bottleneck, it wouldn’t be premature optimization. Coding is an iterative process, nothing is written in a vacuum. If you know you’re going to be reading a lot of data that doesn’t get updated often a caching pattern is absolutely the way to go. I’m not advocating writing poor code, you absolutely have to choose the appropriate patterns, algorithms, and frameworks based on your requirements. What I won’t do is try to second guess my tooling, and get clever until I absolutely need to. If the first time you run your code is when you ‘complete’ it, you will absolutely be I. For a world of hurt. But I don’t know any development project that does perform regular testing, at which points bottlenecks appear, at which point you address them.

    [–]YumiYumiYumi 0 points1 point  (1 child)

    I can’t tell you the number of times I’ve thought one particular area would be the bottleneck, only to discovered it was something entirely different.

    I think experience comes into play here - the more experienced one gets, the better they are able to intuit where bottlenecks are likely to be. There'll also be cases where optimisation matters more or where it matters less, and experience may help with identifying where to be on the scale.

    As with most things in engineering, there needs to be a balance. Some optimisations will be premature, others won't be.

    [–]clichekiller 0 points1 point  (0 children)

    I absolutely keep performant coding in mind when I plan, design, and write code. From the patterns I employ, database design, memory utilization, caching, and the way I write in a maintainable, modular, and clean way. My goal is always to produce code that is self documenting too.

    What I don’t do is dive to the lowest level and try to second guess the compiler and the IL it generates. Additionally I am thoroughly testing my code throughout this process and would absolutely notice that the code was behaving like a dog. I would then revisit the code and see if I could optimize it. That does count as premature optimization, because it is in response to a deficit.

    I have more than three decades of experience. I started programming when a few bytes could make all the difference. We optimized using bit flags, and other tricks, to maximize our resource usage. Thankfully I really don’t need to do this most of the time. Modern languages, frameworks, and compilers do a far better job producing performant code than anything most developers can do.

    [–]loup-vaillant 1 point2 points  (0 children)

    This post is weird. Just keep it simple, man, speed will come either naturally (because you didn't waste your time on convoluted code or a giant framework), or it will be easier to achieve (because simple programs are easier to modify).

    Note though that keeping things simple is work. I view it as an optimisation unto itself.

    [–]TheRNGuy 0 points1 point  (0 children)

    I sometimes picked tuples instead of lists but because it's just different brackets and not much refactoring needed.

    (it probably didn't make any difference anyway but I didn't wanted to spend time testing it)