67 comments

[ 1.4 ms ] story [ 131 ms ] thread
I wonder what things would be like today if the term "message oriented programming" had caught on instead.
The message paradigm is interesting because it decouples the sending and receiving of the message from the mechanism that delivers the message. Sender and receiver could be on the same machine or around the world. The message could be processed in milliseconds or days. And so on.
Until cloud computing became ubiquitous, there would be a lot of programmers complaining about the extra overhead in a native application. Messaging also requires a system to publish, serve and persist messages.
Null is probably a bigger mistake.
I think the problem is more that null exists but we like to simplify and pretend it doesn't most of the time. Null is just an extra state that can be useful, but sometimes it is so uncommon that we pretend that state is not there.

Back when C programming was more prevalent I don't think null was that big an issue because most programmers were aware of it and would check for it.

On second thought, the other big issue with null is that in many languages it just crashes the program which is a rather severe consequence you don't see for most mistakes.

Why is this? Sometimes, you do want to indicate that nothing came back.

Python has the concept of None, which seems to function this way. You must check if the return type is None, and react appropriately.

Null is not a problem with programming languages that correctly support (and enforce) optionals. The problem with null in, say, Java is that any object reference can potentially be null, which makes it very difficult to know when and why you should verify that something is non-null.
It's a more obvious problem in typed languages like C or Java, where the type system can't help much to protect you against null pointer exceptions if you forget to check for null. Specially in C, where the null pointer exceptions cause billions of dollars of damage in the form of segfaults and nasal demons.

In a language like Python the possibility that variables may contain values of different type (such as the None value) is part of the game. An inherent tradeoff of being dynamically typed.

In Racket and Scheme, false is the only 'falsy' value, with everything else evaluating 'truthy', which is nice since you don't have to worry about the specifics of the return type.

I think the bigger issue with null or None, though, is not necessarily using it as a return type (where that makes sense, and can be enforced by a type system) but when objects are mutated to the value of null. The bigger issue there is with mutation and side-effects, but having null there as a convenient short cut can be a foot gun that leads to lots of errors.

(comment deleted)
I think that the biggest mistake is to switch to the next new programming language for no real benefit...
Not going to enable javascript and/or pay money to read this very hot take, but I can definitely agree that OOP is terrible. And, furthermore, spelled backwards it is "POO".

Don't use Medium, please.

Do you still use Python for parts of Sourcehut? Have you eliminated all uses of OO in your use of that language?
We still have Python, but use few to none of its OOP features. Almost all of our classes are just there to rig up SQLAlchemy (which totally blows, I regret using it). We're moving away from Python in general.
In portuguese it's always POO. I always found that amusing :)
Works fine in w3m, but not really worth the read. It's on Medium, after all.
Video game programming, where OOP actually maps pretty well to the problem domain, would beg to differ.
Agreed, never understood the appeal for something like web applications but as soon as I tried game Dev it feels like the perfect fit for lots of entities with their own internal state.
There are many enterprise web applications that have large amounts of internal state, so I think OOP techniques work relatively well there.

Game programming is a lot more fun though.

Very well architected OOP is fantastic to work with/read on any moderately complex application. The problem is very few people know how to architect an application well, regardless of OOP or not.
Even then, from what I've heard the trend is turning sharply away from inheritance and towards composition of components and systems. Maybe you could argue that that's still OOP, but it's not what most people mean by the term these days
Personally, when I think of OOP, I think of objects which combine state and the code to modify that state.

The details of how it’s implemented - inheritance vs. composition - strikes me as more of an implementation detail than a vital difference.

ECS, the emerging game pattern, breaks off the state-modification code as well
OOP should be applied to a specific domain, namely GUI and video games.

In other cases it's a meh.

ECS (data-oriented programming?) is slowly taking over in the video game industry as a clearly superior paradigm. i did some UE4 programming recently, and as powerful as that engine is, the super-heavyweight object/inheritance system was the source of almost all unnecessary complexity i dealt with
I was under the impression OOP with classes is not cache performant when doing common game engine tasks like mass updating the velocity or position of objects.
(comment deleted)
A lot of powerful claims made in this article. Are we sure 737s crashed because of spaghetti code? As far as I am concerned the max crashes were due to a string of management failures pushing for wrong ideas.
Absolutely not, that was just an early meme. The overall MCAS system responsible for the failure was so critically flawed that no software algorithm could have possibly made it work as intended.
That is not my understanding of the MCAS failures at all. The primary cause of the failures was:

1. Lack of redundancy with the AoA sensors. This is obviously straightforward to rectify.

2. Lack of proper pilot training and awareness of the different handling characteristics of the 737 Max with MCAS compared to previous versions of the 737. Also obvious to rectify with proper training.

That was my point. The lack of AoA redundancy was an egregious design flaw that no software could have fixed.

A design with a simple but catastrophic & easily foreseeable error isn't a good or even OK design overall. If you make a suspension bridge missing one of the towers, or lacking sufficient cable strength causing it to collapse, your bridge design is terrible, even if everything else you did was flawless.

Maybe the engineers had excuses, were rushed by management etc., but their design was still insane.

OOP seems to force you to leave the entire codebase for that class open.

The member variables can be modified by the methods, which makes the variables a type of global variable, from the perspective of the method.

Then over time as your code size increases, you add more methods, and they keep modifying the member variables. Now, if you’re not careful, you can have multiple vectors modifying your member variables, any which way it wants.

Thus, when working with OOP, you can never seem to close out parts of the code that you had already completed and tested. Since the entire code base is opened for continual modifications.

There are lots of languages that prevent this.
OOP doesn't even mention classes in its definition, just objects. Class oriented programming is undoubtedly a mistake, but to be fair, OOP has been so distorted that the fault cannot be in the paradigm
What? Class methods are responsible for upholding the class invariants. That is, it provides you a way to encapsulate internal state. Of course all your class methods should be responsible for upholding that - but if you find that there are too many methods, you perhaps need a rethinking of architecture. Perhaps adding a wrapper class over an inner class? The inner class is the only thing responsible for upholding said class invariants, but the outer one can access it in different ways, without hurting the invariants.
The problem is that it is a giant internal state.

And your class can be thousands of lines long. Of which you have to keep open, as you develop it. Which forces you to keep the entire code base in your head, thus increasing the cognitive load on developing the classes.

Of course, there may be ways to refactor it, but the tools given in most OOP languages, tends to be insufficient.

It’s as big of an internal state as you make it/minimum as large as the problem domain requires.

Functional programming doesn’t solve any of these problems by itself. There are cases where mutating state is better, and there are others, where it is worse fit. And the latter can just as well be expressed inside a class, like there is no requirement for mutation.

I think the two should go hand-in-hand, and for different parts of a program different paradigms can be used? Maybe even add actos-based programming as a possibility, but there is nothing inherently bad with OOP imo, and it is the best way to encapsulate some logic.

If all you have is a hammer you will eventually come across things that are not nails, but close enough you try to approximate them as nails. As the abstracts get more and more leaky you get the "biggest mistakes". I don't think really it matters what it is, if you take it too far it will fall apart.

I think clearly this applies to functional programming as well, and probably every other way of thinking.

The issue with OOP is that it is taught, and for many programmers they think it is the only way to think so they try to make every problem a nail.

Lately I think that the React framework is the biggest mistake. It's worse than a pile of jQuery spaghetti.

It's probably single-handedly responsible for why Reddit, Twitter, and myriad modern popular sites are slower and buggier than ever. They are written in an un-debuggable framework...

Thinking of react as a framework is a mistake, it's the view layer only.
Framework doesn't mean that it is across all layers. It can still be a framework for the view layer only. Libraries become frameworks when they start to dictate how you write and structure your code units, and also when they take the charge and decide which code should be called and when. React does all that, and thus is a framework, even if it's concerned with the view layer only.
The mobile Twitter site completely broke for me the other week on the latest iOS and a 2020 iPhone. Scrolling just caused the site to glitch like crazy. Had to switch to the app!
I happen to both hate balloning frontends and work with React so I can say that it is debuggable. It is not as smooth as Java, .Net or even Python IMO, but absolutely debuggable.

I will however strongly recommend that one uses it with TypeScript; that way there will usually be a whole lot less to debug in the first place.

what is the alternative that we should use? functional programming? message oriented?
The right tool for the job, including OOP in many cases.
Go's minimalist object-oriented approach (interfaces, embedding types within types, and associating functions with named types) is small, simple, and effective

No mistake about it

I think the greatest UX improvement in programming is namespacing. UFCS plus namespacing is enough to make people happy to not OO, I think.
(comment deleted)
People still focuses a lot on procedures, algorithms and paradigms and tend to forget the simplest most basic aspect of computer programming: it is a language before everything.

It needs structure, semantics and good abstractions, so that we can better encode programmer intention into procedures, and not only rely on algorithmic effects to tell whether a program works.

I believe the software community would be in way better shape if we approached computer science a little bit more like linguistics. We would understand each other better, we would integrate ideas easier and work more cooperatively. But until code stops being just a tool to implement some end and until code quality stops being regarded as cost we will keep writing spaghetti code. Regardless of language. Because when the team culture tolerates bad code, bad code will arise, be that in java, c, python, rust, Haskell. Whatever.

This blog post seems to equate spaghetti code with OO, which is a false equivalency. I mean, yes, you can achieve spaghetti code with OO, but you can achieve some degree of spaghetti code in most paradigms.

It also seems to imply that OO has cost lives, specifically with the Boeing 737 Max MCAS system and Toyota's "unintended acceleration" problem. But I can't seem to find what language MCAS was written in (I'd wager C, Fortran, Ada, and possibly some assembly based on other Boeing systems I've been involved with). And Toyota was using C.

mwell that's your point... I'm no sure you are right about it...

The real big mistake in programming, it's to able to write a program with few knowledges...

appropriating others words/phrases and assuming you are a programmer.

This is the biggest mistake an individual can do in programming.

"Read the rest of this story with a free account."

No thanks.

But judging by the title, it seems click-baity. The "biggest mistake" is definitely not OOP. You can definitely abuse and misuse OOP, where other abstractions would be a better pick, but it's not just universally bad.

OOP is domain-specific in its applicability if you are following the original intent. If you are not strictly following the original intent of OOP, you can get the best of all known worlds if you apply strong discipline and your tools are capable enough.

For instance, in most OOP languages you can define your domain model as bags of facts without methods. Then, you could define a separate domain service layer that is exclusively permitted to mutate instances of those types. Next, you enforce immutability by defining a copy ctor for every type in your model. When you return anything to a caller from a domain service you always send a copy. Same idea on create/update requests. The way I look at it, the domain services (methods) protect the model (facts) from unwanted mutations.

Having your facts separate from your methods means you can apply things like normalization and start to leverage functional and/or relational techniques. Being able to query your domain model with SQL is next-level productivity if you can manage it.

So, the biggest mistake to me in computer science is not OOP, but the blind following of any one specific doctrine to an inevitable dead-end. Good software outcomes require an incredibly difficult balance between many ideologies, as well as conformance to actual realities presented by the real world (i.e. customer requirements, regulations, developers having bad moods, etc.).

do what works best for you.

Peace.

(comment deleted)
This is not a very good article.

OOP has a lot of flaws for why it was a poor design decision, but this article doesn’t seem to address them.

Instead, it focuses on things like spaghetti code.

> OOP has a lot of flaws, but this article doesn’t seem to address them

Besides spaghetti code it mentions that functions have non-deterministic results because the internal state of an object depends on the global state of the application as a result of being shared by reference.

OOP has more flaws which the article does not mention, true.

What I miss from articles like this, which make some rather grand claims about how poor OOP is and how much better X is, is less claims and more proof.

I really enjoyed the rs-pbrt[1] project that was posted here[2] the other day, as it allowed me to compare some non-trivial code in a (to me) different and interesting language.

Does anyone have some good comparative examples for FP? Doesn't have to be as grand as rs-pbrt, but ideally something a bit realistic and non-trivial.

[1]: https://www.rs-pbrt.org/

[2]: https://news.ycombinator.com/item?id=25812330

OOP is not "the biggest mistake"; following it blindly and applying to everything is. We saw this pattern then and we see it today.
I still hold type systems with null as being worse - but someone of course had to combine the two...
ah, this strawman banging again. OOP is not mistake, there are too many weak developers.
While I agree, it must be understood that OOP was about getting the design right by pre-analysis. Not about making code easy to understand for 'weak developers'. It definitely doesn't do that.
Agree with the design part. For making code easy to understand, my point in case is Qt; it's beautiful lib (always has been). It's not just 'approach' (e.g OOP) or 'language' (C++, java) it's a lot about context. Functional langs (and feature, looking at you java) are getting into spotlight because the computation model has changed. Shared state is too expensive. Once there will be exponential growth in RAM in place, the OOP model (e.g. shared state) will come back. Side note: one can write shitty code code regardless of technology. No need for OOP for that.