Re: DbC & Exceptions & Style
From: daza (dadaza_at_excite.com)
Date: 11/20/03
- Next message: Leif Roar Moldskred: "Re: Agile developement -- A Parable"
- Previous message: Phlip: "Re: SproutMethod.pdf"
- In reply to: Graham Perkins: "Re: DbC & Exceptions & Style"
- Next in thread: H. S. Lahman: "Re: DbC & Exceptions & Style"
- Reply: H. S. Lahman: "Re: DbC & Exceptions & Style"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 20 Nov 2003 06:21:36 -0800
First of all, thank you to H.S.Lahman and Graham Perkins for taking
the trouble to address a rather vague question! I certainly appreciate
it.
I am trying to assess why I dislike the implementation of the class.
Is it because it is poorly implemented? Or is my dislike based on a
style issue, ie. "that's not the way I would have done it"?
I kept the problem space context small to elicit feedback on whether
others would consider this a well designed domain (business) class: do
you consider its implementation sound and solid, and would you re-use
it yourself? Unfortunately, I kept the problem context too small. I
should have mentioned that the line
<<DesignByContract.Check.Require(act != null, "TheActivity must not be
null");>>
causes a debug assert which halts the program without throwing an
exception (like a C macro assert).
Here are the things that nag at me:
1. Different ways the constructor can fail
<<public Mission(IActivity act, string missNum)>>
If act == null or missNum == null the constructor will debug assert
(DesignByContract.Check.Require()). Because this failure will not
cause an exception to be thrown the client code cannot deal with it
(whether it wants to is another question). On the other hand, if
missNum fails to meet the business rules, the constructor will throw
an exception and the client code can choose to handle it.
In one case the class implementor makes the decision that the
constructor failure is a programming mistake. In the other case the
class implementor makes the decision to allow the client to determine
whether the constructor failure is an "exception" or a bug.
We use debug assert to express implementation mistakes. We use
exceptions to signal that the assumption of an interface has been
violated. With debug asserts the class implementor hard codes the
meaning of the violation. With exceptions the client code is being
given the freedom to choose what the violation means (e.g. a
FileNotFound exception could be a programming error or just an
exceptional event).
My preference is for the constructor to either use only DbC asserts or
to only throw exceptions, but not both.
2. No public methods to check pre-conditions
<<private void CheckMissionNumber(string missNum)>>
The class does not provide any methods to allow the client to check
that preconditions are valid, i.e. a public CheckMissionNumber()
method that returns a boolean value (rather than a private method that
throws). I used to think that methods that validate pre- and/or
post-conditions should always be public and should never throw
exceptions. After reading Graham Perkins' e-mail I am now wondering
whether my "should be public" should become a "must be public".
My style is to write classes that provide the client code with a means
to verify the pre-conditions before the respective method gets
invoked, but not to make the violation of "preconditions" part of the
DbC contract.
3. Insufficient Diagnostic Information
<<throw new ApplicationException("The Mission Number must have a
length between 1 and " + MAX_MISS_NUM_LEN + " characters.");>>
I definitely agree with H.S.Lahman when he points out that "the
diagnostic information does not provide any explicit information about
the context of the failure". This kind of information is indeeed
important. Moreover, ApplicationException is a generic exception; I
believe that a more meaningful exception type should have been used.
4. Default Mission Number
Seeing that each mission object requires a unique mission number (when
it gets persisted into the database), I don't believe it to be
appropriate for the Mission class to have a default constructor with a
default string "TBD". In this case I am inclined not to provide a
default constructor. As a matter of fact, I think I would have written
a separate MissionNumber class that would encapsulate relevant
business rules.
So this leads back to my question – is this an inappropriate
implementation or just a difference in personal styles?
The context that led to the implementation of the above class is as
follows:
To capture all business (user input validation) rules in one place and
to avoid writing code that converts GUI data into objects, we decided
to "bind" our domain (business) object to the GUI forms, or, to be
exact, to bind each GUI text field to a single domain object's data
member. However, the implementation of the GUI imposes certain
constraints on bound domain objects:
The UI needs to have a domain object bound before it gets displayed to
the user. All domain objects must now provide a default constructor.
Also, the GUI expects to receive an exception as a signal that the
user entered an invalid value. Every text field in the GUI is bound to
a corresponding data member (via a Set method) on the domain object.
Because the GUI is using the domain object's Set methods to validate
user input, each Set method must throw an exception on invalid input.
Though it is valid for DbC violations to throw exceptions, they don't
have to.
It is obvious that GUI design will influence the abstractions found in
the domain layer. It will influence the data members found in domain
classes. But in our case, the implementation of the GUI has imposed
implementation constraints on our domain classes, especially in
regards to an exception throwing policy.
The code that enables the interaction between the GUI and the domain
object layer is simple and it works. But are the domain objects well
designed? Or have they been hacked? I tried to raise some discussion
with my colleagues, but the usual time pressure intervened.
Sorry if I'm rambling; it's late, and I've had a long day… (Haven't we
all!)
Daza
- Next message: Leif Roar Moldskred: "Re: Agile developement -- A Parable"
- Previous message: Phlip: "Re: SproutMethod.pdf"
- In reply to: Graham Perkins: "Re: DbC & Exceptions & Style"
- Next in thread: H. S. Lahman: "Re: DbC & Exceptions & Style"
- Reply: H. S. Lahman: "Re: DbC & Exceptions & Style"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|