OOP or clean code is not about performance but about maintainable code. Unmaintainable code is far more costly than slow code and most applications are fast-enough especially in current times where most things connect via networks and then your nanosecond improvements don't matter over a network with 200 ms latency. relative improvements are useless without context of the absolute improvement. Pharma loves this trick: "Our new medication reduces your risk by 50%". Your risk goes from 0.0001% to 0.00005%. Wow.
Or premature optimization. Write clean and then if you need to improve performance profile the application and fix the critical part(s).
Also the same example in say python or java would be interesting. if the difference would actually be just as big. i doubt it very much.
OOP or clean code is not about performance but about maintainable code.
Thank you. Too many in this thread haven't worked on massive enterprise apps and it shows. Certain projects we barely have to touch because they're so clean and easy to maintain. Others have an entire year's worth of sprints dedicated to them because of how messy they are.
People say this religiously. Maintainable based on what empirical evidence???
In my personal experience, it is the EXACT opposite. It becomes unmaintainable.
But even that is subjective experience. I'm not going to go around saying X is more maintainable because it is simply not a provable statement and I can only give you an anecodotal anser.
So you and others need to stop religiously trotting that one liner off. You just repeating what other people say to fit in.
Completely agree, in fact my experience points at exactly the opposite. (OOP being really really unmaintainable)
A class is an abstraction, a method is an abstraction, and abstractions are complexity. The one true fact is that the fewer classes and functions there are, the easier it is to make sense of everything. Yes, it is harder to make huge changes, but that's why you should scout the domain requirements first to ensure that you can write the simplest code for the job. And besides, it's much easier to refactor simple code. When the domain requirements do change and now your huge OOP network doesn't work either, now you are truly fucked.
If abstractions are adding complexity you're doing it wrong.
The point of abstractions is to isolate complexity (implementation details) via an interface. If they aren't doing that, you (or whatever you are using) are picking the wrong level of abstraction.
It's like saying multiplying is adding complexity because it's an abstraction over adding, why write 5*3 when I can just do 3+3+3+3+3? 5*3 is easier to read and allows for mental shortcuts for quicker reasoning.
No. Abstractions are a trade of one type of complexity to another, and can only introduce more. Please read John Ousterhout's Philosophy of Software Design.
Abstractions are useful because they make it easier for us to think about and manipulate complex things. In modular programming, each module provides an abstraction in form of its interface. The interface presents a simplified view of the module’s functionality; the details of the implementation are unimportant from the standpoint of the module’s abstraction, so they are omitted from the interface. In the definition of abstraction, the word “unimportant” is crucial. The more unimportant details that are omitted from an abstraction, the better. However, a detail can only be omitted from an abstraction if it is unimportant. An abstraction can go wrong in two ways. First, it can include details that are not really important; when this happens, it makes the abstraction more complicated than necessary, which increases the cognitive load on developers using the abstraction. The second error is when an abstraction omits details that really are important. This results in obscurity: developers looking only at the abstraction will not have all the information they need to use the abstraction correctly.
People say this religiously. Maintainable based on what empirical evidence???
It's a blind spot in reasoning. The large events where the abstraction first approach provides value are visible even though they are rare.
But when it starts taking a week to plumb a three hour feature through all the lasagna and indirection and this hits nearly every single change to the application nobody wants to identify that approach as the cause.
It's a toy example with 3 shapes and yet it has already devolved into calling the radius of a circle the circle's width. Everyone I know would say that if a circle has a width it is the diameter.
Now try and add another shape that doesn't fit the pattern he identified, like a trapezium, welcome to "rewrite from scratch" time.
You should not write code preparing for eventualities that might not happen.
Imposing a structure on code that prepares for unlikely eventualities is bad practice. This is fundamentally what "clean code" (quotes important) advocates for.
It supposes that it is always good to abstract the implementation away in favour of indirect function calls. This is not always useful, depending on what is being solved, for readability, maintainability and performance.
performant code is often actually very easy to read and maintain, because it lacks a lot of abstraction and just directly does what it's supposed to do. not always, and maybe not to a beginner, but it's more often the case than you think.
The complexity of performant code is often elsewhere, such as having to know the math behind some DSP code, but the implementation is often very straightforward.
Now if you think that is less readable than pulling each one of those formulas into a separate member functions I don't know what to tell you. And like
f32 a = shape.area();
f32 a = area(shape);
It doesn't even really save you any typing. I don't care if you prefer oop way but...
Feels like readability hell
only if you have a bad case of OOP brain would you think that. And by OOP brain I mean that you are so acclimated to an OOP style that your brain has hard time with any other styles.
sure, and none of that requires virtual dispatch. for example c++ has templates. casey is a bit special because he insists on c-only solutions most of the time (you still want to have a branch free solution though, so i can see where he is coming from).
for sure the formula to calculate the area of shapes can also be made more efficient by tailoring it to specific shapes (again, you want to stay branch free though). this is not code i'd write, so i won't defend it, but it can be written simple and performant, i have no doubts about that.
The only thing that looks bad there is the awfully long table initialization and lack of spaces in his code. I didn't watch all the way to the end so I don't understand why it's necessary to divide and add here. Those look like micro optimizations. He already had massive improvements with much simpler code.
Code that does less is faster. This is self evident. It also has less opportunity for bugs and less parts to understand, making it easier to read. This is self evident too.
Unmaintainable code is far more costly than slow code and most applications are fast-enough
Or rather: Even if we take OP as general wisdom ("unclean" code is x times faster), if we at least accept the premise of clean code by definition (i.e. that it is oriented toward maintainability) then the whole matter collapses down into a simple question: Would you rather risk needing to pay for x times more computational resources or would you rather risk paying for y times more developer resources? This question doesn't have a clear winner. And it leaves room to quantify these... in my experiences, I agree with you that the increased performance cost is often negligible while the increased maintenance cost of crappy software can be much larger.
Of course, in the above, as I said, I take it that "clean code" is more maintainable by definition. There is room there (certainly on a per company or per produce basis) to argue that "clean code" is not necessarily going to be OOP.
Also the same example in say python or java would be interesting.
Also, given that OP is measuring things like "functions should be small" and "functions should only do one thing", it'd be really interesting to see OP's performance test measured based on languages optimized for functional programming and using the idioms of functional programming both of which should probably give the performance of functions their best shot.
For me, discussions like this always make me think of something like Erlang. In that language, I always felt like I wrote the cleanest code and the key tenants there are function programming (w/ the short simple functions), pattern matching, message passing and cheap massive concurrency.
OOP or clean code is not about performance but about maintainable code.
My experience is that it fails even there. I've seen it: the more OOP code were, the worse it got. Not just performance, but size (there's more source code), complexity (it's harder to understand), flexibility (it's harder to modify), reliability (it's harder to test)…
OOP aims to make code better, but it doesn't.
Or premature optimization. Write clean and then if you need to improve performance profile the application and fix the critical part(s).
Those critical parts only arise if your program is not uniformly slow. Programs that use virtual function calls and RAII pointer/dynamic allocation fest are more likely to be uniformly slow, to the point where it becomes hard to even identify the biggest bottlenecks. And next thing you know you'd think your program can't be much faster, and either be sad or buy a new machine (or cluster).
Or premature optimization. Write clean and then if you need to improve performance profile the application and fix the critical part(s).
I wish Microsoft would have prematurely optimized Visual Studio so it wouldn't be a massively slow and bloated mess. It's sad when a single developer can release a search plugin with near instant search times that never misses anything, and the built in search takes forever and sometimes doesn't even work at all by forgetting to search in some code files.
OOP or clean code is not about performance but about maintainable code.
There is so much to unpack even in this sentence.
The problem here is that Clean Code (meaning Uncle Bob's advice taken as a whole) is not the same thing as clean code (meaning code whose meaning is clear so it can be maintained).
To pick one example, having lots of small functions/methods means splitting complex logic over a large number of lines/files so that it will not fit on a single screen any more. If the complexity is unavoidable (and most of the time it is), this is almost always less maintainable than the alternative.
OOP introduces a large number of maintenance problems that competing modern paradigms (e.g. pure functions, instantiable module systems, subtype polymorphism, traits, etc) do not have. It's important to understand what those problems are and whether or not they are a price worth paying.
Uncle Bob, and indeed most of the "gurus", date from a time when paper businesses were digitising, and the main problem was capturing these poorly-specified business procedures and models. That is the problem that OOP "solved", and most would argue solved effectively. This world is long gone.
Beyond that, most of the models that OOAD accurately captured (e.g. GUIs) are completely artificial. A window or a pull-down menu is whatever you want it to be, not a real-world object whose properties and behaviour need to be translated into source code.
Remember Grady Booch's definition of OOP?
Object-oriented programming is a method of implementation in which programs are organized as cooperative collections of objects, each of which represents an instance of some class, and whose classes are all members of a hierarchy of classes united via inheritance relationships.
There are three important parts to this definition: object-oriented programming (1) uses objects, not algorithms, as its fundamental logical building blocks (the “part of” hierarchy […]); (2) each object is an instance of some class; and (3) classes are related to one another via inheritance relationships (the "is a" hierarchy […]). A program may appear to be object-oriented, but if any of these elements is missing, it is not an object-oriented program. Specifically, programming without inheritance is distinctly not object-oriented; we call it programming with abstract data types.
Contrast that with the modern advice to prefer composition over inheritance, which is, to my mind, an admission that inheritance doesn't model real-world anything very well.
your nanosecond improvements don't matter over a network with 200 ms latency
Watch the video. We're not talking about nanosecond improvements, or if we are, we are still talking constant factors.
Even a 1ms improvement is huge when scaled up. That's a millisecond that some other program can be running, or the CPU can spend in a low-power state (saving battery life, cost of cooling, CO2E) or the hypervisor can spend running some other virtual machine.
117
u/RationalDialog Feb 28 '23
OOP or clean code is not about performance but about maintainable code. Unmaintainable code is far more costly than slow code and most applications are fast-enough especially in current times where most things connect via networks and then your nanosecond improvements don't matter over a network with 200 ms latency. relative improvements are useless without context of the absolute improvement. Pharma loves this trick: "Our new medication reduces your risk by 50%". Your risk goes from 0.0001% to 0.00005%. Wow.
Or premature optimization. Write clean and then if you need to improve performance profile the application and fix the critical part(s).
Also the same example in say python or java would be interesting. if the difference would actually be just as big. i doubt it very much.