Monday, September 13, 2010

Push libraries vs pull libraries

Ever get the feeling there's something very wrong with the library you're using, something a little too framework-y about it, but you can't quite put your finger on the problem? My pet theory: it's often that the library is structured to push its functionality to client code, rather than having client code pull functionality that's needed.

In a push library, the library pushes the functionality to clients, who then override how certain steps are performed. In this model, client code can only change overall program behavior by overriding or changing code in places predetermined by the library. A consequence is that overall control flow is rigid - it is mostly fixed by the library writer. As push libraries develop over time, they accumulate more and more options and hooks in different places to handle all the different control flows users want. The result isn't pretty. But even with all the complexity that accumulates, the library never seems to do exactly what you want it to.

In contrast, a "pull" library puts client code in control. Client code makes all decisions regarding control flow and the library provides control flow combinators appropriate for the domain. Not only is this way more flexible and expressive (the client can construct control flows not envisioned by the framework designer), it's also much more pleasant for the client programmer. The client programmer now just has to understand the primitives and the control flow combinators he's using for his particular application, and nothing more.

Libraries written in the pull style are more like combinator libraries and tend to make use of higher order functions, closures, etc. Perhaps this explains why this style isn't very common in languages like Java and why the big "frameworks" in these languages are often bloated monstrosities nobody likes using.

7 comments:

Eric said...

I had the same idea recently without being able to give it a good name. One "cultural" explanation for that difference might be the background of the library implementor: OO people would tend to use some kind of Template pattern while FP people would use combinators.

Luca Bruno aka Lethalman said...

I totally agree, except for performance reasons. Push libraries tend to be more optimized as they try to not keep "state" while pull libraries have to keep more state for further client code requests. For example SAX and DOM simple implementations. It's obvious that SAX is faster though you don't have as the same control as with a DOM implementation. For normal usage instead, when you want design over performance, pull libraries are they way to go.

Anonymous said...

Is this not the basic division between "normal" libraries and software frameworks? At least, that's exactly how I remember it taught. Framework forces client code to be in predefined form but specialized behavior.

But the terms push and pull are new to me, and indeed feel natural.

Anonymous said...

It's a matter of who drives the car. In pull, you drive, in push, it's driven by the framework. Each has its merit.

Paul Chiusano said...

@Anon1 - 'framework' sort of has that connotation for me too but I'm not sure it's a standard meaning.

@Anon2 - I don't think there's anything inherently wrong with a 'push' library. The problem is when a library just ends up a 'push' library by accident, rather than as a result of a deliberate design decision.

Rafael de F. Ferreira said...

It is a standard meaning for frameworks vs. libs. See [1], for instance.

What you describe is similar to the IoC pattern (the original, not dependency injection), also called The Hollywood Principle.

[1] http://www.google.com.br/search?q=Ralph+E.+Johnson.+Components,+Frameworks,+Patterns

Alexander Poluektov said...

Putting it to extreme, every time you use higher-order function is "push" model (though on smaller scale): control flow is fixed by HOF, you just override certain step that you are interesting in.

Where am I wrong?