loading...

A different syntax for enforcing business requirements

shalvah profile image Shalvah ・2 min read

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 ifs. 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!

Posted on by:

shalvah profile

Shalvah

@shalvah

Writer and builder. APIs, dev tools, automation. Advocate of simple design.

Discussion

markdown guide