Thursday, February 21, 2013

Permissions and Capabilities

Users are a central concept to any software system. Even single-user systems have users, maybe even multiple users, just never at the same time. Looking at the user concept through the eyes of a developer, however, roles are a better concept. The reason is simple — roles are abstract where a user is an instance of one role or another. This is how we think about most other things in the system, so why not the actors that we're interacting with too? We're not interested in the user who is currently interacting with the system, because that's not how the UI components are designed. They're designed around roles. The role describes for the developer, what this user instance is capable of doing. Roles are about permissions and the underlying capabilities of system. The two are interrelated, but when separated, as they so often are, cause major headaches in the code.

Forget about roles for a second, and think about the software system under consideration as a collection of all its capabilities. Every last feature, we don't care who is allowed to use it. This is a starting point from which roles are born because we do care who uses a particular feature. And so we're able to construct a schema for default permissions for default roles as we see them. But we'll also need some flexibility with regard to adding new user roles. And so if the role is based on a collection of CRUD permissions, then we're easily able to extend the system with as many roles as we want. Of course, the problem is that roles aren't the only changing entity in our application. This is a top-down change, usually triggered by a specific customer. What about when the capabilities of the system are changed or expanded?

When we add new capabilities to a role-based software system, we have to update each and every role that has already been defined. Which shouldn't be that big of a deal, really, because you're just adding a new permission for the new capability, or updating a permission that already exists. These reflect the new capability of the system. But we're not done because we also have to update the code that makes use of these roles, which is usually user interface code. And, depending on how this code is structured, this isn't a trivial thing to do.

All the user interface should be asking the role about is the capability, and not necessarily the permissions on using that capability. I find that when I start writing UI code that needs to take into consideration, permissions such as these, everything starts out fine. The code looks and runs beautifully, everyone wins. But the bottom-up extension of the system poses the problem. More often than not, a capability is a generic interface, at least from the user interface point of view. And so, we're able to substitute the underlying components that realize those interfaces, maybe at 90% accuracy. The 10% that isn't supported leads to ugly code in the UI. This is why we should hide the permission checking behind component capability checking. We ask the role one question, not several.