Live data from Hacker News

“Clean” code, horrible performance

computerenhance.com

121–130 of 932 posts

Re: “Clean” code, horrible performance

#121
post #92
post #74

There is no doubting Casey's chops when he talks about performance, but as someone who has spent many hours watching (and enjoying!) his videos, as he stares puzzled at compiler errors, scrolls up and down endlessly at code he no longer remembers writing, and then - when it finally does compile - immediately has to dig into the debugger to work out something else that's gone wrong, I suspect the real answer to progra…

If you're talking about Handmade Hero, the real answer to programmer happiness is not using a language you despise and refusing to leverage the features of, not refusing to use libraries in that language or frameworks, not re-implementing everything from first principles, and to actually have your game designed first (not designing while you code.)

Casey is a bad example of a game designer and he'll be the first to admit it. However, it is worth noting that Jonathan Blow very much does design while he codes and recommends the practice. He also generally abstains from library dependencies and implements a lot of thing himself.

Of course, part of the point of Handmade Hero is to show that you can totally reimplement everything from first principles. Libraries are not magical black boxes, they're code written by human beings like you or me, and you can understand what they're doing.

For instance, he wrote his own PNG decoder[0] live on stream, with hardly any prior knowledge of the spec, even though I'm confident that under normal circumstances he'd just use stb_image. I'm sure he did this just to show how you'd go about doing that sort of thing.

[0] He only implemented the parts necessary to load a non-progressive 24bit color image, but that still involved writing his own DEFLATE implementation.

Re: “Clean” code, horrible performance

#122
post #45

Earlier quoted context omitted.

> TDD or XP methodologies > the more concepts and abstractions you apply to your code the better programmer you are! These contradict each other. XP very explicitly opposes introducing (unnecessary) abstractions: YAGNI, DTSTTCPW, etc. And TDD is a good tool for enforcing that, as you only get to write code that you have a failing test case for.

> TDD is a good tool for enforcing that, as you only get to write code that you have a failing test case for. TDD encourages the use of mocks and unit testing to increase code coverage. And unit testing is specially dangerous. You write a test, then program, so the test is helping you (the programmer). Selling the idea that the higher the test code coverage is the better and safer your code is. Not true at all. If yo…

> TDD and exhaustive unit testing make the maintenance process harder because you don't know if a test is useful or not.

TDD was later given the name BDD (Behaviour Driven Development) to emphasize that you are not testing, but actually documenting behaviour. What kind of behaviour are you documenting that isn't useful and why did you find it necessary to document in the first place?

> If you follow TDD, most unit tests are re-written all the time.

What for? If changing requirements see that your behaviour has changed to the extent that that your unit does something completely different, it's something brand new and should be treated as such. Barring exceptional circumstances, public interfaces should be considered stable for their entire lifetime and, at most, deprecated if they no longer serve a purpose.

The implementation beneath the interface may change over time, but TDD is explicit that you should not test implementation – it is not about testing – only that you should document the expected behaviour of any implementation that may carry out your desired behaviour.

Re: “Clean” code, horrible performance

#123
post #88

The example of using shape area seems like a poor choice. First 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 b…

To summarize: if you make the problem complex enough, then the specific performance methods used in the article don’t work. But hey, why not take your complex example? If you apply a polymorphic approach to Bézier curves and polygons, then you still get a 1.5x slowdown compared to a switch statement. If you have any commonality between your implementations of area for them, it’s harder to find, which could be worth 2…

> You’re right that once you’ve done the 15x performance gain that Casey demonstrates, the code is pretty brittle and prone to maintenance problems if the requirements change a lot.

In some sense, it is a good thing. It creates natural backpressure to scope creep.

The "Clean Code" developer can add a new complex shape type to their program in 15 minutes; just subclass here, implement the methods, done, no changes to other code. No performance impact - the program remains as badly performant as it was before.

The Casye-style developer will take 15 minutes and come back to you with:

"Oh, we can make the calculations for this new shape approximate to, idk. +/- 50%, by adding another parameter to the common equation; this will, however, cause 1.1x performance drop across the board. We could make it accurate by special-casing, at the cost of 2-3x perf drop for the whole app. We can also spend a person-week looking into relevant branch of mathematics to see if there isn't a different equation that could handle the new shape accurately with no performance penalty."

"Or, you know, we could just not do it at all. Why exactly do we need to support this new shape? Is supporting it worth the performance drop?"

Whichever option the developer and their team chooses, their software will still remain an order of magnitude more performant than the "Clean Code" style. Which is to say, those devs are aware of the costs - the "Clean Code" style is so ridiculously wasteful, as to not even notice such costs in the first place.

Re: “Clean” code, horrible performance

#124

Earlier quoted context omitted.

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.

>I don't find Casey's performant version less readable It does create implicit coupling. If you try to add a new shape you will run into the problem. In the clean code version, your compiler will remind you to implement calculateArea With his version you have to add a new `case` to every switch statement and hope you didn't miss one with a default case, because the compiler won't catch this one. It's a crap way to co…

people using clean code ideologies are being prematurely pessimistic and assuming they know much more about a problem than they actually do when they use these clean code techniques. "I don't know how many shapes I've been asked to do, so I'll assume the worst case scenario and make the code slower and harder than the simple naïve solution that would be hard to read(debatable) if we had one million shapes" is a terrible argument and it is why everything goes slow.

The correct way to deal with this, is refactoring to a more maintainable code once you know the amount of shapes will wildly change, As soon as we get too many shapes as the problem has changed. You can only pretend to know what is the best architecture for a problem when you have dealt with it several times.

Clean code apologists pretend their single time dealing with website backend is proof enough that clean code works and that it works for every problem and that it has to be the default approach and is the most readable for most problems. It is a total insanity for something that can't be measured with any tool.

Edit:

I fully understand that "premature optimization is wrong" but using these "guidelines" is premature optimization of scalability and maintainability. Somehow when the "premature optimization" is about things you people want that's somehow okay? pff

Also, I don't find clean code readable, it looks like complex, un-refactorable garbage to me 9 out of 10 times. No wonder why people are so fucking scared of rewriting a class and act is if it will take months to do so, this ideology makes impossible to actually play around with your code, you can't neither make it more readable or more performant, you are locked in with a sluggish collection of dozens of files even for the simplest of problems.

Re: “Clean” code, horrible performance

#125
post #11

The problem with the contemporary "clean code" concept is that the narrative that performance and efficiency don't matter has been pushed down the throat of all programmers. Re-usability, OOP concepts or pure functional style, design patterns, TDD or XP methodologies are the only things that matter... And if you use them you will write "clean code". Even worse, the more concepts and abstractions you apply to your cod…

> Even worse, the more concepts and abstractions you apply to your code the better programmer you are! I had an Android programmer, who was eager to write clean code following GOF patterns, OP and the rest of the fancy things senior developers usually do. Ended up Android team with 3 devs required 3x time to develop same feature compared to single iOS engineer.

Well they weren’t a good senior developer then. Part of the art is knowing when to use the patterns. An incredibly im protest differentiation as it’s so so easy for someone a bit green behind the ears to see this and think that any sort of architectural thinking is useless.

Re: “Clean” code, horrible performance

#126
post #11

The problem with the contemporary "clean code" concept is that the narrative that performance and efficiency don't matter has been pushed down the throat of all programmers. Re-usability, OOP concepts or pure functional style, design patterns, TDD or XP methodologies are the only things that matter... And if you use them you will write "clean code". Even worse, the more concepts and abstractions you apply to your cod…

One of the most insane things I hear repeated constantly is that "servers are cheaper than programmers", implying that runtime efficiency doesn't matter, only developer efficiency.

Which is all well and good, until you need to hire all the network engineers, systems administrators, devops people, security staff, datacenter operations managers, database sharding engineers, etc to manage the 10x more hardware and network surface area you have to throw at your slow codebase.

Re: “Clean” code, horrible performance

#127
post #120
post #59

Earlier quoted context omitted.

One can argue that simple code is both fast and clean. However, you can only measure how fast (or slow) your code is, so make it simple, aim for fast and hope it's clean (:

One can argue that extremes of fast and clean code will both result in something horrific. What Casey is doing is showing how bad a hammer is at removing screws. I mean duh, you're removing screws with a hammer.

I don't understand what you are saying.

My comment was a jest (as suggested by the smiley).

What I take from Casey's post is that a simple non-pessimistic representation allows for efficient code. That is, using a table instead of a class hierarchy gives massive performance boost. Compared to a "clever" loop unrolling doesn't give that much of a boost.

So we need simpler representation. IMHO the table implementation is not less readable nor less flexible than the class hierarchy. But it is less common in the code I am used to, in other words, it's not a widely used pattern).

Re: “Clean” code, horrible performance

#128
post #114
post #31

Earlier quoted context omitted.

Nobody is saying maintainable code isn't important but rather that clean vs fast is a false dichotomy.

There are competeing in my opinion. Many techniques to make code fast will make it less readable. Techniques like manual code unrolling/inlining, writing branchless code, compressing data to fit into a pointer, etc.

I agree .. fast doesn't take account of how verbose or understandable code will be.

As an extreme example, people choose not to write low level code for a good reason, even if it might be fast.

High level / interpreted code will be more understandable, but will automatically have an overhead in most cases.

Re: “Clean” code, horrible performance

#129
David Farley’s new book is good. It advocates for the tenants of “clean code” (at least in all lowercase), but given his background I trust that he knows how to balance performance and code hygiene.

There are people that are wrong on both extremes, obviously. I’ve worked with one too many people that quite clearly have a deficient understanding of software patterns and try to pass it off as being contrarian speed freaks. Just as I’ve worked with architecture astronauts.

I’m particularly skeptical of YouTubers that fall so strongly on this side of the argument because there’s a glut of “educators” out there that haven’t done anything more than self-guided toy projects or work on startups whose codebase doesn’t need to last more than a few years. Not to say that this guy falls into those two buckets. I honestly don’t think I know him at all, and I’m bad with names. So I’m totally prepared for someone to come in and throw his credentials in my face. I can only have so much professional respect for someone that is this…dramatic about something though.

Re: “Clean” code, horrible performance

#130

Earlier quoted context omitted.

I think "them" is someone named Robert Cecil Martin, but I'm not sure if this example from the video appears in his book. What compiler are you using that devirtualizes every class hierarchy? I suspect that Casey is using C++ so he may (unfortunately) have multiple translation units in his program.

>I suspect that Casey is using C++ so he may (unfortunately) have multiple translation units in his program. Yes, the video uses C++. Obviously if one compiles a library then the compiler has no way of knowing that other subclasses of `shape_base` do not exist. My point is that when compiling a binary as they are doing for their video, the compiler knows that there are no other subclasses that it needs to cater to. I…

Correct me if I'm wrong. Even if the compiler devirtualizes the classes, you still have the memory cost of storing the vtable pointer in each of the object instances (8 bytes for each instance), which means you need to do more fetches from memory. Does CPU prefetching negate the cost of these additional memory lookups?
Post reply on HN