A different syntax for enforcing business requirements
Have you ever had to implement some tricky business requirement that involved on a multitude of conditions? Sometimes, the requirement might actually be easy to express in human language, but when it comes to code, you'd have a hard time expressing it in a way that's easy for other humans to understand.
For instance, say you have a fictional school portal where students can apply for financial aid. You're given a requirment:
Students who have a GPA less than 2.0 should not be permitted to apply, except they are in their final year or have a medical condition.
Here's one way you could write this:
if ($student->hasGpaLessThan(2.0)) {
if (!$student->isInFinalYear() || !$student->hasMedicalCondition()) {
throw new BadRequestException("We can't provide you with aid right now.")
}
}
Here's another way:
if ($student->hasGpaLessThan(2.0)
&& (!$student->isInFinalYear() || !$student->hasMedicalCondition())
) {
throw new BadRequestException("We can't provide you with aid right now.");
}
What if you could write it like this instead?
when($student->hasGpaLessThan(2.0))
->ensure($student->isInFinalYear() || $student->hasMedicalCondition())
->orElseDeny("We can't provide you with aid right now.")
I think you'll agree with me that the third version is easiest to mentally parse and closer to the wording of the requirement. It's also less bug-prone than the first two.
One more example. Say we have a second requirement:
Students may apply for aid only if they are studying one of the aid-eligible courses or they have a letter from the President.
(Ignore our crazy rules; it's a fictional schoolđź¤)
This would work:
if (!$student->isStudyingEligibleCourse() && !$student->hasPresidentsLetter()) {
throw new BadRequestException("Sorry, no aid for you.");
}
Using our ensure
syntax, this would be:
ensure($student->isStudyingEligibleCourse() || $student->hasPresidentsLetter())
->orElseDeny("Sorry, no aid for you.");
Both syntaxes are pretty similar, but to my mind, the second is easier to understand at first read.
For what it's worth, I don't intend to reinvent or eliminate if
s. I just believe that using when...ensure...orElseDeny
can be more expressive in certain scenarios. I'd like to hear your thoughts, too.
If you like this syntax, I made it into a package, so you can use it in your project by running composer require shalvah/ensure
. Please star and share if you find it useful!
I write about my software engineering learnings and experiments. Stay updated with Tentacle: tntcl.app/blog.shalvah.me.