What are the limitations of the object-oriented paradigm?

My experience is more with the object-oriented paradigm. Ok, " if all you have is a hammer, all problems look like nails."

And I say: it is a complicated paradigm, full of good practices, S. O. L. I. D., design principles, design patterns, code smells and a mental model that, on the one hand reduces the representational gap between the problem and the solution, on the other requires time, study and experience to learn how to model this solution in accordance with what the paradigm asks for and in order to obtain the benefits it proposes. From "objects are a natural way of thinking" he has nothing. Not in the medium long term at least, when the problems of design begin to appear.

Is a powerful weapon with the risk of being shot in the foot. It is used perhaps for lack of better thing, but I understand when they say that it is mainstream too much. Maybe because of marketing. But it was a very researched paradigm and I don't believe that so many people are mistaken that it is beneficial for a large number of uses.

It can be said that the problem lies in the developer who does not invest time in mastering the paradigm. I do not know if other paradigms suffer from the same problem, or if the problem is the design discipline itself that is complicated in general, or conflicts with the deadlines of the projects when evaluating a design, or both.

But the OO paradigm itself receives some criticize. In Wikipedia most of it comes from proponents/idealizers of functional languages. I do not know the arguments, but this suggests a sardine pull for this paradigm (I'm not saying that there is a dichotomy there, only that the arguments run the risk of being biased and there is no advantage in defending a paradigm that has no prospect of supplanting another - it is, at least in this aspect there is a dichotomy).

My question is: how if not if these criticisms were enough (or perhaps should pay more attention to them), are there others that the OO programmer needs to be aware of? What are the weak points of OO?

Author: Maniero, 2018-02-16

3 answers

you can produce useful information here, but our mechanism does not help people understand that this information is not canonical and universal, which reflects some bias

First let's combine about who uses object orientation. Let's not talk about that pseudo programmer who does not understand anything of what is OO, maybe not programming in general and some even basic mathematics and can not even calculate percentage, much less know how to interpret a text or problem, no they can gather the parts of what they are doing, search for information in a structured way, analyze it and complete something on their own. Not least because these people will probably not even read this page, or not know what to do with it.

Unfortunately I think that by 90% of people who Program fall into this category, not least because it is wide and takes from the guy who should be banned from selling hot dogs on the corner, to the one who can deliver projects that work and to some extent they are right, but still only vaguely understand what they are doing.

I don't think there are many people who understand what OOP is, probably not even who created the term (I explain below). And obviously I'm not saying that I understand. People who categorically state that her definition is the right one should suffer from the Dunning-Kruger effect , which is different from being assertive about what she believes to be the right one.

I'm sorry if anyone if you feel offended, my intention was only to put a basis of what occurs in the market to justify why we have reached this point, I do not want to offend anyone, and if you felt like this, reflect if you can change something because you saw that it serves you, or suffer from the impostor syndrome or you should take I think the people actively participating here and almost everyone who passively participates are among those not offended, or unconsciously think to be "imposter".

I'm not talking about anyone specific!

Unfortunately nowadays we have to do all this disclaimer.

I will say what I agree and disagree with Victor's excellent answer and the question and adopt a different point of view, not least because the question is dubious about what kinds of problems she is talking about.

It was a much researched paradigm and I don't believe that so many people are mistaken in it being beneficial to a large number of uses

Hasn't been much researched, seriously, and what happens most in the world is people fool themselves, they do it all the time, they love to fool themselves, everyone, some more than others, at one point or another. Why do you think politicians are so bad but still hold power? Why does the bulk of what we consume have something bad and yet nothing changes? Why do rich people spend fortunes on things that have little or nothing aggregate other than the fact that they are caro? And I'll stop here so as not to catch Heavy:)

Requires time, study and experience to learn to Model

Yes, to model, to learn the mechanisms is not even that complicated. But of course the guy who does not want to learn everything right will not achieve anything. But then the problem is another, he also does not know that can not use double for money, cannot accept inputs without positively validating , a CPF is a description , cannot debug or ask a question on the internet, anyway, the problem is lower.

Objects are a natural way of thinking

Yes, for those who think: P Ok, seriously now it is difficult to establish limits of the object and this has nothing to do with what Victor answered, thinking OOP is the difficult part.

I'm talking about Java OO, but everyone has complexity when it comes to crafting the design, right? Or one design principle OO does not apply to other certain OO?

Java does not have an OO, it has Oo mechanisms, but the project can be done following some schools. Java has static typing that forces certain mechanisms to work in a way. Victor covers most aspects well. Java uses a number of mechanisms that have nothing to do with OOP, and people don't even realize it.

Opacity of polymorphic abstractions

I corroborate the view of jsbueno that there seems to be scrutiny of the implementation of the language and not of the object orientation paradigm. More specifically, at least in part, it is talking about the difficulty with typing.

Remembering that in dynamic typing languages the functions are naturally polymorphic(although not all are written like this, in static typing language neither).

For me this whole section is talking about the difficulty imposed on static typing when using polymorphism (not necessarily OOP).

The difficulty in using is a little if you are not using an IDE. But I don't think the oop problem is there, OOP just helps the IDE better inform the code structure.

What I always talk about is that people don't understand what OOP is. She does not have this difficulty because it is common for her to not even use it, especially in the right way. Most create classes and think this is OOP. But for the "real programmer" I agree that it has this difficulty cited.

I think affects the readability of the code. Everything that needs context to know what will occur is less readable. I typed because it is common for proponents of OOP to defend readability with teeth and nails, which I even agree, I only disagree that OOP helps in this. Victor's argument shows that it's more complicated to know what that is.

Some may say that it affects even is intelligibility. Whatever. And as a result maintainability.

People who advocate OOP often sell the idea that programming gets easier and this is not true. It gives the impression that you abstract and encapsulate everything and make everything simple. Hiding concreteness has its drawbacks. I love abstractions, but when used in excess it only puts more cognitive load and hides relevant points. I know some people will defend that with philosophy. I love philosophy, but when it comes to making the project it needs to be with rice and beans (I know who will understand this wrong, but whatever ).

People overcomplicate what can and should be simple.

Simulating polymorphism in a structured language

With branches (if, switch, etc.) you do polymorphism, not just simulate. Not in the way people often refer to polymorphism, it's true. The problem is the same.

There's nothing wrong with doing this, unless you have a reason not to do. Maintenance can complicate if you need to add behaviors, this way leaves no cohesion. But it's not just any project or any specific problem that needs all that cohesion. Cohesion has harms too. I'm not advocating the use of this mechanism, just making it clear that it has utility and not using it where it should is as bad as using it where it shouldn't. I see a lot of misusing because one only sees traditional polymorphism as the correct one.

The use of pointer for function has even more to do with functional programming.

These concepts are more concrete, which is always easier to understand.

OOP abstracts the mechanism and makes it harder to understand what is occurring. Even if the person says no, even for himself, it is common for the person to see it as magic.

It's magic

Double-dispatch

I agree and find it one of the biggest problems of the whole engine. Enough for disqualify use where it should not.

Is too abstract an example for me to state, but it is very common this problem arises when trying to model something that does not actually exist, when trying to use OOP where it does not fit, maybe a relationship would be more suitable.

Often this goes unnoticed

My perception is that this occurs too much in the use of OOP.

Here Comes the problem I talk about, the person gets so blind to using OOP for everything she it manages to ignore that it has easier means to solve the problem. The relational model is often easier for people to understand. I don't know why, you need to have a Pedagogia.SE for us to ask.

If I'm not mistaken elixir solves this, but pays a price.

Multiple implementation inheritance

I see this as implementation problem, which is simpler in dynamic languages.

I've discussed this several times with several people, a lot of the complaint about OOP is actually about static typing.

Has several ways to have multiple inheritance. Some languages do this too generically (C++ cof cof), others can restrict too much, and it is rare, if any, that languages have everything they need to work (abstract classes, interfaces, traits, mixins , roles, protocols, delegations, extensions, attributes (I'm not talking about Fields), etc.).

In fact people they don't quite understand what to inherit, when to put things together, what is a mechanism and what is a business rule, what is the business limit of that object, how it can or can't be extended, why not extend what could because of optimization, just to name a few things. People do not understand ontology and taxonomy. Not that this is irrelevant in other paradigms, but in OO it is quite important.

The project starts well, over time it starts to be a lot of gambiarra, because the person did not classify and named things right. Oh, but it has the miraculous refactoring . Um, it seems to me that these people have only worked on small, short-lived projects or that are very statically defined. I know who talks about these things and has worked on dozens of times more projects than I have in a third of the time I have of profession. I don't know if they understand what it's like to keep a big project for the long term. There is no time to take care of three hundred projects when it has such a complicated one. And to solve this there are people complicating the projects even more, but if you follow the standard recipe that you have done before, everything is solved and it seems that the person works a lot, productivity measured in KLOCs.

I've seen people have to change almost the entire system because of this. Is this OOP?

The problem I see is that it is difficult to define what is what. Of course you need to understand the mechanism as well. The point is that if the person knows well what he is doing it can make good use of other paradigms like the modular, which is simpler and more organized.

OOP doesn't make people create good projects magically, OOP is just the tool. Just because you have water, a refrigerator, and a saw doesn't mean you'll be able to do this:

Ice sculpture

Simple implementation inheritance

I agree 100%, especially the last sentence of the 1st paragraph. And this is a relational and modular model and not OO.

Much of the problems we deal with today were created because they began to inherit where they should not, and in many cases should not. Unfortunately people do not see this, they do not understand what problems she will have in the future for having this coupling.

And guess why it often gives no problem? Because the problem was too simple and / or static, and OOP was not needed there.

Crosscutting-concerns

Is a limitation of OOP and other paradigms. The functional handles this better with its own limitations, metaprogramming in its various forms as well, as does the modular but less because it turns out to be a middle ground, but it has a problem, it is worse defined than OOP.

Aspect-Oriented Programming has not been well accepted because it has a strong negative side as well: it causes the code to acquire in it behaviors that there are not expressed and that are encoded very far from the point where are executed, without there being any clear indication for such fact

Oop too and was very well accepted.

But it's a fact that she doesn't handle real-world modeling well. So now some people deny that this was the goal of the paradigm, even though it is full of material from the past saying it. So what is the advantage of using OO? Reuse? There are those who deny it too. And you can only reuse well if you do not try to make objects that take care of everything.

This is the largest paradigm limitation, taxonomy needs to be perfect to work well, but this is difficult or impossible.

Focus on objects and not actions

There speaks that the languages that were said OO surrendered to the functional. They are neither one thing nor the other, they just allow something in this line. Essentially these languages are imperative .

People focus on actions and it seems hard to understand that this is not OO. OO is structure of give.

Class Inextensibility

Has several solutions to this. In fact I believe that this limitation is not OOP, as far as I know pure OOP requires that classes should be able to be extended. But there must be controversy about this.

However, mix-in still has a disadvantage, which is that it is a behavior assigned to an object that does not appear in the code of the class corresponding to that object, being located outside the class where it is applied (and possibly somewhere far from it and quite difficult to be determined).

This is a criticism I make, proponents of OOP tend to destroy cohesion by wanting to put everything together that is separate. The procedural/modular / functional tends to allow these compositions in a much simpler way, greatly facilitating maintenance and simplifying creation. The error charges you much less when it's all more granular.

In dynamic languages this is usually much simpler, even in OOP.

There was presented a limitation of Java. Although the existing solution in other languages is also not well object-oriented.

Dependency Injection

I agree. And this complication is something that most do not understand right, and they do not know when to stop doing this. It's too common to violate KISS and YAGNI to be "OOP".

There are some questions that are very difficult to answer. In fact almost everything, when it is modeling objects is difficult. The worst thing is that people learn that the answers to this are wrong recipes. They teach in bad abstract examples and people can't apply it in the real context properly.

Are often said to do DI to facilitate testing. Then you will see the tests and they are a pile of bad engineering, testing the obvious and leaving aside what matters because the person does not understand the difficulties he will have with that object. That's why TDD doesn't work. And o unit test done after only resolves regressions... if the project holds firm in its initial philosophy of quality, which is rare in long projects that are not products for other developers to use (even these are not always so).

Greater complexity than other paradigms

I agree with everything before the bullets. Too bad people do not understand that OOP is modeling.

Few people reach the level of using OOP well, and many find that they arrived (I'm not talking about the alloprados). I didn't get there after 30 years doing this because I don't do the same project every time. Again, learn to do better those who have made mistakes in various projects. Anyone who did multiple projects, due to their size, probably worked on things that OOP wasn't as useful as that. There are exceptions.

Making a form using your GUI classes is not object-oriented programming, it is using what was Object-Oriented Programming. The same for MVC and other frameworks . And yes, the biggest utility of OOP is to build frameworks. My experience in business systems is that it almost always has less utility than people imagine.

Are already looking for studies that indicate that OOP has these qualities that they propagate and have not found. This doesn't prove anything, unless it has no proof that OOP is that much better. It's all perception. Mine is the one I just said above.

Done wrong, and this includes using OOP where it shouldn't, it doesn't deliver value.

  • There are those who complicate the code just to not break the rule that says switch is capeta's thing.

  • I'll wait to see if Victor tells me what's wrong with PessoaJuridica extends Pessoa. I think normal, almost all inheritance should be on top of abstract class, interface or something, there it serves only as taxonomy and/or reuse. I find it strange the Cliente extends PessoaJuridica that detonates cohesion.

  • In fact "pure" OOP not he likes primitives. So I think oop bad, it is the academic thing and not the engineer who uses what is best suited to the problem.

  • In OOP what I see most is the use of copycat.

The fact is that OOP is taught all wrong, and it has become almost impossible to teach right, not least because "no one" agrees with what OOP is. There it diminishes even more its usefulness, making it even more difficult to communicate. And the biggest mistake is teaching that OOP solves everything very well and ignore other paradigms.

Extra complexity in the representation of abstract concepts

There seems to be more of a critique of abstraction. It's a problem when you say you can only do it abstractly. Modeling things that change is complicated. Not complicating what can be easily changed is more complicated to see, then the person goes to the default and complicates everything.

Note that all products used by US devs use OOP to some extent and go on the concrete where it is better.

Of course everyone can have the opinion that this is not a valid criticism, I validate it, until the day they prove to me that it is not valid.

Object-Oriented Programming has lower performance

The problem is not the engine , it is the model. If you overdo it starts to have problems yes. If you need maximum performance is something else. The functional has problems too. When performance matters, other paradigms may be more useful. metaprogramming can help with abstraction at no cost. It is common for OOP to end up hiding complexities that are only shown to be slow too late. Sure, it's design error, but oop helps to have that.

The problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.

Joe Joe Armstrong

Excess specification without generic types

Curious that a good oop modeling is to make use of genericity and not OOP. It is an OOP problem in static typing. And OOP (not all definitions) preaches inheritance and not genericity.

Lack of a canonical definition of what is Object-Oriented

Whether everyone understands one way is a complicated paradigm to follow. It is complicated for people to understand each other in the projects, first you have to learn what is the OOP of the team, and today the team can be the world.

If people even know what OOP is it becomes difficult to use and evolve in the paradigm. Every hour you are influenced by a different thing, you do not know if what is being taught applies to the by-product you are using. This is one of the biggest problems of the paradigm. Much of the mistakes made in him are because of this.

The pillars described is what I think, but the creator of the term thinks not, although he himself has already said (or almost that:)) that should have called that message-oriented or server-oriented and says that mistakenly chose the term .

I have been wondering about what encapsulation and abstraction is, I have the impression that I have always understood wrong, and a lot of people too, so they teach wrong and everyone learns wrong. I post something the day I'm right (I started doing).

Some people say almost the opposite of these things, so it's a problem. It is complicated to know if you are doing right if you have the one who has to put everything in the class, and who has each class to do only one thing.

Victor disputed in comments in his answer that inheritance is something inherent to OO. I live doing these things, it is complicated to deal with something poorly defined.

If it has only one of the three pillars, is it OOP? There are those who say yes and say it's encapsulation, and I think it could be, if you consider that this is just putting everything together in the class. We only one that is unique to OOP is the inheritance.

Interestingly has dynamic typing language that has subtype inheritance, I won't name names, but it starts and ends with P: P: D

Anemic model

Is a modular model that greatly facilitates maintenance. There are people who have no problem with cramming everything into a class, or do not see it as a problem, even though it is, or do relatively static systems, as I said above.

It doesn't matter if it's anemic or no, sole responsibility matters. In other paradigms it is easier to have this, some are automatic. Hitting the" size " of the class is very difficult. And everything that has been said throughout the text is worth it.

100% oop encourages violating the DRY, and there is a strong movement towards this lately. People are going crazy:)

Cohesion is not about putting everything together, it's about putting together what needs to stick together. We don't even talk about classes. Being cohesive is important, being encapsulated to the extreme no.

Cohesion depends on context. How to model this in OO? Simple, making modular / functional or even procedural. A lot of people do, but they think they're doing OO (remember, I'm not talking about the noobs).

Since we don't even know the definition of what OOP is, we don't know the details of what is cohesive for OOP. What I do know is that cohesion is fundamental, and this has existed in computing for over 50 years, before OOP and before the term software engineering exist. I'm talking about the term using in our area, in others it is secular, or millennial, I know, question pro ptlang.SE .

Spreading things out without criterion and putting everything together without criterion are equally bad.

Difficulty writing a compiler

Yeah, it doesn't matter.

It is only good to make it clear that more modern languages (Rust, Go, Erlang, etc.) are not adopting oop explicitly, do not encourage it, and older ones are moving away one little of the paradigm, even if they deny it. This applies to Java, C# and especially C++. The languages that bet everything on the paradigm did not succeed. Alias The Alan Kay considers Lisp to be the best language that exists and she is not OOP, she has nothing of what people talk about OOP :)

Other problems

Has problems with concurrency. There's no room for detail.

The biggest problem is the difficulty in modeling, it's not so much OOP. Is that oop requires doing Okay. When asked about learning oop for Alan Kay, he responded with a book that doesn't teach programming . I always talk, the problem is that people can't sort things out, and that's key in OOP. So she groups distinct things together. And we deal with problems that we do not know, or we are repeating what we have done before, which is not a very noble task.

I just don't like the book indication so much because almost nothing we program works like biology. Get the wrong idea. Hence comes a lot of bad example of how to model OO.

If people are bad at ontology, something that forces them to be good at it is a invitation to disaster.

It is only easy to understand a code written well Oo if it was you who wrote it or is in a language very well mastered by the team.

Oo inhibits creativity, because it has to follow certain standards to everything work out. OO makes it more right to do recurring things. I won't even talk about DDD which is Oo in the worst form (the idea of DDD is good, the implementation adopted is one of the most terrible things I've ever seen in computing).

SOLID is an interesting case. Is he or isn'T he OOP? If you follow everything right you will be doing modular/functional programming and nothing in it is unique to OOP, in fact some OOP things are not in SOLID. The impression I have that he opposes OO. If this is true, and of course I think it is, it would be another case who needs to get out of the purity of the paradigm to get what he wants. And you need to know all this.

The difference between people who like OOP languages and these people are that these people are pioneers who are actually solving huge problems in computing; whereas the designers, supporters, and implementers of OOP languages waste all their efforts on aesthetics or trying to prevent a strawman idiot from doing idiotic things.

Joe Joe Armstrong

Item 4 of the last objection is the most important.

If you search for OOP, OOD or word that indicates the same thing along with flaw, sucks, evil, bad, problem, misuse, and similar things will find a lot of thing, most of it makes sense.

Conclusion

I think there is a lot of evaluation of implementations, of languages and not of the paradigm in the response of Victor. Apparently the answer indicates that it does not matter to be OOP, it matters is a language that is said OOP can do everything even through other paradigms. I may have misunderstood. But it is a fact that this indicates that pure OOP does not work.

OOP does not solve all problems and adds new ones. In its pure form it requires doing very unpractical things and inefficient codes. It requires things that most people are not qualified to do and done wrong it causes more problem. Whoever created the term also thinks that problems are too complex and needs an understanding that people don't have, and they can't be solved in isolation as people want. I understand that he knows that OOP is not all of this, the problem is the people who think it is.

There are two groups of people: those who are distancing themselves* of OOP (or have already been distant) even if they do not even notice this, and those who are sticking in the hole of the paradigm more and more. The good news is that if you have this type of attitude most of the problems we take care of do not cause much difficulty nowadays, not least because the problems are too small and static to cause.

*distancing is not abandoning, it is using where you need to.

Is the biggest problem we have in our area, and it's getting worse: something very good is created and serves 1% of the problems, maybe 10%, but people want to use it for 100% of.

Phrases from excellent programmers (almost all) who do or have done important things, hitting OOP , at least in the way people use it. They look like empty sentences, but if you search you will find the context where they were said and almost all have concrete arguments behind the sentence.

Read the comments of the question, the AP found more interesting things.

I like the GRASP , not everything, but the basic idea, because if you do all that it runs away from the central idea of OO. At least it's just a guide line and that says you should do what needs to be done to achieve an overall goal. It doesn't mean much, but it's better than having "rules" that you need to follow purely because otherwise you're a moron.

If you follow all the rules you invented and keep inventing (OO has new rules almost every day :)) it can work out. If following a series of rules in other paradigms also has a great chance of working out, many times more, only that these rules were not disseminated, perhaps because they were created before computing "exploded".

As a curious note is to see the irony of Rob Pike, the creator of UTF-8 and this part is important in this sentence, saying that OO is the same as Roman numerals.

Object-oriented programming is popular in big companies, because it suits the way they write software. At big companies, software tends to be written by large (and frequently changing) teams of mediocre programmers.

Paul Paul Graham (the whole text is interesting )

It is not OOP that is broken - we just haven't figured out (after over 40 years) how best to develop with it

Oscar Oscar Nierstrasz

 14
Author: Maniero, 2019-09-16 16:08:29

The paradigm of Object-Oriented Programming imposes some difficulties. They may or may not be overcome to a greater or lesser extent. The following list is by no means exhaustive, but it should serve to answer this question.

Real reviews I consider valid

Here I list some things that I consider typical problems in Object-Oriented Programming languages that can be disadvantages.

Opacity of abstractions polymorphic

The Object-Oriented Programming paradigm is significantly more complex than the structural/procedural one because now functions and procedures are replaced by possibly polymorphic and even abstract methods. This polymorphism no longer allows the function/procedure now invoked to be precisely determined beforehand, so that it will only become known at runtime. This can then leave the analysis and understanding of more complicated programs.

In a procedural / structured program, when a function xpto is invoked, you know exactly where it is statically and you can then quickly look at its code. That is, in this case, abstraction is transparent because you can easily locate and inspect your content. Already in the object-oriented no. Method calls in Object-Oriented Programming can be abstract and polymorphic, being determined only in time therefore being opaque, that is, not amenable to be quickly located and inspected.

This is something that tends to get in the way of beginners in OO who are left with that thing of not knowing exactly what method they are calling, since there can be multiple implementations. It can complicate when you are looking at the code, looking for some bug or trying to understand some behavior of the code and falls into an abstract method and is left without knowing where to find the implementation of it or even which of the various implementations is the one that matters.

simulating polymorphism in a structured language

Programs written in procedural programming languages do not usually attempt to explicitly use polymorphism. However, the need for polymorphism exists when we see that function salvar that has a parameter of type int where 1 is a file, 2 is a socket, 3 is a pipe, etc. Or where instead from having only one function salvar, we have the function salvarNoArquivo, salvarNoSocket, salvarNoPipe, etc.

It is possible to simulate polymorphism in procedural programming by using function pointers or by means of functions that have a gigantic if or switch inside to choose the appropriate implementation. However, it is noted that by doing this, one is actually doing a gambiarra with the aim of simulating a different paradigm than the one the language imposes.

In the case of a procedural language, the use of polymorphism based on function pointers, if done in a standardized and well organized way ends up producing a design pattern capable of simulating the polymorphism of object-oriented languages (including, this is exactly how they are implemented in practice). But we use very atypical constructions with very different structures from those that would be natural for the language. In other words, gambiarra becomes a design standard promoting something that is not natural to be expressed in the language in question.

When doing this in a procedural language, the opacity of the object-oriented arises and it is no longer possible to know statically which function will be called since what you have is a function pointer whose value is only known at runtime (or even if it is/was a value to be used a very large switchZon). The structure of the resulting program presents an extra complexity that serves only to simulate the orientation to objects in the procedural program, complexity that would disappear if the language was Object-Oriented, but without the opacity of the corresponding abstractions disappear. This demonstrates that this opacity is not in fact something that procedural programming is immune to, but rather something that arises when polymorphism is added to it.

Double-dispatch

This here is the opposite of the previous item, it is lack of sufficient abstraction. Polymorphic calls use the object to which they refer as a context in which they execute in order to provide a dimension of polymorphism. It happens that not always a single dimension is enough.

For example, imagine that we have different types of robots that inspect different types of cars and that each robot-car combination occurs in a different way:

  • In the structured paradigm, we would either have a function / procedure for each robot-car combination or we would have a single and gigantic function / procedure with a zillion ifs and switches to separate these cases all.

  • In Object-Oriented Programming, we can put the method visita(Carro) in the class Robo and choose the type of car within each implementation or else put the method receberVisita(Robo) in the class Carro and choose the type of robot within it. Neither of these two approaches is ideal because whichever one you choose, you choose whether the polymorphism is based on Robo or Carro, but not both of us.

  • In the ideal paradigm, given a combination of Carro and Robo, by invoking the visitar method, the ideal polymorphic implementation would already be chosen.

The name of this is double-dispatch, for the implementation to be executed depends on the type of two objects rather than just one (single-dispatch).

There are some techniques to try to get around this problem in object-oriented languages, such as using the project pattern Visitor , introspection or reflection techniques or use tables containing dozens of objects that represent each of the possible different implementations, these being defined by an interface. However, in this case you will already be trying to simulate a different paradigm using constructions that are not natural to the language in question, in the same way that occurs when simulating polymorphism in structured programming. Result again it is a good amount of code and complexity to manage this that would be dispensed with if the language in question already had this feature built in.

Often this goes unnoticed, but sometimes it happens when we have that decision if we create in class A a lot of methods to deal with all the different types of B or else if we create in class B a lot of different methods to deal with all the different types of A, or else we end up creating objects that relate different types of A to different types of B in order to choose what to do with them. All these things would be unnecessary in a language that already had the double-dispatch naturally.

Multiple implementation inheritance

One thing that has been considered a major problem in Object-Oriented Programming Languages is the inheritance of multiple implementations.

The first languages to go by this path allowed for multiple implementation inheritance. Programs resulting from the use of multiple inheritance tend to be confusing and difficult to understand. The main problem that arises is the Diamond Problem:

 class A:
     void x()
         print('a')

 class B extends A:
     void x()
         print('b')

 class C extends A:
     void x()
         print('c')

 class D extends B, C:
     void y()
         x()

Note that the method y() of the class D invokes the method x that was inherited. It is unclear whether the method inherited from C or the method inherited from B will be called. Some languages try to solve by imposing an order of inheritance precedence, but it can create problems:

  • A method of B may end up calling a method of C on the same object since B is not a subclass of C and neither is C a subclass of B.

  • When there are several inherited methods, defining the correct order of the superclasses can be difficult. There are cases where the correct order can vary in different contexts of the same class implying that there are cases where no order is the right.

Another problem is with respect to casts.in many object-oriented languages, objects are organized in memory by placing superclass members first followed by subclass members. In this way, by casting from a memory address of the subclass to the superclass, the resulting address would be the same. In a cast from the subclass to the superclass as well, the address is the same. However, when there is more than one superclass, this trick no longer works and it is necessary to make address corrections in the casts, which brings a lot of complications and makes the same object may have more than one memory address or have to have a significantly more complex memory organization.

Simple implementation inheritance

Many object-oriented languages have abolished implementation multiple inheritance and only allowed inheritance simple, with at most one superclass. It happens that even simple inheritance introduces problems.

Analyzing and understanding the code of a superclass can be difficult, as it is incomplete code to be finished or overwritten by the subclass. A subclass is also somewhat incomplete, as it is strongly coupled to its superclass. That is, inheritance introduces a type of strong coupling . For this reason, subclasses are especially fragile if superclasses undergo changes. In particular, it is often that the behavior of the subclass depends on details of the implementation of the superclass, breaking even in the face of changes in internal details of this.

Inheritance can almost always be replaced by composition. An object in memory consists of several fields that correspond to other objects (or primitive/built-in values). For example, an object of class Veiculo would be represented by a sequence of data placa, proprietário, tipo-de-combustível. An object of type Carro (subclass of Veiculo) would be represented by placa, proprietário, tipo-de-combustível, cor, modelo, marca. Note that this is almost the equivalent of making the subclass structure Veiculo, cor, modelo, marca. That is, by using composition in place of inheritance, you come to a structure with the same data, but the subclass is more flexible as to what it can encapsulate from the superclass and how.

Crosscutting-concerns

One thing that tends to get in the way a lot in programs oriented to objects is the following case: Imagine that you have a method that saves an employee's record. It would ideally be something like this:

void salvar(Funcionario f) {
    Arquivo a = ...;
    a.escrever(f.cpf);
    a.escrever(f.nome);
    a.escrever(f.salario);
}

But, it happens that you still have to deal with concepts such as logging, transactions, error handling, among others, and the code ends up turning this:

void salvar(Funcionario f) {
    Logger.trace("Salvando o funcionário " + f.id);
    Arquivo a = null;
    Transacao tx = Transacao.abrir();
    try {
        Arquivo a = ...;
        a.escrever(f.cpf);
        a.escrever(f.nome);
        a.escrever(f.salario);
        tx.commit();
        Logger.trace("Salvou o funcionário " + f.id);
    } catch (ErroDeIO x) {
        Logger.error("Erro ao salvar o funcionário " + f.id, x);
        tx.rollback();
    } finally {
        a.close();
    }
}

This introduces a lot of additional and accidental complexity to the program. In addition, all these features logging, transactions, error handling (called crosscutting-concerns ) are scattered and copied-and-pasted in a bunch of different places for everything that is side in the code. When any detail regarding transaction management has to change, it will require extensive modifications to various parts of the code.

There are several attempts to solve this in Object-Oriented Programming Languages, but all of them end up leaving at least some line of code, some command, or some annotation to back in code that still amounts to crosscutting-concern , and ideally there was none of that in the code, but that was still there at runtime.

It was with this in mind that Aspect-Oriented Programming arose, which separates the code of the crosscutting-concerns from the code where it is applied. However, Aspect-Oriented Programming was not well accepted because it has a strong downside as well: it causes the code to acquire in it behaviors that there are not expressed and that are encoded far from the point where they are executed, without there being any clear indication for such a fact. It is difficult or even impossible to look at a code and know what the crosscutting-concerns that apply to it and whether they are being properly managed.

Focus on objects and not actions

This is a critique of functional language advocates of object-oriented languages. In functional languages you have lambdas that are like anonymous methods, pieces of code that you can pass as a parameter to methods.

This makes it possible to simulate in more purely object-oriented programming languages without much difficulty, but it comes at a cost: it produces an explosion in the number of classes and interfaces and a significant complexity to encode them. This has been mitigated in more modern object-oriented programming languages that they incorporate the concepts of lambdas natively, making them hybrid between object-oriented and functional.

Class Inextensibility

Everyone has been through a case where you want to add any method to an existing class, but you can't do that because that class can't be modified. It is from this limitation that classes like StringUtils, DateUtils and XptoUtils of life eventually emerge. These classes are gambiarras arising from the fact that there is a need in extend classes that for some reason can not be modified.

The solution to this is in the concept of mix-ins, which consists of adding methods to existing classes, things that languages like JavaScript and Ruby allow easily and that can not be done (at least not easily and without gambiarras) in languages like Java and C#. However, mix-in still has one drawback, which is that it is a behavior assigned to an object that does not appear in the code of the class corresponding to this object, being located outside the class where it is applied (and possibly somewhere far from it and quite difficult to be determined).

For example, let's assume you want to add a method to invert a string. In JavaScript, which supports mix-ins, this is easy:

String.prototype.reverse = function() {
    let r = "";
    for (let x = 0; x < this.length; x++) {
        r = this.charAt(x) + r;
    }
    return r;
}

var teste = "abcd";
document.write(teste.reverse());

Note that the above code uses teste.reverse() instead of reverse(teste). This is because the method * reverse was injected inside the class* string.

*: in JavaScript there are no classes and methods per se, but the way it implements functions with scoping and object prototypes serve to simulate these concepts well.

However, if we try to do the same in Java:

 public class StringUtils {
     public static String reverse(String in) {
         return new StringBuilder(in).reverse().toString();
     }
 }

public class Main {
    public static void main(String[] args) {
        String teste = "abcd";
        System.out.println(StringUtils.reverse(teste));
    }
}

Note that instead of using teste.reverse(), we have to use reverse(teste), reverting the code structure to a typical procedural programming structure. We cannot use teste.reverse() because we cannot change the class String and not inject an external method into it.

The resulting class StringUtils does not represent a concept of object orientation, since instances of this class do not make sense and it only serves to group methods that we wanted to be elsewhere.

Dependency injection

Several objects, in order to perform their work, must be able to locate their dependencies, that is, other objects with which they must collaborate.

Getting the proper objects to know each other can be quite laborious, as it can involve very complicated object creation processes or very difficult constructors to use. From this comes a lot of creative design patterns, such as the Builder and the factory , which although they are design patterns, can also be seen in a negative way as gambiarras invented to circumvent limitations of the language.

One possible solution to this is dependency injection, where the object a declares that it needs an instance of B to operate and when a is created, B is delivered to it from some sort of magic (which often ends up turning into a 95]} dependency injection frameworkor in a service locator).

In addition, there is the problem of the egg and the chicken. We should object "egg" create object "chicken" or should object "chicken" create object "egg"? Does DAO create Connection or does Connection create DAO? This problem becomes simpler to solve with dependency injection, where the framework responsible for this takes care of figuring out the best order to create such objects. If dependency injection can be lazy (i.e. done on demand only at the time it is required), even if the objects A and B depend on each other, they can be created separately and will only know each other when one needs the other.

Note that all these dependency injection approaches again add a lot of complexity to a project that comes to enjoy it. Again, we fall into the case where too much complexity is added to get around programming language or paradigm limitations of.

Greater complexity than other paradigms

Understanding and knowing how to properly use the Object-Oriented Programming paradigm is in fact much more difficult than doing so with the procedural paradigm. It is one thing to understand the concept of what is a method, constructor, class, instance, inheritance, polymorphism, etc. Another thing quite different is to know how to use it effectively and intelligently.

The design of a well-made object-oriented program is difficult to do, and sometimes it turns out to be easier and faster to opt for a program with a more simplistic structure. Sometimes this more simplistic structure is a procedural model with little object orientation such as an anemic model (I explain more about it below).

It is very common on a day-to-day basis to have tight deadlines and insufficient training and experience, which results in structurally more deficient projects. By the way, this fact occurs in any programming language with any paradigm and with any software development methodology, but it affects more those that are more difficult to learn correctly, such as the object-oriented paradigm.

When this barrier is overcome and the programmer starts to use object orientation properly, no longer programming in a structured way or just piling a bunch of methods into any classes, he gains a lot of flexibility and robustness in the code structure, mainly due to polymorphism and encapsulation. However, to reach this point of maturity, it is necessary to go a long and difficult way, and many simply do not want or can not get there or are still going through it and will still take some time. Before they are matured, they will try to use object orientation (and will often think they are in fact using it) but will not be able to reap the fruits of it, thus having the impression that it's just extra complexity for nothing and naturally they will make various criticisms, claiming to be unproductive, overly complex or not deliver real value.

Bad programming practices in particular tend to make this path already quite difficult and slow to be traveled, even more difficult and slow:

  • It is common to see those who insist on using switch instead of polymorphism and teach it to others.

  • It is common to teach yourself models procedures painted of OO instead of real OO, such as proliferation of classes that are nothing more than getters and setters, practices of the type PessoaJuridica extends Pessoa, monstrous classes that have Troc hundred different methods to do everything that is crooked and right, etc.

  • It is common to see people using inappropriate data structures such as a bunch of ints, strings and arrays rather than classes and objects.

  • It is common to see people imitating patterns and coding processes (often addicted) without understanding or questioning why them.

  • It is common to see people programming in the X language imitating the coding standards and conventions of the y language and ignoring the recommended standards in X.

This spread of bad practices makes it more difficult for those learning to separate the chaff from the wheat and introduces several vices that are difficult to unlearn afterwards. Again, I stress that this learning and application problem applies to any programming paradigm and any language, but affects more strongly those that are more difficult to learn correctly, reaching the paradigm of Object-Oriented Programming.

Criticisms that I do not consider valid

Here I list some of the criticisms linked on Wikipedia that I do not see as valid and some that I have seen elsewhere.

Extra complexity in the representation of concepts abstract

A common criticism is that it can often be simple and easy to use a int or a string to represent something of type 1=monkey, 2=Dog, 3=Fish, 4=cat and then put a if or switch in the parts where the behavior varies from one case to another rather than defining specific classes for all of them. In more bobbly cases, this is even valid, but this solution has no scale. One thing is when there are 1 or 2 places where these objects (animals in the case) may have different behaviors and you enter an arbitrary code 1, 2, 3 and 4 to deal with it, another thing is when there are 1000 different places. Object orientation brings polymorphic behaviors into the object in question, eliminating the spread of ifs and switches with a bunch of crazy and arbitrary codes that would otherwise dominate it.

Object-Oriented Programming has lower performance

Although it may be true that the fact since calls to polymorphic functions require a more complex mechanism than non-polymorphic ones to realize them and that this can inhibit some optimizations, in practice this is not a real problem. The biggest performance bottlenecks are within loops that must be run too often and as quickly as possible, and the porns of Object-Oriented Programming are optimized in these circumstances very well by all the decent compilers out there on the market, including those of interpreted languages (which typically compile just-in-time before executing the code).

In addition, most performance issues relate to algorithm designs, which changes very little in relation to the choice of procedural vs Object-Oriented.

Over-specification without generic types

It is often pointed out that classes BoloDeCenoura, BoloDeChocolate and BoloDeMorango are subclasses of Bolo, and with that you create a lot of classes and subclasses for all kinds of things. This criticism ignores the fact that this is not good object-oriented modeling, although it is often taught that way. The ideal is to do in class Bolo, a method getSabor(). If the taste type should not be lost, let it be done Bolo<Cenoura>, Bolo<Chocolate>, Bolo<Morango>.

This type of class modeling appears when:

  • The language in question is strongly typed but has no types generics and the programmer tries to simulate this in a bad way (gambiarra) using inheritance.

  • The programmer modeled this way because it seemed to him to be a good idea to use inheritance to specialize behavior in this way without considering the possibility of using composition.

In the case of dynamically typed languages, this criticism is totally innocuous. In fact, this is a criticism of the misuse of inheritance and the lack of generic types in a strongly typed language. Using this to attack object orientation is not something valid, although this type of attack is common.

Lack of a canonical definition of what is Object-Oriented

It is true that there is no canonical, single and universal definition of what is or is not object-oriented programming and definitions of it will vary greatly depending on who you are asking. However, this is something that has little value in practice, and although there may be disagreement or divergence as to certain terms and certain occasions, most people more or less agree that Object-Oriented Programming preaches the concepts of polymorphism, encapsulation, inheritance (of type and implementation) and the Union of structures with the codes that operate on it.

Anemic model

There are a lot of people who create objects of type FuncionarioVO which contains a lot of fields/attributes and a lot more getters and setters with little or no additional functionality and then creates business classes of type AtualizaFolhaDePagamentoFuncionario that contain the business rules that operate on FuncionarioVO.

This is a rather bad architecture, called anemic model and that deserves much criticism for separating the behaviors that an object has or may have from its structure, spreading business logic in several different places, promoting poor encapsulation and low class cohesion. However, this is a typical architecture of a procedural system, and not object-oriented. In an object-oriented architecture, an object's data should not be separated from its behaviors, which is exactly what the anemic model does.

I have seen many criticisms that object-oriented design ends up becoming something complicated and difficult because it is organized in this way. But in this case the problem is not of object orientation, but precisely because it has been violated. This kind of criticism it's not valid for putting the victim in the dock.

Difficulty writing a compiler

I've seen criticism of object-oriented languages for being more difficult to write a compiler for them. Well, in that case, this is a compiler problem, not a language problem. True, in general it is more difficult to write a compiler for an object-oriented language than to write one for a procedural one, but this in no way serves as a justification in order not to adopt object-oriented languages, at most it serves as a warning to someone who is designing a programming language or is in order to write a compiler. In addition, the challenges inherent in implementing object orientation in the compiler are generally much smaller than other challenges inherent in this, such as parsing and code generation.

 11
Author: Victor Stafusa, 2018-11-21 20:26:21

This answer is not new but a summary of the other two answers. No need to give upvote or anything. It serves to consolidate the arguments against OO and can serve to add/correct the understanding of them or give continuity to the discussion (in Victor's answer more things fit, that of Maniero reached the limit).

Opacity of polymorphic abstractions

Inherent in polymorphic static languages

Victor: hinders beginners, which they get lost trying to figure out which polymorphic version is being called.

Maniero: is not a limitation of OO but of static languages making use of polymorphism. It impairs readability and thus maintainability. Additionally, excessive abstraction can be harmful.

Simulating polymorphism in a structured language

Irrelevant

Victor: causes gambiarradas patterns (syntaxes) because it goes against support language.

Manor: Disagrees. There is nothing wrong with doing this unless there is reason not to. Cohesion also has harms.

Piovezan: I did not understand why this criticism. It is only limitation in languages not designed for OO.

Double-dispatch

Relevant

Victor: occurs when one needs to do something that is not supported by the paradigm: choose which method to call based on the type of two objects and not one. Solutions involve the visitor pattern, introspection/reflection or tables with N X m objects, and result in good amount of code and complexity to manage.

Maniero: agrees and finds one of the biggest problems of the paradigm. Common happens when you try to model something that does not exist, when it does not fit to use OO. When it happens maybe a relationship would be more appropriate. It occurs often and it is difficult to understand why the model happens after all relational is often easier to understand.

Multiple implementation inheritance

Inherent in static typing

Victor: diamond problem. And it makes it difficult to implement the language.

Maniero: is actually a complaint with static typing. Rarely do languages implement all the language features necessary for proper multi-inheritance support (abstract classes, interfaces, traits, mixins, roles, protocols, delegations, extensions, attributes, etc.). In addition, people do not understand ontology and taxonomy and have difficulty dealing with multiple inheritance. If they understand they have more ease also with the modular paradigm, which is simpler and more organized.

Piovezan: boy, if multiple inheritance needs all these features to work well, then it's the demo thing :P I'm happy to stay only in simple inheritance, if that way it works, so that more?

Simple implementation inheritance

Relevant

Victor: inheritance introduces a strong coupling between the superclass and the subclass. Subclasses are especially fragile if the superclass undergoes changes. The behavior of the subclass often depends on details of the implementation of the superclass, breaking in front of changes in internal details of the superclass. One way to mitigate this is by preferring composition to inheritance.

Maniero: agrees to everything. And the car and vehicle example is a relational and modular model, not OO.

Crosscutting-concerns

Relevant in several paradigms, including OO

Victor: Logging, transaction management, closing I/O resources, error treatments, introduce additional and accidental complexity to the program. And they are usually spread across the code and not concentrated at a single point, which it makes maintenance very difficult. The various attempts to resolve this have always left a bit of concerns behind. Thinking about it came Aspect-Oriented Programming, which is not well accepted because it keeps away the code that executes the behavior and what implements it.

Maniero: Oo too and was very well accepted. Cross-cutting concerns are also problems in other paradigms. It's real-world modeling and OOP doesn't get along with it. Some deny that this it was the goal of the paradigm. It is the biggest limitation of the paradigm: taxonomy needs to be perfect to work well, but this is difficult or impossible.

Focus on objects and not actions

Mitigated / irrelevant

Victor: is a criticism of functional language advocates of OO, although it is not an inherent problem of OO. It has been mitigated in more modern languages with the introduction of the concept of lambdas, making them hybrids.

Maniero: disagrees that languages with some functional features have surrendered to the functional; they remain imperative. And OO has nothing to do with actions, OO is data structures, zero algorithms.

Class Inextensibility

Inherent in static typing

Victor: Everyone has ever wanted to add functionality to an existing class, and for failing to create a StringUtils, DateUtils, etc. It is not a problem inherent in OO, because in dynamic languages this is solved through mix-ins, but with the disadvantage of keeping away the extra code of the class that includes it.

Maniero: as far as you know the pure paradigm requires that classes should be extended, but there can be controversy. OOP tends to destroy cohesion by leaving together what is separated. The granularity of other paradigms avoids this.

Dependency Injection

Relevant / wrong applied

Victor: creating an object involves providing dependencies to your constructor. The chain of dependencies can get complicated (Piovezan: I don'T understand DI so this sentence may be inaccurate). The solution is dependency injection frameworks, which unfortunately add complexity to projects.

Manor: Agrees. Modeling objects is complicated, people learn DI to help with tests and then the tests are not because they are poorly applied or because the quality philosophy of the project does not maintain consistency.

Piovezan: that's what I understood from Maniero's answer, I don't know if it's correct.

Greater complexity than other paradigms

Relevant

Victor: the path to mastering OO is longer and more difficult than procedural for example, and in addition people practice and perpetuate inappropriate programming practices that they make the path even more difficult.

Manor: agrees in part. Too bad people do not understand that OOP is modeling. OOP is more useful for frameworks, in business systems the experience seems to be that it is not that good. Use the wrong OOP and use where it should not not deliver value.

Extra complexity in the representation of abstract concepts

Criticism of abstraction and not OOP

Victor: enumerations of ints or strings are only preferred to classes when they occur in few parts of the code, otherwise they make maintenance difficult, while OO eliminates the problem.

Maniero: I consider criticism valid, but to abstraction and not to OOP.

Object-Oriented Programming has lower performance

Relevant when performance is important

Victor: in practice it is not a real problem.

Maniero: if performance is important, OOP can if it shows slow when it is too late; it is a design error but the choice of the paradigm contributes.

Over-specification without generic types

Pertinent / inherent to OO languages with static typing

Victor: is a critique of languages without generic types or the misuse of inheritance, and not OO.

Maniero: you can't do OO in static languages the right way because you have to use a separate paradigm that is that of genericity, and that is a serious problem.

Lack of a canonical definition of what is Object-Oriented

Inconclusive

Victor: in practice there is sufficient agreement.

Maniero: No. For lack of consensus there are conflicting recommendations, such as who commands to put everything in the class vs. who commands the class to only do one thing (example?).

Anemic model

Inconclusive

Victor: Anemic model deliberately violates OO, so it is not a valid criticism.

Maniero: anemic model is a modular model that greatly facilitates maintenance. It is not a violation of cohesion. What matters is the sole responsibility. 100% OOP encourages to violate DRY, something that has found strong resistance lately.

Difficulty writing a compiler

Irrelevant

Victor and Maniero: problem of who creates the language and not from those who use it (comment from Maniero: languages are to some degree moving away from the paradigm).

Additional points of the Manor

  • OO was not much researched, otherwise the definition of OO would be canonical.

  • It is difficult to establish the boundaries of the objects. In other words, OO does not model the human mind.

  • Java static typing forces certain mechanisms to work in a way. This is covered in the largest part for Victor's answer.

  • Have problems with competition(did not fit detail in the answer).

  • OOP requires modeling right, it requires ontology, which people have a hard time doing, and we always deal with problems we don't know, or repeat what we already know. It's an invitation to disaster.

  • OOP inhibits creativity as it has to follow certain patterns to work out. Works for recurring things, modeling what you know how to model.

  • Hide (encapsulate) state is the worst possible option compared to, for example, isolate it.

  • If you search OOP / OOD + flaw/bad/sucks/evil/misuse / etc. you will find many arguments that make sense.

  • Many excellent programmers beat OOP and have good arguments for it.

  • People are distancing themselves from OOP. Distancing is not abandoning, it is using where need.

  • OOP in its pure form (without other mechanisms that cover the shortcomings of the paradigm) requires doing things that are not pragmatic and codes that are not efficient.

  • It applies to 1%, maybe 10% of cases and not to 100% as people think. In business systems is not so beneficial.

  • If you follow all the various rules, it can work out.

 6
Author: Piovezan, 2019-01-20 20:02:39