Decoupled Design For Async Http Request
Solution 1:
When you want to compose computations that may involve a lot of asynchronous steps, there aren't any really good options that will let you write super-clean code.
Of the options that are available -- event-driven design, continuation passing, monads, etc., monads are the modern choice, because they let you write asynchronous code that has the same basic structure as the equivalent synchronous code. It's still won't be very pretty code, but at least it's built of the same functional blocks.
In JavaScript the asynchronous monad is Promise, and in Java it's CompletionStage/CompletableFuture. This is what your class looks like in that style (I'm assuming all the calls to client
are async and return a CompletionStage):
DeviceClient client;
DeviceInfoMgr deviceInfoMgr;
public CompletionStage<Void> registerDevice(String name) {
return checkIfNameTaken(name)
.thenCompose( (unused) -> client.createDevice())
.thenCompose(deviceResponse -> {
Device device = deviceResponse.getBody();
device.setName(name);
return client.updateDevice(device);
}).thenApply(unused -> {
deviceInfoMgr.set(name);
return (Void)null;
});
}
private CompletionStage<Void> checkIfNameTaken(String name) {
return client.getAllDevices()
.thenCompose(devices -> {
for(Device dev : devices) {
if(dev.getName() == name) {
//I use a helper for this
CompletableFuture<Void> err = new CompletableFuture<>();
err.completeExceptionally(new DeviceNameTakenException());
return err;
}
}
return CompletableFuture.completedFuture((Void)null);
});
}
You see that it has the same methods that it had before, and those methods do the same thing they did before, and they do it with the same sequence of operations... but now they return a CompletionStage, indicating that they may run asynchronously and the results may depend on things that aren't done when those methods return.
Post a Comment for "Decoupled Design For Async Http Request"