Let's say that we have a class PersonName
and we throw an exception when some one try to create a instance of PersonName
passing an invalid name to the constructor. Should the exception InvalidPersonName
be expressed on the domain model? And if it should, how should it be represented?
-
Where else might you express it?– candied_orangeSep 6, 2016 at 2:04
-
Due to some possible misunderstanding in the answers, could you please edit your question and clarify what kind of domain model you have in mind? A graphical UML model? Which kind of diagram & semantics?– Doc BrownSep 7, 2016 at 6:10
4 Answers
Maybe. Domain model does need to express what errors exist and possibly how should they be handled. All that domain model needs to tell you is that "Valid name is XXX. And user needs to have a valid name at all times." It doesn't tell you how to actually implement it.
Exceptions are language/framework specific ways of expressing this kind of error and there are many other ways how to express invalid operation. It should be up to developer to decide what way to express errors. But that is different question of exceptions, error monads, etc..
Personally, I wouldn't use exceptions (unless using Checked exceptions). I would most probably use return value to indicate if ValidName
structure can be created or that Name can be set. Eg. I would ensure calling code is fully aware of the case that name cannot be valid. When using unchecked exceptions, the programmer writing calling code might be unaware of this case and won't write code for handling it.
In general, throw an exception when a condition occurs that your code cannot recover from itself.
If you provide a constructor for an object, and the caller of the constructor can hand that constructor some data that makes it impossible to construct a valid and consistent object, then throwing an exception is the proper response in those languages that support exceptions.
If your question includes "should I create a custom exception for each such occurrence, the rule of thumb is "generally no. Just use some general-purpose exception like an InvalidOperationException, or even just an Exception with a description."
-
While this is absolutely true, it does not answer the question about how to express it in the domain model Sep 6, 2016 at 5:25
-
What does that mean, "express it in the domain model?" The exception would be thrown in the constructor method. Why would you throw it anywhere else? Sep 6, 2016 at 5:44
-
Just use some general-purpose exception like an InvalidOperationException I disagree. Especially in this case, the code handling the user name would need to handle "InvalidUserName" in some specific way. And this goes for most domain errors. IOE should only be used if only real way to handle the exception is to crash the application. Which is extremely rare.– EuphoricSep 6, 2016 at 5:51
-
1@Euphoric: That's why exceptions have error descriptions. I know that Java advocates checked exceptions and all sorts of complex exception hierarchies, but they're unnecessary and overly complicated. The programmer can work out what the problem is by looking at the error message. If you're trying to build logic around specific exceptions, that means that the code could really handle the condition after all, and an exception is no longer the preferred handling mechanism. Sep 6, 2016 at 6:14
-
Robert, I guess the OP is talking about something like a graphical domain model, like an UML model. Sep 6, 2016 at 14:30
You should always keep in mind that graphical models are created for the sole purpose of communicating specific information. In that regard, there is no such thing as "should" this model contain "this information" because it all depends on what information you are trying to convey to the reader in each specific diagram.
The only rule of thumb is that each model should contain the information you are trying to communicate in a clear manner. Nothing more, nothing less.
Frequently, this "rule of thumb" could lead to needing multiple diagrams describing more or less the same thing but from different viewpoints. For example, a domain model and a class diagram. On the surface, these might appear to be the same or very similar because they both usually use class diagram notation to represent them and the class names are sometimes the same. However, a domain model generally describes "real-world" domain objects whereas the class diagram shows the software implementation classes that are used to implement the "real-world" objects. While each model represents essentially the same thing, they each are trying to communicate very different kinds of information.
Having each diagram clearly depict the information it is trying to convey is far more preferable to force-fitting all the information in the same diagram and leaving it up to the reader to decipher all the tidbits of information hidden in the details.
So in answering your question about should Exception classes be in the domain model then that seems to be an obvious no. Should it be in the class diagram? You need to decide if that is an important concept for the class diagram you are drawing. Personally, I generally wouldn't show it in a class diagram for a subsystem. However, if I were to put it in a diagram at all it would be a class diagram of all the custom exception classes the system created or used. On the other hand, if I were creating a subsystem library for use by others (on a totally different project) then I very well might consider showing the exception class on the subsystem class diagram, but probably only if there were something "special" about the exception class that I think the users should be aware of.
This is probably redundant but is important enough to reiterate explicitly. Your class diagrams don't need to show every single class if showing them doesn't provide useful communicative value. Sometimes, showing too much is worse than showing too little because too much information can easily hide the most important concepts that the diagram should really be trying to convey.
You need to create reusable code. E.g. PersonNameExpception can be applied only to PersonEntity. What if you want to add same validation logic for another entity? From this point of view exceptions should be more generic. As common pattern there are separate domain entities and separate validation rules that can be applied to entities. In java you can look for JSR303 Bean validation as example