I also don't see the exceptions are part of the domain language, instead I see the associated rules as being part of the domain language. So for me the rule name should become part of the domain language but the exceptions do not have to be, its the rules that matter to me when discussing things with the domain experts.
Colin, I have to disagree with you. Here is an example from a real life project (as per your request in my blog comments) and a real discussion session with one of the domain experts.
Here is a snippet from a Capital Market Solutions codebase. The codebase is replete with domain specific terms, as it should be in a domain model implementation, starters (and unstarters) of the capital market domain are requested to look up relevant information for background of the terminologies .. apologies :-(
Class
PositionManager
is the domain abstraction for managing the Position
of an account. Note that Position
is the domain term which indicates the balance of the account.class PositionManager {
//..
//..
void updatePosition(Instrument ins, Date tradeDate,
BigDecimal amount, TradeType tt, ..) {
Position currentPosition = getPosition(acc, ins, tradeDate);
currentPosition.doUpdate(amount, tt);
}
//..
}
Now have a look at the method
Position#doUpdate
invoked above. Here the update is done through a business rule modeled as a Strategy design pattern. The rule can have multiple implementations, hence modeled as an interface. Again we use domain driven principles here to isolate the execution of a process from the rules on which it operates. Note the checked exception which the method catches - ShortPositionException
, we will come back to the name in just a moment. Keep reading .. Here is the definition :
class Position {
private PositionUpdationStrategy strategy;
//..
//..
void doUpdate(BigDecimal amount, TradeType tt) {
try {
strategy.doUpdate(amount, tt);
} catch (ShortPositionException sbex) {
//.. handle
}
}
//..
}
The
PositionUpdationStrategy
is the actual business rule for updating the position of an account and I show the default implementation of the rule.interface PositionUpdationStrategy {
void doUpdate(..) throws ShortPositionException;
}
The rule has been modeled purely using the domain language (aka the Ubiquitous Language) and is fairly intuitive to read even by a non-programmer domain guy. Just wear the hat of a domain guy and see if the following codebase sounds domainish.
If the trade is a buy-trade, add to the existing position. If the update results in a short-balance, throw an exception ShortPositionException
.
I have highlighted the domain terms above to indicate that the rule implementation is a direct translation of what the domain guy speaks. Colin also agrees to the rule being part of the domain language. Now what about the exception which the rule throws ? We could have named it
InsufficientBalanceException
and in fact, we did it exactly that way only. Then I was going through a session with one of the domain experts, when he was trying to interpret the correctness of the business rule implementation looking at the codebase. He noted that the short-balance check should ideally raise an exception which indicates that it is related to a short-balance check - once again a part of the domain language. InsufficientBalanceException
is too generic a term and should be narrowed to a more fitting domain terminology for the exception here. And thus came the ShortPositionException
name, which is part of the Ubiquitous Language. Here is the snippet ..class DefaultPositionUpdationStrategy
implements PositionUpdationStrategy {
//..
//..
void doUpdate(BigDecimal amount, TradeType tt)
throws ShortPositionException {
if (tt.isBuyTrade()) {
// add to position
} else if (isShortBalance(currentPosition, amount)) {
throw new ShortPositionException(..);
}
// subtract from position
}
}
Look at the interface for the rule, how the checked exception makes the contract much more domain friendly.