2

Recently reading a lot materials on Reactive Programming, one thing frequently mentioned is the 'PUSH' versus 'PULL' style of application. Event driven ( Reactive programming )

Some of the authors say that both these styles have their area of applications, but aren't most application domains we are trying modeling are all changing rapidly in real world and thus event driven is more appropriate?

And why we started from the 'PULL' approach and now turning into 'PUSH' approach, are there specific reasons causing the change?

5

It can be hard to reconcile push models with separation of concerns. Loose coupling, generally seen as good practice, means designing the components of your system with minimal dependencies and the least possible knowledge of the overall structure and other components. Push semantics either break this (if implemented simplistically) or add significant complexity (c.f. the observer pattern); either way, at least one component needs good knowledge of all of its dependants to implement the push.

Maintaining a loose coupling between components in an event-driven system requires a corresponding increase in the complexity of the overall system and can, perversely, tightly couple each component to the semantics of the event model. This can make it hard to extend or alter the model, so that the system designers find they have simply swapped one set of constraints for another. Pub/Sub mechanisms (e.g. Message Queues) are very prone to this but it is a general problem.

For simple real-world examples look at e-mail. SMTP mail delivery is a push model; it is very robust, but has proved very difficult to extend to deal with unforeseen scenarios (spam would be the classic example, but also look at the problem that ETRN and ATRN were developed to address, and how partially and inconsistently those were adopted). Look at how much more complex SMTP is than POP or even IMAP (both essentially pull models) and how much more work had to go into making it resilient.

Historically, the complexity surrounding push mechanisms made them harder to implement. Our capacity for this complexity has increased over time. However, event-driven systems have their own pitfalls.

I would question your assertion that all the domains we model are changing rapidly. The context in which we use them may become more complex (and richer), but some problems stay simple. Loose coupling is one of the ways we limit the necessity to change individual components as the system around them changes.

1

Even today, there are some areas, where you have to pull data, because a push option is simply not available to you. As far as those that I know of, these have been around for a long long time, such that early systems may have simply accepted from those that pull is the way to go.

Let's start with a very simply example: you want to monitor a folder on your harddrive and do something whenever a new file appears in that folder. In modern languages, you are offered abstractions that allow you to register a sort of listener, which will be called once a file is detected. Earlier, when these abstractions were not yet available, you had to check for yourself, by continuously pulling the folder information and check for a new file.

While this may sound old to you, the problem appears again in a modern setting, when you go from a simple folder to f.ex. a source code repository. Most of us have a CI server like Jenkins running, and lo and behold, how does it get to know that someone commited something to the project's SVN repository? It pulls data from the repo every x minutes (or whatever is configured for the pull interval). As usual, we could invest some effort to move this towards a push-style implementation, but you'd have to find something that works for all code repository implementations, which is not that simple after all.

Finally, in the embedded area, the pull approach has been predominant for a long time and will not go away anytime soon either. When you have simple hardware that you can access, you will often end up having to pull its data and check for changes. Only higher-level hardware elements, like a CPU, can provide abstractions over that. On the lowest level, however, you simply have 0 and 1, power off or on.

For this reason, I assume that early software development, which was still close to the hardware level, was influenced by having to pull data from hardware elements. I still know lots of embedded programmers, which still write endless polling loops that just keep getting the latest sensor data in order to do stuff whenever a significant enough change happened. So writing pull-based code just seems to come naturally from this perspective.

What we have done in the past, though, was to add an abstraction layer on top, which gave us the insight that a push approach is much better in many respects. Hence, we continously looked for ways to move from one to the other. People realized that if a folder watch can be implemented such that all watchers are simply notified via push-style approach, then our resulting software that we have to write gets much easier, hence, cheaper and faster to market.

To answer your question on appropriateness: if you already have a push-style interface available for use, then most likely it's the better alternative. But there are cases, where you don't have such an interface yet and are left with but two options: either create the abstraction level yourself, or go straight for the pull approach. Appropriateness in general depends on your actual context and some rare cases (see above) exist, in which your only feasible way is to pull.

  • Even in the embeded area, I think the push/pull coexist early enough. as far as I know, the POLL is accompanied with the INTERUPTION approach. And my take is that if we neglect the cost of implementation, PUSH is always better than pull. – zinking Nov 20 '13 at 1:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.