OO-BS Watch

A critique of sloppy OOP promotion in the media and books

Updated: 4/22/2002


It is my opinion that OOP has grown "popular" primary because of the "demo power" of its cliches. These cliches are in the form of both words and coding examples. On closer inspection, these cliches often deviate from the problem space of the real world, or assume poor procedural programming techniques and/or limitations of specific languages. This page looks at some of these examples found in books and the media and dissects them in ways that the author skipped for whatever reason.


1. Generic Menu System

Mark Lutz in "Programming Python", O'Reilly Press, 1st. Ed., ISBN 1-56592-197-6

In this book, Mark likes to brag about OOP using poorly conceived code examples. I expect a more balanced, or a least a better thought-out approach from O'Reilly than found in "Learn X in 13 Days" kinds of books. But not this time. (The second edition has changed significantly, so the criticisms here may not apply to it.)

The most glaring example given is the menu management example which uses two different "types" of menu data structures: a dictionary and a list. An example IF statement based on these two types can be found on page 218 (example 9-6).

It seems the author went out of his way to implement these as procedurally different as possible. For one "type" he uses a ")" the include numbers next to each menu option, but not the other. in other words, the output being different is (or should be) orthogonal (unrelated) to which array type is being used.

Second, in one he uses an exception handler to handle non-found menu choice options being input, but the other uses something roughly equivalent to an "if not found..." arrangement.

It is bad practice to use exceptions for this kind of detection anyhow. Exceptions should be used for uncontrollable environmental factors like low memory, lost communication connections, etc., and NOT user input validation. Users pressing the wrong key should be expected, not an "exception".
It would be much easier to factor out the similarities of the handling of each array type if issues not related to the individual structures were either eliminated or dealt with independently of array type. The code may then resemble (pseudo-code):
  if arrayType is X
    ....
  else    // type Y
    ....
  end if
  ....
  if displayFormat is B
    ....
  end if

Thus, Mark's claim that OOP "eliminates redundancy" (page 219) does not hold water.

Further, one should stick with one structure to hold the menu information in my opinion. If a menu component user has to translate from one structure to another first, then so be it. This allows the code to focus on handling menus rather than try to deal with every different "type" of collection that can be thrown at it. Even if we use textbook polymorphism for each collection type, one still has to write new "drivers" or "handlers" for each collection engine/format. Most of the code could end up being devoted to converting or adapting collection types if we don't get out of that business soon. (One may also use a delimited string to represent/store menus, I would note.)

Move the burden of translation to the component user. If you need to make a set of adapters and converters, then so be it. Under most circumstances a given programmer or team will use one collection type for all their menus to begin with.

However, a bigger-scale problem here is the lack of interface consistency between Python's different structures. The requirements of a given collection change all the time in the real world. It creates too much code-rework to change from one structure to another if the interfaces are not consistent.

Languages like Smalltalk partially solve this problem (more-or-less) by using the same verbs/commands/interface for the different collection implementations. Thus, if you have to change the collection engine, you don't have to overhaul your code. This applies to procedural as well as OOP. After all, you cannot directly polymorph if the interfaces are different for each "type". (One definition of polymorphism is, "Same interface, different implementation.")

If one is truly interested in making a generic menu system, then one should give up the idea of using a simple array-like structure anyhow. (I avoid arrays because collections can grow and change like the wind. See Arrays Can Be Harmful).

Lacking in Mark's design are items like description-independent short-cut keys and the ordering. Dictionary arrays technically don't have any sort order, and have only 2 columns. We need at least 3 columns and an ordering. Thus, I suggest using a table. Example listing:

Menu Options Listing
Description Shortcut
Char.
Ordering Function
Search S 1 Search()
Browse B 2 Browse()
Customize C 3 Options()
Help H 4 Help("main")
Exit E 5 Exit(1)
We don't have to put the functions in the menu table. They could also be in a regular if or case statements. This may make our table more generic since many languages don't support dynamic function/method execution.

In GUI menus, often one specifies where the shortcut character goes via some marker in the description such as an asterisk or a backslash. However, for character console menus, sometimes one may want to use numbers instead of letters as the short-cut keys. Thus, making it generic across UI paradigms may be rather tricky. But, this is not unique to menu interfaces. I suppose we could use the Ordering field if we want numbers, but it may contain decimals for inserted items. Having it auto-number is another possible alternative, but reduces control. For example, a console-based menu might use numbers for all options, but zero for all exit commands as a convention.

Some will say that tables are "too bulky" to serve as menu holders. Just because Oracle is too bulky does not mean that all table engines are bulky. Relational table engines used to fit on CPM machines with around 30K of RAM. (True, they didn't parse SQL, but SQL is not a prerequisite for tables. Table options are currently are indeed somewhat sparse, but this is not the paradigm's fault, but the fault of fashion and hype.)

"Black Art"

Lutz makes an interesting, and revealing comment on page 254.
"...we did have to change Menu [class] radically. Menu was completely restructured to use the hooks....

In more complex programs, restructuring classes to fit in with new method protocols like this might be a costly transformation. So how can we know what sort of shape our class hierarchies should take? Of course, large frameworks are usually designed ahead of time: it helps to know your requirements early on......

....But good object-oriented framework design is still something of a "black art"; it gets simpler with practice." [Emphasis added]

OOP is often touted as being more "change-friendly". If it is so change-friendly, then why does one need so much more design up-front? He admitted that he had to overhaul his menu framework to handle new requirements. See Global Modeling for my speculation on this.

Regarding his "black art" comment, I completely agree. However, why is he saying that OOP is "better" if it is (still) a black art? Procedural/relational modeling, on the other hand is not a black art. It is admittedly not 100 percent defined, but I claim that different skilled p/r proponents will tend to have more consistent designs than different OO practitioners. In other words, there is more consistency in p/r methodologies. (Or, at least the differences are easier to catalog and articulate.)

OOP should graduate into a gray art instead of a black art before being shoved down the industry's throat. Keep it inside the lab until it graduates to gray.


2. Over-active Auto-Propagation

This is described on the Java Criticism page.


OOP Criticism | Main | Web Replies