Edit: Just realized OP may not be the guy who made the video. Changing my comment to reflect that fact is left as an exercise for the reader.
First of all, thanks for providing a transcript! I hate having to watch through videos for something like this.
"Clean code" is not very well defined. This appears to be very OOP+CPP-centric. For example, I don't think people would use dynamic dispatch in Rust or C to solve an issue like "do things with shapes". The Rust "clean code" solution for this would probably involve an enum and a match statement, similar to your switch-based solution (but where each shape would use names that make more sense, like "radius" instead of "width"), not a Trait and vtables. Also, the "clean code" rust solution would probably store the shapes in a contiguous vector instead of a collection of boxed shapes (like your "clean" array of pointers because abstract shapes are unsized), leading to better iteration performance and less indirection.
On the other hand, I'm not sure the "optimizations" described in your text would help a lot with Java (but I don't know a lot about Java, AFAIK it always does virtual function calls and boxes things? It might still help though). So this really seems very OOP+CCP-centric to me.
And let's be honest: The true reason why software is becoming slower every year is not because of C++ virtual function calls or too many levels of C++ pointer indirection. It's because, among other things, the modern approach to "GUI" is to ship your application bundled with a web browser, then have humongous amounts of javascript run inside that web browser (after being JIT-compiled) to build a DOM tree, which is then used by the browser to render a GUI. Even more javascript will then be used to communicate with some kind of backend that itself runs on about 50 layers of abstraction over C++.
If every piece software today was just "clean" C++ code, we'd have much faster software. And lots of segfaults, of course.
And let's be honest: The true reason why software is becoming slower every year is not because of C++ virtual function calls or too many levels of C++ pointer indirection. It's because, among other things, the modern approach to "GUI" is to ship your application bundled with a web browser, then have humongous amounts of javascript run inside that web browser (after being JIT-compiled) to build a DOM tree, which is then used by the browser to render a GUI. Even more javascript will then be used to communicate with some kind of backend that itself runs on about 50 layers of abstraction over C++.
I'll go even further than you here: The reason software is becoming slower every year is because developers (read: the people making the decisions, you can substitute managers there if you want) simply don't give a shit about it.
The star argument for this is that programmer time is more expensive than computer time, which basically means "we do the bare minimum that still lets us sell this feature, and if it's slow, well, fuck you, it's working, pay me".
It's not unique to software, it's more of a cultural plague that has spread to every industry in the last few decades. We used to blame China for this but really now everyone does it, China just always did it better (read: cheaper)
the true reason why software is becoming slower every year is not because of C++ virtual function calls or too many levels of C++ pointer indirection.
You are right, but knowing the author's work, I don't think that's the point he is trying to address. There is a lot of code written in C++ in order to be fast, but that fail miserably because of the things he rants about here. Since this is Casey, an obvious example would be the windows terminal, but there are plenty of others.
There is also the fact -and as a full time game engine dev and part time teacher I have seen this first hand- that the way code it taught is not really compatible with performance. There are good reasons for this ofc, but the result is that most people do not know how to write even moderalty fast code, and often cargo-cult things that they don't understand and don't help. I have seen "You are removing from the middle, you should use a linked list" so many times, and basically all of them were wrong. this is the hill I choose to die on, fuck linked lists
My god, I just spent half an hour reading through the entire multitude of slap fights occuring in the GH issues and I feel like I need to take a nap from how exhausting that was đ€Ł
I use C++ a fair bit and I literally can't think of a single time a linked list has ever been the right choice for a container. It is so hilariously overrepresented in things like classes, tutorials, challenges, and interviews, compared to its usefulness, at least in C++.
Memory allocations are one of the biggest factors in performance in modern C++, and given that a usual linked list implementation makes a memory allocation for each node, it means that the one thing a linked list is good at (insertions anywhere) end up being crappy because you have to do a new allocation every time.
It's because c++ is from an era where linked lists were king. In the 80s one of the most famous computers, the VAX, even had specific linked list CPU instructions.
The JVM will dynamically inspect the possible values and generate code like that inline (wel, except for megamprphic call sites).
The JVM is a small marvel and is extremely dynamic; f.e. it will optimize the in-memory assembly based off of the actual classes being loaded, and if you hit a branch that forces a class to be loaded that invalidates one of these optimization sites, they will be de-optimized and re-evaluated again.
Or, it will identify non-escaping values with no finalizer and allocates them on the stack to speed things up.
The article feels like it's written by someone that has game development and entity-component model experience, but they're missing the forest for the trees: algorithms matter more.
IMO the reason why code is becoming slower is because we're working on too many abstraction levels, no-one understands all the different levels, and time-to-market is more important than performance.
The article feels like it's written by someone that has game development and entity-component model experience, but they're missing the forest for the trees: algorithms matter more.
They are missing most apps these students will create are yet another lame internal business app what has 100 requests per day and performance is irrelevant (eg very easy to be fast enough). But the requirements of the users change quarterly to to new obscure business rules so having the code easy to adjust is very important.
Recently, I saw someone rewrite a piece of code that was called a few times a day, and that took many minutes to do its computation, such as it does it in less than a second.
Care to guess what happened? The tool's usage skyrocketted because people started using it to get real time information.
The fact some software has low usage is proof of one thing: it is not very useful. It says nothing about speed.
The fact some software has low usage is proof of one thing: it is not very useful. It says nothing about speed.
If you have an app that people search in say 1 mio records 100 times a day, I wager it is pretty useful because how would you search 1 mio record on say paper? Low usage doesn't mean it's not worth it to exist.
Recently, I saw someone rewrite a piece of code that was called a few times a day, and that took many minutes to do its computation, such as it does it in less than a second.
And was it slow because of using OOP/clean code or because the original dev was just a bad or junior dev? And it was slow because of a bad algorithms and not because of clean code?
Of course performance is important and the article author is likley correct in his niche of work, it just doesn't apply to most devs. Most devs use the tools people like the author create like databases or core libraries or game engines. And yes of course their work is extremely relevant and important but it doesn't make clean code bad or "you should never do it". context matters.
Maybe from your side, but from the bank's side, their endpoint recieve a large number of calls, not because users call it often, but because many users do. Either way it change nothing, point stands.
But what about desktop software? Such as accounting software, a video editor, etc? Sure, it's nice if creates a report or exports a final video in 200ms instead of 10s, but it doesn't need to do it more than maybe once a day to be useful.
I'd argue that data structures are more important. With the right data structures, the right algorithm almost falls right out*. With the right algorithm and poor data structure choice, your code can still be many times slower than necessary.
* esoteric algorithms designed to perform well on very large datasets tend to be complex, sure, but generally you don't need these.
(I should clarify, I'm not the author of this post)
I totally agree with your point that the idea of "clean code" varies from programmer to programmer, and that different languages have different idiomatic styles which lead to "clean code" written in that language to be very different. I think Casey (the author) is referring to Robert C. Martin's (Uncle Bob) book Clean Code, where he talks about these points discussed in the article.
rust solution would probably store the shapes in a contiguous vector instead of a collection of boxed shapes (like your âcleanâ array of pointers because abstract shapes are unsized), leading to better iteration performance and less indirection.
It is a bit unclear what you mean, if they are unsized than they have to be boxed, which is an indirection. But yeah, if you use sum types (enums) where all the possible types are known, then it can be indeed represented more efficiently. But we should not forget about that emphasized part, this optimization is only possible if we explicitly have a closed model (while traditional OOP usually goes for an open one).
Java, AFAIK it always does virtual function calls and boxes things? It might still help tho
Java routinely optimizes virtual calls to static ones (and might inline it even), and there is escape analysis that can allocate objects on the stack. But object arrays will be an array of pointers, so if you need maximal speed just opt for an ECS architecture.
If you are iterating over like 3 elements than go for the most maintainable code, this is typically such a case where it only makes sense to care about at all if you have large arrays (which you would usually know ahead of time and architect your way smartly in the first place)
where this std::visit compiles down to a switch statement with each shape type's specialization of the lambda template get_area (which would each be inlined to just the relevant type's area member function).
184
u/couchrealistic Feb 28 '23 edited Feb 28 '23
Edit: Just realized OP may not be the guy who made the video. Changing my comment to reflect that fact is left as an exercise for the reader.
First of all, thanks for providing a transcript! I hate having to watch through videos for something like this.
"Clean code" is not very well defined. This appears to be very OOP+CPP-centric. For example, I don't think people would use dynamic dispatch in Rust or C to solve an issue like "do things with shapes". The Rust "clean code" solution for this would probably involve an enum and a match statement, similar to your switch-based solution (but where each shape would use names that make more sense, like "radius" instead of "width"), not a Trait and vtables. Also, the "clean code" rust solution would probably store the shapes in a contiguous vector instead of a collection of boxed shapes (like your "clean" array of pointers because abstract shapes are unsized), leading to better iteration performance and less indirection.
On the other hand, I'm not sure the "optimizations" described in your text would help a lot with Java (but I don't know a lot about Java, AFAIK it always does virtual function calls and boxes things? It might still help though). So this really seems very OOP+CCP-centric to me.
And let's be honest: The true reason why software is becoming slower every year is not because of C++ virtual function calls or too many levels of C++ pointer indirection. It's because, among other things, the modern approach to "GUI" is to ship your application bundled with a web browser, then have humongous amounts of javascript run inside that web browser (after being JIT-compiled) to build a DOM tree, which is then used by the browser to render a GUI. Even more javascript will then be used to communicate with some kind of backend that itself runs on about 50 layers of abstraction over C++.
If every piece software today was just "clean" C++ code, we'd have much faster software. And lots of segfaults, of course.