Legacy DB Storage Strategies and why bitwise pick lists are actually counterproductive

One of my first projects in a new job was to rewrite a .NET web-app to use more modern tools and an MVC architecture. It was fine. I had never written a line of .NET code, but thankfully, the code was mostly readable. That is until I read the .NET equivalent of something that looked like this:

$user_rights = 4;
if ($user_rights & 2) {
    echo "what";
} elseif ($user_rights & 4) {
    echo "is";
} elseif ($user_rights & 6) {
    echo "this";
}

There’s a few things going on here: there’s a multi-case if block that looks like it evaluates user rights. And inside each if statement there’s a bitwise AND comparison going on against some arbitrary integer. But what does it mean!?

Bitwise operations are available in all major programming languages and allow for lower-level bit manipulations. That is, bitwise operators allow for comparing each individual bit value another bit value in an equivalent memory address (ie. an equivalent “index” in the memory “array”).

So the first step here was to grab what permission each integer value represented. This was easy enough as I had to reference the right Join table from the DB mapping the values to the definitions.

After seeing the definitions it became obvious that the $user_permissions variable was being used to store several user permissions in a single integer value. This value would then run through the if statement and run some operation if the bitwise result was not zero. In the example above, 4 & 4, 4 & 6 would evaluate to four (true), and 4 & 2 would evaluate to zero (false). The true values indicate the user had the permission-level set.

After running a quick Google-search about how common this was I found quite a few articles describing the technique, but none that were recent. The articles near the top of the Google search were all at least 5 years old.

Google Search Results. Some of these guys are old!

This step was the toughest to unravel since all the permissions were rolled up to this one number. While this may be a strategy to conserve disk-space (maybe it was popular because memory was expensive back then?) I found it to be hard-to-read. Another weakness to this approach is also pulling descriptive metrics like,

“ Tell me all users that have permission x,”

becomes a little more complicated.

The alternative, of course, is to have a column for each permission which uses a boolean as a value. A little more of a hassle to set up, but less of a pain going forward. It took our team much more time to figure out what was going on, and modify this part of the code ultimately nullifying any convenience or time that the bitwise operations were intended to gain.

I’m still learning lots, and this was was an example of a truism I heard repeatedly as I learned to code, “don’t be clever, be clean.” This was a great example of the truism. Being clever in this case proved to be counterproductive.