We're building a large application with complex logic, which is composed of modules. I used to build larger scale methods of simpler methods, for instance,
# fig. 1
package Foo;
sub highlevel {
my ($self, $user, $event) = @_;
my $session = $self->get_session($user);
my $result = $self->do_stuff($session, $event);
$self->save_session($session);
return $result;
};
(this is simplified of course). Results are returned, exceptions are thrown, everyone's happy.
Now, we're making a move to AnyEvent. My module is NOT the uppermost level, so I can't do just
# fig. 2
my $cv = AnyEvent->condvar;
# do stuff
return $cv->recv;
Most AE modules I've seen so far work like this:
# fig. 3
$module->do_stuff( $input,
on_success => sub { ... },
on_error => sub { ... }
);
So I'm done rewriting the lower-level methods and tried to proceed with highlevel() and...
# fig. 4
package Foo;
sub highlevel {
my ($self, $user, $event, %callbacks) = @_;
my $done = $callbacks{on_success};
my $error = $callbacks{on_error};
$self->get_session( $user,
on_error => $error,
on_success => sub {
my $session = shift;
$self->do_stuff( $session, $event,
on_error => $error,
on_success => sub {
my $result = shift;
$self->save_session( $session,
or_error => $error,
on_success => sub { $done->($result); }
);
}
);
}
);
};
Not exactly beautiful. I call it "the Infinite ladder".
Now the next thing I could come up with was an ad-hoc state machine where highlevel() is broken up into _highlevel_stage1(), _highlevel_stage2() etc. But that doesn't satisfy me as well (it's unmaintainable, and thinking of good names instead of stageXX gives me headache).
We're already looking into a full-blown state machine to drive the whole app, but having to add a transition for every interaction looks a bit too generous to me.
So the question is: What are the best practices for writing modules that implement business logic (fig. 1) for running within an AnyEvent app (fig. 3)?