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.
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.
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.
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".
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.
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.
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
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.
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.
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.
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...
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.
Go's minimalist object-oriented approach (interfaces, embedding types within types, and associating functions with named types) is small, simple, and effective
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.
"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.).
> 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.
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.
67 comments
[ 1.4 ms ] story [ 131 ms ] threadBack 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.
Python has the concept of None, which seems to function this way. You must check if the return type is None, and react appropriately.
Didn’t Go or Rust figure this out correctly?
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.
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.
Don't use Medium, please.
Game programming is a lot more fun though.
The details of how it’s implemented - inheritance vs. composition - strikes me as more of an implementation detail than a vital difference.
In other cases it's a meh.
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.
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.
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.
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.
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.
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.
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...
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.
No mistake about it
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.
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.
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.
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.
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.).
Peace.
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.
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.
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