More Frustration With the State of OO

Ovid on 2008-11-29T21:58:16

From Encapsulation, Inheritance and the Platypus effect:

It's common practice to develop extensive in-house class libraries. However, when one examines the code in a typical class library, one finds a lot of excess generality and functionality which not only makes the code inefficient, but cluttered and hard to read, or even to debug.

The article itself is short, clear, and helps to make clear that OO code is often a dangerous beast. Please read it before continuing.

I find myself growing more disenchanted with OO as I go along because programmers are simply abusing it. One key thing that Schwern likes to remind us is that code should be skimmable. I really, really wish more programmers would understand this. I often go into projects and find that I cannot make heads or tails of their code not just because the work is complicated, but multiple levels of "abstraction" and "refactoring" have rendered code impenetrable.

Frankly, I'm not a stupid programmer, but I confess that there are many programmers who do a better job understanding complex systems than I do. Part of that is because we don't try hard enough to make our code understood. What I like to cleanly write the code the programmer's likely to look at first and then if there are gory bits, hide them lower down. The programmer who really needs to know will dig down, but at the higher level, well-named variables and functions, even if they take a bit longer to write out, are a win. Consider, for example, my Test::Kit module. This module let's you list several test classes in an import list and compose all of them together and export their test functions en masse to your namespace. This makes it easy to build custom testing modules. There are complicated bits, but here's the import method:

sub import {
    my $class = shift;

    my $callpack = caller(1);

    my $basic_functions = namespace::clean->get_functions($class);

    my ( $packages, $features ) = $class->_packages_and_features(@_);
    $class->_setup_import($features);

    foreach my $package ( keys %$packages ) {
        my $internal_package = "Test::Kit::_INTERNAL_::$package";
        eval "package $internal_package; use $package;";
        if ( my $error = $@ ) {
            Carp::croak("Cannot require $package:  $error");
        }

        $class->_register_new_functions( 
            $callpack,
            $basic_functions, 
            $packages->{$package},
            $package,
            $internal_package,
        );
    }
    $class->_validate_functions($callpack);
    $class->_export_to($callpack);

    {
        # Otherwise, "local $TODO" won't work for caller.
        no strict 'refs';
        our $TODO;
        *{"$callpack\::TODO"} = \$TODO;
    }
    return 1;
}

That's not perfect (_register_new_functions is particularly heinous), but at the high level, I made it easy to read because you need to understand the logic flow. And this is alpha code that I just threw together. You could contrast this with a class I was trying to understand the other day which had a bunch of Moose attributes declared, a couple of methods, inherited from three different classes and used two roles! You couldn't tell what the class did. The multiple inheritance (each of the parent classes in turn inherited from other things) and the two roles made it a mess to try and figure out where any functionality was. It's stuff like this which leads programmers to write articles like the one I linked to.

This style of coding is pervasive enough that I am beginning to think that OO encourages it. Take, for example, Mason and Template Toolkit. I've used both extensively, but Mason, while being lovely and powerful, makes it seductively easy to push application/business logic into the view layer (sorry Dave!). It makes this so easy that every shop I've worked at which makes extensive use of Mason has problems with this. I don't see those problems nearly as often with Template Toolkit.

So is OO, like Mason, a fantastic idea which nonetheless is so easy to abuse that it ultimately leads to more problems than it solves? I won't say this is true, but I suspect it. Unfortunately, so many have simply assumed the superiority of OO that trying to gain any traction here will be difficult, at best.

And for the record, I started whingeing about whether OO sucks back in 2002.


But everyone does it with TT too!

autarch on 2008-11-30T00:51:10

At least, the two places I've worked at that used TT (Socialtext and LiveText) both had gobs and gobs of logic in the templates. And TT's crippled language made dealing with this much harder than dealing with the same thing in Mason, since at least with Perl you have a sane language to use.

People keep saying TT helps with this problem, but I have yet to see a good example of using it cleanly.

Re:But everyone does it with TT too!

abw on 2008-11-30T11:50:12

I agree that there are people who abuse TT by putting application logic in templates. But given enough rope, there will always some people who end up hanging themselves, or at best, tripping themselves up.

TT's language is deliberately "crippled" because it's a presentation language, not a programming language. And the fact that TT makes it so trivially easy to write and use a plugin means that no-one should ever be doing "programming" using TT.

But they do :-(

However, that fact that some people don't use the tool properly doesn't imply that the tool is broken (although I accept that some of the blame may lie at the feet of the tool designer for not making it's intended use more obvious, or fitting it with a suitable anti-hanging device).

But the underlying principle of separation of concerns is sound. The skill is in knowing how far to go in separating a system without reaching the fragmentation ceiling, where the overhead incurred by having something split into a jillion files outweighs the benefit. This is not always simple or straighforward, but then neither is programming in the large.

Sometimes doing it "all in one" in the style of PHP or Mason is the right way to do it, particularly if you're not bothered about being able to re-skin the application, or splitting the workload between designers and programmers. But it's not the right way to do it if you are.

Re:But everyone does it with TT too!

Aristotle on 2008-11-30T13:49:40

I think the TT has the fault lines at all the wrong places. Templates have three classes of complexity: static text (obviously a large part of the output); simple interpolation and undemanding logic (loops, conditionals; very common as well); and then hairy complicated formatting stuff with lots of little conditionals and munging and all sorts of wiry bits poking out of the data (common, but only in small amounts). The TT language is far more powerful than necessary for the simple logic but not enough to handle the complicated stuff well

Trying to solve the problem in Perl is annoying because you must either break out of the templates and put the code in some other place within your application (and this is a layer of abstraction that most models don't conceive of, so it is organisatorially awkward to get the right idea for where it goes) or use PERL blocks which live in this weird limbo of being more like a TT dialect that is based on Perl, than being Perl. (You have no easy access to call other blocks like subs, you have to use the TT stash, etc -- it's not like writing normal Perl.)

Let's not forget that templates are display logic, and the same concerns apply as to any other kind of logic: you should not repeat yourself etc. Display logic needs the same facilities for abstraction as business logic.

So my conclusion is that the template language should be far less powerful than the TT language, leaving anything non-trivial to be handled by the host language through good integration (eg. exposing template blocks as easily callable methods from inside the host language or such), while making it extremely difficult to generate output directly from the host language side.

Because the upshot is that any errant business logic that ends up in the template will still be somewhat decoupled from output generation, so that it can be factored out after the fact without too much pain. After all, let's be honest with ourselves: when time is at a premium, we all put business logic in the template with a FIXME and move on. Or sometimes we do not realise at the time that what we are writing is actually not a display concern. Better to plan ahead for what will inevitably happen and make it easy to recover from it, than try to prevent it.

TT's design does not.

(Mind, I might have come to disagree with its design, but I still admire its scope and execution; it's a tremendous piece of work.)

Re:But everyone does it with TT too!

chromatic on 2008-12-01T18:28:37

Display logic needs the same facilities for abstraction as business logic.

Some days, it seems that only four people in the world understand this. (The third is Avi Bryant.)

Re:But everyone does it with TT too!

pudge on 2008-12-05T01:33:16

I am convinced there's no such thing as a perfect separation of application and presentation logic.

That said, we've done quite well with TT in Slash over the years.

Proximity of concern?

davehodg on 2008-11-30T01:09:38

Maybe it's time to start keeping code that does related stuff, you know, like grabbing from a database and prepping it for desplay, *together*! So when it needs to be tweaked, everything is close by not in 3 or more separate files?

Nice article!! I'd like to see more follow up

dearfrankg on 2008-11-30T02:47:22

I think you bring up an excellent point. I agree that OO can bring in complexity in the cases that you specify. But I would not write off OO in its entirety. I'm very interested in seeing what many other programmers think about this.

Thanks -frank

Just another kind of pasta

Aristotle on 2008-11-30T13:51:58

You are talking about ravioli code.

Re:Just another kind of pasta

jplindstrom on 2008-11-30T17:34:29

I think that node nicely illustrates what's going on here.

Lots of insightful comments, as is usually the case with the c2 wiki.

Square peg...round hole.

sigzero on 2008-12-01T16:25:38

A problem that I see is when OO is pushed to solve every problem.

State

zby on 2008-12-01T23:58:07

One idea - OO makes it easier to cope with state - and this means people write more state-full apis where pure procedural languages would produce more stateless (functional) apis. And state is always more difficult to reason about.

I don't want to single anything out - but what comes to mind is a hypothetical encoding API - that used to be of the form: my $encoded = encode( $from, $to, $what ); And then it became more OO with: my $encoding = Some::EncodingLib::new( $from, $to ); my $encoded = $encoding( $what );