I suspect the problem might be the focus on objects instead of actions. If I may quote from Steve Yegge's Execution in the Kingdom of Nouns:
Verbs in Javaland are responsible for all the work, but as they are held in contempt by all, no Verb is ever permitted to wander about freely. If a Verb is to be seen in public at all, it must be escorted at all times by a Noun.
OOP focuses primarily on the object and expresses actions in terms of the object's abilities. A airplane object can be flown (Airplane.fly()). A door object can be opened (Door.open()). But we really don't view the world in terms of objects and what actions can be done to them. It's backwards. We view the world in terms of ourselves and our abilities. We are the ultimate object. (And no, I don't mean a God object.)
Imagine you are returning from a trip to the local flower garden. Would you say "I smelled the flowers" or "The flowers were smelled by me?" Now you want to tell a friend to go and smell the flowers. Would you say "Go and smell the flowers" or "The flowers must be smelled by you?" When we convey instructions, we give them in terms relative to ourselves. What is programming but conveying instructions to a computer process how some sort of work should be done on our behalf.
How to make a Peanut Butter Sandwich:
- Get Jar of Peanut Butter
- Get Loaf of Bread
- Get Knife
- ...
class PeanutButterJar extends Jar ...Express them as such and they take on methods.
PeanutButterJar.open()Whoa! In my world, peanut butter doesn't do anything but sit there and taste yummy. And I'd start looking for a good exorcist the moment a knife starts performing actions all by by itself. A more realistic transcription of the instructions would be:
Knife.spread(PeanutButter, Bread)
You.open(PeanutButterJar)Specifying You as a universal object would seem rather redundant as the scenario progressed, so a good language designer would remove the need to expressly identify it. This would yield
You.spread(Knife, PeanutButter, Bread)
open(PeanutButterJar)which starts to look vaguely procedural.
spread(Knife, PeanutButter, Bread)
The truth is, procedural and OOP paradigms languages express the complexity of their problem space in different ways. Procedural code is flat and wide with functions. OO code is hierarchical with inheritance. OO-code is not inherently better organized than procedural code merely because it is encapsulated in objects. A reusable library can consist of functions just as easily as a collection of objects.
The way some OOP languages (like Java and C#) force objects on the programmer borders on the absurd. If I'm writing a library of reusable code that needs to maintain its own state, then of course writing classes with proper encapsulation and dating hiding makes sense. On the other hand, If I'm generating a web page with some data stored in a database, then some procedural code and a handful of function calls makes more sense. One of the things I like about PHP so much is that it allows the programmer to decide which paradigm is best suited for the task at hand.
Sadly though, that decision isn't left to the programmer who has been tasked with developing and maintaining a system. Management can tend to focus too much on buzzword compliance. A procedural programming language designed today would never receive wide-spread adoption if it didn't offer some sort of OO construct despite both paradigms having produced successful libraries and applications. And the programmers that don't learn to think beyond themselves will be unfairly left in the dust.
5 comments:
When looking at PHP in particular, I would venture to say that procedural programming will be on better footing than OOP come 5.3. Classes will still be bound to names, whereas functions are now first-class citizens with the addition of support for lambda functions and closures. This coupled with the ability to maintain state via static members makes them more portable. Horizontal reuse is accomplished by functions simply calling/composing other functions without the constraits of single inheritance. I definitely think the procedural paradigm deserves reexamination both in general and in the enterprise. It should not be abandoned in favor of OOP simply because it came earlier.
I disagree with your comments on people understanding OOP. I think that people (and developers really) get too hung up on the actions of an object more than the object. They get a method of an object to do a certain action, and in the end result it works fine, but add extra code that complicates things like encoding, encrypting, or sorting which could be handled by another object greatly reducing method size and adding readability to ones code
I would put forth that many developers using OOP are "doing it wrong." Textbook examples of OOP tend to focus on modeling literal, real world "objects." This is great for learning the basics of OOP, but in practice it is usually quite silly to model objects directly on "real" objects. I would suggest reading Eric Evans' Domain-Driven Design book. The book has lots of great advice on how to create useful models using OOP. The book also talks about how OOP is not the only way to create useful models.
I'd agree with bradely-holt. Most people do OO wrong. I am not sure if that's because it's taught wrong, or just that it's hard to do right.
Java is a great example of OO gone wrong. The wrong patterns are used and there is a class explosion of heirarchies and dependencies. However, OO doesn't dictate that outcome.
When I started programming for the Mac about 5 years ago I saw OO in a new light, one that was much flatter and used patterns like delegation much more often to keep coupling down. But frankly OO and procedural are really no different; both have functions that mutate state, it's only a matter of where the state is kept. Of course that's oversimplifying a bit, but there is a lot of truth to it.
See, the real benefit of OO comes from encapsulation and inheritance structures. This generally (if not done poorly) leads to more flexible, readable and maintainable code.
Of course, with closures and such we're be able to introduce some of the flexibility into the procedural world, but that won't really help for readability or maintainability if that's the *only* approach you're using for altering behaviour of existing methods, etc.
The 'real world' object relationships are always up for debate (as you're doing with the knife/peanut butter example), but they're usually adequate for what we all seem to need them to do..
Post a Comment