| This is just lipstick. The real problem is branching - when reading code I have to think through two conditional cases. In this particular example (where you have to validate a client request), I don't see a way out of branching. However I don't think this post has produced the ideal: JsonParser.parse(request.getBody())
.flatMap(Validator::validate)
.map(ServiceObject::businessLogic)
.flatMap(JsonGenerator::generate)
.match(l -> HttpResponse.internalServerError(l.getMessage()),
r -> HttpResponse.ok(l));
The problem with this is that I have to think through branching all the way through the data flow. However the only function that should branch is validate, to prepare the request to meet the preconditions of the rest of the data flow, all of which should be non-branching.In other words, I should be able to read this part of the data flow without thinking of branching: (generate-json (business-logic req))
So this I believe is objectively better: (if (valid? req)
(generate-json (business-logic req))
(generate-json (errors req)))
Yes, I've used an if. (If we don't like ifs we can easily get rid of it, of course - but again our problem is branching not the if.)Why is this objectively better? Because we now have to think about branching wrt to the validation function ONLY. We've minimized where branching matters, and that's solving the core issue. |