The Coad Letter: Modeling and Design Edition, Issue 76, Modeling User Roles, by Stephen Palmer
Welcome to the first issue of the CoadLetter for 2001.
Some more object modeling in color to start the year off:
A question that keeps being asked by the teams I work with is, "How
do we model the roles of employees and users of a system?"
So this month lets consider some options...
Modeling User Roles
OM:SPA Actor-Participant Pattern
A long time ago (1997 in other words) Pete, with David North and Mark Mayfield,
published the second edition of the Object
Models: Strategies, Patterns, & Applications book. Page 435 describes
a small object model pattern called 'Actor-Participant'. Today this is
reflected in the Party and Role class archetypes with added detail including the
typical types of attributes and operations you would find in classes of those
By the way, it is also very interesting to compare the 'Overview of
transactional patterns' on the same page of the OM:SPA book with today's
Domain Neutral Component.
Anyway enough of history. Here are five strategies to consider when
modeling employee and user roles.
Strategy 2001-01-01: Model Each User Role as a Separate Class
Separate attributes and operations that are specific to each role into
separate classes. Associate each role class with the relevant role-player
class (either a Party, Place or Thing). Make the role-player class responsible
for ensuring only valid combinations of roles are played by a role-player.
In the example below, the person class is the role-player class and
controls the roles that maybe played. Each role is represented by a separate
class. Possible attributes and operations are shown for some of the roles.
Others are left as an exercise for the reader :-) and to keep the diagram
small. Note: It is common in larger systems for Person to be a subclass
of a more generic Party class that holds the attributes and operations
that are common to both people and organizations.
This strategy leads to a conceptually simple model.
There is good separation of responsibilities.
In larger systems this strategy could result in a large number of almost
The constraints on which combinations of roles may be played when are
hard-coded into the role-player class.
The role player class has to specifically know about each different
Strategy 2001-01-02: Use a Role superclass and a Description class to simplify
the Role-Player class
Introduce an abstract superclass for the individual role classes. Link
the role-player class to zero or more instances of the superclass. Add
a Description class for the role-player class with an optional Plug-in
point for the policy on valid role combinations. Have the role-player class
delegate to the Description class (which in turn delegates to its plugin
if it has one) when asked questions about valid combinations of roles.
We introduce the PersonRole superclass. This super class contains anything
that is common across all the role classes. Often this is just the knowledge
of the role-player of the role (if even this were not needed then the superclass
could be replaced by an interface in Java). Rather than have a plugin for
each instance of the Person class use a description class to hold the policy.
(Note: static or class attributes and operations are a slightly less flexible
alternative to using a separate Description class).
When it comes to adding or removing a role, the Person class consults
the PersonDescription class to see whether, with the combination of roles
the Person already holds, the addition or removal is allowed.
The role-player class is simpler, more loosely coupled to the role classes
and more reusable as a result.
It is easier to change the policy on which combination of roles can
be played and when.
Extra classes are required for the superclass, the PersonDescription and
the plugin policy classes.
Strategy 2001-01-03: Subsequent Role Strategy
Coding constraints on which combinations of roles can be played can become complex.
Model a rigid constraint of 'You can only play role B if you already play role
A' as a subsequent role. Instead of linking role B directly to the role-player,
link it instead to role A (see Java
Design 2nd ed. pg. 133 for more subsequent roles and Java interfaces).
In the example below, the constraint 'A person must be an employee before
they can use the system' is modeled as a subsequent role. Instead
of being linked directly to the Person role-player class, the SystemUser
role class is linked to the Employee role class. Now for a Person object
to be able to play a SystemUser role they must first play an Employee role.
Once a Person object is indirectly associated with a SystemUser role
object it can be given further roles (Cashier, Admin, Manager, InventoryClerk).
The constraint is modeled explicitly through associations rather than being
left to code or an external policy.
This only works if the constraint will never change. Imagine a system that
was used only by employees but now needs to be opened up to allow internet
users limited access. The example above would need some 'refactoring'.
Strategy 2001-01-04: Challenge a role. Is it anything more than a set of
authorizations or permissions?
Often a role can be little more than a name for a particular combination
of application permissions, assignments or authorizations. In these cases,
use a more generic role class and derive the specific roles from the associated
permissions, assignments or authorizations.
A person playing an employee role could be assigned to manage a department
for a time. That assignment makes them a manager.
A Point Of Sale system user may be authorized to work on a particular
cash-register. That authorization makes them a Cashier.
In general many user 'roles' can be modeled as a single User role class
associated with a particular combination of permissions (operations that
the person playing that role may perform).
The reduced number of role classes make it easier to manage inter-role
Bigger more complex role classes requiring deductive logic to identify
Strategy 2001-01-05: Use a Rules or Policy Engine
For large enterprise systems with many complex combinations of permissions
and access rules, have the User role class delegate to a rules engine.
The SystemUser class requests a list of permissions from the rules engine
when the user logs on. The SystemUser class hides the use of the rules
engine from the rest of the system.
More flexible permissions policy administration.
Third party software available to buy rather than building your own.
Using a separate rules engine may impose a performance overhead (in complex
cases it may actually improve performance however).
The permissions policy is constrained by limits of the rules engine.
As usual, trade-offs! Design is all about them. There is almost never a
single right design. Show me three or four possible solutions, tell me
the advantages and disadvantages of each so I can make an informed selection
of the solution I want for my context. And, of course, the best answer
this time may be a combination of two or three of the possible approaches.
This core principle of design can be found at the heart of the analysis
and design steps in Feature Driven Development.