I don't want to start holy war, but I thought I'd share my rant from the other day.
tldr OOP is a tool and shouldn't be treated like an all-or-nothing programming paradigm.
OOP is best suited to problems where you have lots of varied and complex state and many instances of complex state. The history of OOP certainly suggests that at least - it was initially used for simulations, ie many instances of varied complex state evolving over time. Then it found market-fit in GUI frameworks which face a similar problem. Then programmers, with this hammer, treat everything like a nail. They use OOP to solve problems with primitive and singular state, tightly coupling logic to state merely out of habit.
OOP programmers spend most of their time building more and more complex, and abstract, families of logic-state chimera. As a result OOP code tends to be the hardest to read and reason about because at any point of execution there's a bunch of implicit bespokely organized state. OOP encourages state, state organization, and mutability rather than state minimization and immutability. It rejects electing the simple, predictable, and obvious execution stack to carry a program's state. When the execution stack carries state:
- the complexity of a program's ephemeral state is roughly proportional to its execution depth
- state is defined by simple, often primitive, explicit statements exactly where the state begins being used
I think what OOP wants to be is declarative (ie understand these classes, objects, and organization and you know what the code does), which is the way most programming languages and frameworks have evolved, but instead often ends up being the opposite - state mutates state that mutates state that mutates state, times a million, and all according to some random OOP engineer/state architect. Very few problems require the ephemeral, complex, custom, kind-numerous, interdependent state that OOP encourages.