Rant: OOP and spaghetti bolognese
Under the category of "some parts are not a bad idea but the rest was a mistake", it is needless to say that I don't really like OOP. Some of the ideas aren't bad; (virtual) interfaces and single inheritance has been done for many years in C and older languages.
A chimera
What is a bad idea however is combining data and functions into one structure. Those two do not fundamentally belong together. A data structure is just a descriptor of raw data. A function is what transforms this data. There is no hidden state. Anyone can transform the data as they please.
In OOP (almost) any type of data (with sometimes the exception to primitives) is an object
. You bind methods that define how the instance of the class (an object) should be manipulated. When the functionality you need is not defined in this class, need to extend it from the outside (extension methods). Classes may contain hidden state (defined by access modifiers), which may make it impossible to modify the data unless you bypass it with an often build-in mechanism called reflection
.
The fact the language includes a system to bypass the access modifiers included in the language should be enough to tell you how bad of an idea this is. the fact you need to add a mechanism to extend functionality which instead could be done much simpler when using just plain data structures and functions should say enough to say that it's a bad idea.
What upsides?
What is supposed to make OOP great is simplicity and abstraction, but simplicity is nowhere to be found and abstraction hurts more than it's solving.
Classes to me are much more complex than data structures and functions, because in a class I have to worry about both and internal state. Without OOP I just have to worry about the layout of my data structure, and the functions transforming them properly.
Abstraction is like putting a layer of red pasta sauce on top of your spaghetti. The difference is that the spaghetti is abstracted away by the sauce instead of plain naked. Abstraction does not provide simplicity. In fact, it just hides your problem into another layer. And when you have sufficient enough layers, it becomes much harder to track what problems you're actually solving. Everything depends on these abstractions so you better get it right the first time.
Design patterns
"But design patterns based on abstractions is what makes it great! Now everyone understand what I write!". Right. For C and most imperative programs, design patterns haven't been a big thing because the complexity of the code and language itself is sufficiently low enough to not need them. The need for design patterns came in OOP because the language itself is too complex and thus people needed tools to solve these issues. The fact that most OOP software need these patterns to remain properly structured highlights a fundemental flaw in OOP languages.
Don't get me wrong, design patterns themselves are not bad ideas. It's just not something you should religiously follow. They are names for common code structures, not a solution to your problem. It becomes dangerous when people start to think "what design pattern should I use to solve this problem" instead of "how should I solve this problem", because then you cannot think of the best solution.
People would argue that not using a design pattern would reduce readability of the code, but I disagree. Code remains code. I am a programmer, so I should be able to understand someone else's code as long as he/she uses the same programming language I understand. A simple but straight-forward solution to the problem is far more readable and debuggable than a design pattern.