Web Log of Ross Chapman

Web Log of Ross Chapman

Deeper software concepts showing up in UI problems

I’ve got three posts in my brain backlog now about more complex software concepts showing up in UI work. Here’s the first!

I’ve been waiting a long time to use a bitwise operator in “real world” JavaScript – like 5-6 years – and the opportunity finally presented itself the other day.

In UI, near 100% of the time the basic comparison and logical operators of the JavaScript language give us the power and control we need to express product requirements in code. Equal, not equal, AND, OR, NOT, etc.. But then there’s that arcane set of bitwise comparison operators. These special boolean operators give us expressiveness for more complex comparison scenarios. They’re also just kinda weird because they do comparisons at the binary integral level – that is, they coerce the values to bits first.

Take XOR. Which in more layman terms is “exclusive OR”. In JavaScript XOR will return 1 when the output of either side of the operator is different and 0 if otherwise. Similar to a boolean return, we can easily pass around the result of a bitwise operator as a predicate.

As it turns out, this happens to be the very logic we need for testing existence between two dependent form fields.

At Eventbrite our UI library has graphical pickers for both date and time form fields. Our designs typically place these individual components next to each other and make them required. The user is free to change their values, though we do provide sensible defaults. One not so surprising possibility is that a user can leave one field blank by accident. Of course, not having an exact date and time for ticket sales dates doesn’t really make sense. Therefore, since we want to give the user some immediate feedback if they put the form in this state, we run a validation on blur using XOR logic!

Nonetheless, for checking existence, we don’t want to bitwise compare the two sides of the expression directly which could be many kinds of strings. To make the comparison reliable, we cast each side to boolean values with a bang. Then we wrap up the expression in a composable function. The result is a very concise one-liner:

const isOneTruthyAndTheOtherNot = (a, b) => !a ^ !b;

Which might be passed around in my hypothetical React event handler like:

dateTimeValidator: (dateValue, timeValue) => {
    const hasEmptyField = isOneTruthyAndTheOtherNot(dateValue, timeValue);
    const error = hasEmptyField ? FORM_ERRORS('dateTimeField') : null;

    this.setState({
        dateTimeFieldError: error
    }

    this.props.onError(error)
}

This could be written in a couple ways without the more arcane XOR:

... = ( foo && !bar ) || ( !foo && bar );
... = foo ? !bar : bar

I’m generally against using overly clever code in codebases that are worked on by less experienced engineers, but I think the bitwise operators are a great tool for anyone to know. And the MDN docs are very clear about how XOR works:

“Performs the XOR operation on each pair of bits. a XOR b yields 1 if a and b are different”

The docs will also introduce you to the algorithmic decision table for the XOR logic, which is another useful tool to expose new developers to.

a b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0

What always makes this sort of exposé interesting is that the early-web understanding of UI still colors our perception of UI work; like, UI is just a sprinkle of scripting and layout and browser wrangling that gently rests on top of the real software where the computer science happens. Or maybe it’s changing. But I feel like there’s still too much emotional labor educating the web dev community about complexity throughout all layers of this mushy cake stack. “Mushy” as in blended, bleeding, fluid, transitional. Not as in gross, unfit, unstable.