Live data from Hacker News

The Case Against OOP Is Wildly Overstated

medium.com

181–190 of 312 posts

Re: The Case Against OOP Is Wildly Overstated

#181
post #41
post #4

This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful, and that statefulness is fine to freely sprinkle throughout your program.

So what is your preferred solution for programs that intrinsically need to deal with a lot of state ? Global variables ? I used to see that type of approach in some complex Fortran simulation programs where every function referenced a huge common block. I really don't think that leads to easier to manage solutions.

Ideally you want to have all your state in one place, the "single point of truth", in tightly modeled data structures, keeping it as lean and immutable as possible. The program is then just a function of the state, consisting mainly of self-contained functions, that take arguments and produce a result, without causing side effects. Realistically, that doesn't mean there are no classes or objects with internal vars, but these are more of ephemeral nature, and can be created predicatively and deterministically from your centralized global state. In the best case you can have complex applications with tens of thousands LoCs that feed from just a few dozen state variables.

Re: The Case Against OOP Is Wildly Overstated

#182

Since I accepted I was no Einstein I embraced the KISS principle. My code became simpler, easier to understand. Of course it wouldn't get the approval of any software architect or any design pattern fanatic, but I can take any code I wrote 3 years ago, understand it on the fly and edit it with confidence. There are few bugs and they're never a nightmare to find. Now if I have to modify the code I was writing before m…

Amen. I think the mistake is to reach for the complicated patterns first. Rather than refactoring later when it’s obvious they are needed to simplify your code.

Re: The Case Against OOP Is Wildly Overstated

#183

Earlier quoted context omitted.

You might want to consider examining another programming language for clues here. Perhaps look to a language that has a more modern approach to state such as Clojure.

My understanding is that Clojure is basically lisp implemented inside the Java ecosystem. I'm not sure how that makes it "modern" given that the only higher level language older than lisp is the original version of Fortran.

Clojure has quite a few specific libraries. As far as I know, one of these implements a lot of persistent data structures - data structures that make it efficient to expose an API that returns a copy of the whole structure for any mutation (by sharing all of the unmodified substructure behind the scenes).

Re: The Case Against OOP Is Wildly Overstated

#184
post #163

Earlier quoted context omitted.

I'm not the one you're asking. But... Here's a data structure that represents a bill of materials. It has a list of components, and a total cost, which is the sum of the costs of the components on the list. That's the invariant - that the total cost is the sum of the costs of the components in the list. If it's just a structure, then someone can add or remove a component, and forget to update the total cost, and the…

For what it’s worth, with ADTs and non-exposed constructors you can achieve the same result (i.e. only the creating module can actually _build_ such a list but other modules can read the data).

"Abstract data types and non-exposed constructors" is enough to give you object-based code, which is not too far from a definition of "the good parts" of OOP. Though some could quibble that "object-based" doesn't include sensible ideas such as composition, interface inheritance, delegation etc.

Re: The Case Against OOP Is Wildly Overstated

#185

Earlier quoted context omitted.

Actually my response would be that you just have a plain-ish vanilla list of `Component`, and a function `TotalCost(List[Component]) -> float`, which is implemented as, approximately, lambda arr: sum(x.cost for x in arr). This maintains the invariant without state. There's a potential performance cost here, but that usually doesn't matter a whole lot.

That's true - but where do you put the function? In a complex system I can end up with loads of these totalling functions scattered about. I might have gross and net versions of the total and, given human nature, they get created near the use of them. The variants then get duplicated. The objects give you a modular structure which means you can see the interface.There is a disconnect when you have to shift to the obj…

There are a few answers for this: you might include common ones in the same file as the struct (see rust for how this looks, usually).

Re: The Case Against OOP Is Wildly Overstated

#186
I have difficulty maintaining a stance in the OOP vs. FP debate. Like, all I see in my day-to-day is OOP, so I know what good, production-ready OOP looks like, but I've never an equivalent for FP. Would be nice to see a before/after article, i.e. an OOP app refactored into FP, talking about why the latter is better.

Re: The Case Against OOP Is Wildly Overstated

#187

Earlier quoted context omitted.

I'm not the one you're asking. But... Here's a data structure that represents a bill of materials. It has a list of components, and a total cost, which is the sum of the costs of the components on the list. That's the invariant - that the total cost is the sum of the costs of the components in the list. If it's just a structure, then someone can add or remove a component, and forget to update the total cost, and the…

Actually my response would be that you just have a plain-ish vanilla list of `Component`, and a function `TotalCost(List[Component]) -> float`, which is implemented as, approximately, lambda arr: sum(x.cost for x in arr). This maintains the invariant without state. There's a potential performance cost here, but that usually doesn't matter a whole lot.

> This maintains the invariant without state.

Yes, but this is not possible in general. For instance, what if you want to endow your List with a "MaxTotalCost", set at creation. You can't ensure that your list respects that invariant, other than by encapsulating it behind some custom interface.

Re: The Case Against OOP Is Wildly Overstated

#188
post #4

This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful, and that statefulness is fine to freely sprinkle throughout your program.

"Tightly binding data and code" allows you to maintain complex invariants via code, and to abstract away from the specifics of any single implementation. Statefulness per se is quite manageable; what's not manageable is shared, mutable state that isn't isolated to a single, modular, highly cohesive "unit" of code that can be understood in its totality. The real issues with OOP have to do precisely with things that br…

Not just invariants, covariants as well.

State and zip code always change together. Having had to fix code that passed 5 variables around for an address (which needed to go to 6 for “address 2”) I replaced it with an address object.

Re: The Case Against OOP Is Wildly Overstated

#189
A little off-topic, but when thinking about the reasoning behind OOP, in particular how it shows up in C++ and the C++-influences in other languages, I think it is worth looking at how large-scale C projects (OpenSSL, Gnome, etc.) organize their code: long prefixes in front of function names complex structs with lots of function pointers complicated macros for code generation

These directly relate to some of the core features of C++ like namespaces, virtual functions, and templates.

I think this perspective makes the differences between C++ style object orientation and Smalltalk style object orientation understandable.

Re: The Case Against OOP Is Wildly Overstated

#190

Earlier quoted context omitted.

The entire point of OOP is to encapsulate state within objects and to have objects communicate through messages, that is to say to 'program without a center'. Global or interconnected state is if anything a violation of OO principles. In proper OO state is hidden and insofar as it causes issues it does so in a way that is handled by the object rather than the program overall. Also treating code as data isn't a featur…

> The entire point of OOP is ... One problem is that every OOP advocate has a different perspective on "what the entire point of OOP is". Another problem is that irrespective of what any OOP advocate believes is OOP, the body of code that is commonly understood to be "OOP" is plagued with abuses of inheritance (I'm not even convinced there are legitimate uses), mutable state, the "banana with a reference to the goril…

The problem with lookibg at bad X code and concluding X is bad is that X can be anything.

It's true that bad OO code suffers of different problems than bad FP code, and both are different from bad procedural code. But there is no guarantee that an organization which produced bad OO code would have produced good FP code, just as there was never a reason to imagine (though many did) that an organization that produced bad procedural code would produce good OO code if forced to switch to OO.

In general, there is no solver bullet. We can absolutely replace the problems specific to bad OO code with problems specific to bad FP code if we move from OO to FP, but we cant be sure of any other outcome.

More likely than not, we need to change more than the style of code we build if we want to take an org that has produced bad code and make it produce good code - we should change incentives, testing, goals, timelines etc.

And just to be clear, you're absolutely right that saying 'that's not good OO code' is no-true-Scotsman and not helpful in any way, other than pointing out that it is possible to produce good OO code (some people doubt that, I think).

Post reply on HN