The Post-OOP Paradigm
Kallahar writes "American Scientist has an article up about Computing Science: The Post-OOP Paradigm. The article has a great overview of how OOP works, and then goes on to a brief outline of the possible successors to OOP such as Aspect, Pattern, and Extreme Programming. Also a pretty picture of OOP Spaghetti."
However most OOP programmers try to over-OO everything. This is a problem from day one - their instructors show them how to make an object and how cool it is to have the object do something on its own. Thereafter, the students objectize everything. This leads to situations where you've got horribly bloated code that runs slow as hell.
It's this kind of instruction that leads to programmers writing whole object-oriented interfaces to things that can be very easily manipulated without all the overhead. For example I had a consultant working (briefly) with me who wrote several thousand lines of code that would edit colon delimited files (like /etc/passwd, for example) when a simple strtok in C or split() in perl would have done the trick in a few lines, without all that code to debug.
People need to always take a step back and see if the language contstructs they plan to use are appropriate for the task at hand. More often than not, they'll find that they higher level languages are too much. Don't write a C program when you can write it in shell. Don't write daemonizing code in your app if it can run from /etc/inittab. Don't write a scheduler when you can do it in cron. And never write OO when procedural programming can do the same trick in less space.
A real shape library would have methods like isConvex() and numberOfSides() instead of implementing the number of sides as an infinite number of subclasses (triangle, quadrilateral, etc.)
Perhaps these guys should have read Antipatterns or Pitfalls of Object Oriented Development instead of wasting their time with this article.
The example that is brought up with all the shapes turns out to have a fault. Inheritence might not be a good way to model those relationships.
So, all this article has done is show that the P-OOP thing is better than a octopus inheritance tree. Of course it is. Inheritence tends to get used way too much anyway.
Consider the famous example that we have all seen: an employee class is derived from a person class. That example appears in countless books, and probably countless systems in actual production today. But is it correct? The challenge of designing a system is to make it flexible enough to stand in the future.
Suppose we have a person who is an employee and a student at the same time. Should we use multiple inheritence? That would be screwy, and also not natural to implement in a language like Java. It turns out that breaking the problem apart into an inheritence type arrangement isn't the best or most flexible way to approach the problem.
In short, the article has made a good case why inheritence is sometimes not the right tool to use. But remember that OOP is three things: 1) inheritence 2) encapsulation and 3) polymorphism. And a language like C++ (and Java soon) has the notion of *generic programming* which the article didn't talk about.
If tits were wings it'd be flying around.
XP is heavily influenced by TDD -- Test Driven Development. The idea is that you only write code when you have a failing test. You write the test, it fails, you write the code to make the test pass. Then you go back to the requirements, write another test specified by the requirements, run it, it fails, so you write the code to fix it. Repeat until all tests (unit and functional) pass. When all your functional tests pass, you've met the requirements for the app (because the functional tests represent the use cases) and you're done.
Coding in this fashion does two things. It ensures that you've got a safety net at all times, and it forces your code to be loosely coupled and modular. Because you have 100% coverage, you're not afraid to change the code, because if you break something, you'll get a failing test. If you make a change and all your tests pass, you have the confidence that you didn't inadvertently break something in your code.
Additionally, your code needs to be modular and loosely coupled because it's tough to test if it isn't. If you have a God Class with lots of dependencies, you won't be able to unit test it because of all the dependencies. That's to say, you won't be able to test it as a unit. If you have a method that's doing lots of things, you'll have to write lots of tests to verify every path of execution. So instead, you're strongly encouraged to write simple methods that do one thing well for ease of testing.
A real OO guru knows all sorts of things about coupling and cohesion and patterns and when to use composition and when to use inheritance. They always obey the Law of Demeter and consistently separate the implementation from the interface. And to be able to do this, they've got a dog's life of OO experience under their belt. Here's the kicker. The XP evangelists say that using XP and TDD, in particular, gives you the benefits of all this experience as an emergent property of the methodology.
You obey the Law of Demeter because testing a class that breaks it isn't a unit test -- it's a subsystem test. You use interfaces because it allows you to substitute mock objects for the objects that your object under test interacts with. You use composition and inheritance appropriately because your tests will fail if you don't. Oh, and by the way, if you start with inheritance and move to composition, it's not a problem because all your tests will insure you don't leave something broken.
The point is that a programmer really only needs to learn how to write good tests in order to be a good programmer. TDD gives you all the stuff that you would normally have to have gained through experience.
So, that's why I think it's similar to AOP. They both produce higher quality and more maintainable software. However, TDD is a social solution, while AOP is a technical one. And, as long as I'm on my soapbox, I'll just mention that many patterns are compensations for things that more powerful languages do easily. For example, lisp's map procedure is an example of Visitor. Generally, languages that support higher order functions, or that treat functions as first class types, don't require as much pattern silly-walking. Also, AOP is old. Lisp has had it for a long time. In fact, the main architect of AspectJ, Gregor Kiczales, worked on the Common Lisp Object System (CLOS) with Richard Gabriel. Plus ca change, plus ca meme chose, innit. Here's a link to some thoughtful writings on the subject.
One other point -- for those inclined towards genetic programming. I think that the XP TDD way of programming suffers from the same problems as the hill climbing algorithm. It tends to produce quality, but I think it's easy to get stuck at a local minimum.
It pisses me off every time somebody comes along and thinks they can shoe-horn all possible solutions to all possible problems into a single programming style. So for everybody who's a newbie, let me impart a little wisdom to you so you don't have to learn it the hard way.
Use the right tool for the right job. Sometimes, a functional style is useful (especially when one's teaching programming language concepts and higher-order mathematics). Sometimes, procedural tools with abstract data types are useful. And sometimes, functional, procedural, and object-oriented styles can work together to solve a problem (such as the machine simulator I'm writing in Lisp).
Rant mode off.
I'm proud of my Northern Tibetian Heritage