Tuesday, July 17, 2007

Domain Modeling Users in Java - Part 2

In my previous post, I analyzed a common mistake made by developers in designing flexible domain models for users: using hierarchical (is-a) relationships to model what are actually aggregate (has-a) relationships.

In this post, I stop analyzing what went wrong and try to put forth one design that helps eliminate all of the observed problems, giving you a user domain model flexible enough to handle the changing nature of whatever business you're in.

Users Are Not Roles. Users Have Roles.

Instead of trying to model a type hierarchy for your users, consider instead that a user is simply someone who uses your system, plain and simple. Typically, users have things like usernames, passwords, email addresses, and the like. Frequently, users are tied to permissions via roles (e.g., "an administrator can do function X"). It is this role-based solution which provides the flexibility -- whether you use it for security and permissions or not is irrelevant. Let's examine.

A role is a set of motivations for a given user. And, as with any good actor, users can play many different roles -- frequently at the same time. This important distinction leads us to aggregate roles into a user rather than attempt to model by hierarchy.

Once you aggregate the roles, you begin to see the power of the solution. Now you can create hierarchical models of roles to support your business needs, and you can have a user play as many (or few) roles as necessary.

Figure 2

In Figure 2 above, we've refactored the inflexible design from the previous post. A user can now have several different Roles and a hierarchy of Role provides us with ample flexibility to use inheritance the way it was meant to be used -- to pass common attributes and methods along to children. Each Role implementor provides domain-specific information making it easy to use and clear to read.

What's even more fantastic about this methodology is something I didn't even bother to touch on in the previous post. Previously, you would have broken into tears trying to come up with a flexible database schema to go with your domain model. But with this model, you can easily map a role to a table and use an intermediate mapping to go from users to their roles. Presto, a flexible domain model and persistence strategy to boot.

On a final note, this model also meshes very well with security frameworks, where the Role implementations are likely to map to permissions -- another side benefit with no additional work.

Monday, July 16, 2007

Domain Modeling Users in Java - Part 1

Developing a domain model to ensure future flexibility is not a trivial task. One of the most common domain problems clients run into is the changing nature of what defines a "user".

In the first part of this series, I'll try to illustrate a common design mistake people make and explain how and why it causes trouble later on down the line. In the second part of this series, I'll cover a more flexible solution that overcomes the observed limitations.

As always, while this blog tends towards Java for its examples, problems covered here occur in many languages.

The Common Design Mistake

Let's examine what is typically the first and only design for a user model in an example domain (which is a simplified form of the design I've seen in the last two clients I worked with)

Figure 1
Figure 1 shows a typical user model implementation. As you can see, there is a base class User implementation and additional attributes (and methods, one would assume) are modeled as extension classes from this base. In this simple model, there are advertisers, affiliates, and partners, each with some varying attributes.

There are a couple of interesting questions already, both of which strike at the very heart of why this is a design mistake.

  1. What happens when a Partner is also an Advertiser?
  2. Are Advertiser, Affiliate, and Partner "types of user" or are they "roles played by a user"
  3. All three user "types" appear to have phoneNumber as an attribute. Assuming not all future users will have this as an attribute, how can the developer simplify this design so as not to repeat commonly used attributes all over the place?
While you may already see there is a problem with the design, anyone in doubt need only examine what comes next. With the above design, the following code will very likely be found somewhere in the business logic or UI logic:
if ( user instanceof Advertiser )
  doSomething();
else if ( user instanceof Affiliate )
  doSomethingElse();
else if ( user instanceof Partner)
  doYetAnotherThing();

So much for object-oriented design...

In part 2 of the series, I'll cover a simple object-oriented design solution that allows for future flexibility and gives solid answers to the three questions asked.

Tuesday, July 10, 2007

The Great LDAP-Database Divide

It is a frequent requirement in enterprise application development that a system integrate with an external security store for authentication/authorization -- typically an LDAP system or derivative.

It is also almost always a requirement to leverage some kind of database for persistent storage of information.

But what happens when the information in one store must frequently be related to the information in the other? For example, your reports call for data that is both in LDAP and the database? This is the stuff religious wars are fought over. Use LDAP for everything! Use databases for everything! And the ever-famous Let's Just Copy All The Data Into the Database and Have it in Both Places!

None of these is very useful in practice because, well, it is what it is and you don't always get to choose your environment or your requirements. To find a good solution, you are going to need to work with a distributed, multi-type data store. Assuming that you don't want corrupted data across the stores, this means an external transaction server and transaction-aware services. This means ensuring that your client understands the issue at hand -- and the costs of requiring your application work in this manner.

The first thing you'll probably want to do is hide the fact that there are disparate data stores at all. The last thing you want is application developers trying to manage the connectivity and mechanics of working across LDAP and databases. Ideally, you want them working with a unified API that consists of business methods and that's all.

As an example of this, one of the Java-based implementations I was involved with used a high-level interface to expose the business methods. The implementation was dependency-injected (via Spring beans) and was composed of two data sources -- an LDAP data source and a database data source, each wrapped in transactionally-aware JTA containers. Annotations specified in the interface signal how the transactional nature of the method should be treated.

But all of this is, to me at least, Herculean effort, and almost never worth it. The performance of such applications often suffers, the level of complexity goes up significantly, and the costs of developing and maintaining such a solution go up with it.

So far the only way I've figured out how to get around this is to attempt to limit the relational usage of the data -- force scenarios where I can load user and permission data from LDAP during the authentication process and then never touch it again, and resist scenarios where reporting is done with user data as part of the result set. But this is not always possible -- again, it's not always possible to choose your environment or requirements.

I'd be very interested to hear the experiences of other architects -- how have you bridged (or avoided) the LDAP/database divide? Have you developed best practices for this issue?