The problem with OO is that it is exactly the opposite of failure: it was immensely succesful (in contrast to the actual benefits it provides).
In the dark days of OO's height of success it was treated almost like a religion by both language designers and users.
People thought that the combination of inclusion polymorphism, inheritance, and data hiding was such a magical thing that it would solve fundamental problems in the "software crisis".
Crazier, people thought that these features would finally give us true reuse that would allow us to write everything only once, and then we'd never have to touch that code again. Today we know that "reuse" looks more like github than creating a subclass :)
There are many signs of that religion being in decline, but we're far away from it being over, with many schools and textbooks still teaching it as the natural way to go, the amount of programmers that learned to program this way, and more importantly, the amount of code and languages out there that follow its style.
Let me try and make this post more exciting and say something controversial: I feel that the religious adherence to OO is one of the most harmful things that has ever happened to computer science.
It is responsible for two huge problems (which are even worse when used in combination): over engineering and what I'll call "state oriented programming".
1) Over Engineering
What makes OO a tool that so easily leads to over engineering?
It is exactly those magical features mentioned above that are responsible, in particular the desire to write code once and then never touch it again. OO gives us an endless source of possible abstractions that we can add to existing code, for example:
You can iteratively apply the above operations, and in most cases thus produce code of arbitrary complexity. Worse, because all code appears to be doing something and has a clear name and function, this extra complexity is often invisible. And programmers love creating it because it feels good to create what looks like the perfect abstraction for something, and to "clean up" whatever ugly interfaces it sits on top of some other programmer made.
Underneath all of this lies the fallacy of thinking that you can predict the future needs of your code, a promise that was popularized by OO, and has yet to die out.
Alternative ways of dealing with "the future", such as YAGNI, OAOO, and "Do the simplest thing that could possibly work" are simply not as attractive to programmers, since constant refactoring is hard, much like perfect clustering over time (for abstractions and modules) is hard. These are things that computers do well, but humans do not, since they are very "brute force" in their nature: they require "processing" the entire code base for maximum effectiveness.
Another fallacy this produces is that when over engineering inevitably causes problems (because, future), that those problems were caused by bad design up front, and next time, we're going to design even better (rather than less, or at least not for things you don't know yet).
2) "State Oriented Programming"
There's a famous quote: "There are only two hard things in Computer Science: cache invalidation and naming things". This is about the first of those two.
First a thought exercise: take a complex program that reads a file, like a compiler, or maybe a word-processor. By definition (before any further user input), all objects in that programs memory are derived from the contents of its input file. The reason why those objects exist at all is because if the program needs some kind of information (like the compiler asking "what is the type of variable a?"), for speed reasons, it needs to have cached this information. In theory, we could write a functions, such that every time any information was needed, it would re-scan the input file, and never store any objects at all. Slow, but possible, even for interactive software.
As programmers, we choose how much to cache, all the way from nothing to redundant amounts.
The problem with caching is the invalidation part: as data is derived from other data (which in turn is derived from other data, etc.), if the original data changes, so should all the derived data. Almost no programming languages do this for you automatically, meaning the programmer is in charge or writing code that detects when data has changed, how to recompute it, and to make sure all parts of the program "hear" about it, which is very error prone. Programs that would re-scan the source data every time are less buggy (don't ever get into an inconsistent state), and are easier for a programmer to change (dependencies are more explicit).
Ever wonder why so many problems with computers can be fixed simply by restarting/rebooting/re-running/re-generating/re-compiling? Welcome to cache invalidation.
This is a problem with almost every language, but OO exacerbates it by promoting copies of data (because, data hiding) and generally making it harder to track and update these data dependencies (because, many layers). Beyond that, thinking of your code as defined by "objects" makes you more likely to want to store everything, even in cases where data is transient, and could be defined much better as a sequence of transformations. You cannot add a field to an object just for a short amount of time, once you add it, you are now responsible for it to be valid for the lifetime of the object.
Is this some thin-veiled way of trying to promote everyone to rewrite their code base in Haskell or another pure functional language? No. First, Haskell doesn't even solve all these problems. But being aware that every time you "cache" something that this is a choice, and there may be an alternative way of structuring things that can make the cached data be more transient or simply be recomputed is one of the most important ways to reduce complexity in software. In most any language, you can structure code to be "as functional as possible", within practical limits.