I'm using an Java Servlet (with embedded Jetty, no Spring, no frameworks) and I'm adding asynchronous processing and caching to it. The exact implementation is irrelevant to this question and it's not very Java-specific. My problem is the overall code structure, which before the additions looks like this pseudocode
void service1() {
addFixedHeaders();
try {
service2();
} catch (MyException e) {
...
} catch (AnotherException e) {
...
}
addMoreHeadersUnlessAlreadySet();
writeResponse();
}
void service2() {
addCorsIfNeeded();
if (needsForwarding()) {
doForwarding();
} else {
service3();
}
}
void service3() {
if (hasEtag() && isStillValid()) {
serveMotModified();
} else {
service4();
}
}
Basically, it's a sequence of calls service1 -> service2 -> service3 -> ...
with some pre- and postprocessing (kind of inline FilterChain), where some calls are conditional. I used to be satisfied with it.
However, adding caching (I mean serving 200 response from server cache rather than serving 304, which fits nicely) requires changes in multiple methods. This gets complicated by caching static and dynamic content differently and using the same cache also for avoiding compression. This makes the code rather ugly, while I'd prefer some functional style like
return cache.getOrCompute(key, key -> someComputation(key))
Independently, as an experiment, I've also added asynchronous processing (which is needed for some requests only). This required a major rewrite and lead to something exceptionally awful (and would get even worse when caching was added). I'm thinking about something like this chain
void service1() {
process1();
if (isSimple1()) {
shortcut1();
} else if (wantsAsync1()) {
callAsync(service2);
} else {
service2();
}
}
when most methods will have only some parts. What I dislike here, is that there's no possibility to handle exceptions in a single place (like my in first service1
. It also forces me to move the postprocessing to some service99
which doesn't make obvious, that it always happens.
I wonder, if there's a suitable pattern, something like promise chaining or whatever (I'm not looking for a library though I don't insist on reinventing the wheel). Something simple, yet flexible, so that further additions fits nicely in the pattern.