Do you think Object Oriented Programming is a solution to complexity. Why? This topic may be a bit controversial but my intentions to know the answer of Why from the experts here !
There is no solution to complexity.
In "The Mythical Man-Month", Fred Brooks discusses the difference between accidental and essential complexity in programming. Accidental complexity is caused by our tools and methods, such as having to write and test additional code in a language because we can't express our ideas directly, and things like that. New methods and techniques can reduce accidental complexity. I can write programs faster and better than I could twenty-five years ago, because I have better languages and tools.
Essential complexity comes from the fact that what we try to do with programming is inherently complicated, and that there is an irreducible complexity. "Essential", in this context, means "relating to the essence of the thing" rather than "very necessary".
Therefore, he claimed that there would be no silver bullet, that writing software would continue to be difficult.
I strongly recommend that you read his book: specifically, I recommend the Silver Anniversary edition, with an additional essay "No Silver Bullet". In that, he reviews the proposed solutions to complexity and considers their impact. (What he finds the most effective is shrink-wrap software - write something complex once, and sell thousands or millions of copies.)
Now, object-oriented programming helps, when done right, by creating abstractions and hiding away complexity. An object of a class has a certain defined behavior that we can reason from, without caring about the complexity of the implementation. Properly written classes have low coupling with each other, and divide-and-conquer is an excellent way to deal with complexity if you can get away with it. They also have high cohesion, in that they're a set of functions and data that relate very closely to each other.
I expect you'll get some better answers shortly, but here's a simple one:
OOP helps* with complexity by modeling software in a way closer to the way we model everything else in the world. It's just generally easier to image a ball object interacting with a wall object than it is to imagine a series of routines and data structures to do the same thing, since it's closer to how we interact with the real world.
*Because nothing can 'solve' complexity
I think the current mainstream definition of OOP is not a good solution for managing complexity.
If you go back to its roots, I believe Alan Kay was influenced by "lisp" a great deal.
Because Lisp hasn't been corrupted by mainstream adoption, it probably managed to conserve its core values. So I think looking at how lisp tackles this problem of complexity might gives us some insight, and we can use it as a basis to sort of judge how useful is OOP at dealing with complexity.
If you look at the end of the "Lecture 3a: Henderson Escher Example" of SICP, Hal Abelson proposes that complexity is managed not by breaking the task into smaller subtasks, but by creating layers of abstraction. At the highest level, you express the solution to the complicated problem in terms of the the solution to the lower level of abstraction.
I think OOP was originally intended as a mechanism to create these layers of abstractions.
Unfortunately nowadays, OOP is (ab)used to write spaghetti code/structures.
I will make up an example: an FPS multi-player game.
At the highest level, the game works by having a bunch of players running around a map and shooting at each other using weapons.
At the next lower level, we have to talk about maps and weapons and players. Perhaps we can talk about them as physical objects that interact within the world of the game.
At the next lower level, we can talk about how objects interact physically (movement, collisions, etc).
And so on and so forth.
What this means, (and I'm sort of quoting from SICP..), is that at each layer, we not only solve a particular specific problem, but a class of problems that sort of fall in the neighborhood of the problem we're trying to solve. So if there's a small change in the problem's description, it would likely require only a small change in the solution.
So, the wise way to use OOP is to create layers of abstractions, at each level of abstraction, you solve the problem at hand using the "objects" from the level that's directly below.
Here's the bit I was quoting from the lecture: http://www.youtube.com/watch?v=CYtrfncMqHQ
As usual I disagree with everyone. Far from giving you tools to manage complexity, OOP creates a huge amount of complexity because it is an inadequate and mathematically bogus paradigm. It confuses programmers no end, to try to model things with OOP that cannot be modelled with OOP.
In my view the seminal work here is Meyer's Object Oriented Software Construction. It details a set of requirements, including one I regard as crucial: the Open-Closed Principle. This says that a thing must be open for extension but closed for use, at the same time.
Meyer proceeds to derive Object Orientation from these requirements, as embodied in Eiffel. Encapsulation provides closure, inheritance open-ness, and the "thing" mentioned is the class.
I regard this work as good science because Meyer was demonstrably wrong, and it is possible because of the quality of his work, to pin point the error and fix it.
The error is making the class, or type, the unit of modularity. That's wrong, and provably so. Even Meyer recognized the problem (called the covariance problem), that OOP cannot handle relations of arity higher than one (that is, OOP works fine for properties but fails on binary relations). In Eiffel, this problem resulted in an unsound in the type system!
The solution is quite clear. The unit of modularity must be bigger than a single type. It must consist of several types, and the methods relating them.
It is hardly surprising that this model of abstraction is backed by the mathematical theory of abstraction, namely category theory: types are objects of a category, and methods (functions) are arrows.
With this model, the representations of several types are known to a set of functions. The representation is hidden from the public, so this is encapulsation, but we use modules, not classes.
The Standard Meta-Language (SML) and Ocaml are based directly on this model. Ocaml also has classes and OOP: it's not useless because OOP gives you dispatch on properties, aka dynamic binding. However most real world problems involve relations and it is hardly surprising classes aren't used much in Ocaml.
It is hardly surprising inheritance is hardly used at all in the C++ Standard template library.
The simple fact is, OOP does not give you the right tools to handle complexity, it doesn't even give you the tools to handle really simple problems, instead it has mislead and confused two generations of programmers. Far from helping, OOP is the most Evil and Bad thing that has happened to programming in since C, Fortran and Cobol started to get tired.
Object-oriented programming has roots that can be traced to the 1960s. As hardware and software became increasingly complex, manageability often became a concern. Researchers studied ways to maintain software quality and developed object-oriented programming in part to address common problems by strongly emphasizing discrete, reusable units of programming logic.
An object-oriented program may thus be viewed as a collection of interacting objects, as opposed to the conventional model, in which a program is seen as a list of tasks (subroutines) to perform. In OOP, each object is capable of receiving messages, processing data, and sending messages to other objects. Each object can be viewed as an independent 'machine' with a distinct role or responsibility. The actions (or "methods") on these objects are closely associated with the object itself.
This separation of concerns, along with other features of Object Orientation such as polymorphism, inheritance, message passing, decoupling and encapsulation, provide a logical and conceptual framework by which the complexity of large programs can be managed in a highly effective way.
There are many kinds of complexity to software development. At the programming level, OOP seeks to address complexity by using objects and classes to model the problem domain. A well-known guru said problem solving is just representing the problem so that the solution is the representation itself. Hence, by abstraction using classes, encapsulation using access modifiers and methods, inheritance for specifying relationship and reuse, composition in establishing relationship and collaboration between classes, polymorphism as a means to simplify the determination of different behaviors in similar objects, complexity can be managed.
There are also other ways to manage software complexity, for example, Logic (Prolog) and Functional (Haskell) programming.
At a level higher than programming, we need Design Patterns and Principles to guide OOP. Hence OOP is managing complexity at a low (coding) level while these methodologies such as Design Patterns and Principles guide the design of the solution at a higher (system and application) level and make software development and handling complexities more manageable.
To answer your question, yes, OOP is just a solution to handling complexity among many other solutions. It is a solution at a low level. We need Design Patterns and Principles to guide OOP in a higher level.
Object oriented programming manages essential and optional complexity, but does not reduce either.
I prefer the definition provided by Eric Steven Raymond in The Art of Unix Programming, because it delineates between essential, optional, and accidental complexity. http://www.faqs.org/docs/artu/ch13s01.html#id2964646
OOP does nothing for essential or optional complexity, they are a function of the program's requirements. It can have an effect on accidental complexity, in that you can create a more elegant design sometimes with OOP. Sometimes however, the design is worse when using OOP.
Complex problems cannot be rendered simpler through technology, they can only be managed through technology.
OOP is a technology, a concept, and a way to approach a problem.
OOP gives you the tools to enforce a design that can make it easier to manage complexity, but you can just as easily have a bad design that increases your complexity. In other words, if not used properly, you can have technology-induced complexity in your problems.
Keep in mind that there are many other aspects that will dictate how successful your project will be (i.e. project management style, problem definition, change management, etc...). The technology you use is only relevant in how much will it help you manage the problem.
In the end, object oriented programming cannot be a solution to complexity; it's just a tool to manage it. (if used properly)
Object Orientation (as conventionally used) is a useful tool in many circumstances, but it isn't a sufficient solution to complexity.
In particular, it often adds a lot of "incidental complexity". Examples are the complexity surrounding implementation inheritance, the need to provide lots of "standard functionality" suach as equals() and hashCode() etc. A nice presentation by Stuart Halloway on this topic: "Simplicity Ain't Easy"
Objects in most languages also tend to encapsulate a lot of mutable state - which in a concurrent world is increasingly starting to look like a poor design decision. Again an interesting video by Rich Hickey looks at the distinction between object identity and state, and how it might be a mistake to conflate the two.
Object oriented programming is a way of representing a problem, nothing more, nothing less. It is, in and of itself, not any less complex than any other programming paradigm. A well designed OOP system manages and reduces complexity, but it is also very easy to design a system that is much more complex than necessary and gets in the way of everything.
As oft said of C++, OOP gives you enough rope to hang yourself.
OOP is an attempt at a solution.
The best way to manage complexity is to create abstractions. If I can turn my data into useful collections, with recognizable functions which operate on those collections, I can start thinking about the collections as discrete "things." That's the basis for classes and methods. In that respect, properly designed OOP can help to manage complexity.
Somewhere along the way, someone decided that we could use OOP to help solve the problem of code-reuse. I mean, why reinvent the wheel? If someone else has done much of the work towards solving this problem, leverage what they've done, add the tweaks that your, particular project requires and voila! You've created a powerful, sophisticated application with relatively little work on your part. OO programmers can be very productive programmers.
The end result is that modern OO programmers end up being "sorcerer's apprentices," where they tie together a bunch of large, unwieldy libraries with a few lines of "glue" and get something which works. Sorta. Kinda. Most of the time. Are there potential side-effects from using this library with that one? Maybe. But who has time to really dig into the code contained in those libraries? Especially when the libraries are evolving. The result is that we end up with bloated applications, where a programmer needed a handful of classes and methods from that library, but the app has to carry the weight of all the OTHER stuff they didn't need.
The end result is that you end up with much more complexity than you need.
Another mechanism to deal with complexity that you want to separate functionality. You want all of your data access functions in one place. You want all of your user interface functionality in one place. You want all of your controllers in one place. So you create different classes which manage different parts of the functionality. So far, so good. And this scales, to a degree; your developers who are skilled with data access can write those classes, your user-interface people can write the user-interface classes, etc. All is well and good.
Until you have to maintain something written by someone else.
Yes, it's good to know that all of the data access functions are located here. But what calls them?
This method is calling that method on that class. But when I look at the class definition, there is no method with that name. Oh, that's inherited from something else one or two layers up in the inheritance chain. Wait a minute; that class implemented an interface? How many different classes implement that interface? And we're using some complicated run-time system (I'm looking at you, Spring) to "wire together" instances of classes at run-time? Where ANY class that implements that interface can be used?
You end up with lots of small, discrete methods which do precise things. But this one calls that one, in another class. Which calls that one, in yet another class. Which calls that one, in still another class. Which calls that one, in an additional class. Which returns a result of a particular type. On which you have to call a method to do a certain thing. Which returns a result of another type. Etc.
There's a term for this: spaghetti code.
You end up with a very complex system needed just to compose the code. Hence IDEs like Visual Studio, Eclipse and NetBeans. All of which have a significant learning curve. Indeed, many of them are able to encapsulate/aggregate multiple tools, developed by different groups, each of which have their OWN learning curves.
This is managing complexity?
Debugging code is twice as hard as writing it. Good luck debugging some of this stuff. Especially if it's using multiple libraries, "wired together" at run-time using some kind of dependency-injection system.
In summary: OOP provides what looks like a promising tool to help manage complexity. The reality is the resulting code tends to be horribly bloated (because you can't extract just the pieces you need from all of those linked libraries) and you need sophisticated tools just to navigate the code. It quickly becomes a maintenance nightmare.
IMHO, it's a net loss; it adds more complexity than it eliminates. It does allow you to do things which would be exceedingly difficult, possibly even impossible, without it. But any large project rapidly evolves into an unmaintainable mess.
If you already know how it works, and you can remember that, you might stand a chance at maintaining it.
Remember to apply Eagleson's Law: any code of your own, which you haven't looked at in six months, might as well be written by someone else.
The reason Object-oriented programming seems to help us handle complexity is because it forces us to write code in a specific fashion instead of a huge variety of ways. Task-oriented programming is much more intuitive, which is why programming started that way. Object-orientation takes training and practice to understand and use effectively, but by constraining programming into a certain path, it allows those trained to effectively maintain the code that was written.
It's no more logical or real-world than any other method, it's just a way of focusing our problem solving through similar lenses. A lot of technical specialties use the paradigm of a non-intuitive rigid methodology to handle the complexity of their tasks.
A third method to handle complexity would be functional programming, and there will be probably be other new methods in the future also.
i think it's more of a solution to maintainability, because, as a programmer, you are supposed to put methods where you have the data, thus creating an object model of your application.
yes, it's also a solution to complexity by providing a model for you to "see" your code in a natural way, as objects that have properties and possible actions