Live data from Hacker News

“Clean” code, horrible performance

computerenhance.com

21–30 of 932 posts

Re: “Clean” code, horrible performance

#21
post #19

Earlier quoted context omitted.

Is there any flexbility tradeoff at all here?

The shapes example is pretty contrived so I don't really have an opinion on it either way. But imagine you have something like a File interface and you have implementations of it e.g. DiskFile, NetworkFile, etc., and you anticipate other implementors. Why would you do anything other than have a polymorphic interface?

I don't know, I've never done anything where code needed to have runtime dispatch on the kind of file it has without also knowing anything about what kind of file it has.

Re: “Clean” code, horrible performance

#23
post #15

This guy is so dogmatic about it it hurts. I would argue that clean code is a spectrum from how flexible vs how rigid you want your abstractions to be. If your abstractions are too flexible for good performance, dial them back when you see the issue. If your abstractions are too rigid for your software to be extendable, then introduce indirection. We can all write code that glues a very fixed set of things end to end…

But is it true that "clean code" makes the adaptation to changing requirements easier? I saw a few testimonies saying otherwise.

I think it really truly depends. I think it's always good to do the minimal viable thing first instead of being an architecture astronaut, but if you've been asked for three (random ballpark number) different implementations for the same requirement it might be time to start adding some indirection.

Re: “Clean” code, horrible performance

#24
The original submitted link was a youtube video that's been deleted for some reason.

Probably a better link is the blog post because the author updated it with the new replacement video a few minutes ago as of this comment (around 09:12 UTC):

https://www.computerenhance.com/p/clean-code-horrible-perfor...

Re: “Clean” code, horrible performance

#25
post #19

Earlier quoted context omitted.

The shapes example is pretty contrived so I don't really have an opinion on it either way. But imagine you have something like a File interface and you have implementations of it e.g. DiskFile, NetworkFile, etc., and you anticipate other implementors. Why would you do anything other than have a polymorphic interface?

I don't know, I've never done anything where code needed to have runtime dispatch on the kind of file it has without also knowing anything about what kind of file it has.

Have you never used C++ iostreams? Or the Python file abstraction? Or Rust std::io::Read/std::io::Write? Or Node.js streams? Or DOM Web Streams? Or Ruby files? Or Haskell conduits? Or hell, fopencookie/funopen in C?

The abstraction is super common and allows you to connect streams to each other without worrying about the underlying mechanism, which 99% of the time I don't really think you want to worry about unless you're sure it's a performance overhead. And that's great, because I surely don't want to write specializations by hand for all the different combinations of streams I need to use if I don't have to.

Re: “Clean” code, horrible performance

#26
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…

If you have more than one person working on a codebase; clean code matters a lot.

A code base that can't be understood and maintained by the whole team, will degrade quickly.

Re: “Clean” code, horrible performance

#27
post #9

"Use subclasses over enums" must be some niche advice. I've never heard it. The youtuber seems to be referring to some specific example (he refers to specific advice from "them") so I guess there's some context in the other videos of the series. re: the speedup from moving from subclassing to enums - Compiler isn't pulling its weight if it can't devirtualize in such a simple program. re: the speedup from replacing th…

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.

It might require LTO explicitly, of course. At the very least godbolt doesn't devirtualize without LTO [1], but godbolt itself breaks if I enable LTO [2] and I CBA to test locally right now.

[1]: https://gcc.godbolt.org/z/498nKEzhK

[2]: https://gcc.godbolt.org/z/WqhP3fzxK

Re: “Clean” code, horrible performance

#28
post #25

Earlier quoted context omitted.

I don't know, I've never done anything where code needed to have runtime dispatch on the kind of file it has without also knowing anything about what kind of file it has.

Have you never used C++ iostreams? Or the Python file abstraction? Or Rust std::io::Read/std::io::Write? Or Node.js streams? Or DOM Web Streams? Or Ruby files? Or Haskell conduits? Or hell, fopencookie/funopen in C? The abstraction is super common and allows you to connect streams to each other without worrying about the underlying mechanism, which 99% of the time I don't really think you want to worry about unless y…

I've used open(2) and the io_uring openat :)

I use generic readers and writers every day, but they don't have any runtime dispatch. The question was "Why would you do anything except vtables and runtime dispatch?" One answer is that my code that uses generic readers and writers and gets monomorphized gets to also be generic over async-ness.

Re: “Clean” code, horrible performance

#29
post #25

Earlier quoted context omitted.

Have you never used C++ iostreams? Or the Python file abstraction? Or Rust std::io::Read/std::io::Write? Or Node.js streams? Or DOM Web Streams? Or Ruby files? Or Haskell conduits? Or hell, fopencookie/funopen in C? The abstraction is super common and allows you to connect streams to each other without worrying about the underlying mechanism, which 99% of the time I don't really think you want to worry about unless y…

I've used open(2) and the io_uring openat :) I use generic readers and writers every day, but they don't have any runtime dispatch. The question was "Why would you do anything except vtables and runtime dispatch?" One answer is that my code that uses generic readers and writers and gets monomorphized gets to also be generic over async-ness.

Except in the kernel, of course.

Re: “Clean” code, horrible performance

#30
post #25

Earlier quoted context omitted.

Have you never used C++ iostreams? Or the Python file abstraction? Or Rust std::io::Read/std::io::Write? Or Node.js streams? Or DOM Web Streams? Or Ruby files? Or Haskell conduits? Or hell, fopencookie/funopen in C? The abstraction is super common and allows you to connect streams to each other without worrying about the underlying mechanism, which 99% of the time I don't really think you want to worry about unless y…

I've used open(2) and the io_uring openat :) I use generic readers and writers every day, but they don't have any runtime dispatch. The question was "Why would you do anything except vtables and runtime dispatch?" One answer is that my code that uses generic readers and writers and gets monomorphized gets to also be generic over async-ness.

There you go, actually: you can have your clean code cake and eat it too if you have the right language abstractions (like parametric polymorphism).
Post reply on HN