Modeling Account Membership at a Simple Video Rental Business
Let's have a go at modeling account membership at a simple video rental business. We'll start by replacing the archetypes in the DNC with names from our problem domain. The event or activity we want to track is a person applying for a membership account. So let's replace the MomentInterval class with a class called AccountApplication.
The DNC consists of three similar-looking legs connected to the MI classes; the Party leg, the Place leg, and the Thing leg.
Attacking the Party leg first, the role being played by a party in the AccountApplication is that of a membership holder (potential and/or confirmed). So we replace the PartyRole class with a class called Member. We'll restrict ourselves to renting to people (and not include organizations), so we replace the Party class with Person. Similarly, the PartyDescription class becomes PersonDesc; we could use this class to handle people of different age groups and store the video ratings that an age group may legally rent, for example.
The Thing leg is next. The membership account is the thing for which we're applying; therefore, we replace Thing with Account. ThingDescription becomes AccountDesc; we can use this to provide default values for different types of account (maximum number of tapes rentable at any one time, for example). The ThingRole class? Any attributes and behavior specific to the way an Account participates in the AccountApplication can be placed here, so we'll call it AccountInApplication.
Finally, the Place leg. People apply for accounts at a video store. We can model this as some type of building or Property (high rise/low rise, commercial/residential, and so on) playing the role of a video store.
The result is a very powerful, flexible model shape in no time at all. Notice that we've lost the MomentIntervalDetail class because we didn't identify any parts to our account application process. Conceivably we could allow a person to apply for multiple accounts at the same time, and that would require a suitable MomentIntervalDetail class, but this capability would not be useful in our video rental domain. Another side effect of this decision to support only one account per person is the narrowing from 0..* to 1 in cardinality between the AccountApplication class and the AccountInApplication class (see Figure 2).
Figure 2 Initial domain-specific model.
Much of the flexibility provided by our model is obviously overkill for a simple video rental business. Therefore, let's see what other classes we can drop out along the legs, where we don't need the extra flexibility.
The rather contrived name of AccountInApplication is a clue. If there is little or no behavior and/or attributes specific to an Account while it participates in the application process, we can drop the AccountInApplication role class. If the difference in account types is very small and AccountDesc only has a handful of methods, we can also drop the AccountDesc class and represent the type as a simple attribute (probably enumerated) in the Account class, plus a handful of static methods such as listNewAccounts ().
Static methods wouldn't work in most distributed object frameworks because they don't support remote invocation of static methods.
It doesn't make sense to allow video store members to close and reopen membership accounts unless members are charged regular subscription fees. This is not usually the case for a simple video rental business, though; membership is normally for life. Therefore we can replace the other 0..* cardinality between AccountApplication and Account with 1.
The result is shown in Figure 3.
Figure 3 Simpler model with redundant flexibility removed.
For a small video rental business, the store at which you apply for membership is of no relevance; indeed, the business may only operate one store or may be operated via the web. In this case, the whole Place leg can be dropped. If the store is relevant (for example, in the case of a video store chain), we can again challenge the need for a separate role class and the need for a separate description class in addition to the Property class (maybe just a green Place class would be good enough). For the purposes of this example, let's assume that we don't need the store at all. Now our model looks like Figure 4.
Figure 4 Model for a single video store.
Let's review the Party leg of the model. Again, if the PersonDesc doesn't add much value to our model, we can fold it into a simple attribute and maybe a static method or two in the Person class. Do we need the Member role? Party roles are far more common than Thing roles and Place roles. We'll probably need some other party roles at some point (Cashier springs to mind), so it's safer to keep the Member role for now. Role classes have attributes and operations that are specific to the role-player's participation in that role. Typical attributes are an ID or a status, and typical operations for a Member role class could include assessAccountArrears(), listFavoriteGenre(), listRentalHistory(), and so on.
We still allow a Member to make multiple applications. We have already decided that membership is for life, however, so a member will only ever have one successful AccountApplication that we need to keep around at any one time. Keeping record of previous failed AccountApplications doesn't seem important enough to warrant the complexity of a 0..* relationship between Member and AccountApplication; let's reduce that to 1.
The 1:1 association between AccountApplication and Account suggest we can collapse AccountApplication and Account into one class. It's really the account that we're interested in; we've reduced the application process until it's trivial. At most, we might keep a dateApplied attribute and a dateApproved attribute so that we could ask the Account class its status. Let's see what we have left (Figure 5).
Figure 5 Model for trivial membership-application process.
We now have another 1:1 association between Member and Account. Let's merge Account into Member (see Figure 6). Why keep Member and not Account? After all, in the end it's little more than a choice of name and color for a class, right? Choosing Person and Member leaves us with a role-player class and a related role class. Remember that the DNC is a pattern that occurs again and again in business systems. Person and Member fit the DNC better than Person and Account; it helps us plug Member into other MomentIntervals (Rental, for example).
Figure 6 Simple role playerrole pattern.
In some cases, we may be uninterested in the actual role-player, or the role-player may only play one role. If this were the case, we would end up with a single role class, Member, representing account membership, as shown in Figure 7.
Figure 7 A reasonably simple object model.
We started with 10 classes and ended up with one. Okay, this example is a little artificial, but I hope it has demonstrated some of the subtle power of the Domain Neutral Component and illustrated some of the design tradeoffs between flexibility and simplicity. Obviously, our start and end points represent two extremes; the object model we want is the simplest that does the joband no simpler. Color modeling and the DNC are great techniques that we can use to make our work easier, but they're certainly not a silver bullet or an excuse to disengage our brains.
Stephen Palmer is the editor of The Coad Letter, a special report on new advances in building better object-oriented software, focusing on analysis and design issues. This article originally appeared in The Coad Letter 68. (Click here for subscription information.)
TogetherSoft™ is a trademark of TogetherSoft Corporation. The Coad Letter® is a registered trademark of Object International, Inc.