|
Softpanorama
(slightly skeptical)
Open Source Software Educational Society |
May the
source be with you,
but remember the KISS principle ;-)
|
A Slightly Skeptical View on the Object-Oriented Programming
The road to Hell is paved with good intentions.
cargo cult programming: n. A style of (incompetent) programming
dominated by ritual inclusion of code or program structures
that serve no real purpose. A cargo cult programmer will usually
explain the extra code as a way of working around some bug encountered
in the past, but usually neither the bug nor the reason the
code apparently avoided the bug was ever fully understood (compare
shotgun debugging,
voodoo programming).
The term `cargo cult' is a reference to aboriginal religions
that grew up in the South Pacific after World War II. The practices
of these cults center on building elaborate mockups of airplanes
and military style landing strips in the hope of bringing the
return of the god-like airplanes that brought such marvelous
cargo during the war. Hackish usage probably derives from Richard
Feynman's characterization of certain practices as "cargo cult
science" in his book "Surely You're Joking, Mr. Feynman!" (W.
W. Norton & Co, New York 1985, ISBN 0-393-01921-7).
Jargon 4.2
|
|
|
I often wonder why OO is so popular, despite being a failure a programming
paradigm. Is not this because "a hoard of practically illiterate researchers
publishing crap papers in junk conferences." ? Like a variant of computer
science Lysenkoism (and I can attest that the level of degradation of CS
is pretty close to the level of degradation of social sciences under Stalin).
In the end, productivity and quality are the only true merits a programming
methodology is to be judged upon. As Paul Graham noted the length of the
program can serve as a useful (although far from perfect) metric for how
much work it is to write. Not the length in characters, of course, but the
length in distinct syntactic elements (tokens) -- basically, the number
of lexical elements or, if you wish, the number of leafs in the parse tree.
It may not be quite true that the shortest program requires the least effort
to write, but in general length of program in lexical tokens correlated
with the complexity and the effort. Being extremely verbose OO (Java
might be a king of verbosity among widely adopted languages ;-) has huge
problems in this area. I would say OO is one step forward, two steps back.
First of all OO is not a panacea and is not, never was and never will
be a universally applicable programming paradigm. Object orientation has
limited applicability and should be used when it brings distinct advantages
but not be pushed for everything like naive or crooked (mostly crooked)
authors of Object oriented books try to sell to unsuspecting fraud audience.
Many common applications can better be developed under different paradigms
such as "multi-pass processing", compiler like structure, abstract machine
paradigm, functional language and so on. Just imagine that somebody
tries to solve in object oriented way typical parsing of text string problem
that can be solve with the regular expressions. Or look at poverty of books
that sell object oriented approach to algorithms and data structures. Those
snake oil salesmen who wrote such book using OO as a marketing trick to
get a quick buck do not deserve the title of computer scientists and
their degrees probably should be revoked ;-) Lord Tebbit once said
"You can judge a man by his enemies." Judging from the composition of
pro-OO camp in computer science any alternative paradigm/mythology
promoter or even skeptic like me looks good by definition ;-)
As a programming methodology it also competes with several other (who
level design methodologies using scripting language + low level language;
Abstract machine methodology; specialized language methodology to name a
few). That's why most object-oriented algorithms book are junk, and
their authors as close to charlatans as one can get.
When I think about OO I see two distinct trends:
- One is positive and is connected with the refinement of traditional
programming constructs (generic procedures, templates, hierarchical
namespaces and controlled visibility of variables, etc.). The hierarchical
structuring of namespace and, to a certain extent, limited hierarchical
namespace inheritance is a very good idea and here OO languages added
to the language design arsenal.
- The second is hugely negative as try to position OO as a new universal
software engineering paradigm. Often OO is oversold as panacea and even
as a cult (Bertrand
Meyer).
Actually true OO is very similar to the idea of compiler-compiler and
I think that in many cases combination of a scripting language and a regular
compiled programming language (for example TCL+C) is a better paradigm of
software development. Sometimes defining a specialised language for the
problem and writing a specialized compiler for it is also a viable approach.
For example in his paper
Object Oriented Programming Oversold! B. Jacobs wrote:
OOP became popular primarily because
of GUI interfaces. In fact, many non-programmers think that
"Object" in OOP means a screen object such as a button, icon, or listbox.
They often talk about drag-and-drop "objects".
GUI's sold products. Anything associated with GUI's was sure to
get market and sales brochure attention, regardless of whether this
association was accurate or not. I
have even seen salary surveys from respected
survey companies that have a programming classification called "GUI/OOP
Programming".
Screen objects can correspond closely
with OOP objects, making them allegedly easier to manipulate in a program.
We do not disagree that OOP works fairly well for GUI's,
but it is now being sold as the solve-all and
be-all of programming.
Some argue that OOP is still important
even if not dealing directly with GUI's. In our opinion, much
of the hype about OOP is faddish. OOP in itself does NOT allow programs
to do things that they could not do before. OOP
is more of a program organizational philosophy rather than a set of
new external solutions or operations.
He also provided a deep insight that attractiveness of OO
is somewhat similar to the attractiveness of the social doctrine like communism
(with its ideas of central hierarchical planning model and idealistic hopes
that that will eliminate wasteful, redundant procedures):
Why OOP Is Like Communism
Economic communism spread like wildfire in the first half of the 20th
century because it had such appealing ideals. Like OO, these ideals
were very seductive on paper. Intellectuals all over the world were
drawn in by it's concepts in droves. However, the complexities and
dynamism of human nature proved not to favor economic communism as a
productive model.
Perhaps it allows for more equality,
but mostly by making everybody equally poor. Further, it forms a
kind of "social currency" based on schmoosing and favoritism that
is nearly impossible to objectively measure and tax. Thus, it is
still not really class-less, but simply makes classes harder to
measure.
One of these ideals was central control
and planning of the economy. Duplication and coordination of production
would eliminate wasteful, redundant procedures; thus increasing the
overall wealth. A watchful, central eye would also keep people in line
so that they would produce only what was deemed useful and fair.
OOP has a similar appeal. Data
and operations (methods) are tightly integrated and controlled within
the watchful eye of the OO paradigm.
Unfortunately, OOP and economic communism
suffer similar problems. They both get bogged down in their own
bureaucracy and have a difficult time dealing with change and outside
influences which are not a part of the internal bureaucracy.
For example, a process may be stuck in department X because it may
be missing a piece of information that the next department, Y, or later
departments may not even need. Department X may not know or care that
the waiting piece of information is not needed by later departments.
It simply has it's rules and regulations and follows them like
a good little bureaucratic soldier.
In his old Usenix paper
Objecting To Objects Stephen C. Johnson wrote
Object-oriented programming (OOP)
is an ancient (25-year-old) technology, now being pushed as the answer
to all the world's programming ills. While not denying that
there are advantages to OOP, I argue that
it is being oversold. In particular, OOP gives little
support to GUI and network support, some of the biggest software problems
we face today. It is difficult to constrain
relationships between objects (something SmallTalk did
better than C++). Fundamentally, object reuse has much more to do with
the underlying models being supported than with the "objectness" of
the programming language. Object-oriented
languages tend to burn CPU cycles, both at compile and execution time,
out of proportion to the benefits they provide. In summary,
the goods things about OOP are often the information hiding and
consistent underlying models which derive from clean thoughts, not linguistic
cliches.
In his April 2003 Keynote for PyCon2003) Paul Graham suggested
[The Hundred-Year Language]
:
...Somehow the idea of reusability
got attached to object-oriented programming in the 1980s, and no amount
of evidence to the contrary seems to be able to shake it free. But although
some object-oriented software is reusable, what makes it reusable is
its bottom-upness, not its object-orientedness.
Consider libraries: they're reusable because they're
language, whether they're written in an object-oriented style or not.
I don't predict the demise of object-oriented
programming, by the way. Though I don't think it has much to offer good
programmers, except in certain specialized domains, it is irresistible
to large organizations. Object-oriented programming offers a sustainable
way to write spaghetti code. It lets you accrete programs as a series
of patches.
Large organizations always tend to develop software this way, and
I expect this to be as true in a hundred years as it is today.
...One helpful trick here is to use the
length of the program
as an approximation for how much work it is to write. Not the length
in characters, of course, but the length in distinct syntactic elements--
basically, the size of the parse tree. It
may not be quite true that the shortest program is the least work to
write, but it's close enough that you're better off aiming for the solid
target of brevity than the fuzzy, nearby one of least work.
Then the algorithm for language design becomes: look at a program and
ask, is there any way to write this that's shorter?
Dr. Nikolai Bezroukov
Notes:
- This is a Spartan WHYFF (We Help
You For Free) site written by people for whom English
is not a native language.
Some amount of grammar and spelling errors should be
expected.
- The site contain some broken links
as it develops like a living tree...
Please try to use Google, Open directory,
etc. to find a replacement link (see
HOWTO search the WEB for details). We would appreciate
if you can
mail us a correct link.
|
|
|
|
| Object Oriented Programming (OOP)
is currently being hyped as the best way to do everything
from promoting code reuse to forming lasting relationships with
persons of your preferred sexual orientation.
This paper tries to demystify the benefits of OOP. We point
out that, as with so many previous software engineering fads,
the biggest gains in using OOP result from applying principles
that are older than, and largely independent of, OOP. Moreover,
many of the claimed benefits are either not true or true only
by chance, while occasioning some high costs that are rarely
discussed. Most seriously, all the hype is preventing progress
in tackling problems that are both more important and harder:
control of parallel and distributed applications, GUI design
and implementation, fault tolerant and real-time programming.
OOP has little to offer these areas. Fundamentally, you get
good software by thinking about it, designing it well, implementing
it carefully, and testing it intelligently, not by mindlessly
using an expensive mechanical process.
-- Abstract to
Objecting to Objects, by Stephen C. Johnson,
Melismatic Software
|
Historically, research suggests that students have always found
computer programming difficult; the abstract nature of programming
involving problem solving and logical thinking requires a certain
aptitude, and the necessary skills and disciplines are not always
easy to learn and execute.
Even students who are bright and successful in other areas of
study often struggle to grasp the basics of programming, and this
has traditionally led to higher than average failure and drop-out
rates. Many students end up disillusioned and look for ways to avoid
the subject later in the programme.
Modern programming paradigms, based upon the object-oriented
programming (OOP) paradigm, and introduced in recent years, have
additional complex concepts and constraints associated with them.
OOP languages such as Java and VB.NET are now widely used for
teaching introductory programming modules in many universities.
These place an additional cognitive
burden on students over and above the already difficult programming
principles associated with all programming languages.
Many students complain that they find it difficult to understand
some of the complexities associated with object orientation. Trying
to deal with these concepts at an early stage leads to having less
time to focus on more fundamental principles and often results in
students having a poorer understanding of the basics.
Add to this the need to include modern windows programming
environments with graphics controls and event handling, and it all
becomes too much for many students to handle; they simply cannot see
the wood for the trees.
If the principles of OOP are
introduced too early it may lead to cognitive overload for some
students resulting in confusion and disillusionment with the
subject.
This additional complexity makes the problem of teaching
contemporary programming at an introductory level even more acute
and if not addressed is likely to lead to even higher failure and
drop-out rates in the early phases of computing programmes, with
more students trying to avoid programming at all costs.
Why is it that students find programming courses more difficult
than they did in the past?
One reason is that the range of abilities of student cohorts has
undoubtedly widened in recent years. Another is simply that OOP
programming is more complex and difficult to understand. It has
often been suggested that the difficulty in the teaching and
understanding of a programming language can be seen by examining the
complexity of the ubiquitous 'Hello World' program.
The 'Hello World' program illustrates the simplest form of
human-computer interaction (HCI); it sends a text message from a
computer program to the user, displayed on the screen. 'Hello World'
will be familiar to many computer lecturers and students as it is
considered to be the most basic of programs, and is normally used as
the first program example in many undergraduate programming text
books and introductory programming modules.
To illustrate the additional complexity of OOP consider as a
simple metric the comparison of the program code for 'Hello World'
written in Pascal, a language used in many universities to teach
introductory programming in the past, and Java a contemporary OOP
language widely used commercially and in universities today to teach
programming.
PASCAL:
program HelloWorld
begin
write ('Hello World')
end.
JAVA:
class Message
{
public static void main (String args[ ])
{
Message helloWorld = new Message ( );
helloWorld.printMessage ( );
}
void printMessage ( )
{
System.out.print ("Hello World");
}
}
These two programs perform exactly the same function. It is not
difficult to see that the early generation Pascal program is very
simple and easy to understand, most students and even most ordinary
adults would have no problem understanding what is going on.
1994 | USENIX
Object Oriented Programming (OOP) is currently being hyped as the
best way to do everything from promoting code reuse to forming lasting
relationships with persons of your preferred sexual orientation. This
paper tries to demystify the benefits of OOP. We point out that, as
with so many previous software engineering fads, the biggest gains in
using OOP result from applying principles that are older than, and largely
independent of, OOP. Moreover, many of the claimed benefits are either
not true or true only by chance, while occasioning some high costs that
are rarely discussed. Most seriously, all the hype is preventing progress
in tackling problems that are both more important and harder: control
of parallel and distributed applications, GUI design and implementation,
fault tolerant and real-time programming. OOP has little to offer these
areas. Fundamentally, you get good software by thinking about it, designing
it well, implementing it carefully, and testing it intelligently, not
by mindlessly using an expensive mechanical process.
Define Your Terms
Object Oriented Programming (OOP) is a term largely borrowed from
the SmallTalk community, who were espousing many of these techniques
in the mid 1970's. In turn, many of their ideas derive from Simula 67,
as do most of the core ideas in C++. Key notions such as encapsulation
and reuse have been discussed as far back as the 60's, and received
a lot of discussion during the rounds of the Ada definition.
Although there have been, and will always
be, religious fanatics who think their language is the only way to code,
the really organized OOP hype started in the late 1980's.
By the early 1990's, both Next and Microsoft were directing their
marketing muscle into persuading us to give up C and adopt C++, while
SmallTalk and Eiffel both were making a respectable showing, and object
oriented operating systems and facilities (DOE, PenPoint, COBRA) were
getting a huge play in the trade press--the hype wars were joined.
It is said that countries get the governments
they deserve, and perhaps that is true of professions as well--a lot
of the energy fueling this hype derives from the truly poor state of
software development. While hardware developers have
provided a succession of products with radically increasing power and
lower cost, the software world has seen very little productivity improvement.
Major, highly visible products from industry leaders continue to be
years late (Windows NT), extremely buggy (Solaris) or both, costs skyrocket,
and, most seriously, people are very reluctant to pay 1970's software
costs when they are running cheap 1990's hardware. I believe a lot of
non-specialists look at software development and see it as so completely
screwed up that the cause cannot be profound--it must be something simple,
something a quick fix could fix. Maybe if they just used objects...
To be more precise, most of what I say will apply to C++, viewed
as a poor stepchild by most of the OOP elite. Actually, the few comments
I will make about more dynamically typed languages like SmallTalk make
C++ look good by comparison. I will also focus my concern fairly narrowly.
I am interested in tools, including languages,
that make it easier and more productive to generate large serious high
quality software products. So focusing rules out a bunch of sometimes
entertaining philosophical and aesthetic arguments best entertained
over beer.
... ... ...
What Works in OOP
Those who report big benefits from using OOP are not lying. Many
of the reported benefits come from focusing on designing the software
models, including the roles and interactions of the modules, enabling
the modules to encapsulate expertise, and carefully designing the interfaces
between these modules. While most OOP systems allow you, and even encourage
you, to do these things, most older programming systems allow these
techniques as well. These are good, old ideas that have proved their
worth in the trenches for decades, whether they were called OOP, structured
programming, or just common sense. I have seen excellent programs written
in assembler that used these principles, and terrible programs in C++
that did not. The use of objects and inheritance is not what makes these
programs good.
What works in all these cases is that the programs were well thought
out and the design was done intelligently, based on a clear and well
communicated set of organizing principles. The language and the operating
system just don't matter. In many cases, the same organizing principles
used to guide the design can be used to guide the construction and testing
of the product as well. What makes a piece of software good has a lot
to do with the application of thought to the problem being addressed,
and not much to do with what language or methodology you used. To the
extent that the OOP methodology makes you think problems through and
forces you to make hidden assumptions explicit, it leads to better code.
OOP Claims Unmasked
The hype for OOP usually claims benefits such as faster development
time, better code reuse, and higher quality and reliability of the final
code. As the last section shows, these are not totally empty claims,
but when true they don't have much to do with OOP methodology. This
section examines these claims in more detail.
OOP is supposed to allow code to be developed faster; the question
is, "faster than what?". Will OOP let you write a parser faster than
Yacc, or write a GUI faster than using a GUI-builder? Will your favorite
OOP replace awk or Perl or csh within a few
years? I think not.
Well, maybe faster than C, and I suppose if we consider only raw
C this claim has some validity. But a large part of most OOP environments
is a rich set of classes that allow the user to manipulate the environment--build
windows, send messages across a network, receive keystrokes, etc. C,
by design, has a much thinner package of such utilities, since it is
used in so many different environments. There were some spectacularly
productive environments based on LISP a few years back (and not even
the most diehard LISP fanatic would say that LISP is object oriented).
A lot of what made these environments productive was a rich, well designed
set of existing functions that could be accessed by the user. An that
is a lot of what makes OOP environments productive compared to raw C.
Another way of saying this is that a lot of the productivity improvement
comes from code reuse.
There is probably no place where the OOP claims are more misleading
than the claims of code reuse. In fact, code reuse is a complex and
difficult problem--it has been recognized as desirable for decades,
and the issues that make it hard are not materially facilitated by OOP.
In order for me to reuse your code, your code needs to do something
that I want done (that's the easy part), and your code needs to operate
within the same model of the program and environment as my code (that's
the hard part). OOP addresses some of the gratuitous problems that occasionally
plagued code reuse attempts (for example, issues of data layout), but
the fundamental problems are, and remain, hard.
An example should make this clearer. One of the most common examples
of a reused program is a string package (this is particularly compelling
in C++, since C has such limited string handling facilities). Suppose
you have written a string package in C++, and I want to use it in my
compiler symbol table. As it happens, many of the strings that a compiler
uses while compiling a function do not need to be referenced after that
function has been compiled. This is commonly dealt with by providing
an arena-based allocator, where storage can be allocated out of an arena
associated with a function, and then the whole arena can be discarded
when the function has been processed. This minimizes the chance of memory
leaks and makes the deallocation of storage essentially free (Similar
techniques are used to handle transaction-based storage in a transaction
processing system, etc.).
So, I want to use your string package, but I want your string package
to use my arena-based allocator. But, almost certainly, you have encapsulated
knowledge of storage allocation so that I can't have any contact with
it (that is a feature of OOP, after all), so I can't use your
package with my storage allocator. Actually, I would probably have more
luck reusing your package had it been in C, since I could supply my
own malloc and free routines (although that
has its own set of problems).
If you had designed your string package to allow me to specify the
storage allocator, then I could use it. But this just makes the point
all the more strongly. The reason we do not reuse code is that most
code is not designed to be reused (notice I said nothing about implementation).
When code is designed to be reused (the C standard library
comes to mind) it doesn't need object oriented techniques to be effective.
I will have more to say about reuse by inheritance below.
One of the major long-term advantages of object-oriented techniques
may be that it can support broad algorithmic reuse, of a style similar
to the Standard Template Library of C++.
However, the underlying language is enormously overbuilt for such
support, allowing all sorts of false traps and dead-ends for the unwary.
The Standard Template Library took several generations
and a dozen of the best minds in the C++ community to reach its current
state, and it's no mistake that several of the early generations were
coded in Ada and SCHEME--its power is not in the language, but in the
ideas.
The final advantage claimed for OOP is
higher quality code. Here again, there is a germ of truth to this claim,
since some problems with older methods (such as name clashes in libraries)
are harder to make and easier to detect using OOP. To the extent that
we can reuse "known good" code, our quality will increase--this doesn't
depend on OOP. However, basically code quality depends on intelligent
design, an effective implementation process, and aggressive testing.
OOP does not address the first or last step at all, and falls short
in the implementation step.
For example, we might wish to enforce some simple style rules on
our object implementations, such as requiring that every object have
a print method or a serialize method for dumping
the object to disc. The best that many object- oriented systems can
do is provide you (or, rather, your customer) with a run-time error
when you try to dump an object to disc that has not defined such a method
(C++ actually does a bit better than that). Many of the more dynamically
typed systems, such as SmallTalk or PenPoint, do not provide any typing
of arguments of messages, or enforce any conventions as to which messages
can be sent to which objects. This makes messages as unstructured as
GOTO's were in the 1970's, with a similar impact on correctness and
quality.
One of the most unfortunate effects of the OOP bandwagon is that
it encourages the belief that how you speak is more important than what
you say. It is rather like suggesting that if someone uses perfect English
grammar they must be truthful. It is what you say, and
not how you say it.
... ... ...
He said that She said that He had Halitosis
Using a computer language is a social,
and even political act, akin to voting for a candidate or buying a certain
brand of car. As such, our choices are open to manipulation by marketeers,
influence by fads, and various forms of rationalization by those who
were burned and have trouble admitting it. In particular,
much of what is "known" about a language is something that was true,
or at widely believed, at one point in the language's history, but may
not be true currently. At one point, "everybody" knew that PL/I had
no recursive functions, ALGOL 68 was too big a language to be useful,
Ada was too slow, and C could not be used for numerical problems. Some
of these beliefs were never true, and none of them are true now, but
they are still widely held. It is worth looking at OOP in this light.
Some of the image manipulators target nontechnical people such as
our bosses and customers, and may try to persuade them that OOP would
solve their problems. As we have seen, however, many of the things that
are "true" of OOP (for example, that it makes reuse easy) are difficult
to justify when you look more carefully. As professionals, it is our
responsibility to ask whether moving to OOP is in the best interests
of ourselves, our company, or our profession. We must also have the
courage to reject the fad when it is a diversion or will not meet our
needs. We must also make this decision anew for each project, considering
all the potential factors. Realistically, the answer will probably be
that some projects should use OOP, others should not, and for a fair
number in the middle it doesn't matter very much.
Summary
The only way to construct good software is to think about it. Since
the scope of problems that software attempts to address is so vast,
the kinds of solutions that that we need is also vast. OOP is a good
tool to have in our toolbox, and there are places that it is my tool
of choice. But there are also places where I would avoid it like the
plague. It is important to all of us that we continue to have that option.
OO is definitely overkill for a lot of
web projects. It seems to me that so many people use
OO frameworks like Ruby and Zope because “it’s enterprise level”.
But using an ‘enterprise’ framework for
small to medium sized web applications just adds so much overhead and
frustration at having to learn the framework that it just doesnt seem
worth it to me. Having said all this I must point out
that I’m distrustful of large corporations
and hate their dehumanising heirarchical structure. Therefore
i am naturally drawn towards open source and away from the whole OO/enterprise/heirarchy
paradigm. Maybe people want to push open source to the enterprise level
in the hope that they will adopt the technology and therefore they will
have more job security. Get over it - go and learn Java and .NET if
you want job security and preserve open source software as an oasis
of freedom away from the corporate world. Just my 2c
===
OOP has its place, but the diversity of frameworks is just as challenging
to figure out as a new class you didn’t write, if not more. None of
them work the same or keep a standard convention between them that makes
learning them easier. Frameworks are great, but sometimes I think maybe
they don’t all have to be OO. I keep a small personal library of functions
I’ve (and others have) written procedurally and include them just like
I would a class. Beyond the overhead issues is complexity. OOP has you
chasing declarations over many files to figure out what’s happening.
If you’re trying to learn how that unique class you need works, it can
be time consuming to read through it and see how the class is structured.
By the time you’re done you may as well have written the class yourself,
at least by then you’d have a solid understanding. Encapsulation and
polymorphism have their advantages, but the cost is complexity which
can equal time. And for smaller projects that will likely never expand,
that time and energy can be a waste.
Not trying to bash OOP, just to defend procedural style. They each have
their place.
===
Sorry, but I don’t like your text, because you mix Ruby and Ruby
on Rails alot. Ruby is in my opinion easier to use then PHP, because
PHP has no design-principle beside “make it work, somehow easy to use”.
Ruby has some really cool stuff I miss quite often, when I have to program
in PHP again (blocks for example), but has a more clear and logical
syntax.
Ruby on Rails is of course not that easy to use, at least when speaking
about small-scale projects. This is, because it does alot more than
PHP does. Of course, there are other good reasons to prefere PHP over
Rails (like the better support by providers, more modules, more documentation),
but from my opinion, most projects done in PHP from the complexity of
a blog could profit from being programmed in Rails, from the pure technical
point of view. At least I won’t program in PHP again unless a customer
asks me.
===
I have a reasonable level of experience with PHP and Python but unfortunately
haven’t touched Ruby yet. They both seem to be a good choice for low
complexity projects. I can even say that I like Python a lot. But I
would never consider it again for projects where design is an issue.
They also say it is for (rapid) prototyping. My experience is that as
long as you can’t afford a proper IDE Python is maybe the best place
to go to. But a properly “equipped” environment
can formidably boost your productivity with a statically typed language
like Java. In that case Python’s advantage shrinks to
the benefits of quick tests accesible through its command line.
Another problem of Python is that it wants
to be everything: simple and complete, flexible and structured, high-level
while allowing for low-level programming. The result is a series of
obscure features
Having said all that I must give Python all the credits of a good language.
It’s just not perfect. Maybe it’s Ruby

My apologies for not sticking too closely to the subject of the article.
===
The one thing I hate is OOP geeks trying to prove that they can write
code that does nothing usefull and nobody understands.
“You don't have to use OOP in ruby! You
can do it PHP way! So you better do your homework before making such
statements!”
Then why use ruby in the first place?
“What is really OVERKILL to me, is to know the hundreds of functions,
PHP provides out of the box, and available in ANY scope! So I have to
be extra carefull wheter I can use some name. And the more functions
- the bigger the MESS.”
On the other hand, in ruby you use only functions avaliable for particullar
object you use.
I would rather say: “some text”.length than strlen(”some text”);
which is much more meaningful! Ruby language itself much more descriptive.
I remember myself, from my old PHP days, heaving alwayse to look up
the php.net for appropriate function, but now I can just guess!”
Yeah you must have weak memory and can`t remember wheter strlen()
is for strings or for numbers….
Doesn`t ruby have the same number of functions just stored in objects?
Look if you can`t remember strlen than invent your own classes you
can make a whole useless OOP framework for PHP in a day……
I'm not a fan of object orientation for the sake of object orientation.
Often the proper OO way of doing things ends up being
a productivity
tax. Sure, objects are the backbone of any modern programming language,
but sometimes I can't help feeling that
slavish
adherence to objects is making my life a lot more difficult. I've
always found
inheritance
hierarchies to be brittle and unstable, and then there's the massive
object-relational
divide to contend with. OO seems to bring at least as many problems
to the table as it solves.
Perhaps Paul Graham
summarized it best:
Object-oriented programming generates a lot of what looks like work.
Back in the days of fanfold, there was a type of programmer who
would only put five or ten lines of code on a page, preceded by
twenty lines of elaborately formatted comments. Object-oriented
programming is like crack for these people: it lets you incorporate
all this scaffolding right into your source code. Something that
a Lisp hacker might handle by pushing a symbol onto a list becomes
a whole file of classes and methods. So it is a good tool if you
want to convince yourself, or someone else, that you are doing a
lot of work.
Eric Lippert observed a similar occupational hazard among developers.
It's something he calls
object happiness.
What I sometimes see when I interview people and review code is
symptoms of a disease I call Object Happiness. Object Happy people
feel the need to apply principles of OO design to small, trivial,
throwaway projects. They invest lots of unnecessary time making
pure virtual abstract base classes -- writing programs where IFoos
talk to IBars but there is only one implementation of each interface!
I suspect that early exposure to OO design principles divorced from
any practical context that motivates those principles leads to object
happiness. People come away as OO True Believers rather than OO
pragmatists.
I've seen so many problems caused by excessive, slavish adherence
to OOP in production applications. Not that object oriented programming
is inherently bad, mind you, but a little OOP goes a very long way.
Adding objects to your code is like adding salt to a dish: use a little,
and it's a savory seasoning; add too much and it utterly ruins the meal.
Sometimes it's better to err on the side of simplicity, and I tend to
favor the approach that results in less code, not more.
Given my ambivalence about all things OO, I was amused when
Jon Galloway forwarded
me a link to
Patrick Smacchia's
web page. Patrick is a French software developer. Evidently the
acronym for object oriented programming is spelled a little differently
in French than it is in English: POO.
April 2003 (Keynote from PyCon2003)
...I have a hunch that the main branches of the evolutionary
tree pass through the languages that have the smallest, cleanest cores.
The more of a language you can write in itself, the better.
...Languages evolve slowly because they're not really technologies.
Languages are notation. A program is a formal description of the problem
you want a computer to solve for you. So the rate of evolution in programming
languages is more like the rate of evolution in mathematical notation
than, say, transportation or communications. Mathematical notation does
evolve, but not with the giant leaps you see in technology.
...I learned to program when computer power was scarce. I can remember
taking all the spaces out of my Basic programs so they would fit into
the memory of a 4K TRS-80. The thought of all this stupendously inefficient
software burning up cycles doing the same thing over and over seems
kind of gross to me. But I think my intuitions here are wrong. I'm like
someone who grew up poor, and can't bear to spend money even for something
important, like going to the doctor.
Some kinds of waste really are disgusting. SUVs, for example, would
arguably be gross even if they ran on a fuel which would never run out
and generated no pollution. SUVs are gross because they're the solution
to a gross problem. (How to make minivans look more masculine.) But
not all waste is bad. Now that we have the infrastructure to support
it, counting the minutes of your long-distance calls starts to seem
niggling. If you have the resources, it's more elegant to think of all
phone calls as one kind of thing, no matter where the other person is.
There's good waste, and bad waste. I'm interested in good waste-- the
kind where, by spending more, we can get simpler designs. How will we
take advantage of the opportunities to waste cycles that we'll get from
new, faster hardware?
The desire for speed is so deeply engrained in us, with our puny computers,
that it will take a conscious effort to overcome it. In language design,
we should be consciously seeking out situations where we can trade efficiency
for even the smallest increase in convenience.
Most data structures exist because of speed.
For example, many languages today have both strings and lists. Semantically,
strings are more or less a subset of lists in which the elements are
characters. So why do you need a separate data type? You don't, really.
Strings only exist for efficiency. But it's lame to clutter up the semantics
of the language with hacks to make programs run faster. Having strings
in a language seems to be a case of premature optimization.
... Inefficient software isn't gross. What's gross is
a language that makes programmers do needless work. Wasting programmer
time is the true inefficiency, not wasting machine time. This will become
ever more clear as computers get faster
...Somehow the idea of reusability got attached
to object-oriented programming in the 1980s, and no amount of evidence
to the contrary seems to be able to shake it free. But although some
object-oriented software is reusable, what makes it reusable is its
bottom-upness, not its object-orientedness. Consider libraries: they're
reusable because they're language, whether they're written in an object-oriented
style or not.
I don't predict the demise of object-oriented programming, by
the way. Though I don't think it has much to offer good programmers,
except in certain specialized domains, it is irresistible to large organizations.
Object-oriented programming offers a sustainable way to write spaghetti
code. It lets you accrete programs as a series of patches.
Large organizations always tend
to develop software this way, and I expect this to be as true in a hundred
years as it is today.
...As this
gap widens, profilers will become increasingly important. Little attention
is paid to profiling now. Many people still seem to believe that the
way to get fast applications is to write compilers that generate fast
code. As the gap between acceptable and maximal performance widens,
it will become increasingly clear that the way to get fast applications
is to have a good guide from one to the other.
...One of the most exciting trends in the last ten years has been the
rise of open-source languages like Perl, Python, and Ruby. Language
design is being taken over by hackers. The results so far are messy,
but encouraging. There are some stunningly
novel ideas in Perl, for example. Many are stunningly
bad, but that's always true of ambitious efforts. At its current rate
of mutation, God knows what Perl might evolve into in a hundred years.
...One helpful trick here is to use the
length of the program
as an approximation for how much work it is to write. Not the length
in characters, of course, but the length in distinct syntactic elements--
basically, the size of the parse tree. It
may not be quite true that the shortest program is the least work to
write, but it's close enough that you're better off aiming for the solid
target of brevity than the fuzzy, nearby one of least work.
Then the algorithm for language design becomes: look at a program and
ask, is there any way to write this that's shorter?
An extensive discussion of subtyping, insidious problems with subclassing,
and practical rules to avoid them.
- Does OOP really separate interface from implementation?
- The manifestation of a problem: an example of how an implementation
inheritance prevents separation of interface and implementation
- Subtyping vs. Subclassing
- Explanation why the problem above happened
-
Subclassing errors, OOP style and practically checkable to prevent
them
- Demonstration how statically checkable rules can prevent the
problem from occurring [a separate document]
A more formal and general presentation of this topic is given in
a paper and a talk at a Monterey 2001 workshop (June 19-21, 2001, Monterey,
CA):
Subtyping-OOP.ps.gz [35K] and
MTR2001-Subtyping-talk.ps.gz
[67K]
Does OOP really separate interface from implementation?
Decoupling of abstraction from implementation is one of the holy
grails of good design. Object-oriented programming in general and encapsulation
in particular are claimed to be conducive to such separation, and therefore
to more reliable code. In the end, productivity and quality are the
only true merits a programming methodology is to be judged upon. This
article is to show a very simple example that questions if OOP indeed
helps separate interface from implementation. The example is a very
familiar one, illustrating the difference between subclassing and subtyping.
The article carries this example of Bags and Sets one step further,
to a rather unsettling result. The article set out to follow good software
engineering; this makes the resulting failure even more ominous.
The article aims to give a more-or-less "real" example, which one
can run and see the result for himself. By necessity the example had
to be implemented in some language. The present article uses C++. It
appears however that similar code (with similar conclusions) can be
carried on in many other OO languages (e.g., Java, Python, etc).
Suppose I was given a task to implement a Bag -- an unordered collection
of possibly duplicate items (integers in this example). I chose the
following interface:
typedef int const * CollIterator; // Primitive but will do
class CBag {
public:
int size(void) const; // The number of elements in the bag
virtual void put(const int elem); // Put an element into the bag
int count(const int elem) const; // Count the number of occurrences
// of a particular element in the bag
virtual bool del(const int elem); // Remove an element from the bag
// Return false if the element
// didn't exist
CollIterator begin(void) const; // Standard enumerator interface
CollIterator end(void) const;
CBag(void);
virtual CBag * clone(void) const; // Make a copy of the bag
private:
// implementation details elided
};
|
Other useful operations of the CBag package are implemented without
the knowledge of CBag's internals. The functions below use only the
public interface of the CBag class:
// Standard "print-on" operator
ostream& operator << (ostream& os, const CBag& bag);
// Union (merge) of the two bags
// The return type is void to avoid complications with subclassing
// (which incidental to the current example)
void operator += (CBag& to, const CBag& from);
// Determine if CBag a is subbag of CBag b
bool operator <= (const CBag& a, const CBag& b);
inline bool operator >= (const CBag& a, const CBag& b)
{ return b <= a; }
// Structural equivalence of the bags
// Two bags are equal if they contain the same number of the same elements
inline bool operator == (const CBag& a, const CBag& b)
{ return a <= b && a >= b; }
|
It has to be stressed that the package was designed to minimize the
number of functions that need to know details of CBag's implementation.
Following good practice, I wrote validation code (file vCBag.cc
[Code]) that tests all the functions and methods of the CBag package
and verifies common invariants.
Suppose you are tasked with implementing a Set package. Your boss
defined a set as an unordered collection where each element has a single
occurrence. In fact, your boss even said that a set is a bag
with no duplicates. You have found my CBag package and realized that
it can be used with few additional changes. The definition of a Set
as a Bag, with some constraints, made the decision to reuse the CBag
code even easier.
class CSet : public CBag {
public:
bool memberof(const int elem) const { return count(elem) > 0; }
// Overriding of CBag::put
void put(const int elem)
{ if(!memberof(elem)) CBag::put(elem); }
CSet * clone(void) const
{ CSet * new_set = new CSet(); *new_set += *this; return new_set; }
CSet(void) {}
};
|
The definition of a CSet makes it possible to mix CSets and CBags,
as in set += bag; or bag += set; These operations
are well-defined, keeping in mind that a set is a bag that happens to
have the count of all members exactly one. For example, set +=
bag; adds all elements from a bag to a set, unless they are already
present. bag += set; is no different than merging a bag
with any other bag.
You too wrote a validation suite to test all CSet methods (newly
defined and inherited from a bag) and to verify common expected properties,
e.g., a+=a is a.
In my package, I have defined and implemented a function:
// A sample function. Given three bags a, b, and c, it decides
// if a+b is a subbag of c
bool foo(const CBag& a, const CBag& b, const CBag& c)
{
CBag & ab = *(a.clone()); // Clone a to avoid clobbering it
ab += b; // ab is now the union of a and b
bool result = ab <= c;
delete &ab;
return result;
}
|
It was verified in the regression test suite. You have tried this function
on sets, and found it satisfactory.
Later on, I revisited my code and found my implementation of foo()
inefficient. Memory for the ab object is unnecessarily
allocated on heap. I rewrote the function as
bool foo(const CBag& a, const CBag& b, const CBag& c)
{
CBag ab;
ab += a; // Clone a to avoid clobbering it
ab += b; // ab is now the union of a and b
bool result = ab <= c;
return result;
}
|
It has exactly the same interface as the original foo(). The code hardly
changed. The behavior of the new implementation is also the same --
as far as I and the package CBag are concerned. Remember, I have no
idea that you're re-using my package. I re-ran the regression test suite
with the new foo(): everything tested fine.
However, when you run your code with the new implementation of foo(),
you notice that something has changed! You can see this for yourself:
download the complete code from
[Code]. make vCBag1 and make vCBag2 run
validation tests with the first and the second implementations of foo().
Both tests complete successfully, with the identical results.
make vCSet1 and make vCSet2 test the CSet package.
The tests -- other than those of foo() -- all succeed. Function foo()
however yields markedly different results. It is debatable which implementation
of foo() gives truer results for CSets. In any case, changing internal
algorithms of a pure function foo() while keeping the same interfaces
is not supposed to break your code. What happened?
What makes this problem more unsettling is that both you and I tried
to do everything by the book. We wrote a safe, typechecked code. We
eschewed casts. g++ (2.95.2) compiler with flags -W and -Wall issued
not a single warning. Normally these flags cause g++ to become very
annoying. You didn't try to override methods of CBag to deliberately
break the CBag package. You attempted to preserve CBag's invariants
(weakening a few as needed). Real-life classes usually have far more
obscure algebraic properties. We both wrote regression tests for our
implementations of a CBag and a CSet, and they passed. And yet, despite
all my efforts to separate interface and implementation, I failed. Should
a programming language or the methodology take at least a part of the
blame?
[OOP-problems]
Subtyping vs. Subclassing
The problem with CSet is caused by CSet design's breaking of the
Liskov Substitution Principle (LSP)
[LSP]. CSet has been declared as a subclass of CBag. Therefore,
C++ compiler's typechecker permits passing a CSet object or a CSet reference
to a function that expects a CBag object or reference. However, it is
well known
[Subtyping-Subclassing] that a CSet is not a subtype of
a CBag. The next few paragraphs give a simple proof of this fact, for
the sake of reference.
One approach is to consider Bags and Sets as pure values,
without any state or intrinsic behavior -- just like integers are. This
approach is taken in the next article,
Preventing-Trouble.html. The other point of view -- the one used
in this article -- is Object-Oriented Programming, of objects that encapsulate
state and behavior. Behavior means an object can accept a message, send
a reply and possibly change its state. Let us consider a Bag and a Set
separately, without regard to their possible relationship. Throughout
this section we use a different, concise notation to emphasize the general
nature of the argument.
We will define a Bag as an object that accepts two messages:
(send a-Bag 'put x)
- puts an element x into the Bag, and
(send a-Bag 'count x)
- gives the count of occurrences of x in the Bag (without changing
a-Bag's state).
Likewise, a Set is defined as an object that accepts two messages:
(send a-Set 'put x)
- puts an element x into a-Set unless it was already there,
(send a-Set 'count x)
- gives the count of occurrences of x in a-Set (which is always
either 0 or 1).
Let's consider a function
(define (fnb bag)
(send bag 'put 5)
(send bag 'put 5)
(send bag 'count 5))
|
The behavior of this function can be summed as follows: given a Bag,
the function adds two elements into it and returns
(+ 2 (send orig-bag 'count 5))
Technically you can pass to fnb a Set object as well.
Just as a Bag, a Set object accepts messages put and
count. However applying fnb to a Set object
will break the function's post-condition, which stated above. Therefore,
passing a set object where a bag was expected changes behavior of some
program. According to the Liskov Substitution Principle (LSP), a Set
is not substitutable for a Bag -- a Set cannot be a subtype of
a Bag.
Let's consider a function
(define (fns set)
(send set 'put 5)
(send set 'count 5))
|
The behavior of this function is: given a Set, the function adds an
element into it and returns 1. If you pass to this function a bag (which
-- just as a set -- replies to messages put and count),
the function fns may return a number greater than 1. This
will break fns's contract, which promised always to return
1.
Therefore, from the OO point of view, neither a Bag nor a Set are
a subtype of the other. This is the crux of the problem. Bag and Set
only appear similar. The interface or an implementation of a
Bag and a Set appear to invite subclassingof a Set from a Bag
(or vice versa). Doing so however will violate the LSP -- and you have
to brace for very subtle errors. The previous section intentionally
broke the LSP to demonstrate how insidious the errors are and how difficult
it may be to find them. Sets and Bags are very simple types, far simpler
than the ones you deal with in a production code. Alas, LSP when considered
from an OOP point of view is undecidable. You cannot count on
a compiler for help in pointing out an error. You cannot rely on regression
tests either. It's manual work -- you have to see the problem
[OOP-problems].
Subtyping and Immutability
One may claim that "A Set *is not a* Bag, but an ImmutableSet *is an*
ImmutableBag." That is not correct. An immutability per se does not
confer subtyping to "derived" classes of data. As an example, consider
a variation of the previous argument. We will use a C++ syntax for a
change. The examples will hold if re-written in Java, Haskell, Self
or any other language with a native or emulated OO system.
class BagV {
virtual BagV put(const int) const;
int count(const int) const;
... // other similar const members
};
class SetV {
virtual SetV put(const int) const;
int count(const int) const;
... // other similar const members
};
|
Instances of BagV and SetV classes are immutable, yet the classes
are not subtypes of each other. To see that, let us consider a polymorphic
function
template <typename T> int f(const T& t)
{ return t.put(1).count(1); }
|
Over a set of BagV instances, the behavior of this function can be represented
by an invariant
f(bag) == 1 + bag.count(1)
If we take an object asetv = SetV().put(1) and pass
it to f(), the invariant above will be broken. Therefore,
by LSP, a SetV is not substitutable for BagV: a SetV is not a
BagV.
In other words, if one defines
int fb(const BagV& bag) { return bag.put(1).count(1); }
|
he can potentially pass a SetV instance to it: e.g., either by making
SetV a subclass of BagV, or by reinterpret_cast<const BagV&>(aSetV).
Doing so will generate no overt error; yet this will break fb()'s invariant
and alter program's behavior in unpredictable ways. A similar argument
will show that BagV is not a subtype of SetV.
C++ objects are record-based. Subclassing is a way of extending records,
with possibly altering some slots in the parent record. Those slots
must be designated as modifiable by a keyword virtual. In this context,
prohibiting mutation and overriding makes subclassing imply subtyping.
This was the reasoning behind BRules [Preventing-Trouble.html].
However merely declaring the state of an object immutable is not
enough to guarantee that derivation leads to subtyping: An object can
override parent's behavior without altering the parent. This is easy
to do when an object is implemented as a functional closure, when a
handler for an incoming message is located with the help of some kind
of reflexive facilities, or in prototype-based OO systems. Incidently,
if we do permit a derived object to alter its base object, we implicitly
allow behavior overriding. For example, an object A can
react to a message M by forwarding the message to an object
B stored in A's slot. If an object C
derived from A alters that slot it hence overrides
A's behavior with respect to M.
For example,
http://pobox.com/~oleg/ftp/Scheme/index.html#pure-oo
implements a purely functional OO system. It supports objects with an
identity, state and behavior, inheritance and polymorphism. Everything
in that system is immutable. And yet it is possible to define something
like a BagV, and derive SetV from it by overriding a put
message handler. Acting this way is bad and invites trouble as this
breaks the LSP as shown earlier. Yet it is possible. This example shows
that immutability per se does not turn object derivation into subtyping.
The present page is a compilation and extension of two articles posted
on comp.object, comp.lang.functional, comp.lang.c++.moderated newsgroups
on Jun 18 and Jul 14, 2000.
Discussion thread:
http://www.deja.com/viewthread.xp?AN=644379349.1&search=thread&recnum=%3c8katsh$fmf$1@nnrp1.deja.com%3e%231/5&group=comp.object&frpage=viewthread.xp
Acknowledgment
Andy Gaynor has asked the right questions. This article is merely an
answer.
Actually Spolsky does not understand the role of scripting
languages. But hi is right of target with his critique of OO. Object oriented
programming is no silver bullet.
Dec
14, 2006
(InfoWorld)
Joel Spolsky is one of
our most celebrated pundits
on the practice of software
development, and he's full of
terrific insight. In a recent
blog post, he decries the fallacy
of
"Lego programming" -- the
all-too-common assumption that
sophisticated new tools will
make writing applications as
easy as snapping together children's
toys. It simply isn't so, he
says -- despite the fact that
people have been claiming it
for decades -- because the most
important work in software development
happens before a single line
of code is written.
By way
of support, Spolsky reminds
us of a quote from the most
celebrated pundit of an earlier
generation of developers. In
his 1987 essay
"No Silver Bullet," Frederick
P. Brooks wrote,
"The essence of a software entity
is a construct of interlocking
concepts ... I believe the hard
part of building software to
be the specification, design,
and testing of this conceptual
construct, not the labor of
representing it and testing
the fidelity of the representation
... If this is true, building
software will always be hard.
There is inherently no silver
bullet."
As Spolsky
points out, in the 20 years
since Brooks wrote "No Silver
Bullet," countless products
have reached the market heralded
as the silver bullet for effortless
software development. Similarly,
in the 30 years since Brooks
published "
The Mythical Man-Month"
-- in which, among other things,
he debunks the fallacy that
if one programmer can do a job
in ten months, ten programmers
can do the same job in one month
-- product managers have continued
to buy into various methodologies
and tricks that claim to make
running software projects as
easy as stacking Lego bricks.
Don't you
believe it. If, as Brooks wrote,
the hard part of software development
is the initial design, then
no amount of radical workflows
or agile development methods
will get a struggling project
out the door, any more than
the latest GUI rapid-development
toolkit will.
And neither
will open source. Too often,
commercial software companies
decide to turn over their orphaned
software to "the community"
--
if such a thing exists --
in the naive belief that open
source will be a miracle cure
to get a flagging project back
on track. This is just another
fallacy, as history demonstrates.
In 1998,
Netscape released the source
code to its Mozilla browser
to the public to much fanfare,
but only lukewarm response from
developers. As it turned out,
the Mozilla source was much
too complex and of too poor
quality for developers outside
Netscape to understand it. As
Jamie Zawinski
recounts, the resulting
decision to rewrite the browser's
rendering engine from scratch
derailed the project anywhere
from six to ten months.
This is
a classic example of the fallacy
of the mythical man-month. The
problem with the Mozilla code
was poor design, not lack of
an able workforce. Throwing
more bodies at the project didn't
necessarily help; it may have
even hindered it. And while
implementing a community development
process may have allowed Netscape
to sidestep its own internal
management problems, it was
certainly no silver bullet for
success.
The key
to developing good software
the first time around is doing
the hard work at the beginning:
good design, and rigorous testing
of that design. Fail that, and
you've got no choice but to
take the hard road. As Brooks
observed all those years ago,
successful software will never
be easy. No amount of open source
process will change that, and
to think otherwise is just more
Lego-programming nonsense.
Resolved: Objects Have Failed
I participated in a debate on the question "Objects Have Failed"
at OOPSLA 2002 in Seattle, Washington. My teammate was Brian Foote,
and our opponents were Guy L. Steele Jr. and James Noble. My opening
remarks were scripted, as were Guy Steele's, and my rebuttals were drawn
from an extensive set of notes.
- rpg's Opening Remarks [html]
- gls's Opening Remarks [html]
- Discursive Notes [1.1 mb
pdf ]
- Notes as Slides [7.1 mb
pdf ]
(Opening remarks by Richard P. Gabriel, November 6, 2002)
What can it mean for a programming paradigm to fail? A paradigm fails
when the narrative it embodies fails to speak truth or when its proponents
embrace it beyond reason. The failure to speak truth centers around
the changing needs of software in the 21st century and around the so-called
improvements on OO that have obliterated its original benefits.
Obsessive embrace has spawned a search for
purity that has become an ideological weapon, promoting an incremental
advance as the ultimate solution to our software problems.
The effect has been to brainwash people on the street. The statement
"everything is an object" says that OO is universal, and the statement
"objects model the real world" says that OO has a privileged position.
These are very seductive invitations to a totalizing viewpoint. The
result is to starve research and development on alternative paradigms.
Someday, the software we have already written will be a set of measure
0. We have lived through three ages of computing—the first was machine
coding; the second was symbolic assemblers, interpreter routines, and
early compilers; and the third was imperative, procedural, and functional
programming, and compiler-based languages. Now we are in the fourth:
object-oriented programming. These first four ages featured single-machine
applications. Even though such systems will remain important, increasingly
our systems will be made up of dozens, hundreds, thousands, or millions
of disparate components, partial applications, services, sensors, and
actuators on a variety of hardware, written by a variegated set of developers,
and it won’t be incorrect to say that no one knows how it all works.
In the old world, we focussed on efficiency, resource limitations, performance,
monolithic programs, standalone systems, single author programs, and
mathematical approaches. In the new world we will foreground robustness,
flexibility, adaptation, distributed systems, multiple-author programs,
and biological metaphors for computing.
Needless to say, object-orientation provides
an important lens through which to understand and fashion systems in
the new world, but it simply cannot be the only lens.
In future systems, unreliability will be common, complexity will be
out of sight, and anything like carefully crafted precision code will
be unrealistic. It’s like a city: Bricks are important for building
part of some buildings, but the complexity and complicated way a variety
of building materials and components come together under the control
of a multitude of actors with different cultures and goals, talents
and proclivities means that the kind of thinking that goes into bricks
will not work at the scale of the city. Bricks are just too limited,
and the circumstances where they make sense are too constrained to serve
as a model for building something as diverse and unpredictable as a
city. And further, the city itself is not the end goal, because the
city must also—in the best case—be a humane structure for human activity,
which requires a second set of levels of complexity and concerns. Using
this metaphor to talk about future computing systems, it’s fair to say
that OO addresses concerns at the level of bricks.
The modernist tendency in computing is to engage in totalizing discourse
in which one paradigm or one story is expected to supply all in every
situation. Try as they might, OO’s promoters cannot provide a believable
modernist grand narrative to the exclusion of all others. OO holds no
privileged position. So instead of Java for example embracing all the
components developed elsewhere, its proponents decided to develop their
own versions so that all computing would be embraced within the Java
narrative.
Objects, as envisioned by the designers of languages like Smalltalk
and Actors—long before C++ and Java came around— were for modeling and
building complex, dynamic worlds. Programming environments for languages
like Smalltalk were written in those languages and were extensible by
developers. Because the philosophy of dynamic change was part of the
post-Simula OO worldview, languages and environments of that era were
highly dynamic.
But with C++ and Java, the dynamic thinking fostered by object-oriented
languages was nearly fatally assaulted by the theology of static thinking
inherited from our mathematical heritage and the assumptions built into
our views of computing by Charles Babbage whose factory-building worldview
was dominated by omniscience and omnipotence.
And as a result we find that object-oriented
languages have succumbed to static thinkers who worship perfect planning
over runtime adaptability, early decisions over late ones, and the wisdom
of compilers over the cleverness of failure detection and repair.
Beyond static types, precise interfaces, and mathematical reasoning,
we need self-healing and self-organizing mechanisms, checking for and
responding to failures, and managing systems whose overall complexity
is beyond the ken of any single person.
One might think that such a postmodern move would have good consequences,
but unlike Perl, the combination was not additive but subtractive—as
if by undercutting what OO was, OO could be made more powerful. This
may work as a literary or artistic device,
but the idea in programming is not to teach but to build.
The apparent commercial success of objects and our love affair with
business during the past decade have combined to stifle research and
exploration of alternative language approaches and paradigms of computing.
University and industrial research communities retreated from innovating
in programming languages in order to harvest the easy pickings from
the OO tree. The business frenzy at the end of the last century blinded
researchers to diversity of ideas, and they were into going with what
was hot, what was uncontroversial. If ever there was a time when Kuhn’s
normal science dominated computing, it was during this period.
My own experience bears this out. Until 1995, when I went back to
school to study poetry, my research career centered on the programming
language, Lisp. When I returned in 1998, I found that my research area
had been eliminated. I was forced to find new ways to earn a living
within the ecology created by Java, which was busily recreating the
computing world in its own image.
Smalltalk, Lisp, Haskell, ML, and other languages languish while
C++, Java, and their near-clone C# are the only languages getting attention.
Small languages like Tcl, Perl, and Python are gathering adherents,
but are making no progress in language and system design at all.
Our arguments come in several flavors:
- The object-oriented approach does not adequately address the
computing requirements of the future.
- Object-oriented languages have lost the simplicity—some would
say purity—that made them special and which were the source of their
expressive and development power.
- Powerful concepts like encapsulation were supposed to save people
from themselves while developing software, but encapsulation fails
for global properties or when software evolution and wholesale changes
are needed. Open Source handles this better. It’s likely that modularity—keeping
things local so people can understand them—is what’s really important
about encapsulation.
- Objects promised reuse, and we have not seen much success.
- Despite the early clear understanding of the nature of software
development by OO pioneers, the current caretakers of the ideas
have reverted to the incumbent philosophy of perfect planning, grand
design, and omniscience inherited from Babbage’s theology.
- The over-optimism spawned by objects in the late 1990s led businesses
to expect miracles that might have been possible with objects unpolluted
by static thinking , and when software developers could not deliver,
the outrageous business plans of those businesses fell apart, and
the result was our current recession.
- Objects require programming by creating communicating entities,
which means that programming is accomplished by building structures
rather than by linguistic expression and description through form,
and this often leads to a mismatch of language to problem domain.
- Object design is like creating a story in which objects talk
and interact with each other, leading people to expect that learning
object-oriented programming is easy, when in fact it is as hard
as ever. Again, business was misled.
- People enthused by objects hogged the road, would not get out
of the way, would not allow alternatives to be explored—not through
malice but through exuberance—and now resources that could be used
to move ahead are drying up. But sometimes this exuberance was out-and-out
lying to push others out of the way.
But in the end, we don’t advocate changing the way we work on and
with objects and object-oriented languages. Instead, we argue for diversity,
for work on new paradigms, for letting a thousand flowers bloom. Self-healing,
self-repair, massive and complex systems, self-organization, adaptation,
flexibility, piecemeal growth, statistical behavior, evolution, emergence,
and maybe dozens of other ideas and approaches we haven’t thought of—including
new physical manifestations of non-physical action—should be allowed
and encouraged to move ahead.
This is a time for paradigm definition and shifting. It won’t always
look like science, won’t always even appear to be rational; papers and
talks explaining and advocating new ideas might sound like propaganda
or fiction or even poetry; narrative will play a larger role than theorems
and hard results. This will not be normal science.
In the face of all this, it’s fair to
say that objects have failed.
[Feb 14, 2006]
OOP Criticism Object Oriented Programming Oversold by B. Jacobs.
OOP criticism and OOP problems. The emperor has no clothes! Reality
Check 101. Snake OOil. Updated: 5/14/2005
OOP Myths Debunked:
- Myth: OOP is a proven general-purpose technique
- Myth: OOP models the real world better
- Myth: OOP makes programming more visual
- Myth: OOP makes programming easier and faster
- Myth: OOP eliminates the "complexity" of "case" or "switch" statements
- Myth: OOP reduces the number of places that require changing
- Myth: OOP increases reuse (recycling of code)
- Myth: Most things fit nicely into hierarchical taxonomies
- Myth: Sub-typing is a stable way to model differences
- Myth: Self-handling nouns are more useful than self-handling verbs
- Myth: Most operations have one natural "primary noun"
- Myth: OOP does automatic garbage-collection better
- Myth: Procedural cannot do components well
- Myth: OO databases can better store large, multimedia data
- Myth: OODBMS are overall faster than RDBMS
- Myth: OOP better hides persistence mechanisms
- Myth: C and Pascal are the best procedural can get
- Myth: SQL is the best relational language
- Myth: OOP would have prevented more Y2K problems
- Myth: OOP "does patterns" better
- Myth: Only OOP can "protect data"
- Myth: Implementation changes significantly more often than interfaces
- Myth: Procedural/Relational ties field types and sizes to the code
more
- Myth: Procedural cannot extend compiled portions very well
- Myth: No procedural language can re-compile at the routine level
- Myth: Procedural/Relational programs cannot "factor" as well
- Myth: OOP models human thought better (Which human?)
- Myth: OOP is more "modular"
- Myth: OOP divides up work better
- Myth: OOP "hides complexity" better
- Myth: OOP better models spoken language
- Myth: OOP is "better abstraction"
- Myth: OOP reduces "coupling"
- Myth: OOP does multi-tasking better
- Myth: OOP scales better
- Myth: OOP is more "event driven"
- Myth: Most programmers prefer OOP
- Myth: OOP manages behavior better
Software-engineering has two kinds of cargo-cult; slavish adherence
to process without regard to the effect on product, and reliance on personal
heroics, again without regard to product. In both cases, organizations try
to mimic programming style/paradigm, but only mimic the external appearance
without understanding real programming techniques and ideas behind the technology.
The real difference is not which style is chosen,
but what education, training, and understanding is brought to bear on
the project. Rather than debating process vs. commitment, we should
be looking for ways to raise the average level of developer and manager
competence. That will improve our chances of success regardless of which
development style we choose.
I'm fairly sure you could accurately
gauge the maturity of a programming team by the amount of superstition
in the source code they produce. Code superstitions are a milder form
of
cargo cult software development, in which you find people writing
code constructs that have no conceivable value with respect to the functions
that the code is meant to fulfill.
A recent conversation reminded me of
an example I find particularly disturbing. Sample code for dealing with
JDBC is particularly prone to being littered with this particular error,
as shown below. (I suspect that is not coincidental; I'll be coming
back to that.) I have elided most braces out for clarity and terseness
- imagine that this is a cross between Java and Python:
import java.sql.*;
public class JdbcSample {
public static void main(String[] args) {
Connection conn = null;
try
conn = DriverManager.getConnection("jdbc:someUrl");
// ...more JDBC stuff...
catch (SQLException ex)
// Too often that is silently ignored, but that's another blog entry
finally
if (conn != null)
try
conn.close();
catch (SQLException sqlEx)
conn = null;
}
The "superstition" part is that setting
the connection to null can have absolutely no useful effect; being a
local variable, "conn" will become eligible for garbage collection as
soon as it goes out of scope anyway, which the most rudimentary analysis
of flow control reveals it will immediately after being set to null.
I am always particularly interested in
finding out what goes on in the minds of programmers who write this
kind of thing, because that will sometimes reveal the roots of the superstition.
Most of the time, though, if you raise question in a design review the
programmer will say something like "I copied and pasted it from sample
code". This is how the superstitions spread - and it's also a red flag
with respect to the team's practice maturity - but rarely an occasion
to gain insight into why the superstition took hold, which is what you'll
need to know in "remedial" training.
Now, the "null" concept, obvious as it
seems, is a likely place for superstitions to accrete around. If you
look closely, "null" is nothing but obvious. Comparing Java and Smalltalk,
for instance, we find that they differ radically with respect to calling
instance methods on null, or "nil" as it's called in Smalltalk; "nil"
does have some instance methods you can call. Also, what is the type
of the "null" value in Java ? It is a special type called "the null
type", which looks like a sensible answer but incidentally breaks the
consistency of the type system; the only types which are assignable
to variables are the type of the variable or subtypes of that type,
so "null type" should be a subclass of every Java class. (It actually
works that way in Eiffel, as Nat Pryce reminds me - see comments.)
See also
here for another example of a null-related Java superstition, also
surprisingly common, as you can verify by Googling for "equals null".
In the case of JDBC, I would bet that
idioms of resource allocation and deallocation inherited from non-garbage
collected languages, like C, were the main force in establishing the
superstition. Even people new to Java get used to not calling "dispose"
or "delete" to deallocate objects, but unfortunately the design of the
JDBC "bridges" between the object and relational worlds suffer from
a throwback to idioms of explicit resource allocation/deallocation.
Owing to what many see as a major design
flaw in Java, "going out of scope" cannot be relied on as an indicator
that a resource is no longer in use, either, so whenever they deal with
JDBC Java programmers are suddenly thrown back into a different world,
one where deallocation is something to think about, like not forgetting
your keys at home. And so, in precisely the same way as I occasionally
found myself patting my pockets to check for home keys when I left the
office, our fingers reflexively type in the closest equivalent
we find in Java to an explicit deallocation - setting to null.
You may object that the setting-to-null
superstition is totally harmless. So is throwing salt over your shoulder.
While this may be true of one particular superstition, I would
be particularly concerned about a team which had many such habits, just
like you wouldn't want to trust much of importance your batty old aunt
who avoids stepping on cracks, stays home on Fridays, crosses herself
on seeing a black cat, but always sends you candy for Christmas.
Posted by Morendil
at November 15, 2004 04:57 PM
Laurent Bossavit explains the
notion of "Cargo Cult" programming - the example being setting a temporary
variable to null (i.e., one that is going out of scope)
You may object that the setting-to-null
superstition is totally harmless. So is throwing salt over your shoulder.
While this may be true of one particular superstition, I would be particularly
concerned about a team which had many such habits, just like you wouldn't
want to trust much of importance your batty old aunt who avoids stepping
on cracks, stays home on Fridays, crosses herself on seeing a black
cat, but always sends you candy for Christmas.
What superstitious coding practices does
your group have?
Comments
null helps
GC yes? no? [john mcintosh] November 15, 2004 19:23:32 EST
I once had a fellow phone me from Hong
Kong who explained a performance problem they were having. Seems they
at the end of each method, and in each "destroy" method for a class
(used to to destroy instances), they would set all the variables to
NULL. The best was of course iterating over thousands of array elements,
setting them to NULL since they felt this was helping the GC find NULL
(garbaged) variables faster. Once they stopped doing this why windows
just snapped closed....
[PDF]
Cargo Cults in Java by Gordon Fletcher University of Salford
This paper is a personal account of my experience
of teaching Java programming to undergraduate and postgraduate students.
These students enter their respective subjects with no previous Java
programming knowledge. However, the undergraduate students have previous
experience with Visual Basic programming. In contrast, the postgraduate
students are enrolled in a “conversion” course which, in most cases,
means that they were unfamiliar with any form of programming language
or, in some cases, some core information technology skills. Irrespective
of these differences, I have witnessed how both groups independently
develop, what can be described as, a trade based culture with similarities
to ‘cargo cults’ around the Java language. This anthropological
term provides a useful terms of reference as the focus of programming
activity for many students increasingly centres upon the imitation of
code gathered from the lecturer or, in some cases, each other. This
is particularly evident as project deadlines approach. In extreme examples
of this cargo cult fever, students will discard potentially strong project
developments that incorporate many features of good software design
in favour of inelegant and cobbled together code on the single criteria
of better functionality.
In this paper I use the concept of the
cargo cult to frame the differing expectations surrounding “learning
Java” that are held by students and their lecturer. I draw upon my own
observations and experiences as the teacher in these learning environments
and upon feedback from my most recent cohort of undergraduate students
undertaking an BSc(Hons) programme within a UK university. The student
feedback is drawn from a questionnaire containing six questions relating
to their experiences and expectations regarding a Java programming subject.
The definition and description of the cargo cult is also used to consider
how this relationship can be established in a way that encourages positive
learning outcomes through the obligations and reciprocation associated
with gifts – in this case, clearly labeled gifts of code. The
cargo cult and the erroneous form of thinking associated with it provide
a useful framework for understanding the teaching and learning environment
in which I taught Java. In this way the interactions and motivation
of students and the lecturers who ultimately share the common goal of
obtaining their academic success can be scrutinized with the aim of
improving this experience for all those involved. The cargo cult
is not, however, ‘simply’ an anachronistic analogy drawn from social
anthropology. Cargo cult thinking has been identified within contemporary
culture as readily as tribal cultures and with equal significance
(Hirsch 2002; Cringely 2001, Fitzgerald 1999; Feynman 1974).
2. Cargo Cult Thinking
It is important to acknowledge that cargo
cult thinking is not necessarily the ‘wrong’ way of thinking or that
this paper seeks to castigate students’ study practices. Cargo cult
thinking is based, in part, on conclusions drawn from only partially
observed phenomena. In many respects this paper is a reflexive exercise
regarding my own teaching practices and an examination of the ways in
which cargo cult thinking can be employed to achieve positive learning
outcomes. Nonetheless, despite this acknowledgement, the actions
of cargo cult followers are based upon a “fallacious reasoning” of cause
and effect. This could be summarized in the context of Java programming
as the assumption that if I, as a student, write my code like you, the
lecturer, do, or use your code as much as possible, I will be a programmer
like you and this is what is required for me to do well - or at least
pass - this subject. However, as teachers of Java it is necessary
to acknowledge the – perhaps dormant – presence of this attitude and
to consequently offer offhand code examples with extreme caution. I
have repeatedly spotted examples of my own code embedded within students’
projects. Although the code may originally have been offered as a quick
and incomplete example of a concept or a particular line of thinking
it can too readily become the cornerstone of larger scale classes without
modification. It is perhaps, then unsurprising, that the cargo cult
attitude does, develop among students when they are first learning a
programming language and the concepts of programming. The consequence
of pursuing this belief unchecked parallels the effects of learning
in a “Java for Dummies” manner. Deeper, conceptual understanding and
problem-solving techniques remain undeveloped and students are left
able only to imitate the step-by-step procedures outlined by the textbook.
This step-by-step form of explicit instruction discourages exploration
and discourages students from appreciating the learning that is occurring
when they disentangle java compiler errors. This is perhaps one of the
most revealing differences between students and lecturers. While
experienced programmers use compiler errors, new programmers will see
the errors as “just one more thing” getting in the way of a successfully
executing application. This suggests a lack of awareness that programming
is not synonymous with writing code. The consuming focus in
the majority of undergraduate and postgraduate assessment projects is
upon pursuing and obtaining functionality in their code to the detriment
of the user interface, clear documentation, class structures, code reusability,
extensibility or reliability.
When code is reused, and especially when
code is acquired from outsourced teams or incorporated via Web services
technologies, there's a real opportunity for cargo cult practices to
take hold. Source code may follow unfamiliar naming conventions, and
design documents and internal memos may be written in unfamiliar languages
or in a language that we know by people who don't speak that language
very well. We may not even have the source—we may have only WSDL (Web
Services Description Language) or some other interface definition to
guide us.The wooden headphones
may bear fancy names like "design patterns," but they're still an indicator
that we may be building systems that look like those that have worked
before—instead of designing from deep understanding toward solutions
that meet new needs.
"The first principle is that you must
not fool yourself," said the late physicist Richard Feynman in the 1974
Caltech commencement address that's often considered the origin of the
"cargo cult" phrase, at least as used by coders. That's a good principle.
Reusing code that we don't understand or reusing familiar methods merely
because we do understand them are behaviors for which we should be on
guard.
In the not-so-recent past, headlines proclaimed, "Software
ICs Will Revolutionize Computer Programming." ind development would
reduce programming to assembling standardized "objects," and that the
need for programmers would decline as software "technicians" with minimal
training would develop the software of the future.
Ten years have passed, and this clearly hasn't happened.
Skilled programmers are in greater demand, the skill levels required
are higher, and software is harder to develop. The business press says
that nirvana is now just around the corner; companies that have the
words "object-oriented" in their business plan are in demand among venture
firms. Yet object-oriented methodologies are over 20 years old. Are
today's technological forecasts any more accurate than those of 10 years
ago?
This is not to say that OO can't work. There are examples
of successful OO projects; usually these are showcase projects staffed
with top developers. For the most part, however, object-oriented technology
has not been the "magic bullet." In this article, I'll briefly discuss
some reasons that OO has thus far failed to deliver. More importantly,
I'll address some ways that organizations with average programmers can
achieve high levels of reuse and shorten development cycles.
Let me count the way
The principal benefit cited for object-oriented methodologies
is "reuse." This sounds like a valuable benefit; if we improve reuse,
we write less code. Less code means faster development and easier maintenance
in the future. Less code also means fewer chances for bugs, so it indirectly
affects product quality. However, industry watchers report that there
is only 15 percent average reuse in today's object-based projects. That's
a pretty damning statistic, if true; we did better 20 years ago with
COBOL subroutines! Others have cited different statistics; one major
consulting firm reports 25 percent reuse across clients, and some academic
centers report 80 percent reuse. So what's the real story?
All of these figures beg the question: "How do you
measure reuse?" Is reuse a measure of code that is referenced in more
than one place? (Subroutines could do that before OO.) Is code referenced
in 50 places counted differently from code referenced in two places?
One measure of reuse might be the size of an application developed using
OO technology versus one developed using a different technology. This
measurement, however, is impossible to perform, as such systems don't
exist. Further, a search of the literature turns up no widely-used standards
for measuring reuse.
Yet another complication is the granularity involved
in measuring reuse. The usual unit is the object itself. But no one
looks inside the object. One can create a simple object that can be
used for only one specific function. This object can be made to serve
more functions (thus improving its reuse) by adding methods to it. Perhaps,
however, the same programming benefit could have been achieved by creating
a new object for the additional functions rather than enhancing the
first object with additional methods. The amount of programming work
is the same in both cases, but the bulkier single object with additional
methods counts for a higher level of reuse to most people, even though
this object is carrying around a lot of unused "baggage" in any one
instantiation.
The bottom line is that there is no practical objective
way to measure reuse. Anyone out to make a point (positive or negative)
about reuse can find a metric to prove that point. This creates a new
problem. If you can't measure something, how can you improve it? For
the time being, we will have to assume that we know good reuse when
we see it, even if we can't measure it. We can do this by observing
how long it takes to develop an application or how much code it takes
to develop the application (assuming experienced, competent programmers).
By using this subjective approach, it is apparent to most developers
that we are still losing ground.
Objects and Components
Agreeing on what constitutes an "object" is a fundamental
problem with object-oriented technology. In theory, an object represents
a real-world entity, such as a person, vehicle, merchandise, etc. Yet
most programmers think of objects as processing entities -- listboxes,
text widgets, windows, etc. While it would be possible to start with
widgets and, through encapsulation and inheritance, end up with, say,
vehicles, developers just don't do this when building real systems.
So one problem is that most OO development is not truly object oriented,
but rather programming with predefined widgets. Just because you are
programming in C++ does not mean that you are doing object-oriented
development. As we used to say, "Real FORTRAN programmers can write
FORTRAN in any language" -- and real procedural programmers can write
procedural code in C++.
There is a well-established, theoretical basis for
object-oriented methodology. Even if some developers don't understand
it, don't use it correctly, or disagree with it, there is a body of
reference material that precisely defines objects and regulates their
use.
The computer industry has recently begun to shift
focus from "objects" to "components" as the answer to our dreams. But
what is a component? Some simply use the term "component" as another
name for a widget. I have a catalog in front of me that purports to
offer "components." It includes charting tools, a cryptographic package,
a Text Edit control developer's kit, a collection of widgets (grids,
trees, notebooks, meters, etc.), communications drivers, and similar
entities. This definition of "component" is not the answer we are seeking,
however.
A search of the literature doesn't help, either. There
are many articles that discuss components, but few that actually define
a component. Industry expert Judith Hurwitz says, "Components are made
up of business rules, application functionality, data, or resources
that are encapsulated to allow reuse in multiple applications." Alan
Radding, who writes about multi-tier development, responds, "In [Judith]
Hurwitz Consulting's hypertier scheme, everything in effect ends up
as a component." Don Kiely, writing about components for IEEE's Computer
magazine never actually defines components, but he does define "framework
assemblies" as groups of components "that could be plugged into an application
as easily as individual components." This is a significant statement
because it shows that Kiely, Hurwitz, and Radding are thinking along
the same lines, even if they use different words. Kiely also makes the
useful observation that, "to be truly effective, components should be
portable and inter-operable across applications," something that I will
come back to later.
Slashdot The Object Oriented Hype discussion of B. Jacobs paper
Object Oriented Programming Oversold!
These problems form obstacles to the further development
of object-oriented software engineering, and in some situations are
beginning to cause its outright rejection. Such problems can be solved
either by a variety of ad hoc tools and methodologies, or by progress
in language technology (both design and implementation). Here are some
things that could or should be done in the various areas.
- Economy of execution. Much can be done
to improve the efficiency of method invocation by clever program
analysis, as well as by language features (e.g. by "final" methods
and classes); this is the topic of a large and promising body of
current work. We also need to design type systems that can statically
check many of the conditions that now require dynamic subclass checks.
- Economy of compilation. We need to adopt
languages and type systems that allow the separate compilation of
(sub)classes, without resorting to recompilation of superclasses
and without relying on "private" information in interfaces.
- Economy of small-scale development. Improvements
in type systems for object-oriented languages will improve error
detection and the expressiveness of interfaces. Much promising work
has been done already and needs to be applied or further deployed
[1] [5].
- Economy of large-scale development. Major
progress should be achieved by formulating and enforcing inheritance
interfaces: the contract between a class and its subclasses (as
opposed to the instantiation interface which is essentially an object
type). This recommendation requires the development of adequate
language support. Parametric polymorphism is beginning to appear
in many object-oriented languages, and its interactions with object-oriented
features need to be better understood. Subtyping and subclassing
must be separated. Similarly, classes and interfaces must be separated.
- Economy of language features. Prototype-based
languages have already tried to reduce the complexity of class-based
languages by providing simpler, more composable features. Even within
class-based languages, we now have a better understanding of how
to achieve simplicity and orthogonality, but much remains to be
done. How can we design an object-oriented language that is powerful
and simple; one that allows powerful engineering but also simple
and reliable engineering?
OOP Criticism -- good OOP criticism and OOP problems (The emperor
has no clothes!). Contains a very good collection of links
Contents
External Links
This research study, investigates some
of the problems and unresolved issues in the OOPar. Contrary to adopting
a WHAT (the problem) and HOW (the solution) approach it
uniquely asks WHY these problem and issues exist. We argue that the
WHAT & HOW approach, although useful in the short term, does not provide
a long term solution to the problems in data modelling (DM). As a result
of adopting such an approach and the empirical and wide ranging nature
of chapter 3, four aspects are proposed.
2.0 Concepts of the OO model
The main concepts that underline the
OOPar, are outlined in the following sections.
2.1 Object Classes & Objects
In the OOPar, the problem domain is modeled
using object-classes, and there instances objects (Booch, 1994). An
object is any abstract or real world item that is relevant to the system.
An object class is a grouping of these objects. For example, in a library
information system an object-classes would be such things as members,
books, etc. Objects would be instances of these classes, e.g. Joe Bloggs,
Object-oriented analysis by Martin, etc.
2.2 Methods
Methods are predefined operations, and
are associated with an object-class. "Methods specify the way in which
an object's data are manipulated" (Martin & Odell, (1992), p.17). Therefore,
the member object class identified earlier may contain methods such
as reserve_book, borrow_book, and etc. Access to an object is only granted
via the methods.
This, in fact is one of the key features
of the OO model, that is behaviour (methods) and data-structures (i.e.
the declarative aspect of an object) are not separated - these are encapsulated
together in one module.
2.3 Encapsulation
The process of keeping methods and data
together, and granting access to the object only through the methods
is referred to as encapsulation. This achieves information hiding,
i.e. "The object hides its data from other objects and allows the data
to be accessed via its own methods" (Martin & Odell, p.17).
2.4 Inheritance
Inheritance is the process, where a high-level
object class can be specialised into sub-classes. Wirfs-Brock et al(1990),
define inheritance as "... the ability of one class to define the behaviour
and data structure of its instances as a superset of the definition
of another class or classes." (p.24).
For example, in the library system, at
a later stage we may find that two types of members exist, children
and adult. To accommodate this, we can make use of inheritance by abstracting
all the common features into a high-level member class and further create
two new sub-classes, adult-members and child-members, under the member
class. Sub-classes would also inherit data and functions from the super
class.
2.4.1 Multiple Inheritance
Multiple inheritance, is almost identical
in concepts to single inheritance, however in this case a sub-class
can inherit from many super-classes. For example, at a later design
stage of the library system, we may have a situation, where a book is
of type fiction and is also a reference book. This potentially, allows
the use of multiple inheritance.
2.4 Polymorphism & Dynamic Binding
The term polymorphism, originates from
the Greek word 'poly morph' meaning many forms. In the context of the
OOPar, the polymorphism concept allows different objects to react to
the same stimuli (i.e. message) differently (Hymes, 1995). For example,
adult and child members, may only be allowed to borrow books for up
to 6 and 3 weeks respectively. Therefore the borrow_book message to
the adult-member class will respond differently (i.e. date books by
6 weeks), than the same message to the child-member class (date books
by 3 weeks). There are variations and degrees of polymorphism (e.g.
operator overloading), which the interested reader is guided to standard
OO textbooks (see refs. at end).
2.5 Genericity
Generic (or parametric) classes are those
that define a whole family of related classes, differing only in matters
concerning one or more types that are used as arguments to the class
of declarations (deChampeux et al, 1993). The concept of genericity
allows the designer to specify standard generic classes that can be
reused. For example, in designing any system, a number of common programming
situations require the same class structure to be applied to different
data types. Examples of several situations in user interface systems
are the following:
queue class
* a queue of characters entered by a
user
* a queue of mouse events that have occurred
and are waiting to be handled.
In each case the same basic algorithms
and supporting data structures are needed. What varies among uses of
the class is the type of the data being manipulated. Lists are also
used to maintain relationships in OO programming languages, hence in
the case of the library system a standard generic list class could be
defined to maintain the relationship between members and books reserved,
for example.
3.0 Claimed Benefits
This section describes some of the key,
general claimed benefits of the OOPar. The list is, of course, not extensive
and their are many other claimed benefits of this approach which are
described later, in their respective sections.
3.1 Naturalness of Analysis
& Design (Cognition)
One of the frequently claimed benefits
of the OOPar is that it is natural (therefore more understandable),
and is assumed to be cognitively similar to the way human beings perceive
and understand the real-world (Meyer, (1988); Rosson & Alpert (1988);
Rosson & Alpert(1990). Martin & Odell (1992, p.31) for example, states
"The way of thinking is more natural for most people than the techniques
of structured analysis and design. After all, the world consists of
objects." Mcfadden & Hoffer(1994, p.) similarly note "The notation and
approach of the object-oriented data model builds on these paradigms
that people constantly use to cope with complexity." This claim, therefore
assumes that it is more natural for developers to decompose a problem
into objects, at least as compared to the traditional structured languages.
In other words, it should be natural for developers and users to map
the problem into objects and into classification hierarchies.
3.2 Software Reuse
Software reuse is perhaps the most publicised
benefits of the OOPar. Advocates of the OOPar claim that it provides
effective mechanisms to allow for software to be reused (Meyer,1988).
For example Budd(1996), states "Well designed objects in object-oriented
systems are the basis for systems to be assembled largely from reusable
modules, leading to higher productivity." (p.31). Martin & Odell(1992),
similarly state "It [OO] leads to world of reusable classes, where much
of the software construction process will be the assembly of existing
well-proven classes." (p.31).
These mechanisms are encapsulation, polymorphism,
and inheritance. For example, encapsulation allows object classes to
be modified, or even added to new systems without requiring additional
modification to other classes in the system. The end-goal of this, is
to develop a component based software industry (as Martin & Odell point
out), where classes can be purchased, and plugged in. Inheritance allows
existing code to be reused. Genericity allows the reuse of one standard
class.
3.3 Communication Process
Curtis & Waltz (1990) and Krasner, Curtis,
& Iscoe(1987), report that at the software team level, some of the key
problems encountered are communication and coordination, capturing and
using domain knowledge and organisational issues. With the OO approach,
advocates claim that communication and coordination between the project
team and client(s), and also within the team are enhanced. For example,
Rumbaugh et al(1991, p.4), claimed that "greatest benefits [of OO] come
from helping specifiers, developers, express abstract concepts and communicate
them to each other. Martin & Odell (1992, p.34) also similarly state,
"Business people more easily understand the OO paradigm. They think
in terms of objects.....OO methodologies encourage better understanding
as the end users and developers share a common model." Similar statements
can be found in many popular text books, e.g. (Coad & Yourdan (1991,
p.3); Jacobson, Christerson, Johnsson, & Overgaard, (1992, p.43); Wirfs-Brock,
Wilkerson, & Weiner (1990, pp. 10 - 11).
This claim is based on two premises:
1. Naturalness of OO (described above)
makes understanding easier,
2. Objects are constructed from the problem
domain, hence communication between project team and client(s) is enhanced.
Also, because a single representation permeates throughout all stages
of life-cycle, therefore communication and coordination within the team
is facilitated.
3.4 Refinement & Extensibility
OO advocates, also claim that "software"
developed using the OOPar is easy to refine and extend.
Khoshafian(1990) states "Object oriented
programming techniques allow the development of extensible and reusable
modules" (p.274). Graham(1994), similarly notes, "Inheritance, genericity
or other forms of polymorphism make exception handling easier and improve
the extensibility of systems." (p.37). These claims are related to three
key principles of the OOPar, encapsulation, inheritance and polymorphism.
For example, encapsulation allows the
internal implementation of a class to be modified without requiring
changes to its services (i.e. methods). It also allows new classes to
be added to a system, without major modifications to the system. Inheritance
allows the class hierarchy to be further refined, and combined with
polymorphism, the superclass does not have to "know" about the new class,
i.e. modifications do not have to be made at the superclass.
4.0 Definition of OO Model
In critiquing a concept it is common
to start with a formal definition. However, in this research project
we will not do this, for the following reasons:
1. Unlike the relational model, the OO
model does not have one commonly accepted formal definition.
2. As a result of (1) trying to define
the OO model, is in itself a considerable research task.
Our approach will, therefore be to investigate
reported problems in the application of the OOPar, and academic critiques.
And, then to try and identify common threads and similarities between
these problems.
5.0 Conclusion
In summary, in section 2 we outlined
some of the core concepts that underline the OO model. Section 3 provided
an outline of some of the key claimed benefits of the OO model. Finally
in section 4, we discussed our reasons for not formally defining the
OO model.
Scripting languages
Compiled languages
In case of broken links
please try to use Google search. If you find the page please notify
us about new location
Subtyping, Subclassing,
and Trouble with OOP
UML criticism by A.J.H.Simons and coauthors
Paul Graham and
Jonathan Rees discuss the nature and
appeal of object-orientation. (Graham holds quite hackerish views regarding
language design that want a bit the specific sense of esthetics that comes
with mathematical culture, and his take on abstraction really is somewhat
flat, but anyway ...)
Object Oriented Programming
Oversold! Detailed OOP criticism by a programmer of business
applications who advocates a procedural/relational approach factoring out
the management of relationships to the database.
Why Java is not my favorite programming language
Objecting to Objects, by Stephen C. Johnson (USENIX conference invited
talk, 1994)
Critique
of the Object Oriented Paradigm: Beyond Object-Orientation Date:
14th May, 1997 Shajan Miah
This research study, investigates some
of the problems and unresolved issues in the OOPar. Contrary to adopting
a WHAT (the problem) and HOW (the solution) approach it
uniquely asks WHY these problem and issues exist. We argue that the
WHAT & HOW approach, although useful in the short term, does not provide
a long term solution to the problems in data modelling (DM). As a result
of adopting such an approach and the empirical and wide ranging nature
of chapter 3, four aspects are proposed.
OOP Criticism -- good OOP criticism and OOP problems (The emperor
has no clothes!). Contains a very good collection of links
External Links
USENIX - Invited Talk Objecting to Objects
Object Oriented Programming (OOP) is currently being hyped as the
best way to do everything from promoting code reuse to forming lasting
relationships with persons of your preferred sexual orientation. This
paper tries to demystify the benefits of OOP. We point out that, as
with so many previous software engineering fads, the biggest gains in
using OOP result from applying principles that are older than, and largely
independent of, OOP. Moreover, many of the claimed benefits are either
not true or true only by chance, while occasioning some high costs that
are rarely discussed. Most seriously, all the hype is preventing progress
in tackling problems that are both more important and harder: control
of parallel and distributed applications, GUI design and implementation,
fault tolerant and real-time programming. OOP has little to offer these
areas. Fundamentally, you get good software by thinking about it, designing
it well, implementing it carefully, and testing it intelligently, not
by mindlessly using an expensive mechanical process.
Software
Development Online Four-Wheel Drive, Garbage Barges and Objects. June
2000.
Table of Contents
Object-oriented design is supposed to make our
software more robust and resilient, yet we still see systems that are
as fragile as their procedural ancestors. Are developers adopting aggressive
practices because they think the technology will protect them?
by
Steve Adolph
Object-oriented software development practices are
supposed to make our software more robust and resilient to change. Yet
we still see systems designed using these practices that are as rigid
and fragile as their procedural ancestors. Adding new features still
causes a cascade of change throughout the software and often results
in the creation of new bugs. It wasn’t supposed to be this way. Many
software development organizations invested heavily in object technology,
expecting something better. They expected the changes to be localized
and the software to be resilient to bugs. Is it possible that object
technology is the software equivalent of four-wheel drive? Does it provide
greater control and safety, only to be abused by programmers who develop
more aggressively because they think objects will protect them?
The problem is, today’s object-oriented software often
lacks modularity. The systems are just as hard, if not harder, than
their procedural brethren to modify or enhance. What appear to be simple
one-line fixes end up taking three weeks to implement. Simple alterations
cause a cascade of sympathetic changes to wash over the entire system.
It is my argument that we rely too heavily on object
technology’s safety features and ignore good software development practices
such as planning, design, review and assessment in the name of expediency.
We hope that at least one of our four driving wheels will somehow grab
and prevent us from losing control on the slippery roadway we have been
driving along at a reckless speed.
Re Beware of C Hackers -- A rebuttal to Bertrand Meyer by Robert Martin
(3 Jul 95) Meyer makes a clear difference between C programmers and
C hackers. He even states that he expects everyone to know C (at least back
in '95, when they had that discussion), he knows C himself very well and
he points to the fact that some C hackers are not well-suited for the creation
of huge, complex systems that must be reliable because they (=the hackers)
chase for runtime and memory efficiency and lose sight of the more important
points maintainability, readability etc. I think he has a point there. He
does not use the term 'C hacker' for someone who is a good programmer and
uses C, as you might assume.
I have recently acquired a copy of Bertrand Meyer's
new book "Object Success". I would like to say that I have a great deal
of respect for Meyer. Moreover, I have read many good things in this
book so far.
However I take extreme exception to something he wrote
in this book. On page 91 he writes the following which is included in
its entirety. I will comment on it afterwards.
PRUDENT HIRING PRINCIPLE: Beware of C hackers.
A "C hacker" is somewone who has had too much
practice writing low-level C software and making use of all the
special techniques and tricks permitted by that language.
Why single out C? First, interestingly enough,
one seldom hears about Pascal hackers, Ada hackers or Modula hackers.
C, which since the late nineteen-seventies has spread rapidly throughought
the computing community, especially in the USA, typifies a theology
of computing where the Computer is the central deity and its altar
reads Efficiency. Everything is sacrificed to low-level performance,
and programs are built in terms of addresses, words, memory cells,
pointers, manual memory allocation and deallocation, unsafe type
conversions, signals and similar machine-oriented constructs. In
this almost monotheist cult, where the Microsecond and the Kilobyte
complete the trinity, there is little room for such idols of software
engineering as Readability, Provability and Extendibility.
Not surprisingly, former believers need a serious
debriefing before they can rejoin the rest of the computing community
and its progress towards more modern forms of software development.
The above principle does not say "Stay away from
C hackers", which would show lack of faith in the human aptitude
to betterment. There have indeed been cases of former C hackers
who became born-again O-O developers. But in general you should
be cautious about including C hackers in your projects, as they
are often the ones who have the most trouble adapting to the abstraction-based
form of software development that object technology embodies.
There is only one word that can accurately describe
these sentiments. That word is biggotry. I don't like to use a word
like that to describe the words of someone who is obviously intelligent.
Yet there is no other option. The words he has written create a class
of people whom he recommends ought to be hired, only with caution.
Who are these "C Hackers"? Has Dr. Meyer given us
any means to identify them? Yes.
A "C hacker" is somewone who has had too much practice writing low-level
C software and making use of all the special techniques and tricks
permitted by that language.
What possible recourse can a manager have but to look
with prejudice against anyone who happens to put "C" on their resume.
By associating "C" with "Hackers", Dr. Meyer damages everyone who uses
that language, whether they are hackers are not. In effect, Dr. Meyer
is making a statement that is equivalent to: "Beware of the Thieving
Frenchmen."
What is a hacker? A hacker is someone who writes computer
programs without employing sound principles of software engineering.
Someone who simply throws code together without thought to structure
or lifecycle.
Certainly there are hackers who use C. But there are
Hackers who use every language. And in this, Dr. Meyer is quite negligent,
for he says nearly the opposite:
Why single out C? First, interestingly enough, one
seldom hears about Pascal hackers, Ada hackers or Modula hackers.
This may or may not be true, I have no statistics.
However, *if* it is true I would be willing to bet that the reason has
something to do with the difference in the number of C programmers as
compared to Ada, Pascal and Modula programmers. If there are 20 times
as many C programmers, then there are probably 20 times as many C hackers.
My point is that C does not predispose someone to
be a hacker. And that the ratio of C hackers to C programmers is probably
the same as Ada hackers to Ada programmers.
So Dr. Meyer casts aspersions upon all C programmers
while giving amnesty to Ada, Pascal and Modula programmers. According
to Dr. Meyer, it is only, or especially, the "C hacker" that you must
be wary of. He does not say: "Beware of Hackers", rather he says: "Beware
of C hackers." And this is simply biggotry, the segregation and defamation
of a class of people based only upon the language that the program in.
And why this malevolence towards C? One can only conjecture.
He offers reasons, but they are nearly mystical in their descriptions.
Consider:
C [...] typifies a theology of computing where the
Computer is the central deity and its altar reads Efficiency.
Dr. Meyer does not provide any proof, or even a scrap
of evidence to support this rediculous claim. He states it as fact.
This is an abuse of authority. What every author fears, (or ought to
fear in my opinion) is that he cast his own opinions as unalterable
truth. Yet, rather than proceed with trepdiation, Dr. Meyer seems to
glory in his deprication of C. His writing becomes almost frenzied as
he attacks it.
Everything is sacrificed to low-level performance,
and programs are built in terms of addresses, words, memory cells,
pointers, manual memory allocation and deallocation, unsafe type
conversions, signals and similar machine-oriented constructs. In
this almost monotheist cult, where the Microsecond and the Kilobyte
complete the trinity, there is little room for such idols of software
engineering as Readability, Provability and Extendibility.
Here he names every evil trick and bad practice that
he can, and ascribes it all to C, as though no other language had the
capability of supporting bad practices. He also claims that C programmers
religiously follow these bad practices as the sacrements of their religion.
These statements are extremely irresponsible. There
is no basis of fact that Dr. Meyer has supplied for these extreme accusations
and defamations. Dr. Meyer has a right to dislike C if he chooses. But
his vehemence against its programmers is unreasonable, and unreasoned.
It is easy to refute nearly all of Dr. Meyer's claims
regarding C programmers. I have known many many C programmers who were
very concerned with good software engineering. Who considered the quest
for ulimate efficiency to be absurd. Who were careful with their programming
practices. In fact, I have never met a single C programmer who fits
the description that Dr. Meyer ascribes to them all.
In my opinion, he is very wrong, not only professionally,
but moraly. And he owes the industry an apology and a retraction.
Critique of OOSC2 by Bertrand Meyer
Introduction
I have been doing custom business programming
for small and medium projects since the late 1980's. When Object Oriented
Programming started popping it's head into the mainstream, I began looking
into it to see how it could improve the type of applications that I
work on.
Note that this excludes large business frameworks
such as SAP, PeopleSoft, etc. I have never built a SAP-clone and
probably never will, as with many others in my niche.
I have come to the conclusion that although OO may help
in building the fundamental components of business applications, and
even the language itself, any minor organizational improvement OO adds
to the applications themselves are not justified by the complexity,
confusion, and training effort it will likely add to a business-oriented
language. In other-words, OO is not a general-purpose software
organizational paradigm, and "selling" it as such harms progress in
the alternatives.
I have used languages where the GUI, collections handling,
and other basic frameworks are built into the language in such a way
that OO's benefits would rarely help the language deal with them. It
is also my opinion that the language of base framework implementations
probably should not be the same as the application's language for the
most part. For example, most Visual Basic components are written in
C++. Meyer seems to have more of a one-size-fits-all view of languages
and paradigms than I do.
For a preview of my opinions and analysis of
this situation, may I suggest the following links:
Although the stated niche is not representative of
all programming tasks, it is still a rather large one and should not
be ignored when choosing paradigms.
Here is a quick summary of my criticisms of OOSC2:
- Meyer tends to build up false or crippled representations
of OO's competitors, which distorts OO's alleged comparative advantages.
- A good many of the patterns that OO improves
are not something needed directly by the stated niche, except in
rare cases.
- We have very conflicting views and philosophies
on data sharing.
Note that although my writing style has at times been
called sarcastic and harsh, please do not confuse the delivery tone
with the message.
Also note that I am not against abstraction
and generic-ness. I am only saying that OO's brand of these is insufficient
for my niche.
Critique
of the Object Oriented Paradigm: Beyond Object-Orientation. By Shajan
Miah Date: 14th May, 1997
C++ Critique
For a more or less reasonable sample of OO advocacy one
can read
Object
Orientation: The Importance of Being Earnest
Copyright © 1996-2009 by Dr. Nikolai Bezroukov.
www.softpanorama.org was
created as a service to the UN Sustainable Development Networking Programme (SDNP)
in the author free time.
Submit
comments This document is an industrial compilation designed and created
exclusively for educational use and is placed under the copyright of the
Open Content License(OPL).
Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made
for educational purposes only in compliance with the fair use doctrine.
Disclaimer:
- The statements, views and opinions presented on
this web page are those of the author and are not endorsed by, nor do they necessarily
reflect, the opinions of the author present and former employers, SDNP or any other
organization the author may be associated with.
- We do not warrant the correctness of the information provided or its
fitness for any purpose
- In no way this site is associated with or endorse cybersquatters
using
the term "softpanorama" with other main or country domains (e.g. softpanorama.com) with
bad faith intent to profit from the goodwill belonging to
someone else.
Last modified:
October 11, 2009
Empty Java constructor [Jason Dufair] November 16, 2004 10:08:33 EST
I'm on a team doing Java right now. I see a lot of empty Java constructors. Being a Smalltalker making a living doing Java, I figured they must be there for a reason. Come to find out an empty constructor just calls the super's constructor. As if it weren't there in the first place. Whee!