[HN Gopher] Horrible Code, Clean Performance
       ___________________________________________________________________
        
       Horrible Code, Clean Performance
        
       Author : signa11
       Score  : 104 points
       Date   : 2023-04-17 02:02 UTC (2 days ago)
        
 (HTM) web link (johnnysswlab.com)
 (TXT) w3m dump (johnnysswlab.com)
        
       | 0xbadcafebee wrote:
       | clean, adjective              1. Free from dirt, stain, or
       | impurities; unsoiled.         2. Free from foreign matter or
       | pollution; unadulterated.         3. Not infected.         4.
       | Honest or fair, or showing that you have not done anything
       | illegal
       | 
       | Clean isn't a word that can be used to describe software. It just
       | doesn't have any relevance to an observable, objective quality of
       | software. There is no definition of what 'clean' code is; you
       | can't show me code and say objectively "this is not clean",
       | because there's no real definition of "clean code". It's a loan
       | word, seemingly to indicate a lack of desirability or quality.
       | And it also implies things that don't have anything to do with
       | software. But there really is no concrete example or evidence of
       | what clean software is. So it's nonsense.
       | 
       | We talk about a computer "science". But in reality it's not a
       | science, it's a cargo cult. We use imprecise language with no
       | concrete definition of what we're actually saying and doing. And
       | we wonder why the end result is so poor.
        
         | javier_e06 wrote:
         | I had to ask ChatGPT what is the meaning of "cargo cult"
         | Notwithstanding the fact that most of us don't know how ChatGPT
         | collects data and follow cue from its output: "Originally a
         | religious movement that emerged in Melanesia during World War
         | II. The movement professed that Western technology and
         | prosperity were result of supernatural powers" I don't scoff at
         | people using the phrase "clean code". I know what is conveying.
         | I do find ChatGPT supernatural.
        
       | ch_123 wrote:
       | It is absolutely true that some hot-path code needs to be mangled
       | into an ugly mess to reach performance requirements. The problem
       | is that I have encountered people who somehow take this as a
       | blanket justification for writing unreadable code, and who
       | operate on a false dichotomy about a choice between readable code
       | and performant code. It is important to keep in mind that:
       | 
       | 1) Most code, i.e. at least 80% of the code in a codebase, will
       | never be a performance hotspot and does not need specific
       | optimizations (i.e. as long as the code does not do stupidly
       | inefficient things, it's probably good enough).
       | 
       | 2) Even in performance hotspot codepath, you should not write
       | unnecessarily hard to read code unless it is strictly necessary
       | to achieve required performance.
       | 
       | In both cases, the key point is to benchmark and profile to find
       | the specific places where the ugly hacks need to be introduced,
       | and do not introduce more than is strictly necessary to get the
       | job done.
        
         | louthy wrote:
         | Agree on this. Although the 80% figure is probably more like
         | 99% (I have no metrics, but 80% feels too low to make this
         | point)
        
           | WalterBright wrote:
           | It's about 99% if you haven't run it through a profiler and
           | optimized the hot spots. With such, you can get it down to
           | 90% or so.
        
             | pclmulqdq wrote:
             | I have noticed that great code and terrible code often have
             | the same characteristics on profiles: in both cases,
             | slowness is spread around everywhere.
        
               | kolbe wrote:
               | In this video, David Gross says something along the lines
               | of "if your data is laid out in a memory inefficient
               | manner, it will be the bottleneck everywhere." If you're
               | dependent on a database query for everything, that will
               | be your bottleneck. If your in-memory structures are
               | cache inefficient, that will be your bottleneck. But once
               | you've fixed all of this (if you can), hot paths and
               | whatnot matter
               | 
               | https://m.youtube.com/watch?v=8uAW5FQtcvE
        
         | jeffreyrogers wrote:
         | The problem is that if you don't know what is required to write
         | fast code you won't design your program to be performant from
         | the start. Lots of applications can be sped up dramatically by
         | rearchitecting them, but you're not going to hit on the right
         | architecture without thinking really hard about memory layout,
         | data access, network usage, etc.
         | 
         | It's not really true that 80% of the code doesn't matter. 80%
         | of the code might not matter the way it is currently designed,
         | but that doesn't mean a different design isn't dramatically
         | better. Benchmarking and profiling doesn't help with that. Real
         | expertise is required and that is developed over time by people
         | who care about improving performance and make it a priority.
        
           | szundi wrote:
           | 80% does not matter, period. I mean 20% is a lot. Hotspots
           | are - spots. Like 0,5% of your code. Not UI for example.
           | 
           | You know, when money is flowing in, you have to hire some
           | good people, let them spend time on fixing hotspots and in
           | some rare occasions, rearchitecture a part or maybe two.
           | Probably won't pay off, but if you are growing fast enough,
           | it will pay 100x.
           | 
           | Also you're decreasing all future development speed with all
           | this unreadable shit everywhere, so beware of optimizing
           | unnecessary stuff.
        
             | jeffreyrogers wrote:
             | For seriously high performance systems like webservers or
             | exchanges, you need to get the architecture right from the
             | start. You can't rearchitect a part or two or solve design
             | problems by making skilled hires later on. The 80% part is
             | a distraction (it's also factually untrue that 80% of code
             | doesn't matter. Some applications don't have hotspots, the
             | performance impact is basically smeared all across the
             | code. It really depends on the application. Sqlite found
             | major speedups by implementing hundreds of little changes
             | that were each almost undistinguishable from noise).
             | 
             | High performance doesn't mean unreadable.
             | Microoptimizations can make code less readable, true, but
             | they also give you the least amount of speedup (in the best
             | case you can get several times speedup if you found some
             | hotspot that can be vectorized, but that's pretty rare).
             | You can get huge performance improvements by optimizing
             | networking and system calls and doing that doesn't make
             | much of an impact on readability.
        
               | eklitzke wrote:
               | As someone who has done performance work for most of my
               | career, I strongly agree with what you've written here.
               | If you have a program that isn't well optimized, it might
               | be true that once you start profiling you can find some
               | hot spots and easy wins, but that doesn't last forever.
               | Earlier in my career I was working on Python web apps,
               | now I write high performance C++ systems, but you can
               | apply this equally to both domains.
               | 
               | Take for example a big and slow Python/Ruby/PHP/whatever
               | web app, something that I'm sure a lot of people on HN
               | have experience with. If you profile one of these apps
               | you're probably going to find that it is slow because
               | it's using an ORM that generates hundreds of SQL queries,
               | the ORM creates tons of intermediate objects which put a
               | lot of stress on the memory allocator and GC, and there
               | will be an endless amount of code that is munging data to
               | take it from one representation (e.g. whatever the ORM
               | returned) to some slightly different representation
               | (whatever the caller actually wanted). There might be a
               | few queries that are particularly expensive, but once
               | you've fixed those you're still going to be left with
               | something big and slow with no obvious path forward to
               | make the code faster. Furthermore the root cause of these
               | problems may not be obvious when looking at profiles
               | because things like memory allocation that are internal
               | to the runtime of your interpreter are typically either
               | not exposed by profiling tools, or if they are it's not
               | clear what action can be taken to improve them.
               | 
               | Likewise if you have a C++ program that does a lot of
               | unnecessary copying and memory allocation, the program is
               | going to be slow because there's a lot of time spent
               | everywhere and there's no one thing to fix. Look at a
               | bottom up profile of a C++ program and see how much time
               | is spent in string constructors, memcpy, etc. and unless
               | you've been thoughtful about this stuff from the start
               | what you find is probably going to be alarming. In fact,
               | since a lot of copy constructors are inlined (including
               | for STL types), with many profiling tools it might not
               | even be obvious that copies are happening at all, since
               | they won't show up in call stacks.
               | 
               | Not every program needs to be high performance, but if
               | you start by writing a lot of code that is slightly
               | inefficient everywhere then it's probably going to be
               | impossible to make things fast if you change your mind
               | down the line.
        
               | robocat wrote:
               | Aside: this is the deeply unobvious optimisation video
               | "Performance Matters" by Emery Berger:
               | https://www.youtube.com/watch?v=r-TLSBdHe1A - they got a
               | 25% speedup in SQLite in 2019!
               | 
               | Start at 9:30 and watch to 10:40 if you want to jump
               | straight into the entre. Dessert discusses SQLite at
               | 40:25 to 41:25.
               | 
               | Summary: A: Causal analysis is needed to discover
               | opportunities for improvements - they developed a
               | technique and tool. B: Modern CPUs have so many hidden
               | causes of performance variation, that you require special
               | tools to actually measure small performance gains. C:
               | They found a surprising difference between -O2 and -O3
               | that implied overfitting (false reporting of performance
               | improvement).
               | 
               | I presume these techniques are used in large software
               | companies, but I am guessing many (most?) developers in
               | smaller companies know little about the topic. I still
               | find it unobvious.
        
             | citrin_ru wrote:
             | I often see death by a thousand cuts - everything is slow
             | and there is no single obvious hotspot to fix. We should
             | not assume that performance matters only for a small
             | fraction of the codebase. Sometimes it is the case,
             | sometimes not.
             | 
             | And UI is a bad example IMHO. UI with a high response time
             | which is uncomfortable (or even frustrating) to use is
             | probably the result of thinking that UI performance doesn't
             | matter.
        
               | HacklesRaised wrote:
               | I think sometimes this exact point is lost in the context
               | of a collection of programs that represent a system
               | rather than simply in the context of a single program.
        
               | grogers wrote:
               | Truly bad UI response time is rarely because of a
               | performance hotspot though. It's almost always
               | unintentionally blocking the UI thread on network
               | requests. I might get mildly annoyed using a sluggish UI,
               | but I get perpetually annoyed whenever I'm doing almost
               | anything on my phone and leave my house's wifi range.
        
               | citrin_ru wrote:
               | It may be not performance hotspot by which we usually
               | mean CPU intensive code but some other performance
               | problem which typically happens when performance is
               | ignored. Networks don't have infinite bandwidth, zero
               | latency and 100% reliability but I see some people create
               | software pretending that all above is true. It works
               | sometimes (until it doesn't) but can work better had they
               | tried to minimize dependency on remote hosts or make
               | network interactions asynchronous.
               | 
               | My opinion is that performance as well as security is
               | very hard to retrofit if it was not considered from the
               | beginning. And if you have necessary knowledge it doesn't
               | take much more effort to create software which is faster
               | (or more efficient) and secure compare to software
               | created by an ignorant developer.
               | 
               | I heard many times that one should write a program first
               | not thinking about performance, then profile and optimize
               | a few hotspots. But in my experience 2nd part
               | (optimization) rarely happens and people who can profile
               | and optimize usually also can write faster code from the
               | beginning.
               | 
               | It is painful to see how people who don't know and don't
               | want to know typical latency [1] and throughput numbers,
               | who don't know about algorithm complexity and may other
               | things design and implement very inefficient software.
               | 
               | [1] https://gist.github.com/jboner/2841832
        
           | seadan83 wrote:
           | > Benchmarking and profiling doesn't help with that.
           | 
           | I've learned that benchmarking and profiling is the _only_
           | way to write performant code.
           | 
           | I've seen in code review a number of examples of a very fancy
           | algorithm being broken out, and asked, "You realize N is
           | bounded to be at most 100 here?". Or, "you realize the thread
           | overhead here for parallel processing is two magnitudes
           | slower than serial data access on one thread?"
           | 
           | Humans are _bad_ at intuitively understanding where the slow
           | parts of code are. I 've seen processing be improved to the
           | point of impossible to grok, shaving 10ms of a processing
           | piece that is 50ms long, only to then spend time blocking
           | waiting for network transfers that require 10s.
           | 
           | I'm of the opinion the biggest performance improvements are
           | usually in design and architecture. What if there were a
           | design that avoided the need to do any network IO? In that
           | case the 10s + 50ms would be a 50ms process, rather than a
           | hard to grok "optimized" 10s + 40ms process. Simple code
           | leads to simpler design, which is easier to reason about and
           | spot the places where things like "this entire network round
           | trip can be cut out", or "we are loading this data multiple
           | times throughout this process, we can load it once", or "we
           | are loading this data and then spending a lot of time
           | querying "n+1", instead if we stored the data in this format
           | with some pre-processing we'll avoid the "n+1" query."
           | 
           | To further rant, the emphasis of algorithms in coding
           | interviews, people enjoying algorithms more than cleaning up
           | crufty architecture - _that_ is the root of a lot of bad
           | software rather. In sum, it 's almost always the design that
           | is slow, rarely it's the algorithm. The profiling is key as
           | it let's you know where things are actually slow. (Recently a
           | colleague was trying to optimize a tight loop that processed
           | 1.5M rows. To "optimize" memory usage, they converted all
           | variables to static to 'save' memory and avoid GC pauses.
           | This in effect did _nothing_, the compiler instead was going
           | to inline all the variables anyways and the resulting
           | bytecode was not going to have any extra variables in at all.
           | Converting local variables to static actually made the memory
           | usage just slightly worse. So, this 'optimization' did
           | nothing but make the code worse. A quick benchmark would have
           | shown that optimization having no effect (to really optimize
           | memory usage, we updated the design to stream results to a
           | file rather than keep everything in memory for a final dump
           | to file at the very end). Another example, I once helped a
           | team do performance work for a DB that they spent a year
           | tuning. They did not keep track of any performance
           | benchmarks, what changes did what improvement; and after a
           | year had nothing to show except for a DB that would crash
           | after a few minutes. Taking that over, starting everything
           | over from scratch, benchmarking everything, the project was
           | done a month later and was stupid fast.)
        
             | gct wrote:
             | Disagree, once you know what you're looking for you can
             | thread the needle pretty easily. I've worked in high-
             | performance areas most of my career and it's pretty wild
             | when I solve a leetcode problem for fun and can routinely
             | get into the 99% percentile on speed and memory usage just
             | from knowing what to avoid.
        
               | bick_nyers wrote:
               | I think you are the golf ball balancing perfectly on an
               | upside down bowl. Optimal, but an unstable solution. Most
               | engineers don't yet know because they don't have enough
               | experience (and most engineers haven't worked in high
               | performance for most of their career), so they need the
               | benchmarks and profiling.
               | 
               | Plus, benchmarks are good solely to be able to show your
               | manager that yes, spending 3 weeks on that refactor was
               | indeed useful. Engineers shouldn't need to have to do
               | that, but it is often useful none the less.
        
         | thethirdone wrote:
         | I definitely agree on the false dichotomy between performance
         | and readable code.
         | 
         | > 1) Most code, i.e. at least 80% of the code in a codebase,
         | will never be a performance hotspot and does not need specific
         | optimizations (i.e. as long as the code does not do stupidly
         | inefficient things, it's probably good enough).
         | 
         | The hard part is knowing what "stupidly inefficient things"
         | are. If you never do excessive optimization, its easy to drift
         | towards less efficient over time because your baseline for what
         | performance is possible slows down. Knowing how to do
         | performance optimization that is not worth it and knowing what
         | the best level of efficiency to shoot for is the mark of a good
         | engineer.
        
           | danielvaughn wrote:
           | Yep, it's entirely possible to get into a scenario where you
           | can't determine _where_ things are inefficient, because the
           | inefficiency is _everywhere_. Once you 're in that spot,
           | you're in for a bad time.
        
           | jackmott42 wrote:
           | Yeah, absent an effort to speed up a code base, it will tend
           | to get slower, unless the team has a culture of performance,
           | everyone is looking for easy performance wins and taking
           | them, and common performance mistakes and getting rid of
           | them.
           | 
           | To do that the team needs experience with performance, and
           | most of internet programmer culture is just to lecture people
           | about how programmers are cheaper than hardware if anyone
           | asks or talks about performance. So many people don't get
           | that experience.
        
             | simplotek wrote:
             | > To do that the team needs experience with performance,
             | and most of internet programmer culture is just to lecture
             | people about how programmers are cheaper than hardware if
             | anyone asks or talks about performance.
             | 
             | But this is an absolute truth, isn't it?
             | 
             | I mean, what's more important to your business: avoid the
             | need to launch an EC2 instance, or implement that user flow
             | in one day instead of one week? Do you care if it takes
             | 50ms to show your dialog box instead of 40ms? Do you really
             | care if you pass all your objects by value, with a few deep
             | copies, instead of passing everything by reference?
             | 
             | The truth of the matter is that in general all performance
             | bottlenecks are caused by software architecture and
             | algorithms, not "clean code" implementations.
        
             | hawk_ wrote:
             | > Yeah, absent an effort to speed up a code base, it will
             | tend to get slower, unless the team has a culture of
             | performance
             | 
             | My experience with JVM over the last few years says
             | otherwise. Most teams I have come across try too hard to
             | achieve "performance" where very simple idiomatic code
             | would have sufficed. Idiomatic code improves in performance
             | every release. Instead they picked up some dogmas based on
             | JVMs of the past and their "peformance culture" is a farce.
        
               | cogman10 wrote:
               | Funnily, what I've seen most frequently with the JVM is
               | most optimizations are on the order of "You should have
               | used a HashSet here, not a List that you keep sorting and
               | removing duplicates from!"
               | 
               | The majority of performance issues I've ran into aren't
               | "Oh, I need just the right structure of code to make
               | things go fast" but rather "I used a Map<String, Object>
               | instead of a PoJo, why is my code slow?"
               | 
               | I think a big problem is the "don't prematurely optimize"
               | has been taken to mean "never think about how your
               | algorithm will perform". It allows someone to write an
               | n^2 or n^3 algorithm when the n algorithm is just as
               | readable (usually moreso!)
        
             | johnmaguire wrote:
             | > programmers are cheaper than hardware
             | 
             | Did you mean the reverse of this, I assume?
        
               | 908B64B197 wrote:
               | Depends on your install base/target.
               | 
               | At Apple scale, paying a few performance engineers 1M/y
               | is much cheaper than shipping bibber and more powerful
               | CPU in each iPhone.
               | 
               | Same thing for AWS or Azure.
        
             | jjav wrote:
             | > So many people don't get that experience.
             | 
             | This is very true. The misuse of the "premature
             | optimization" mantra and the thought that valuable
             | programmer time should never be spent on performance have
             | done a disservice to a generation or two of developers. To
             | the point that so many developers don't even believe
             | performance has any significance and the cloud just
             | magically makes it fast.
             | 
             | Spending a week optimizing some function to shave off a few
             | seconds may be totally worth it, just depends how often it
             | runs. If it is a code path being used by millions of
             | people, it can quickly become very valuable.
             | 
             | Cost is another factor. Sure you might be able to
             | effortlessly spin up dozens or hundreds more instances on
             | demand to handle the load because the code is so slow one
             | instance can barely handle a few dozen requests per second,
             | but you're paying for that. Make an instance capable of
             | handling a few thousand rps and suddenly you've save very
             | real money.
             | 
             | And battery life on all portable devices also benefits from
             | more efficient CPU usage.
        
           | OkayPhysicist wrote:
           | > your baseline for what performance is possible slows down.
           | 
           | This is a problem that absolutely plagues our field. If your
           | project isn't some wrapper around some incredibly complicated
           | math or handling files well into the GB range, there's no
           | excuse for a desktop application to take noticeable time to
           | do anything. Yet here we are, with it taking about a half
           | second just to open the search bar on windows. What is it
           | doing? Why does it take so long? Who knows?
        
             | F-W-M wrote:
             | IO on the UI thread.
        
           | simplotek wrote:
           | > The hard part is knowing what "stupidly inefficient things"
           | are.
           | 
           | There are things that are quite obvious non-critical in terms
           | of performance.
           | 
           | One time I had a junior engineer insisting in a PR that we
           | should use a few low-level performance tricks in a code
           | because it was fast, and the code was to open a dialog box.
           | 
           | Also, in general performance bottlenecks are caused by
           | architectural and algorithmic choices, not readability
           | choices. If we're in a domain where, say, inheritance is an
           | unacceptable performance bottleneck and we need to unroll
           | loops and we can't extract functions because the cost of
           | pushing the call stack is prohibitive... We are in an
           | extremely performance-sensitive part of the code.
           | 
           | But most of the time we're far from any of that.
        
             | gpderetta wrote:
             | If inheritance and function calls are a bottleneck, it is
             | probably the time to change programming language.
        
               | F-W-M wrote:
               | LLVM had that problem. But if you are already writing in
               | C++, where do you switch to? (Spoiler: it's code
               | generation).
        
         | dahfizz wrote:
         | This makes assumptions about what the performance requirements
         | are.
         | 
         | In latency sensitive code, _all_ code needs to be optimized. It
         | doesn't matter if your slow function is only called once - it
         | adds N microseconds of latency when it doesn't need to.
        
         | zwieback wrote:
         | I think that's where the craft of programming comes in. I feel
         | like after 30 years in the field I have a reasonable idea how
         | and when to optimize but it's not something I learned from
         | classes or textbooks.
        
         | xg15 wrote:
         | > _1) Most code, i.e. at least 80% of the code in a codebase,
         | will never be a performance hotspot and does not need specific
         | optimizations (i.e. as long as the code does not do stupidly
         | inefficient things, it 's probably good enough)._
         | 
         | That's true, however, I've seen enough code where the author
         | used this argument as a justification to _do_ stupidly
         | inefficient things, such as building monstrous mountains of
         | abstraction layers (or _re-scan the entire codebase at runtime_
         | because why not? [1]) all covered by the  "premature
         | optimization is the root of all evil" mantra.
         | 
         | You can absolutely write code that is both opaque _and_
         | inefficient.
         | 
         | [1] https://docs.spring.io/spring-
         | framework/docs/3.0.0.M4/spring...
        
         | flavius29663 wrote:
         | 80% seems very low, in my experience it's 1% or less of the
         | code that is a hotspot.
         | 
         | On the other hand, we should talk about "doing stupid things",
         | or having a bad design/architecture. For example, if you
         | architect your application such that each web request is
         | serviced by 20 micro-services, and those micro-services make 20
         | requests of their own...no matter how fast your code is, the
         | application will be slow.
        
           | atq2119 wrote:
           | I suspect the 1% number is typical only of programs that
           | haven't been optimized. Once people start to care about
           | performance and address these hotspots, which are often
           | actually quite low hanging fruit, the profile starts to
           | become flatter relatively quickly.
        
         | tombert wrote:
         | I had a manager who would write the most hideous, impossible-
         | to-debug code imaginable and always have some sort of
         | microbenchmark as some kind of justification. At the time I was
         | young enough in my career to just think he was wiser than I
         | was, but upon reflection (and remembering some of the stuff he
         | did involving FFI-ing C into Haskell all the time), I realized
         | that he just didn't he didn't like people criticizing his code,
         | though the first hint should have been when he refused to
         | answer my questions about actual performance profiling of our
         | codebase.
        
         | [deleted]
        
         | jjav wrote:
         | > Most code, i.e. at least 80% of the code in a codebase, will
         | never be a performance hotspot
         | 
         | Yes, and no. That's what makes it hard to write high
         | performance systems, you really need people with solid
         | experience in designing for performance.
         | 
         | Sure, always go for the low hanging fruit which are the
         | hotspots identified by profiling and improve those.
         | 
         | But what often happens after that is that all the code is slow
         | everywhere! So there are no big hotspots, profiling shows
         | nothing egregious. Teams without high performance systems
         | experience might conclude the code is about as good as it can
         | get given the absence of hotspots. Seen this happen often. But
         | there might be 10x or 100x improvements remaining.
        
           | bick_nyers wrote:
           | In other words, what is the speed of light solution? The
           | fastest possible solution that could be achieved?
        
         | commandlinefan wrote:
         | > blanket justification for writing unreadable code
         | 
         | Well, ironically, the site itself is down (so the code must be
         | beautiful?) but assuming I understand the content from the
         | title, another thing that most of these "code quality doesn't
         | matter" types overlook is that software changes over time,
         | quite a bit. That's why it's called "soft"ware, it's supposed
         | to be soft. Readable is changeable. If all the mattered were
         | performance, we'd engrave the code path onto a circuit board.
        
         | systematical wrote:
         | Saved me a lot of typing.
        
         | tincholio wrote:
         | At the same time, one should not automatically assume that
         | "clean code" is actually readable. I've had to deal with
         | architecture astronauts of the Uncle Bob school of "clean
         | code", and their code was anything but readable.
        
         | Shorel wrote:
         | I agree so much with you, "in theory".
         | 
         | In practice, most of the industry has been writing ridiculously
         | inefficient code for decades, and I wish more people would pay
         | attention to that 20%, or the 3% that Knuth described.
         | 
         | Or better yet, I wish some groups don't irreversible sacrifice
         | performance with frameworks and architectures that are
         | impossible to optimize, no matter how the code is written.
        
           | commandlinefan wrote:
           | > I wish more people would pay attention to that 20%,
           | 
           | I agree with both of you - there's no reason why software
           | should be as inefficient as it is, and there's _also_ no
           | reason why code should be as unreadable as it is, and those
           | goals aren 't mutually exclusive.
        
             | simplotek wrote:
             | > I agree with both of you - there's no reason why software
             | should be as inefficient as it is,
             | 
             | Except that it is, and it tends to be development speed.
             | 
             | For example, real world React apps tend to suffer a lot
             | from performance issues, specially when compared with
             | vanilla html+javascript or even the old but true server-
             | side rendered HTML, but it also makes it trivial to
             | implement and rewrite complex UIs that UX designers love to
             | put together. Would it make sense to argue for performance
             | options which lead to productivity hits?
        
               | commandlinefan wrote:
               | > argue for performance options which lead to
               | productivity hits
               | 
               | Always.
        
         | [deleted]
        
         | patrulek wrote:
         | Its true for services/applications. In a case you write
         | library, others will import into their projects, you should
         | always treat performance seriously imo.
        
         | taeric wrote:
         | The problem is that so many practices we have gravitated to are
         | actively harmful to performance. Worse, they are borderline
         | harmful for maintenance. Specifically, some practices are
         | better for larger teams than they are smaller teams.
         | 
         | Difficulty in that last is that the best practice for how to
         | maintain code changes as you get older on the project. This is
         | easy to see in code that is a bit of a mungled mess. But it is
         | also visible on code that it is a beautiful stalled out mess of
         | needing too much to get small contributions in.
        
       | wfurney wrote:
       | https://archive.is/Q82MY
        
       | jackmott42 wrote:
       | The website seems to have gone down under load, if this is a
       | snarky response to Casey's pro performance take previously, then
       | the irony level is high!
       | 
       | I really wish people would stop pushing back on people who are
       | interested or curious about how to make code perform better. Of
       | course you don't want people scattering weird SIMD intrinsics all
       | over mundane parts of your web backend in an unhinged attempt to
       | shave microseconds off a response. But in my career I've never
       | really seen people do this anyway.
       | 
       | What you _do_ want though is programmers who have spent some time
       | understanding how to structure code to perform well on modern
       | hardware. Because often times that structure is NOT a mess, it
       | may even be easier to work with that the usual idioms in your
       | industry or language. Grouping data into adjacent chunks with
       | arrays or array backed data structures has more benefits than
       | just leveraging the L1 cache. It is sometimes also convenient.
        
         | secondcoming wrote:
         | We put a 'does this person understand assembly output' into our
         | interview process. They don't have to get it 100% right, but
         | not knowing anything is a hard No.
        
           | moosedev wrote:
           | Interesting! What kind of company and technology domain is
           | it? Assuming you don't want to get too specific.
           | 
           | My first reaction is that I like this idea, but maybe I'm
           | biased because I feel I'd "pass the test" myself (and thus
           | have one additional small way to differentiate myself from
           | pure Leetcoders :)
           | 
           | In most of the environments I've worked (except maybe the
           | games companies) I feel this would not have been widely
           | considered an acceptable thing to ask in a generalist
           | interview.
        
             | secondcoming wrote:
             | adtech exchange
        
         | wk_end wrote:
         | I'd say it's orthogonal to Casey's take, which was about
         | trading abstraction for (arguable) simplicity + performance.
         | This was an article about aggressively optimizing a simple
         | loop, thus trading simplicity for performance.
         | 
         | Given that it was from a consultancy advertising its
         | optimization services, the irony of it going down is still
         | pretty high, though.
        
           | TremendousJudge wrote:
           | What I didn't like about the "Clean code, horrible
           | performance" video is that he talked about "clean" code as
           | though it was this unjustified, useless way of thinking about
           | programming. This is maybe something you have to think about
           | if you want the most performant code possible, but I don't
           | think it's a good mantra in all situations the way it's
           | presented in the video. Number one priority should always be
           | "understandable code". If you aren't always thinking about
           | the best way to get your point across to future programmers
           | (including yourself) you're going to have a bad time.
        
       | acl777 wrote:
       | I remember this was a holy war amongst programmers (even myself!)
       | - readability OR performance.
       | 
       | With tools like ChatGPT - we can have both readability AND
       | performance, right??
       | 
       | Or am I missing something?
        
         | circuit10 wrote:
         | If you mean automatically optimising code, the reliability
         | isn't quite there (it can't check its own code) and the limited
         | context length means it might struggle to reason about the
         | codebase as a whole
        
           | mlajtos wrote:
           | Could you be the human judge please?
           | 
           | https://mlajtos.mu/posts/no-code-clean-performance
        
         | pjc50 wrote:
         | Correctness?
         | 
         | I've not seen anyone seriously attempting to benchmark chatgpt
         | output, without heavily cherry picking it first.
        
         | mlajtos wrote:
         | I explored this question a bit:
         | 
         | https://mlajtos.mu/posts/no-code-clean-performance
        
         | jerf wrote:
         | Dunno about "readibility" but I fully expect ChatGPT to produce
         | vast swathes of code that nobody understands.
         | 
         | While I'll cop to being more skeptical than the average HN
         | denizen about ChatGPT, this isn't actually cynicism about
         | ChatGPT, but about human cognition. If we do have something
         | that produced large swathes of mostly correct code, it won't be
         | long before the humans using it aren't even checking it
         | anymore. Same reason that cars can do a little bit of
         | assisting, and if they could do 100% of the driving that might
         | be safe, but 98% of the driving is not a very good idea at all.
         | 
         | In 20 years, someone will ask CodeGPT 8.3 to explain what some
         | code does, and it'll give a perfectly understandable
         | explanation back, except the human still won't understand it
         | because the human doesn't actually understand how computers
         | work anymore. They'll think they understand it, though.
        
           | dragonelite wrote:
           | That's why i think the copilot and chat gpt hype will end up
           | as one big balloon and in ten years time we will have a pile
           | of generated code no one really understands anymore that
           | needs to be fixed. Kind of like after the out sourcing
           | adventure people had in tech in the early 2010s or so.
        
       | attractivechaos wrote:
       | The blog post is effectively implementing memmem() or strstr()
       | that searches a short string in a long string. If we are allowed
       | to use GNU extensions, the cleanest solution is to call memmem().
       | Without memmem(), I would implement Boyer-Moore or Knuth-Morris-
       | Pratt, which will be more scalable than the O(MN) implementation
       | in the blog post. Time complexity matters.
        
         | mlajtos wrote:
         | You seem like you know a thing about C++, would you please take
         | a look at this garbage? https://mlajtos.mu/posts/no-code-clean-
         | performance
        
           | verall wrote:
           | > I really hate reading C++ so I really haven't checked any
           | of the produced snippets for correctness.
           | 
           | So they're almost certainly wrong...
        
         | wk_end wrote:
         | Yes, this was my takeaway - it was a very poor choice of
         | example, because a known faster algorithm will crush the sort
         | of micro-optimizations done here _and_ be more readable.
         | 
         | Or perhaps it was actually an incredibly good example, despite
         | itself: a great illustration of precisely why jumping to micro-
         | optimization isn't always the right solution.
        
           | pclmulqdq wrote:
           | This is also a problem where the algorithmically fastest
           | solutions are also pretty much guaranteed to be faster, since
           | they are equally cache-friendly and will almost always work
           | out to fewer instructions.
           | 
           | That is not always the case, but this is one of the times
           | when it is.
        
       | strken wrote:
       | It's interesting to think about the difference between isolated
       | horrible code that sits in a function and does its own thing, vs
       | architecturally horrible code that tends to spread outward and
       | infect the rest of the program.
       | 
       | In cases like ECS (in gaming) or virtual DOM (in web), the
       | "horrible" architecture comes out the other side and becomes
       | almost clean again.
        
       | moomoo11 wrote:
       | I mean it's possible to have both clean and performant.
       | 
       | If you have a high performance requirement you should extract
       | that code into its own "space" and not try to make the existing
       | system shitty.
       | 
       | Use API contracts between systems and don't muddy up existing
       | systems.
        
       | dack wrote:
       | can't read the article because the site timed out.
       | 
       | maybe the code behind his blog is too clean!
        
         | Freedom2 wrote:
         | A capital joke, kudos to you! Made me chuckle.
        
       | bena wrote:
       | Unfortunately, there are many reasons to write horrible code.
       | 
       | I work in-house for a non-tech related company. I'm often the
       | sole developer, sometimes I have help. I'm also the defacto DBA
       | and systems administrator for the machines the software runs on.
       | As the defacto DBA, I'm also roped into data analysis as well.
       | 
       | There are also certain events that are non-compromisable. These
       | events take place whether we are ready or not. Having nothing is
       | not really an option. That means shelving the project until next
       | year. Because the next event must be prepared for.
       | 
       | So, at the end of the day, "done is best". If I have the time, I
       | can go back and refactor everything into something better. But
       | often, there's "the next thing".
        
       | xg15 wrote:
       | I would say this is not horrible code - or at least, it's
       | "hollywood horrible". [1] Yes, it's not directly intuitive and
       | probably would need some illustrating comments, but it's still
       | reasonably close to the "naive" algorithm that you could quickly
       | figure out how it works. More importantly, it's still localized,
       | concrete and side-effects free: The code has a clear goal and
       | accomplishes that goal completely inside that one function. The
       | non-intuitive parts also have a clear reason.
       | 
       | I think actual horrible code is more something that uses global
       | mutable state, has logic spread over half a dozen units or _does_
       | have weird roundabout implementations - however not because of a
       | particular reason but because of unclear goals, big-ball-of-mud
       | architecture, evolving codebase etc.
       | 
       | [1] https://tvtropes.org/pmwiki/pmwiki.php/Main/HollywoodHomely
        
         | KineticLensman wrote:
         | Oh No! I've already been down one TvTropes rabbit hole today.
        
       | fwlr wrote:
       | I have long been in the habit of leaving in the old pre-optimized
       | code, commented out, above the optimized code. I generally don't
       | think that performant code ends up all that mangled, but it costs
       | ~nothing to leave the old code in a comment.
       | 
       | I picked this practice up from an older engineer who would set
       | SLOW = false
       | 
       | at the top of the file and then wrap old code in a
       | if (SLOW) { ... }
       | 
       | block for the compiler to do dead code elimination on. (I found
       | linters and compilers complained less about commented-out code,
       | but he preferred his way so it would always have syntax
       | highlighting.)
        
         | capableweb wrote:
         | > but he preferred his way so it would always have syntax
         | highlighting
         | 
         | On that topic, probably one of the top-3 features from Clojure
         | I miss in other languages, is having the option of making
         | comments being a part of the language itself so everything that
         | works on the code (linters, evaluation, syntax highlighting,
         | etc) works in the comment as well. The `comment` macro really
         | is a godsend in disguise as it's awfully simple implementation-
         | wise. Its cousin `#_` is also a great tool. See
         | https://clojuredocs.org/clojure.core/comment for more examples
        
         | lozenge wrote:
         | Another option is to keep both versions and write a test that
         | they return the same value, e.g. using property-based testing.
        
           | JonChesterfield wrote:
           | Granted I haven't tried to get it through review, but for
           | things where the fast version is complicated I usually end up
           | with                   static bool set_t_contains_fast(set_t
           | x, uint64_t e);         static bool
           | set_t_contains_simple(set_t x, uint64_t e);         bool
           | set_t_contains(set_t x, uint64_t e)         {           bool
           | f = set_t_contains_fast(x, e);
           | assert(set_t_contains_simple(x, e) == f);           return f;
           | }
           | 
           | sometimes with a CONTRACTS macro controlling it instead of an
           | assert.
        
           | fwlr wrote:
           | Although I agree that you _must_ test optimized code for
           | correctness, I think it should be approached very cautiously,
           | as tests can become checkpoints that constrain optimization.
           | 
           | I had a memorable experience of that, actually - for a long
           | time we had a Trello card titled "faster to operate on the
           | bits instead", and the team looked at that card fondly during
           | development. After we started getting traction, it was
           | finally time to optimize! We conscientiously wrote tests to
           | ensure correctness, and then began an incredibly enjoyable
           | informal hackathon. We blazed through every step, replacing
           | the logic piece by piece with bit operations. This step was
           | 2x faster, that step was 5x faster, and so on. A few steps
           | were slower, which was a bit weird, but we were having _so
           | much fun_ shouting out our gains to each other across the
           | room, racing to improve. By the afternoon we had optimized
           | each step and gotten an order of magnitude improvement.
           | 
           | "Great stuff, team."
           | 
           | "I thought it would have been faster."
           | 
           | "Yeah, same."
           | 
           | We did some evening profiling and noticed a lot of time being
           | spent in a dozen or so functions with names like "toRepr",
           | "reconstitute", stuff like that. Actually it was like _most_
           | of the time - what!? And then we saw, at each step we
           | converted to raw bits, performed the equivalent logic with
           | fast bit operations, then converted back to the
           | representation for handoff to the next step. Wait, why we are
           | converting to and from bits like thirty times each run? That
           | can't be right. Realization strikes - right before most
           | handoffs there was a commented-out line that ran out tests on
           | the representation to ensure it was still correct.
           | 
           | Someone pointed out we wrote that test before we had done any
           | investigation of performance (I remember it almost word for
           | word actually, "When we wrote the test, _all we knew_ was it
           | would be faster in bits, but not _how_. And the test doesn't
           | even look at bits!"). So we ripped out all the conversions
           | and stayed in bits from step to step. Without changing the
           | bit logic it was now almost three orders of magnitude
           | performance gain, basically running in milliseconds instead
           | of seconds. Two OOM that we had earned, but left on the
           | table!
           | 
           | Tests introduced arbitrary checkpoints and imposed irrelevant
           | constraints on the problem, without us noticing until
           | afterwards. We caught the problem pretty easily that time,
           | but I do wonder how many other times we (or others) didn't
           | because it wasn't as obvious. The service that accepted the
           | output maybe should have been accepting raw bits instead of
           | the representation. The service that gave us the input
           | _definitely_ should have been staying in the bits.
           | 
           | So, do test your optimizations for correctness, but be really
           | careful. Tests can easily and subtly constrain your
           | optimization space in major and arbitrary ways!
        
             | bluefirebrand wrote:
             | This is actually a really interesting potential pitfall of
             | TDD that I don't think I've seen discussed before.
             | 
             | The idea that test design can actually constrain your
             | solutions if your tests are too opinionated about
             | implementation is fascinating.
             | 
             | Seems like maybe optimization needs to be a loop of "we
             | optimize the code, then we optimize the tests"
             | 
             | Something to that effect.
        
       ___________________________________________________________________
       (page generated 2023-04-19 23:02 UTC)