Having said that, even Java now encourages programmers to use algebraic data types when "programming in the small", and OOP/encapsulation at module boundaries: https://www.infoq.com/articles/data-oriented-programming-jav... though not for performance reasons. My point being is that the "best practice" recommendations for mainstream language does change.
“Clean” code, horrible performance
81–90 of 932 posts
Re: “Clean” code, horrible performance
#821. Prefer polymorphism to “if/else” and “switch” - if anything, that makes code less readable, as it hides the dispatch targets. Switch/if is much more direct and explicit. And traditional OOP polymorphism like in C++ or Java makes the code extensible in one particular dimension (types) at the expense of making it non-extensible in another dimension (operations), so there is no net win or loss in that area as well. It is just a different tool, but not better/worse.
2. Code should not know about the internals of objects it’s working with – again, that depends. Hiding the internals behind an interface is good if the complexity of the interface is way lower than the complexity of the internals. In that case the abstraction reduces the cognitive load, because you don't have to learn the internal implementation. However, the total complexity of the system modelled like that is larger, and if you introduce too many indirection levels in too many places, or if the complexity of the interfaces/abstractions is not much smaller than the complexity they hide, then the project soon becomes an overengineered mess like FizzBuzz Enterprise.
3. Functions should be small – that's quite subjective, and also depends on the complexity of the functions. A flat (not nested) function can be large without causing issues. Also going another extreme is not good either – thousands of one-liners can be also extremely hard to read.
4. Functions should do one thing – "one thing" is not well defined; and functions have fractal nature - they appear do more things the more closely you inspect them. This rule can be used to justify splitting any function.
5. “DRY” - Don’t Repeat Yourself – this one is pretty good, as long as one doesn't do DRY by just matching accidentally similar code (e.g. in tests).
Re: “Clean” code, horrible performance
#83I don't think there is a contradiction or surprising point here. At least my understanding of the case for clean code is that developer time is a significantly more expensive resource than compute, therefore write code in a way which optimises for developers understanding and changing it, even at the expense of making it slower to run (within sensible limits etc etc).
Yeah you're right, nobody ever said to me "use interfaces because the code it's faster". On the other hand, when I studied dynamic dispatch and stuff like that, I don't think enough people told me "when you do that, you are making this tradeoff". I feel like it's worth sharing this kind of knowledge in order to make better informed decisions (possibly based on numbers). There's no need to become an extremist in eithe…
The claim of 20x program performance difference is overblown. Compilers can often remove virtual function calls, JITs can also do it at runtime. Virtual function calls in a tight loop are slow but most of your program isn't in a tight loop and few programs have compute as a bottleneck.
Measure your program, find the tight loops in your program and optimise that small part of your program.
Re: “Clean” code, horrible performance
#84Re: “Clean” code, horrible performance
#85Much of this is very compiler dependent. For example, Java's compiler is generally able to perform more aggressive optimisations, and even virtual calls are often, and even usually, inlined (so if at a particular call-site only one shape is encountered, there won't even be a branch, just straight inline code, and if there are only two or three shapes, the call would compile to a branch; only if there are more, i.e. a…
Last time I checked it could not inline megamorphic call sites, evn if implementations were trivial (returning constants). At the same time I saw C++ compilers able to replace an analogue switch that dispatched to constants with a simple array lookup, with no branching at all.
Re: “Clean” code, horrible performance
#86Earlier quoted context omitted.
> developer time is a significantly more expensive resource than compute Depends on the number of invocations of the program.
Not just that. The “developer time is valuable” mantra is thrown left and right, disregarding how much of that valuable resource will be wasted down the line due to bad implementations. If we optimize for developer time, let’s optimize across the software’s entire lifecycle, not just that first push of a MVP to production.
Re: “Clean” code, horrible performance
#87Re: “Clean” code, horrible performance
#88First off, the number of problems where having an analytical measure of shape area is important is pretty small by itself. Second, if you do need to calculate area of arbitrary shapes, then limiting yourself to formulas of the type `width * height * constant` is just not going to cut it. And this is where the entire optimization exercise eventually leads: to build a table of precomputed areas for affinely transformed outlines.
Throw in an arbitrary polygon, and now it has to be O(n). Throw in a bezier outline and now you need to tesselate or integrate numerically.
What this article really shows is actually what I call the curse of computer graphics: if you limit your use cases to a very specific subset, you can get seemingly enormous performance gains from it. But just a single use case, not even that exotic, can wreck the entire effort and demand a much more complex solution which may perform 10x worse.
Example: you want to draw lines? Easy, two triangles! Unless you need corners to look good, with bevels or rounded joins, and every pixel to only be painted once.
Game devs like to pride themselves on their performance chops, but often this is a case of, if not the wrong abstraction, at least too bespoke an abstraction to allow future reuse irrespective of the use case.
This leads to a lot of dickswinging over code that is, after sufficient encounters with the real world, and sufficient iterations, horrible to maintain and use as a foundation.
So caveat emptor. Framing this as a case of clean vs messy code misses the reason people try to abstract in the first place. OO and classes have issues, but performance is not the most important one at all.
Re: “Clean” code, horrible performance
#89TL;DR: "Game developer optimizes code for execution as opposed to readability that 'clean-code' people suggest". There are few considerations: - most code is not CPU bound so his claims that you are eroding progress because you are not optimizing for CPU efficiency is baseless - writing readable code is more important than writing super optimal code (few exceptions: gaming is one) - using enums vs OOP is not changing…
I'm tired of every tool I install on my latest gen Intel CPU + 32GB RAM + NVMe drive machine being a complete slog. To each their own, but I don't find Casey's performant version less readable, I don't see the need for so many abstractions.
Re: “Clean” code, horrible performance
#90The iPhone comparisons are extremely cringe. Real application do so much more then this contrived example. Something that feels fast isn’t the same thing as something is fast.
Would I advise beginner programmer’s to read this book? Sure, let them think about ways to structure code.
If he just had concluded with, that it is important to optimize for the right thing that would be fine. But he seems more interested in picking a fight with clean code.
And yes performance is a lost art in programming