Avoiding OOP is hard: even those using “non-OOP” languages like C often end up doing some sort of bad OOP where the first parameter is some sort of explicit this pointer. I would tend to agree with the author’s conclusion: it’s often not worth trying to remove all instances of a paradigm from your code, especially if you’re working in a multiparadigm language. If you try to stay away from some of the more problematic aspects (inheritance) while retaining the strengths (encapsulation) I think you’ve done a good job.
If the problem domain naturally maps to OO approach, then programming it as such is reasonable. On the other hand, if the problem, or its understanding at present stage, is not OO (for example not much functional relations, but tons of properties and states), then forcing it into OO implementation in not going to bring any of the promised benefits, but most of the overhead.
Alternatively, spending a lot of lead time doing OO analysis in such cases is more like premature optimization. Instead, if the problem does not appear obviously OO, just implement it as procedural/structural, but implement it properly trying to keep the scopes and states as limited as needed. If a better model, perhaps OO, could emerge from such implementation, then it could be applied in the next iteration.
I agree with you that the biggest strength of OOP is encapsulation that is easily accessible. As for inheritance, I think it is also a good abstraction, but in an very limited number of circumstances. In 10 years as a professional developer I have only ever implemented something using inheritance once. I think the problem with inheritance is that it is far too encouraged, and people fit it into problems which it is unsuitable.
Very true. Implementation Inheritance should be taught as one of the more obscure features of OOP instead of as one of the main features as it is taught often.
But in the end we should be less dogmatic in general . Myself and a lot of people I know started out building big inheritance trees only to find out that this didn’t work so well so we reduced it to a degree that was useful and manageable. But then you have some very loud dogmatists who scream “this is not OOP” and insist on building factories and factories of factories and all the other nonsense. And for some reason the dogmatists often get heard, maybe because they are so loud and convinced of themselves.
> In 10 years as a professional developer I have only ever implemented something using inheritance once.
If you build a library or framework, you'll use it more. There are often plenty of literal "is-a" relationships that don't exist as often in application code. So you probably benefit from inheritance in OOP quite a bit even if you aren't building those relationships yourself.
And now that I think of it, what I was building was a data visualization framework that users could create "plugins" for to handle many disparate types of data. So yeah, frameworks are a great example of cases where inheritance shines, but is rather niche and not many people work on them day to day.
I think the reason a lot of people reach for inheritance is because they're never really taught how to decompose a system into smaller moving parts through analysis. At a high level every watch tells time and date and has complications. But the devil is in the details of what watch we're talking about. And I think most classes on OOP would take it as a trivial example and start with a Watch interface and subclass it. But they never really explain how a Watch consists of a Time and Date, with zero or more Complications and a Face.
If you focus on the compositional relationship you get a lot more mileage out of OOP which is the real revolution over the past 15 years. And the decomposition is how you arrive at the Single Responsibility Principle and Encapsulation. Suddenly you can work only with the set of all Complications, or the Face, or Time or Date without worrying about which Watch you have.
That isn't "bad OOP". It's how you do non-trivial things in C. Got a pointer to various things and need dynamic dispatch to avoid a god function switch statement? Bang! You've got OOP.
how is this bad oop?
You have a function that operates on a struct vs having function pointers on a struct that operates on the values of the same struct?
taking in a pointer to a struct as an argument is much less overhead for the programmer than "ok this is an 'object' here is why it is doing what it's doing oh here is this method etc etc"