Loading ...
Sorry, an error occurred while loading the content.
 

To throw or not to throw on Rule Violation

Expand Messages
  • Jesse Napier
    I have a question regarding business logic validation in my domain. Im not talking about validation in the sense of simple data validation such as checking for
    Message 1 of 26 , Jun 27 6:41 PM
      I have a question regarding business logic validation in my domain. Im not talking about validation in the sense of simple data validation such as checking for null values or specific data ranges.  These days it seems like most people are handling these types of validations with a validation framework and checking an IsValid operation or something similar.  I refer to these as data validations.  It may be fine in some domains for an object to exist and be persisted when that object is in an invalid data state.  I am faced with an issue in which I cannot allow certain objects to ever be in an invalid state. 
       
      In my domain I have PromoCode and Account. PromoCodes can be redeemed by accounts, but there are rules regarding redemption.  If any of these rules are violated, redemption cannot succeed and the application must prevent the redemption.  These rule violations are not fatal and are to be expected, however I must notify the user as to why the redemption did not succeed.  So my question is, what is the preferred way of communicating business rule violations to the UI when an action cannot be performed because it would put the object into an invalid state that cannot be persisted?
       
      I think there are essentialy 4 ways:
      1) Throw an exception describing the first violation
      2) Use Notification pattern to communicate information about all violations.
      3) Throw an exception that encapsulates the Notification object as described in Sergio's blog post, A Notification Strategy for Business Errors
      4) Provide a Check operation which returns a a boolean or a Notification object such as Notification CanRedeem(Account); or bool CanRedeem(Account);  If the check operation returns any violations, Redeem would throw an exception.
       
      The thought of throwing exceptions doesn't sit real well with me but it is the easiest way to get the information to any interested parties because they just have to try...catch it.  The Notification pattern has value but it seems more difficult to get the information to the interested parties.  Granted, the Redeem operation on PromoCode is a void operation and I could just return a Notification object from that call. However, in my research for this problem Im trying to comeup with a solution that would also work with operations that had a return value.  #4 is an instersting option but im a little turned off by it because the check would have to be called multiple times, once from the client and once from the redeem operation.  Here is a sample
       
      public class PromoCode{
       
          string code;
          DateTime expirationDate;
          bool isRedeemed;
          bool isOnlyForNewAccounts; 
         
          public Notification CanRedeem(Account account){
              Notification violations = new Notification();
             
              if(this.isRedeemed){
                  violations.Add(PromoCodeViolation.AlreadyRedeemed);       
              }
       
              if(this.expirationDate > DateTime.Now){
                  violations.Add(PromoCodeViolation.Expired);
              }
       
              if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                 violations.Add(PromoCodeViolation.NewAccountsOnly);
              }
             
              return violations;
          }
         
          public void Redeem(Account account){
              Notification violations = this.CanRedeem(account);
             
              if(violations.HasErrors){
                  throw new BusinessRuleException(violations);
              }
       
              this.DoRedeem(account);
          } 
         
          protected void DoRedeem(Account account){
              ...
          }
      }
       
       
      public class PromoCodeTest{
       
          public void RunCanRedeem(){
             
              Account testAccount = Mock.GetMock<Account>();
             
              PromoCode code = CreateValidPromoCode();
       
              if(code.CanRedeem(testAccount).HasErrors == false){
                  code.Redeem(testAccount);
       
                  Assert.IsTrue(code.IsRedeemed);
              }
          }
      }
       
       
       
      Any thoughts or advice on this?  Any ways to improve it?  Or is the a better strategy that I havent seen?
       
      Thanks,
      Jesse
       
       
    • berthooyman
      My recommendation is to not consider such scenarios as exceptions but treat them as regular business scenarios instead, with their own flow and page output. So
      Message 2 of 26 , Jun 28 12:42 AM
        My recommendation is to not consider such scenarios as exceptions but
        treat them as regular business scenarios instead, with their own flow
        and page output. So one vote for "don't throw".

        Bert Hooyman


        --- In domaindrivendesign@yahoogroups.com, "Jesse Napier" <jnapier@...>
        wrote:
        >
        > I have a question regarding business logic validation in my domain. Im
        > not talking about validation in the sense of simple data validation
        such
        > as checking for null values or specific data ranges. These days it
        > seems like most people are handling these types of validations with a
        > validation framework and checking an IsValid operation or something
        > similar. I refer to these as data validations. It may be fine in some
        > domains for an object to exist and be persisted when that object is in
        > an invalid data state. I am faced with an issue in which I cannot
        allow
        > certain objects to ever be in an invalid state.
        >
        > In my domain I have PromoCode and Account. PromoCodes can be redeemed
        by
        > accounts, but there are rules regarding redemption. If any of these
        > rules are violated, redemption cannot succeed and the application must
        > prevent the redemption. These rule violations are not fatal and are to
        > be expected, however I must notify the user as to why the redemption
        did
        > not succeed. So my question is, what is the preferred way of
        > communicating business rule violations to the UI when an action cannot
        > be performed because it would put the object into an invalid state
        that
        > cannot be persisted?
        >
        > I think there are essentialy 4 ways:
        > 1) Throw an exception describing the first violation
        > 2) Use Notification pattern
        > <http://www.martinfowler.com/eaaDev/Notification.html> to communicate
        > information about all violations.
        > 3) Throw an exception that encapsulates the Notification object as
        > described in Sergio's blog post, A Notification Strategy for Business
        > Errors
        >
        <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busines
        > s.html>
        > 4) Provide a Check operation which returns a a boolean or a
        Notification
        > object such as Notification CanRedeem(Account); or bool
        > CanRedeem(Account); If the check operation returns any violations,
        > Redeem would throw an exception.
        >
        > The thought of throwing exceptions doesn't sit real well with me but
        it
        > is the easiest way to get the information to any interested parties
        > because they just have to try...catch it. The Notification pattern has
        > value but it seems more difficult to get the information to the
        > interested parties. Granted, the Redeem operation on PromoCode is a
        > void operation and I could just return a Notification object from that
        > call. However, in my research for this problem Im trying to comeup
        with
        > a solution that would also work with operations that had a return
        value.
        > #4 is an instersting option but im a little turned off by it because
        the
        > check would have to be called multiple times, once from the client and
        > once from the redeem operation. Here is a sample
        >
        > public class PromoCode{
        >
        > string code;
        > DateTime expirationDate;
        > bool isRedeemed;
        > bool isOnlyForNewAccounts;
        >
        > public Notification CanRedeem(Account account){
        > Notification violations = new Notification();
        >
        > if(this.isRedeemed){
        > violations.Add(PromoCodeViolation.AlreadyRedeemed);
        > }
        >
        > if(this.expirationDate > DateTime.Now){
        > violations.Add(PromoCodeViolation.Expired);
        > }
        >
        > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
        > violations.Add(PromoCodeViolation.NewAccountsOnly);
        > }
        >
        > return violations;
        > }
        >
        > public void Redeem(Account account){
        > Notification violations = this.CanRedeem(account);
        >
        > if(violations.HasErrors){
        > throw new BusinessRuleException(violations);
        > }
        >
        > this.DoRedeem(account);
        > }
        >
        > protected void DoRedeem(Account account){
        > ...
        > }
        > }
        >
        >
        > public class PromoCodeTest{
        >
        > public void RunCanRedeem(){
        >
        > Account testAccount = Mock.GetMock<Account>();
        >
        > PromoCode code = CreateValidPromoCode();
        >
        > if(code.CanRedeem(testAccount).HasErrors == false){
        > code.Redeem(testAccount);
        >
        > Assert.IsTrue(code.IsRedeemed);
        > }
        > }
        > }
        >
        >
        >
        > Any thoughts or advice on this? Any ways to improve it? Or is the a
        > better strategy that I havent seen?
        >
        > Thanks,
        > Jesse
        >
      • Sergio Bossa
        ... 2) Use Notification pattern to communicate information about all violations. ... Hi Jesse, and all DDD
        Message 3 of 26 , Jun 28 1:41 AM
          On 6/28/07, Jesse Napier <jnapier@...> wrote:
          So my question is, what is the preferred way of communicating business rule violations to the UI when an action cannot be performed because it would put the object into an invalid state that cannot be persisted?
           
          [CUT]
          2) Use Notification pattern to communicate information about all violations.
          3) Throw an exception that encapsulates the Notification object as described in Sergio's blog post, A Notification Strategy for Business Errors
          [CUT]

          Hi Jesse,

          and all DDD community, long time has passed since my last post: I've been very busy, so I hope to find ASAP more time again.

          Please don't misunderstand my post about Notifications and exceptions.
          I do not suggest to use exceptions just for the sake of propagating notifications; I'm just saying that the two concepts can be linked, and if your business code already throws exceptions, then they can be used to propagate notifications.

          Talking about your scenario, I think that it is better to use some "event publishing" pattern: let your business code (preferably your services) publish events containing your notifications, and let your presentation layer listen to them. Doing so, your lower layers will be able to communicate with upper layers in a decoupled and transparent way, without violating any DDD/OO principle.
          What do you think?

          Moreover, if you're using Java, the Spring Framework provides several facilities for implementing a custom event publishing solution, plus a ready to use solution provided by its Spring Modules. However, we are off-topic here, so if you're interested go through the Spring forums and/or feel free to contact me by private mail.

          Cheers,

          Sergio B.

          --
          Sergio Bossa
          Software analyst and developer, blogger and Open Source enthusiast.
          Blogging on: http://sbtourist.blogspot.com
        • Patrick Bohan
          I wrote a rather complex validation system for end-user application. I ll take a moment to describe it because the solution I built may help you. We had three
          Message 4 of 26 , Jun 28 5:02 AM
            I wrote a rather complex validation system for end-user application.
            I'll take a moment to describe it because the solution I built may help you.

            We had three levels of validation:
            1) Invalid data entry at a field/property level. (For example the user
            enters 10 when the value can be between 1 and 5)
            2) Valid data for field but invalid for object. (For example the sum of
            two separate fields is greater than some quantity)
            3) Valid data for object but invalid data across objects in the same set
            or hierarchy. (For example two Employees with the same SSN.)

            To solve this we actually used a layered approach which involved all of
            the different techniques you describe. Each layer described above suits
            itself better to one of the types.

            Here was my solution:

            First, create a class that encapsulates the validation error or message.
            Use that everywhere. That makes the consumers only have to deal with one
            type of class (or hierarchy) regardless of how they are notified. (Our
            version referenced the object(s) and field(s) that caused the error so
            we could reference the source of the validation error.)

            1) Throw an exception (that contains the validation class described
            above) on invalid data input. This prevents the object from entering a
            non-persistable state, i.e. the GUI allows values the fields do not
            (which can be the case for some GUI controls) or the Database schema
            would prevent an update. We used exceptions because a) we used get/set
            methods and it allowed us to prevent invalid state from ever occurring.

            2) & 3) Use an event notification system AND an "isValid" check. We used
            the event notification to update GUIs and such while an object was being
            modified. But before we actually persisted anything we ran a final
            "isValid" check. (Both the event notification and the "isValid" method
            used that same validation class described above.)

            For validation rules, we built a library/singleton called
            "ArchValidator" that housed all the validation rules, ran all possible
            checks, and broadcasted the validation class to listeners or through
            Exceptions. The validation rules were a suite of simple little classes
            that had "isValid( object o)" methods which returned validation classes.
            (We found through experience that an "isValid" that returns a boolean
            was never actually useful.)

            The solution worked out surprisingly well. It was clean and ubiquitous;
            both the GUIs and the business logic used the same validation routines.
            The validation also worked against external APIs and against a rule engine.

            ARKBAN

            P.S.: I agree with other posters that exceptions should normally not be
            used, but with a classic "set" method there is no other notification
            back. If you can avoid exceptions I would do so, they are simply not an
            ideal way to send messages back. But remember that the guideline about
            not using exceptions for messaging is like any other guideline - there
            are cases where no other solution works or works as well.

            I state this because I had to fight the "never use exceptions as
            messages" argument repeatedly. I won that fight because I had explored
            many other options and no one could offer any superior solution. In fact
            no one could offer a solid reason NOT to use Exceptions except for the
            guideline (in our situation, not in general).

            Jesse Napier wrote:
            >
            >
            > I have a question regarding business logic validation in my domain. Im
            > not talking about validation in the sense of simple data validation such
            > as checking for null values or specific data ranges. These days it
            > seems like most people are handling these types of validations with a
            > validation framework and checking an IsValid operation or something
            > similar. I refer to these as data validations. It may be fine in some
            > domains for an object to exist and be persisted when that object is in
            > an invalid data state. I am faced with an issue in which I cannot
            > allow certain objects to ever be in an invalid state.
            >
            > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
            > accounts, but there are rules regarding redemption. If any of these
            > rules are violated, redemption cannot succeed and the application must
            > prevent the redemption. These rule violations are not fatal and are to
            > be expected, however I must notify the user as to why the redemption did
            > not succeed. So my question is, what is the preferred way of
            > communicating business rule violations to the UI when an action cannot
            > be performed because it would put the object into an invalid state that
            > cannot be persisted?
            >
            > I think there are essentialy 4 ways:
            > 1) Throw an exception describing the first violation
            > 2) Use Notification pattern
            > <http://www.martinfowler.com/eaaDev/Notification.html> to communicate
            > information about all violations.
            > 3) Throw an exception that encapsulates the Notification object as
            > described in Sergio's blog post, A Notification Strategy for Business
            > Errors
            > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html>
            > 4) Provide a Check operation which returns a a boolean or a Notification
            > object such as /Notification CanRedeem(Account); /or /bool
            > CanRedeem(Account); /If the check operation returns any violations,
            > Redeem would throw an exception.
            >
            > The thought of throwing exceptions doesn't sit real well with me but it
            > is the easiest way to get the information to any interested parties
            > because they just have to try...catch it. The Notification pattern has
            > value but it seems more difficult to get the information to the
            > interested parties. Granted, the Redeem operation on PromoCode is a
            > void operation and I could just return a Notification object from that
            > call. However, in my research for this problem Im trying to comeup with
            > a solution that would also work with operations that had a return
            > value. #4 is an instersting option but im a little turned off by it
            > because the check would have to be called multiple times, once from the
            > client and once from the redeem operation. Here is a sample
            >
            > public class PromoCode{
            >
            > string code;
            > DateTime expirationDate;
            > bool isRedeemed;
            > bool isOnlyForNewAccounts;
            >
            > public Notification CanRedeem(Account account){
            > Notification violations = new Notification();
            >
            > if(this.isRedeemed){
            > violations.Add(PromoCodeViolation.AlreadyRedeemed);
            > }
            >
            > if(this.expirationDate > DateTime.Now){
            > violations.Add(PromoCodeViolation.Expired);
            > }
            >
            > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
            > violations.Add(PromoCodeViolation.NewAccountsOnly);
            > }
            >
            > return violations;
            > }
            >
            > public void Redeem(Account account){
            > Notification violations = this.CanRedeem(account);
            >
            > if(violations.HasErrors){
            > throw new BusinessRuleException(violations);
            > }
            >
            > this.DoRedeem(account);
            > }
            >
            > protected void DoRedeem(Account account){
            > ...
            > }
            > }
            >
            >
            > public class PromoCodeTest{
            >
            > public void RunCanRedeem(){
            >
            > Account testAccount = Mock.GetMock<Account>();
            >
            > PromoCode code = CreateValidPromoCode();
            >
            > if(code.CanRedeem(testAccount).HasErrors == false){
            > code.Redeem(testAccount);
            >
            > Assert.IsTrue(code.IsRedeemed);
            > }
            > }
            > }
            >
            >
            >
            > Any thoughts or advice on this? Any ways to improve it? Or is the a
            > better strategy that I havent seen?
            >
            > Thanks,
            > Jesse
          • Jiho Han
            It seems to me that there are quite a bit of redundant work going on with your design. First, I d agree with the general notion (from many posts) that throwing
            Message 5 of 26 , Jun 28 6:31 AM
              It seems to me that there are quite a bit of redundant work going on
              with your design.
              First, I'd agree with the general notion (from many posts) that throwing
              exceptions as a validation error does not sound like a good idea. And
              of course, that's not just following a guideline but that it's expensive
              to throw and handle exceptions.

              Regarding 1), why not validate in set method before actually setting the
              value if entering an invalid state for the given object is a concern?
              Then upon rule violation, an event (or a callback perhaps, as opposed to
              an exception) can be raised.

              You also indicate that you had an event notification system that updated
              GUIs while the object was being modified so I assume that you actually
              have an implementation of the above in place already. What I don't
              understand is the need for the "final check". Perhaps I'm missing
              something and there are other processes in the app that modifies the
              object at the same time?

              Definitely, however, it should be possible not to throw an exception on
              a setter.

              By the way, I'm new to this list and I must say I'm getting a lot of new
              ideas and clarifications on aspects of design that were dim and dark
              previously :) It's great.

              Jiho

              -----Original Message-----
              From: domaindrivendesign@yahoogroups.com
              [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Patrick Bohan
              Sent: Thursday, June 28, 2007 8:03 AM
              To: domaindrivendesign@yahoogroups.com
              Subject: Re: [domaindrivendesign] To throw or not to throw on Rule
              Violation

              I wrote a rather complex validation system for end-user application.
              I'll take a moment to describe it because the solution I built may help
              you.

              We had three levels of validation:
              1) Invalid data entry at a field/property level. (For example the user
              enters 10 when the value can be between 1 and 5)
              2) Valid data for field but invalid for object. (For example the sum of
              two separate fields is greater than some quantity)
              3) Valid data for object but invalid data across objects in the same set
              or hierarchy. (For example two Employees with the same SSN.)

              To solve this we actually used a layered approach which involved all of
              the different techniques you describe. Each layer described above suits
              itself better to one of the types.

              Here was my solution:

              First, create a class that encapsulates the validation error or message.

              Use that everywhere. That makes the consumers only have to deal with one
              type of class (or hierarchy) regardless of how they are notified. (Our
              version referenced the object(s) and field(s) that caused the error so
              we could reference the source of the validation error.)

              1) Throw an exception (that contains the validation class described
              above) on invalid data input. This prevents the object from entering a
              non-persistable state, i.e. the GUI allows values the fields do not
              (which can be the case for some GUI controls) or the Database schema
              would prevent an update. We used exceptions because a) we used get/set
              methods and it allowed us to prevent invalid state from ever occurring.

              2) & 3) Use an event notification system AND an "isValid" check. We used
              the event notification to update GUIs and such while an object was being
              modified. But before we actually persisted anything we ran a final
              "isValid" check. (Both the event notification and the "isValid" method
              used that same validation class described above.)

              For validation rules, we built a library/singleton called
              "ArchValidator" that housed all the validation rules, ran all possible
              checks, and broadcasted the validation class to listeners or through
              Exceptions. The validation rules were a suite of simple little classes
              that had "isValid( object o)" methods which returned validation classes.

              (We found through experience that an "isValid" that returns a boolean
              was never actually useful.)

              The solution worked out surprisingly well. It was clean and ubiquitous;
              both the GUIs and the business logic used the same validation routines.
              The validation also worked against external APIs and against a rule
              engine.

              ARKBAN

              P.S.: I agree with other posters that exceptions should normally not be
              used, but with a classic "set" method there is no other notification
              back. If you can avoid exceptions I would do so, they are simply not an
              ideal way to send messages back. But remember that the guideline about
              not using exceptions for messaging is like any other guideline - there
              are cases where no other solution works or works as well.

              I state this because I had to fight the "never use exceptions as
              messages" argument repeatedly. I won that fight because I had explored
              many other options and no one could offer any superior solution. In fact
              no one could offer a solid reason NOT to use Exceptions except for the
              guideline (in our situation, not in general).

              Jesse Napier wrote:
              >
              >
              > I have a question regarding business logic validation in my domain. Im

              > not talking about validation in the sense of simple data validation
              > such as checking for null values or specific data ranges. These days
              > it seems like most people are handling these types of validations with

              > a validation framework and checking an IsValid operation or something
              > similar. I refer to these as data validations. It may be fine in
              > some domains for an object to exist and be persisted when that object
              > is in an invalid data state. I am faced with an issue in which I
              > cannot allow certain objects to ever be in an invalid state.
              >
              > In my domain I have PromoCode and Account. PromoCodes can be redeemed
              > by accounts, but there are rules regarding redemption. If any of
              > these rules are violated, redemption cannot succeed and the
              > application must prevent the redemption. These rule violations are
              > not fatal and are to be expected, however I must notify the user as to

              > why the redemption did not succeed. So my question is, what is the
              > preferred way of communicating business rule violations to the UI when

              > an action cannot be performed because it would put the object into an
              > invalid state that cannot be persisted?
              >
              > I think there are essentialy 4 ways:
              > 1) Throw an exception describing the first violation
              > 2) Use Notification pattern
              > <http://www.martinfowler.com/eaaDev/Notification.html> to communicate
              > information about all violations.
              > 3) Throw an exception that encapsulates the Notification object as
              > described in Sergio's blog post, A Notification Strategy for Business
              > Errors
              > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin
              > ess.html>
              > 4) Provide a Check operation which returns a a boolean or a
              > Notification object such as /Notification CanRedeem(Account); /or
              > /bool CanRedeem(Account); /If the check operation returns any
              > violations, Redeem would throw an exception.
              >
              > The thought of throwing exceptions doesn't sit real well with me but
              > it is the easiest way to get the information to any interested parties

              > because they just have to try...catch it. The Notification pattern
              > has value but it seems more difficult to get the information to the
              > interested parties. Granted, the Redeem operation on PromoCode is a
              > void operation and I could just return a Notification object from that

              > call. However, in my research for this problem Im trying to comeup
              > with a solution that would also work with operations that had a return

              > value. #4 is an instersting option but im a little turned off by it
              > because the check would have to be called multiple times, once from
              > the client and once from the redeem operation. Here is a sample
              >
              > public class PromoCode{
              >
              > string code;
              > DateTime expirationDate;
              > bool isRedeemed;
              > bool isOnlyForNewAccounts;
              >
              > public Notification CanRedeem(Account account){
              > Notification violations = new Notification();
              >
              > if(this.isRedeemed){
              > violations.Add(PromoCodeViolation.AlreadyRedeemed);
              > }
              >
              > if(this.expirationDate > DateTime.Now){
              > violations.Add(PromoCodeViolation.Expired);
              > }
              >
              > if(this.isOnlyForNewAccounts && account.IsNewAccount ==
              false){
              > violations.Add(PromoCodeViolation.NewAccountsOnly);
              > }
              >
              > return violations;
              > }
              >
              > public void Redeem(Account account){
              > Notification violations = this.CanRedeem(account);
              >
              > if(violations.HasErrors){
              > throw new BusinessRuleException(violations);
              > }
              >
              > this.DoRedeem(account);
              > }
              >
              > protected void DoRedeem(Account account){
              > ...
              > }
              > }
              >
              >
              > public class PromoCodeTest{
              >
              > public void RunCanRedeem(){
              >
              > Account testAccount = Mock.GetMock<Account>();
              >
              > PromoCode code = CreateValidPromoCode();
              >
              > if(code.CanRedeem(testAccount).HasErrors == false){
              > code.Redeem(testAccount);
              >
              > Assert.IsTrue(code.IsRedeemed);
              > }
              > }
              > }
              >
              >
              >
              > Any thoughts or advice on this? Any ways to improve it? Or is the a
              > better strategy that I havent seen?
              >
              > Thanks,
              > Jesse



              Yahoo! Groups Links
            • Joe A. Reddy
              Count me as vote number two for not using Exceptions to capture what sounds like real business concepts. I like the idea of creating a class, whether vague
              Message 6 of 26 , Jun 28 6:45 AM

                Count me as vote number two for not using Exceptions to capture what sounds like real business concepts.

                I like the idea of creating a class, whether vague like Violations or specific like RedemtionIssues.

                When it comes to events, I first question the developer about their value.

                To me events are often an unneeded level of misdirection for some poor developer to track down when something is not wired up right.

                Whether events are overkill or not would be your own decision based on your other developers and environment.

                (Please don’t start a thread about how Joe thinks events are bad, that’s not what I am saying. I just question anyone’s suggestion of using them much like I question nullable database fields, mutable objects, business objects with no methods, separate bank accounts, deciding a match on penalty kicks, light beer, and cats.)

                 

                Cheers,

                Joe

                 

                -----Original Message-----
                From:
                domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jesse Napier
                Sent:
                Wednesday, June 27, 2007 8:41 PM
                To:
                domaindrivendesign@yahoogroups.com
                Subject: [domaindrivendesign] To throw or not to throw on Rule Violation

                 

                I have a question regarding business logic validation in my domain. Im not talking about validation in the sense of simple data validation such as checking for null values or specific data ranges.  These days it seems like most people are handling these types of validations with a validation framework and checking an IsValid operation or something similar.  I refer to these as data validations.  It may be fine in some domains for an object to exist and be persisted when that object is in an invalid data state.  I am faced with an issue in which I cannot allow certain objects to ever be in an invalid state. 

                 

                In my domain I have PromoCode and Account. PromoCodes can be redeemed by accounts, but there are rules regarding redemption.  If any of these rules are violated, redemption cannot succeed and the application must prevent the redemption.  These rule violations are not fatal and are to be expected, however I must notify the user as to why the redemption did not succeed.  So my question is, what is the preferred way of communicating business rule violations to the UI when an action cannot be performed because it would put the object into an invalid state that cannot be persisted?

                 

                I think there are essentialy 4 ways:

                1) Throw an exception describing the first violation

                2) Use Notification pattern to communicate information about all violations.

                3) Throw an exception that encapsulates the Notification object as described in Sergio's blog post, A Notification Strategy for Business Errors

                4) Provide a Check operation which returns a a boolean or a Notification object such as Notification CanRedeem(Account) ; or bool CanRedeem(Account) ;  If the check operation returns any violations, Redeem would throw an exception.

                 

                The thought of throwing exceptions doesn't sit real well with me but it is the easiest way to get the information to any interested parties because they just have to try...catch it.  The Notification pattern has value but it seems more difficult to get the information to the interested parties.  Granted, the Redeem operation on PromoCode is a void operation and I could just return a Notification object from that call. However, in my research for this problem Im trying to comeup with a solution that would also work with operations that had a return value.  #4 is an instersting option but im a little turned off by it because the check would have to be called multiple times, once from the client and once from the redeem operation.  Here is a sample

                 

                public class PromoCode{

                 

                    string code;

                    DateTime expirationDate;

                    bool isRedeemed;

                    bool isOnlyForNewAccount s; 

                   

                    public Notification CanRedeem(Account account){

                        Notification violations = new Notification( );

                       

                        if(this.isRedeemed) {

                            violations.Add( PromoCodeViolati on.AlreadyRedeem ed);       

                        }

                 

                        if(this.expirationD ate > DateTime.Now) {

                            violations.Add( PromoCodeViolati on.Expired) ;

                        }

                 

                        if(this.isOnlyForNe wAccounts && account.IsNewAccoun t == false){

                           violations.Add( PromoCodeViolati on.NewAccountsOn ly);

                        }

                       

                        return violations;

                    }

                   

                    public void Redeem(Account account){

                        Notification violations = this.CanRedeem( account);

                       

                        if(violations. HasErrors) {

                            throw new BusinessRuleExcepti on(violations) ;

                        }

                 

                        this.DoRedeem( account);

                    } 

                   

                    protected void DoRedeem(Account account){

                        ...

                    }

                }

                 

                 

                public class PromoCodeTest{

                 

                    public void RunCanRedeem( ){

                       

                        Account testAccount = Mock.GetMock<Account>();

                       

                        PromoCode code = CreateValidPromoCod e();

                 

                        if(code.CanRedeem( testAccount) .HasErrors == false){

                            code.Redeem( testAccount) ;

                 

                            Assert.IsTrue( code.IsRedeemed) ;

                        }

                    }

                }

                 

                 

                 

                Any thoughts or advice on this?  Any ways to improve it?  Or is the a better strategy that I havent seen?

                 

                Thanks,

                Jesse

                 

                 

              • Jeff Lowe
                Call me old fashioned, but I prefer simply throwing a checked exception. The exception then becomes part of the method signature, which makes for a more
                Message 7 of 26 , Jun 28 6:52 AM
                  Call me old fashioned, but I prefer simply throwing a checked exception.  The exception then becomes part of the method signature, which makes for a more expressive domain interface, e.g.:
                   
                  public redeem(Account account) throws PromotionRulesViolationException
                   
                  The exception can then encapsulate everything needed by the client (i.e. application) to communicate back to the user, including information about multiple rule violations. 
                   
                  >> The thought of throwing exceptions doesn't sit real well with me but ...
                   
                  I'm curious why it doesn't sit well.  Other folks have also expressed this.
                   
                   
                  Thanks,
                  -Jeff
                   


                  From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jesse Napier
                  Sent: Wednesday, June 27, 2007 9:41 PM
                  To: domaindrivendesign@yahoogroups.com
                  Subject: [domaindrivendesign] To throw or not to throw on Rule Violation

                  I have a question regarding business logic validation in my domain. Im not talking about validation in the sense of simple data validation such as checking for null values or specific data ranges.  These days it seems like most people are handling these types of validations with a validation framework and checking an IsValid operation or something similar.  I refer to these as data validations.  It may be fine in some domains for an object to exist and be persisted when that object is in an invalid data state.  I am faced with an issue in which I cannot allow certain objects to ever be in an invalid state. 
                   
                  In my domain I have PromoCode and Account. PromoCodes can be redeemed by accounts, but there are rules regarding redemption.  If any of these rules are violated, redemption cannot succeed and the application must prevent the redemption.  These rule violations are not fatal and are to be expected, however I must notify the user as to why the redemption did not succeed.  So my question is, what is the preferred way of communicating business rule violations to the UI when an action cannot be performed because it would put the object into an invalid state that cannot be persisted?
                   
                  I think there are essentialy 4 ways:
                  1) Throw an exception describing the first violation
                  2) Use Notification pattern to communicate information about all violations.
                  3) Throw an exception that encapsulates the Notification object as described in Sergio's blog post, A Notification Strategy for Business Errors
                  4) Provide a Check operation which returns a a boolean or a Notification object such as Notification CanRedeem(Account) ; or bool CanRedeem(Account) ;  If the check operation returns any violations, Redeem would throw an exception.
                   
                  The thought of throwing exceptions doesn't sit real well with me but it is the easiest way to get the information to any interested parties because they just have to try...catch it.  The Notification pattern has value but it seems more difficult to get the information to the interested parties.  Granted, the Redeem operation on PromoCode is a void operation and I could just return a Notification object from that call. However, in my research for this problem Im trying to comeup with a solution that would also work with operations that had a return value.  #4 is an instersting option but im a little turned off by it because the check would have to be called multiple times, once from the client and once from the redeem operation.  Here is a sample
                   
                  public class PromoCode{
                   
                      string code;
                      DateTime expirationDate;
                      bool isRedeemed;
                      bool isOnlyForNewAccount s; 
                     
                      public Notification CanRedeem(Account account){
                          Notification violations = new Notification( );
                         
                          if(this.isRedeemed) {
                              violations.Add( PromoCodeViolati on.AlreadyRedeem ed);       
                          }
                   
                          if(this.expirationD ate > DateTime.Now) {
                              violations.Add( PromoCodeViolati on.Expired) ;
                          }
                   
                          if(this.isOnlyForNe wAccounts && account.IsNewAccoun t == false){
                             violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                          }
                         
                          return violations;
                      }
                     
                      public void Redeem(Account account){
                          Notification violations = this.CanRedeem( account);
                         
                          if(violations. HasErrors) {
                              throw new BusinessRuleExcepti on(violations) ;
                          }
                   
                          this.DoRedeem( account);
                      } 
                     
                      protected void DoRedeem(Account account){
                          ...
                      }
                  }
                   
                   
                  public class PromoCodeTest{
                   
                      public void RunCanRedeem( ){
                         
                          Account testAccount = Mock.GetMock<Account>();
                         
                          PromoCode code = CreateValidPromoCod e();
                   
                          if(code.CanRedeem( testAccount) .HasErrors == false){
                              code.Redeem( testAccount) ;
                   
                              Assert.IsTrue( code.IsRedeemed) ;
                          }
                      }
                  }
                   
                   
                   
                  Any thoughts or advice on this?  Any ways to improve it?  Or is the a better strategy that I havent seen?
                   
                  Thanks,
                  Jesse
                   
                   

                • ARKBAN
                  ... I agree there was redundancy; it was intentional. Redundancy is good in many situations, i.e. RAID. It simply needs to be managed well. ... I agree expense
                  Message 8 of 26 , Jun 28 7:01 AM
                    Jiho Han wrote:
                    >
                    >
                    > It seems to me that there are quite a bit of redundant work going on
                    > with your design.

                    I agree there was redundancy; it was intentional. Redundancy is good in
                    many situations, i.e. RAID. It simply needs to be managed well.

                    > First, I'd agree with the general notion (from many posts) that throwing
                    > exceptions as a validation error does not sound like a good idea. And
                    > of course, that's not just following a guideline but that it's expensive
                    > to throw and handle exceptions.

                    I agree expense is a concern. But for a UI heavy application (like the
                    one I built the validation system for) the cost an Exception being throw
                    is imperceptible to the user.

                    > Regarding 1), why not validate in set method before actually setting the
                    > value if entering an invalid state for the given object is a concern?
                    > Then upon rule violation, an event (or a callback perhaps, as opposed to
                    > an exception) can be raised.

                    That's what we did. But it's very easy in a large system to accidentally
                    ignore the callback. Developers are human after all. On our project you
                    then ran the risk of corrupted data. That was a risk we could not allow.
                    Corrupted data would have propagated through the system at very quick
                    rate given the rule engine which acted in parallel with users. Also
                    corrupted data had a very high real-world impact. (You didn't want to
                    find out that the plane you were in didn't have parachutes because some
                    how an operator entered "0" for the parachute count. No I'm not
                    exaggerating.)

                    > You also indicate that you had an event notification system that updated
                    > GUIs while the object was being modified so I assume that you actually
                    > have an implementation of the above in place already. What I don't
                    > understand is the need for the "final check". Perhaps I'm missing
                    > something and there are other processes in the app that modifies the
                    > object at the same time?

                    The final check for us was to perform some more complex validation
                    checking that was too slow to be performed on each edit. And yes you are
                    correct you could edit the object from multiple locations (within the
                    same UI, across different machines, the rule engine in parallel, web
                    service entry points, etc).

                    > Definitely, however, it should be possible not to throw an exception on
                    > a setter.

                    As I said in my original email, it is very possible not to throw an
                    exception. But there are trade-offs, and I explored those trade offs and
                    decide that thrown an Exception was the best approach. I'm not
                    advocating it as a good design philosophy, but on the other hand no rule
                    should be followed blindly. There is a reason GOTO still exists in C,
                    even if it's rarely used.

                    > By the way, I'm new to this list and I must say I'm getting a lot of new
                    > ideas and clarifications on aspects of design that were dim and dark
                    > previously :) It's great.
                    >
                    > Jiho
                    >
                    > -----Original Message-----
                    > From: domaindrivendesign@yahoogroups.com
                    > <mailto:domaindrivendesign%40yahoogroups.com>
                    > [mailto:domaindrivendesign@yahoogroups.com
                    > <mailto:domaindrivendesign%40yahoogroups.com>] On Behalf Of Patrick Bohan
                    > Sent: Thursday, June 28, 2007 8:03 AM
                    > To: domaindrivendesign@yahoogroups.com
                    > <mailto:domaindrivendesign%40yahoogroups.com>
                    > Subject: Re: [domaindrivendesign] To throw or not to throw on Rule
                    > Violation
                    >
                    > I wrote a rather complex validation system for end-user application.
                    > I'll take a moment to describe it because the solution I built may help
                    > you.
                    >
                    > We had three levels of validation:
                    > 1) Invalid data entry at a field/property level. (For example the user
                    > enters 10 when the value can be between 1 and 5)
                    > 2) Valid data for field but invalid for object. (For example the sum of
                    > two separate fields is greater than some quantity)
                    > 3) Valid data for object but invalid data across objects in the same set
                    > or hierarchy. (For example two Employees with the same SSN.)
                    >
                    > To solve this we actually used a layered approach which involved all of
                    > the different techniques you describe. Each layer described above suits
                    > itself better to one of the types.
                    >
                    > Here was my solution:
                    >
                    > First, create a class that encapsulates the validation error or message.
                    >
                    > Use that everywhere. That makes the consumers only have to deal with one
                    > type of class (or hierarchy) regardless of how they are notified. (Our
                    > version referenced the object(s) and field(s) that caused the error so
                    > we could reference the source of the validation error.)
                    >
                    > 1) Throw an exception (that contains the validation class described
                    > above) on invalid data input. This prevents the object from entering a
                    > non-persistable state, i.e. the GUI allows values the fields do not
                    > (which can be the case for some GUI controls) or the Database schema
                    > would prevent an update. We used exceptions because a) we used get/set
                    > methods and it allowed us to prevent invalid state from ever occurring.
                    >
                    > 2) & 3) Use an event notification system AND an "isValid" check. We used
                    > the event notification to update GUIs and such while an object was being
                    > modified. But before we actually persisted anything we ran a final
                    > "isValid" check. (Both the event notification and the "isValid" method
                    > used that same validation class described above.)
                    >
                    > For validation rules, we built a library/singleton called
                    > "ArchValidator" that housed all the validation rules, ran all possible
                    > checks, and broadcasted the validation class to listeners or through
                    > Exceptions. The validation rules were a suite of simple little classes
                    > that had "isValid( object o)" methods which returned validation classes.
                    >
                    > (We found through experience that an "isValid" that returns a boolean
                    > was never actually useful.)
                    >
                    > The solution worked out surprisingly well. It was clean and ubiquitous;
                    > both the GUIs and the business logic used the same validation routines.
                    > The validation also worked against external APIs and against a rule
                    > engine.
                    >
                    > ARKBAN
                    >
                    > P.S.: I agree with other posters that exceptions should normally not be
                    > used, but with a classic "set" method there is no other notification
                    > back. If you can avoid exceptions I would do so, they are simply not an
                    > ideal way to send messages back. But remember that the guideline about
                    > not using exceptions for messaging is like any other guideline - there
                    > are cases where no other solution works or works as well.
                    >
                    > I state this because I had to fight the "never use exceptions as
                    > messages" argument repeatedly. I won that fight because I had explored
                    > many other options and no one could offer any superior solution. In fact
                    > no one could offer a solid reason NOT to use Exceptions except for the
                    > guideline (in our situation, not in general).
                    >
                    > Jesse Napier wrote:
                    > >
                    > >
                    > > I have a question regarding business logic validation in my domain. Im
                    >
                    > > not talking about validation in the sense of simple data validation
                    > > such as checking for null values or specific data ranges. These days
                    > > it seems like most people are handling these types of validations with
                    >
                    > > a validation framework and checking an IsValid operation or something
                    > > similar. I refer to these as data validations. It may be fine in
                    > > some domains for an object to exist and be persisted when that object
                    > > is in an invalid data state. I am faced with an issue in which I
                    > > cannot allow certain objects to ever be in an invalid state.
                    > >
                    > > In my domain I have PromoCode and Account. PromoCodes can be redeemed
                    > > by accounts, but there are rules regarding redemption. If any of
                    > > these rules are violated, redemption cannot succeed and the
                    > > application must prevent the redemption. These rule violations are
                    > > not fatal and are to be expected, however I must notify the user as to
                    >
                    > > why the redemption did not succeed. So my question is, what is the
                    > > preferred way of communicating business rule violations to the UI when
                    >
                    > > an action cannot be performed because it would put the object into an
                    > > invalid state that cannot be persisted?
                    > >
                    > > I think there are essentialy 4 ways:
                    > > 1) Throw an exception describing the first violation
                    > > 2) Use Notification pattern
                    > > <http://www.martinfowler.com/eaaDev/Notification.html
                    > <http://www.martinfowler.com/eaaDev/Notification.html>> to communicate
                    > > information about all violations.
                    > > 3) Throw an exception that encapsulates the Notification object as
                    > > described in Sergio's blog post, A Notification Strategy for Business
                    > > Errors
                    > >
                    > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin
                    > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin>
                    > > ess.html>
                    > > 4) Provide a Check operation which returns a a boolean or a
                    > > Notification object such as /Notification CanRedeem(Account); /or
                    > > /bool CanRedeem(Account); /If the check operation returns any
                    > > violations, Redeem would throw an exception.
                    > >
                    > > The thought of throwing exceptions doesn't sit real well with me but
                    > > it is the easiest way to get the information to any interested parties
                    >
                    > > because they just have to try...catch it. The Notification pattern
                    > > has value but it seems more difficult to get the information to the
                    > > interested parties. Granted, the Redeem operation on PromoCode is a
                    > > void operation and I could just return a Notification object from that
                    >
                    > > call. However, in my research for this problem Im trying to comeup
                    > > with a solution that would also work with operations that had a return
                    >
                    > > value. #4 is an instersting option but im a little turned off by it
                    > > because the check would have to be called multiple times, once from
                    > > the client and once from the redeem operation. Here is a sample
                    > >
                    > > public class PromoCode{
                    > >
                    > > string code;
                    > > DateTime expirationDate;
                    > > bool isRedeemed;
                    > > bool isOnlyForNewAccounts;
                    > >
                    > > public Notification CanRedeem(Account account){
                    > > Notification violations = new Notification();
                    > >
                    > > if(this.isRedeemed){
                    > > violations.Add(PromoCodeViolation.AlreadyRedeemed);
                    > > }
                    > >
                    > > if(this.expirationDate > DateTime.Now){
                    > > violations.Add(PromoCodeViolation.Expired);
                    > > }
                    > >
                    > > if(this.isOnlyForNewAccounts && account.IsNewAccount ==
                    > false){
                    > > violations.Add(PromoCodeViolation.NewAccountsOnly);
                    > > }
                    > >
                    > > return violations;
                    > > }
                    > >
                    > > public void Redeem(Account account){
                    > > Notification violations = this.CanRedeem(account);
                    > >
                    > > if(violations.HasErrors){
                    > > throw new BusinessRuleException(violations);
                    > > }
                    > >
                    > > this.DoRedeem(account);
                    > > }
                    > >
                    > > protected void DoRedeem(Account account){
                    > > ...
                    > > }
                    > > }
                    > >
                    > >
                    > > public class PromoCodeTest{
                    > >
                    > > public void RunCanRedeem(){
                    > >
                    > > Account testAccount = Mock.GetMock<Account>();
                    > >
                    > > PromoCode code = CreateValidPromoCode();
                    > >
                    > > if(code.CanRedeem(testAccount).HasErrors == false){
                    > > code.Redeem(testAccount);
                    > >
                    > > Assert.IsTrue(code.IsRedeemed);
                    > > }
                    > > }
                    > > }
                    > >
                    > >
                    > >
                    > > Any thoughts or advice on this? Any ways to improve it? Or is the a
                    > > better strategy that I havent seen?
                    > >
                    > > Thanks,
                    > > Jesse
                    >
                    > Yahoo! Groups Links
                    >
                    >
                  • ARKBAN
                    I think the concern revolves around the mantra exceptions are for exceptional situations . Validation is most often not exceptional but expected; validation
                    Message 9 of 26 , Jun 28 7:09 AM
                      I think the concern revolves around the mantra "exceptions are for
                      exceptional situations". Validation is most often not exceptional but
                      expected; validation checks for situations that occur easily but can be
                      easily corrected, which are not really exceptional.

                      ARKBAN

                      Jeff Lowe wrote:
                      >
                      >
                      > Call me old fashioned, but I prefer simply throwing a
                      > checked exception. The exception then becomes part of the method
                      > signature, which makes for a more expressive domain interface, e.g.:
                      >
                      > public redeem(Account account) throws PromotionRulesViolationException
                      >
                      > The exception can then encapsulate everything needed by the client (i.e.
                      > application) to communicate back to the user, including information
                      > about multiple rule violations.
                      >
                      >> > The thought of throwing exceptions doesn't sit real well with me but ...
                      >
                      > I'm curious why it doesn't sit well. Other folks have also expressed this.
                      >
                      >
                      > Thanks,
                      > -Jeff
                      >
                      >
                      > ------------------------------------------------------------------------
                      > *From:* domaindrivendesign@yahoogroups.com
                      > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *Jesse Napier
                      > *Sent:* Wednesday, June 27, 2007 9:41 PM
                      > *To:* domaindrivendesign@yahoogroups.com
                      > *Subject:* [domaindrivendesign] To throw or not to throw on Rule Violation
                      >
                      > I have a question regarding business logic validation in my domain. Im
                      > not talking about validation in the sense of simple data validation such
                      > as checking for null values or specific data ranges. These days it
                      > seems like most people are handling these types of validations with a
                      > validation framework and checking an IsValid operation or something
                      > similar. I refer to these as data validations. It may be fine in some
                      > domains for an object to exist and be persisted when that object is in
                      > an invalid data state. I am faced with an issue in which I cannot
                      > allow certain objects to ever be in an invalid state.
                      >
                      > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                      > accounts, but there are rules regarding redemption. If any of these
                      > rules are violated, redemption cannot succeed and the application must
                      > prevent the redemption. These rule violations are not fatal and are to
                      > be expected, however I must notify the user as to why the redemption did
                      > not succeed. So my question is, what is the preferred way of
                      > communicating business rule violations to the UI when an action cannot
                      > be performed because it would put the object into an invalid state that
                      > cannot be persisted?
                      >
                      > I think there are essentialy 4 ways:
                      > 1) Throw an exception describing the first violation
                      > 2) Use Notification pattern
                      > <http://www.martinfowler.com/eaaDev/Notification.html> to communicate
                      > information about all violations.
                      > 3) Throw an exception that encapsulates the Notification object as
                      > described in Sergio's blog post, A Notification Strategy for Business
                      > Errors
                      > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html>
                      > 4) Provide a Check operation which returns a a boolean or a Notification
                      > object such as /Notification CanRedeem(Account); /or /bool
                      > CanRedeem(Account); /If the check operation returns any violations,
                      > Redeem would throw an exception.
                      >
                      > The thought of throwing exceptions doesn't sit real well with me but it
                      > is the easiest way to get the information to any interested parties
                      > because they just have to try...catch it. The Notification pattern has
                      > value but it seems more difficult to get the information to the
                      > interested parties. Granted, the Redeem operation on PromoCode is a
                      > void operation and I could just return a Notification object from that
                      > call. However, in my research for this problem Im trying to comeup with
                      > a solution that would also work with operations that had a return
                      > value. #4 is an instersting option but im a little turned off by it
                      > because the check would have to be called multiple times, once from the
                      > client and once from the redeem operation. Here is a sample
                      >
                      > public class PromoCode{
                      >
                      > string code;
                      > DateTime expirationDate;
                      > bool isRedeemed;
                      > bool isOnlyForNewAccounts;
                      >
                      > public Notification CanRedeem(Account account){
                      > Notification violations = new Notification();
                      >
                      > if(this.isRedeemed){
                      > violations.Add(PromoCodeViolation.AlreadyRedeemed);
                      > }
                      >
                      > if(this.expirationDate > DateTime.Now){
                      > violations.Add(PromoCodeViolation.Expired);
                      > }
                      >
                      > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                      > violations.Add(PromoCodeViolation.NewAccountsOnly);
                      > }
                      >
                      > return violations;
                      > }
                      >
                      > public void Redeem(Account account){
                      > Notification violations = this.CanRedeem(account);
                      >
                      > if(violations.HasErrors){
                      > throw new BusinessRuleException(violations);
                      > }
                      >
                      > this.DoRedeem(account);
                      > }
                      >
                      > protected void DoRedeem(Account account){
                      > ...
                      > }
                      > }
                      >
                      >
                      > public class PromoCodeTest{
                      >
                      > public void RunCanRedeem(){
                      >
                      > Account testAccount = Mock.GetMock<Account>();
                      >
                      > PromoCode code = CreateValidPromoCode();
                      >
                      > if(code.CanRedeem(testAccount).HasErrors == false){
                      > code.Redeem(testAccount);
                      >
                      > Assert.IsTrue(code.IsRedeemed);
                      > }
                      > }
                      > }
                      >
                      >
                      >
                      > Any thoughts or advice on this? Any ways to improve it? Or is the a
                      > better strategy that I havent seen?
                      >
                      > Thanks,
                      > Jesse
                      >
                      >
                      >
                      >
                    • Jeff Lowe
                      That s a cute mantra. exceptional situation is certainly subjective. As Jesse stated, there s a difference between simple data validation, and the violation
                      Message 10 of 26 , Jun 28 7:45 AM
                        That's a cute mantra.  "exceptional situation" is certainly subjective.
                         
                        As Jesse stated, there's a difference between simple data validation, and the violation of business rules during a non-trivial operation in the domain.  I consider the latter to be an "exceptional situation".
                         
                         


                        From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of ARKBAN
                        Sent: Thursday, June 28, 2007 10:10 AM
                        To: domaindrivendesign@yahoogroups.com
                        Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                        I think the concern revolves around the mantra "exceptions are for
                        exceptional situations". Validation is most often not exceptional but
                        expected; validation checks for situations that occur easily but can be
                        easily corrected, which are not really exceptional.

                        ARKBAN

                        Jeff Lowe wrote:

                        >
                        >
                        >
                        Call me old fashioned, but I prefer simply throwing a
                        > checked
                        exception. The exception then becomes part of the method
                        > signature,
                        which makes for a more expressive domain interface, e.g.:
                        >
                        >
                        public redeem(Account account) throws PromotionRulesViola tionException
                        >
                        > The exception can then
                        encapsulate everything needed by the client (i.e.
                        > application) to
                        communicate back to the user, including information
                        > about multiple rule
                        violations.
                        >
                        >> > The thought of throwing exceptions
                        doesn't sit real well with me but ...
                        >
                        > I'm curious why it
                        doesn't sit well. Other folks have also expressed this.
                        >
                        >
                        > Thanks,
                        > -Jeff
                        >
                        >
                        >
                        ------------ --------- --------- --------- --------- --------- -
                        >
                        *From:* domaindrivendesign@ yahoogroups. com
                        > [mailto:
                        href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jesse Napier
                        > *Sent:* Wednesday, June 27, 2007 9:41
                        PM
                        > *To:*
                        href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com
                        >
                        *Subject:* [domaindrivendesign ] To throw or not to throw on Rule Violation
                        >
                        > I have a question regarding business logic validation
                        in my domain. Im
                        > not talking about validation in the sense of simple
                        data validation such
                        > as checking for null values or specific data
                        ranges. These days it
                        > seems like most people are handling these types
                        of validations with a
                        > validation framework and checking an IsValid
                        operation or something
                        > similar. I refer to these as data validations.
                        It may be fine in some
                        > domains for an object to exist and be persisted
                        when that object is in
                        > an invalid data state. I am faced with an issue
                        in which I cannot
                        > allow certain objects to ever be in an invalid state.
                        >
                        > In my domain I have PromoCode and Account. PromoCodes can be
                        redeemed by
                        > accounts, but there are rules regarding redemption. If any
                        of these
                        > rules are violated, redemption cannot succeed and the
                        application must
                        > prevent the redemption. These rule violations are not
                        fatal and are to
                        > be expected, however I must notify the user as to why
                        the redemption did
                        > not succeed. So my question is, what is the
                        preferred way of
                        > communicating business rule violations to the UI when
                        an action cannot
                        > be performed because it would put the object into an
                        invalid state that
                        > cannot be persisted?
                        >
                        > I think there
                        are essentialy 4 ways:
                        > 1) Throw an exception describing the first
                        violation
                        > 2) Use Notification pattern
                        > <
                        href="http://www.martinfowler.com/eaaDev/Notification.html">http://www.martinfo wler.com/ eaaDev/Notificat ion.html> to communicate
                        > information about all violations.
                        > 3) Throw an
                        exception that encapsulates the Notification object as
                        > described in
                        Sergio's blog post, A Notification Strategy for Business
                        > Errors
                        > <
                        href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html>
                        >
                        4) Provide a Check operation which returns a a boolean or a Notification
                        > object such as /Notification CanRedeem(Account) ; /or /bool
                        > CanRedeem(Account) ; /If the check operation returns any
                        violations,
                        > Redeem would throw an exception.
                        >
                        > The
                        thought of throwing exceptions doesn't sit real well with me but it
                        > is
                        the easiest way to get the information to any interested parties
                        >
                        because they just have to try...catch it. The Notification pattern has
                        >
                        value but it seems more difficult to get the information to the
                        >
                        interested parties. Granted, the Redeem operation on PromoCode is a
                        >
                        void operation and I could just return a Notification object from that
                        >
                        call. However, in my research for this problem Im trying to comeup with
                        >
                        a solution that would also work with operations that had a return
                        >
                        value. #4 is an instersting option but im a little turned off by it
                        >
                        because the check would have to be called multiple times, once from the
                        >
                        client and once from the redeem operation. Here is a sample
                        >
                        >
                        public class PromoCode{
                        >
                        > string code;
                        > DateTime
                        expirationDate;
                        > bool isRedeemed;
                        > bool isOnlyForNewAccount s;
                        >
                        > public Notification CanRedeem(Account account){
                        >
                        Notification violations = new Notification( );
                        >
                        >
                        if(this.isRedeemed) {
                        >
                        violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                        >
                        }
                        >
                        > if(this.expirationD ate > DateTime.Now) {
                        >
                        violations.Add( PromoCodeViolati on.Expired) ;
                        > }
                        >
                        > if(this.isOnlyForNe wAccounts && account.IsNewAccoun t
                        == false){
                        >
                        violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                        >
                        }
                        >
                        > return violations;
                        > }
                        >
                        > public void
                        Redeem(Account account){
                        > Notification violations =
                        this.CanRedeem( account);
                        >
                        >
                        if(violations. HasErrors) {
                        > throw new
                        BusinessRuleExcepti on(violations) ;
                        > }
                        >
                        >
                        this.DoRedeem( account);
                        > }
                        >
                        > protected void
                        DoRedeem(Account account){
                        > ...
                        > }
                        > }
                        >
                        >
                        > public class PromoCodeTest{
                        >
                        > public void
                        RunCanRedeem( ){
                        >
                        > Account testAccount =
                        Mock.GetMock< Account>( );
                        >
                        > PromoCode code =
                        CreateValidPromoCod e();
                        >
                        >
                        if(code.CanRedeem( testAccount) .HasErrors == false){
                        >
                        code.Redeem( testAccount) ;
                        >
                        >
                        Assert.IsTrue( code.IsRedeemed) ;
                        > }
                        > }
                        > }
                        >
                        >
                        >
                        > Any thoughts or advice on this? Any ways to improve
                        it? Or is the a
                        > better strategy that I havent seen?
                        >
                        >
                        Thanks,
                        > Jesse
                        >
                        >
                        >
                        >

                      • cbeams
                        Highly recommended for those who haven t read: Effective Java Exceptions. Especially useful here are the distinctions the author draws between Contingency
                        Message 11 of 26 , Jun 28 8:32 AM
                          Highly recommended for those who haven't read:  Effective Java Exceptions.  Especially useful here are the distinctions the author draws between 'Contingency' exceptions and 'Fault' exceptions.  This will be familiar territory for those who have spent time thinking and reading about when to use checked vs. unchecked exceptions, but wrapping some new language around these concepts has proved very beneficial for my team.  We now talk about our code in terms of 'fault exceptions hitting the fault barrier', and have discussions based on whether 'X scenario is really a contingency or not'.  To that end, it's been a bit like developing a ubiquitous language at the level of the technical infrastructure.

                          The seminal work on Java exceptions, for those not familiar, is Chapter 8 of Joshua Bloch's Effective Java.  I'm recommending the article linked above as something of a companion piece to this earlier work.

                          - Chris

                          Chris Beams



                          On Jun 28, 2007, at 7:45 AM, Jeff Lowe wrote:


                          That's a cute mantra.  "exceptional situation" is certainly subjective.
                           
                          As Jesse stated, there's a difference between simple data validation, and the violation of business rules during a non-trivial operation in the domain.  I consider the latter to be an "exceptional situation".
                           
                           


                          From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of ARKBAN
                          Sent: Thursday, June 28, 2007 10:10 AM
                          To: domaindrivendesign@yahoogroups.com
                          Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                          I think the concern revolves around the mantra "exceptions are for
                          exceptional situations". Validation is most often not exceptional but
                          expected; validation checks for situations that occur easily but can be
                          easily corrected, which are not really exceptional.

                          ARKBAN

                          Jeff Lowe wrote:
                          >
                          >
                          > Call me old fashioned, but I prefer simply throwing a
                          > checked exception. The exception then becomes part of the method
                          > signature, which makes for a more expressive domain interface, e.g.:
                          >
                          > public redeem(Account account) throws PromotionRulesViolationException
                          >
                          > The exception can then encapsulate everything needed by the client (i.e.
                          > application) to communicate back to the user, including information
                          > about multiple rule violations.
                          >
                          >> > The thought of throwing exceptions doesn't sit real well with me but ...
                          >
                          > I'm curious why it doesn't sit well. Other folks have also expressed this.
                          >
                          >
                          > Thanks,
                          > -Jeff
                          >
                          >
                          > ----------------------------------------------------------
                          > *From:* domaindrivendesign@yahoogroups.com
                          > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *Jesse Napier
                          > *Sent:* Wednesday, June 27, 2007 9:41 PM
                          > *To:* domaindrivendesign@yahoogroups.com
                          > *Subject:* [domaindrivendesign] To throw or not to throw on Rule Violation
                          >
                          > I have a question regarding business logic validation in my domain. Im
                          > not talking about validation in the sense of simple data validation such
                          > as checking for null values or specific data ranges. These days it
                          > seems like most people are handling these types of validations with a
                          > validation framework and checking an IsValid operation or something
                          > similar. I refer to these as data validations. It may be fine in some
                          > domains for an object to exist and be persisted when that object is in
                          > an invalid data state. I am faced with an issue in which I cannot
                          > allow certain objects to ever be in an invalid state.
                          >
                          > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                          > accounts, but there are rules regarding redemption. If any of these
                          > rules are violated, redemption cannot succeed and the application must
                          > prevent the redemption. These rule violations are not fatal and are to
                          > be expected, however I must notify the user as to why the redemption did
                          > not succeed. So my question is, what is the preferred way of
                          > communicating business rule violations to the UI when an action cannot
                          > be performed because it would put the object into an invalid state that
                          > cannot be persisted?
                          >
                          > I think there are essentialy 4 ways:
                          > 1) Throw an exception describing the first violation
                          > 2) Use Notification pattern
                          > <http://www.martinfowler.com/eaaDev/Notification.html> to communicate
                          > information about all violations.
                          > 3) Throw an exception that encapsulates the Notification object as
                          > described in Sergio's blog post, A Notification Strategy for Business
                          > Errors
                          > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html>
                          > 4) Provide a Check operation which returns a a boolean or a Notification
                          > object such as /Notification CanRedeem(Account); /or /bool
                          > CanRedeem(Account); /If the check operation returns any violations,
                          > Redeem would throw an exception.
                          >
                          > The thought of throwing exceptions doesn't sit real well with me but it
                          > is the easiest way to get the information to any interested parties
                          > because they just have to try...catch it. The Notification pattern has
                          > value but it seems more difficult to get the information to the
                          > interested parties. Granted, the Redeem operation on PromoCode is a
                          > void operation and I could just return a Notification object from that
                          > call. However, in my research for this problem Im trying to comeup with
                          > a solution that would also work with operations that had a return
                          > value. #4 is an instersting option but im a little turned off by it
                          > because the check would have to be called multiple times, once from the
                          > client and once from the redeem operation. Here is a sample
                          >
                          > public class PromoCode{
                          >
                          > string code;
                          > DateTime expirationDate;
                          > bool isRedeemed;
                          > bool isOnlyForNewAccounts;
                          >
                          > public Notification CanRedeem(Account account){
                          > Notification violations = new Notification();
                          >
                          > if(this.isRedeemed){
                          > violations.Add(PromoCodeViolation.AlreadyRedeemed);
                          > }
                          >
                          > if(this.expirationDate > DateTime.Now){
                          > violations.Add(PromoCodeViolation.Expired);
                          > }
                          >
                          > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                          > violations.Add(PromoCodeViolation.NewAccountsOnly);
                          > }
                          >
                          > return violations;
                          > }
                          >
                          > public void Redeem(Account account){
                          > Notification violations = this.CanRedeem(account);
                          >
                          > if(violations.HasErrors){
                          > throw new BusinessRuleException(violations);
                          > }
                          >
                          > this.DoRedeem(account);
                          > }
                          >
                          > protected void DoRedeem(Account account){
                          > ...
                          > }
                          > }
                          >
                          >
                          > public class PromoCodeTest{
                          >
                          > public void RunCanRedeem(){
                          >
                          > Account testAccount = Mock.GetMock<Account>();
                          >
                          > PromoCode code = CreateValidPromoCode();
                          >
                          > if(code.CanRedeem(testAccount).HasErrors == false){
                          > code.Redeem(testAccount);
                          >
                          > Assert.IsTrue(code.IsRedeemed);
                          > }
                          > }
                          > }
                          >
                          >
                          >
                          > Any thoughts or advice on this? Any ways to improve it? Or is the a
                          > better strategy that I havent seen?
                          >
                          > Thanks,
                          > Jesse
                          >
                          >
                          >
                          >



                        • Chris Gardner
                          I tend to agree with Jeff. I m very concerned about keeping an object in a valid state.
                          Message 12 of 26 , Jun 28 10:07 AM
                            I tend to agree with Jeff. I'm very concerned about keeping an object
                            in a valid state.


                            --- In domaindrivendesign@yahoogroups.com, "Jeff Lowe" <jlowe@...> wrote:
                            >
                            > Call me old fashioned, but I prefer simply throwing a checked exception.
                            > The exception then becomes part of the method signature, which makes for
                            > a more expressive domain interface, e.g.:
                            >
                            > public redeem(Account account) throws PromotionRulesViolationException
                            >
                            > The exception can then encapsulate everything needed by the client (i.e.
                            > application) to communicate back to the user, including information
                            > about multiple rule violations.
                            >
                            > >> The thought of throwing exceptions doesn't sit real well with me but
                            > ...
                            >
                            > I'm curious why it doesn't sit well. Other folks have also expressed
                            > this.
                            >
                            >
                            > Thanks,
                            > -Jeff
                            >
                            >
                            > ________________________________
                            >
                            > From: domaindrivendesign@yahoogroups.com
                            > [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jesse Napier
                            > Sent: Wednesday, June 27, 2007 9:41 PM
                            > To: domaindrivendesign@yahoogroups.com
                            > Subject: [domaindrivendesign] To throw or not to throw on Rule Violation
                            >
                            >
                            >
                            > I have a question regarding business logic validation in my domain. Im
                            > not talking about validation in the sense of simple data validation such
                            > as checking for null values or specific data ranges. These days it
                            > seems like most people are handling these types of validations with a
                            > validation framework and checking an IsValid operation or something
                            > similar. I refer to these as data validations. It may be fine in some
                            > domains for an object to exist and be persisted when that object is in
                            > an invalid data state. I am faced with an issue in which I cannot allow
                            > certain objects to ever be in an invalid state.
                            >
                            > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                            > accounts, but there are rules regarding redemption. If any of these
                            > rules are violated, redemption cannot succeed and the application must
                            > prevent the redemption. These rule violations are not fatal and are to
                            > be expected, however I must notify the user as to why the redemption did
                            > not succeed. So my question is, what is the preferred way of
                            > communicating business rule violations to the UI when an action cannot
                            > be performed because it would put the object into an invalid state that
                            > cannot be persisted?
                            >
                            > I think there are essentialy 4 ways:
                            > 1) Throw an exception describing the first violation
                            > 2) Use Notification pattern
                            > <http://www.martinfowler.com/eaaDev/Notification.html> to communicate
                            > information about all violations.
                            > 3) Throw an exception that encapsulates the Notification object as
                            > described in Sergio's blog post, A Notification Strategy for Business
                            > Errors
                            > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busines
                            > s.html>
                            > 4) Provide a Check operation which returns a a boolean or a Notification
                            > object such as Notification CanRedeem(Account); or bool
                            > CanRedeem(Account); If the check operation returns any violations,
                            > Redeem would throw an exception.
                            >
                            > The thought of throwing exceptions doesn't sit real well with me but it
                            > is the easiest way to get the information to any interested parties
                            > because they just have to try...catch it. The Notification pattern has
                            > value but it seems more difficult to get the information to the
                            > interested parties. Granted, the Redeem operation on PromoCode is a
                            > void operation and I could just return a Notification object from that
                            > call. However, in my research for this problem Im trying to comeup with
                            > a solution that would also work with operations that had a return value.
                            > #4 is an instersting option but im a little turned off by it because the
                            > check would have to be called multiple times, once from the client and
                            > once from the redeem operation. Here is a sample
                            >
                            > public class PromoCode{
                            >
                            > string code;
                            > DateTime expirationDate;
                            > bool isRedeemed;
                            > bool isOnlyForNewAccounts;
                            >
                            > public Notification CanRedeem(Account account){
                            > Notification violations = new Notification();
                            >
                            > if(this.isRedeemed){
                            > violations.Add(PromoCodeViolation.AlreadyRedeemed);
                            > }
                            >
                            > if(this.expirationDate > DateTime.Now){
                            > violations.Add(PromoCodeViolation.Expired);
                            > }
                            >
                            > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                            > violations.Add(PromoCodeViolation.NewAccountsOnly);
                            > }
                            >
                            > return violations;
                            > }
                            >
                            > public void Redeem(Account account){
                            > Notification violations = this.CanRedeem(account);
                            >
                            > if(violations.HasErrors){
                            > throw new BusinessRuleException(violations);
                            > }
                            >
                            > this.DoRedeem(account);
                            > }
                            >
                            > protected void DoRedeem(Account account){
                            > ...
                            > }
                            > }
                            >
                            >
                            > public class PromoCodeTest{
                            >
                            > public void RunCanRedeem(){
                            >
                            > Account testAccount = Mock.GetMock<Account>();
                            >
                            > PromoCode code = CreateValidPromoCode();
                            >
                            > if(code.CanRedeem(testAccount).HasErrors == false){
                            > code.Redeem(testAccount);
                            >
                            > Assert.IsTrue(code.IsRedeemed);
                            > }
                            > }
                            > }
                            >
                            >
                            >
                            > Any thoughts or advice on this? Any ways to improve it? Or is the a
                            > better strategy that I havent seen?
                            >
                            > Thanks,
                            > Jesse
                            >
                          • Joe A. Reddy
                            How did we jump from debating using a specific domain object to objects going into an invalid state? I must have missed something. public redeem(Account
                            Message 13 of 26 , Jun 28 10:11 AM

                              How did we jump from debating using a specific domain object to objects going into an invalid state?

                              I must have missed something.

                              public redeem(Account account) throws PromotionRulesViolationException

                              versus

                              public RedemtionIssues redeemIfPossible(Account account)

                               

                               

                              -----Original Message-----
                              From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Chris Gardner
                              Sent: Thursday, June 28, 2007 12:07 PM
                              To: domaindrivendesign@yahoogroups.com
                              Subject: [domaindrivendesign] Re: To throw or not to throw on Rule Violation

                               

                              I tend to agree with Jeff. I'm very concerned about keeping an object
                              in a valid state.

                              --- In domaindrivendesign@ yahoogroups. com, "Jeff Lowe" <jlowe@...> wrote:

                              >
                              > Call me old fashioned, but I prefer simply throwing a checked exception.
                              > The exception then becomes part of the method signature, which makes for
                              > a more expressive domain interface, e.g.:
                              >
                              > public redeem(Account account) throws PromotionRulesViola tionException
                              >
                              > The exception can then encapsulate everything needed by the client (i.e.
                              > application) to communicate back to the user, including information
                              > about multiple rule violations.
                              >
                              > >> The thought of throwing exceptions doesn't sit real well with me
                              but
                              > ...
                              >
                              > I'm curious why it doesn't sit well. Other folks have also expressed
                              > this.
                              >
                              >
                              > Thanks,
                              > -Jeff
                              >
                              >
                              > ____________ _________ _________ __
                              >
                              > From: domaindrivendesign@ yahoogroups. com
                              > [mailto:domaindrivendesign@ yahoogroups. com]
                              On Behalf Of Jesse Napier
                              > Sent: Wednesday, June 27, 2007 9:41 PM
                              > To: domaindrivendesign@ yahoogroups. com
                              > Subject: [domaindrivendesign ] To throw or not to throw on Rule
                              Violation
                              >
                              >
                              >
                              > I have a question regarding business logic validation in my domain. Im
                              > not talking about validation in the sense of simple data validation such
                              > as checking for null values or specific data ranges. These days it
                              > seems like most people are handling these types of validations with a
                              > validation framework and checking an IsValid operation or something
                              > similar. I refer to these as data validations. It may be fine in some
                              > domains for an object to exist and be persisted when that object is in
                              > an invalid data state. I am faced with an issue in which I cannot allow
                              > certain objects to ever be in an invalid state.
                              >
                              > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                              > accounts, but there are rules regarding redemption. If any of these
                              > rules are violated, redemption cannot succeed and the application must
                              > prevent the redemption. These rule violations are not fatal and are to
                              > be expected, however I must notify the user as to why the redemption did
                              > not succeed. So my question is, what is the preferred way of
                              > communicating business rule violations to the UI when an action cannot
                              > be performed because it would put the object into an invalid state that
                              > cannot be persisted?
                              >
                              > I think there are essentialy 4 ways:
                              > 1) Throw an exception describing the first violation
                              > 2) Use Notification pattern
                              > <http://www.martinfo wler.com/ eaaDev/Notificat ion.html>
                              to communicate
                              > information about all violations.
                              > 3) Throw an exception that encapsulates the Notification object as
                              > described in Sergio's blog post, A Notification Strategy for Business
                              > Errors
                              > <
                              href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busines">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-busines
                              > s.html>
                              > 4) Provide a Check operation which returns a a boolean or a Notification
                              > object such as Notification CanRedeem(Account) ; or bool
                              > CanRedeem(Account) ; If the check operation returns any violations,
                              > Redeem would throw an exception.
                              >
                              > The thought of throwing exceptions doesn't sit real well with me but it
                              > is the easiest way to get the information to any interested parties
                              > because they just have to try...catch it. The Notification pattern has
                              > value but it seems more difficult to get the information to the
                              > interested parties. Granted, the Redeem operation on PromoCode is a
                              > void operation and I could just return a Notification object from that
                              > call. However, in my research for this problem Im trying to comeup with
                              > a solution that would also work with operations that had a return value.
                              > #4 is an instersting option but im a little turned off by it because the
                              > check would have to be called multiple times, once from the client and
                              > once from the redeem operation. Here is a sample
                              >
                              > public class PromoCode{
                              >
                              > string code;
                              > DateTime expirationDate;
                              > bool isRedeemed;
                              > bool isOnlyForNewAccount s;
                              >
                              > public Notification CanRedeem(Account account){
                              > Notification violations = new Notification( );
                              >
                              > if(this.isRedeemed) {
                              > violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                              > }
                              >
                              > if(this.expirationD ate > DateTime.Now) {
                              > violations.Add( PromoCodeViolati on.Expired) ;
                              > }
                              >
                              > if(this.isOnlyForNe wAccounts && account.IsNewAccoun t ==
                              false){
                              > violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                              > }
                              >
                              > return violations;
                              > }
                              >
                              > public void Redeem(Account account){
                              > Notification violations = this.CanRedeem( account);
                              >
                              > if(violations. HasErrors) {
                              > throw new BusinessRuleExcepti on(violations) ;
                              > }
                              >
                              > this.DoRedeem( account);
                              > }
                              >
                              > protected void DoRedeem(Account account){
                              > ...
                              > }
                              > }
                              >
                              >
                              > public class PromoCodeTest{
                              >
                              > public void RunCanRedeem( ){
                              >
                              > Account testAccount = Mock.GetMock< Account>( );
                              >
                              > PromoCode code = CreateValidPromoCod e();
                              >
                              > if(code.CanRedeem( testAccount) .HasErrors == false){
                              > code.Redeem( testAccount) ;
                              >
                              > Assert.IsTrue( code.IsRedeemed) ;
                              > }
                              > }
                              > }
                              >
                              >
                              >
                              > Any thoughts or advice on this? Any ways to improve it? Or is the a
                              > better strategy that I havent seen?
                              >
                              > Thanks,
                              > Jesse
                              >

                            • Jesse Napier
                              Sergio, I didnt really think that wraping the notifications in an exception was the point of your post. I just pointed people there to show one of the ways
                              Message 14 of 26 , Jun 28 12:08 PM
                                Sergio,
                                I didnt really think that wraping the notifications in an exception was the point of your post. I just pointed people there to show one of the ways that this can be handled.
                                 
                                I'm not using Java so the Spring eventing infrastructure you talk about is a no go for me.  I do like the idea though, yet it almost seems a little overkill just to get validation errors back to the client. 
                                 
                                I think Jeff was asking why throwing exceptions doesnt sit real well with me.  I think it's because not being able to redeem a PromoCode is a very real possibility. These things expire, or they have a limit on how many people can use the same code, so not being able to redeem a PromoCode doesnt really strike me as an exceptional case.  The only reason that I was thinking of using an exception was to transport the validation messages back to any listening party and its EASY.  So I started thinking about not taking the easy way out and thats what got me to this point. 
                                 
                                Fowler talks of an EventAggregator that could publish notifications to clients, but I havent really seen any implementations of this so I think it would need to be flushed out alot more.
                                 
                                Why do you think that it would be better for a serveice to publish events containing notifications?  I hadnt planned on there being any service necessary to redeem a promo code. Basically, a customer enters in a promo code, pull the promo code from the repository, then redeem it, or let the user know why it cant be redeemed. Not seeing where a service comes into play here  and if I was to using an eventing system why the domain object couldnt publish the event.
                                 
                                Thanks for the discussion,
                                Jesse


                                From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Sergio Bossa
                                Sent: Thursday, June 28, 2007 1:42 AM
                                To: domaindrivendesign@yahoogroups.com
                                Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                                On 6/28/07, Jesse Napier <jnapier@gamefly. com> wrote:

                                So my question is, what is the preferred way of communicating business rule violations to the UI when an action cannot be performed because it would put the object into an invalid state that cannot be persisted?
                                 
                                [CUT]
                                2) Use Notification pattern to communicate information about all violations.
                                3) Throw an exception that encapsulates the Notification object as described in Sergio's blog post, A Notification Strategy for Business Errors
                                [CUT]

                                Hi Jesse,

                                and all DDD community, long time has passed since my last post: I've been very busy, so I hope to find ASAP more time again.

                                Please don't misunderstand my post about Notifications and exceptions.
                                I do not suggest to use exceptions just for the sake of propagating notifications; I'm just saying that the two concepts can be linked, and if your business code already throws exceptions, then they can be used to propagate notifications.

                                Talking about your scenario, I think that it is better to use some "event publishing" pattern: let your business code (preferably your services) publish events containing your notifications, and let your presentation layer listen to them. Doing so, your lower layers will be able to communicate with upper layers in a decoupled and transparent way, without violating any DDD/OO principle.
                                What do you think?

                                Moreover, if you're using Java, the Spring Framework provides several facilities for implementing a custom event publishing solution, plus a ready to use solution provided by its Spring Modules. However, we are off-topic here, so if you're interested go through the Spring forums and/or feel free to contact me by private mail.

                                Cheers,

                                Sergio B.

                                --
                                Sergio Bossa
                                Software analyst and developer, blogger and Open Source enthusiast.
                                Blogging on: http://sbtourist. blogspot. com

                              • Jesse Napier
                                Its so true that exceptional situations are very subjective. I ve found myself battling with that all the time. In my case, it seems like an exceptional
                                Message 15 of 26 , Jun 28 12:42 PM
                                  Its so true that exceptional situations are very subjective.  I've found myself battling with that all the time.  In my case, it seems like an exceptional situation would be if more people redeemed the promo code than were allowed to.  Then Ive got problems.  So the business logic is in place to prevent that from occurring. 
                                   
                                  From reading other discussions on this forum and from the feedback I have recieved in regards to this post, it appears that there is alot of sentiment for not throwing exceptions in situations like this and I tend to agree.  So how do we get the validation errors to the caller in an elegant way?
                                   
                                  There has been some talk of events, but that doesnt really seem elegant to me.  It seems confusing for the client.
                                   
                                  Say im a a controller, I want to do this:
                                   
                                  string codeId = GetCodeFromRequest();
                                   
                                  PromCode promoCode = promoRepository.FindByCode(codeId);
                                   
                                  promoCode.Redeem(account);
                                   
                                     //get validation errors from somewhere
                                     //and register them for the view to display
                                  }
                                   
                                  having some event handler in the controller to trap for redemption errors would be very hard to understand and follow if you ask me.  The code would read better if we handled any violations right next to the code that caused the violation.
                                   
                                  does this smell?
                                   
                                  INotification violations = INotificationFactory.Create();
                                   
                                  promoCode.Redeem(account, violations);
                                   
                                  if(violations.HasErrors){
                                      //register error messages with the view
                                  }
                                   
                                   


                                  From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jeff Lowe
                                  Sent: Thursday, June 28, 2007 7:46 AM
                                  To: domaindrivendesign@yahoogroups.com
                                  Subject: RE: [domaindrivendesign] To throw or not to throw on Rule Violation

                                  That's a cute mantra.  "exceptional situation" is certainly subjective.
                                   
                                  As Jesse stated, there's a difference between simple data validation, and the violation of business rules during a non-trivial operation in the domain.  I consider the latter to be an "exceptional situation".
                                   
                                   


                                  From: domaindrivendesign@ yahoogroups. com [mailto:domaindrive ndesign@yahoogro ups.com] On Behalf Of ARKBAN
                                  Sent: Thursday, June 28, 2007 10:10 AM
                                  To: domaindrivendesign@ yahoogroups. com
                                  Subject: Re: [domaindrivendesign ] To throw or not to throw on Rule Violation

                                  I think the concern revolves around the mantra "exceptions are for
                                  exceptional situations". Validation is most often not exceptional but
                                  expected; validation checks for situations that occur easily but can be
                                  easily corrected, which are not really exceptional.

                                  ARKBAN

                                  Jeff Lowe wrote:

                                  >
                                  >
                                  >
                                  Call me old fashioned, but I prefer simply throwing a
                                  > checked
                                  exception. The exception then becomes part of the method
                                  > signature,
                                  which makes for a more expressive domain interface, e.g.:
                                  >
                                  >
                                  public redeem(Account account) throws PromotionRulesViola tionException
                                  >
                                  > The exception can then
                                  encapsulate everything needed by the client (i.e.
                                  > application) to
                                  communicate back to the user, including information
                                  > about multiple rule
                                  violations.
                                  >
                                  >> > The thought of throwing exceptions
                                  doesn't sit real well with me but ...
                                  >
                                  > I'm curious why it
                                  doesn't sit well. Other folks have also expressed this.
                                  >
                                  >
                                  > Thanks,
                                  > -Jeff
                                  >
                                  >
                                  >
                                  ------------ --------- --------- --------- --------- --------- -
                                  >
                                  *From:* domaindrivendesign@ yahoogroups. com
                                  > [mailto:
                                  href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jesse Napier
                                  > *Sent:* Wednesday, June 27, 2007 9:41
                                  PM
                                  > *To:*
                                  href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com
                                  >
                                  *Subject:* [domaindrivendesign ] To throw or not to throw on Rule Violation
                                  >
                                  > I have a question regarding business logic validation
                                  in my domain. Im
                                  > not talking about validation in the sense of simple
                                  data validation such
                                  > as checking for null values or specific data
                                  ranges. These days it
                                  > seems like most people are handling these types
                                  of validations with a
                                  > validation framework and checking an IsValid
                                  operation or something
                                  > similar. I refer to these as data validations.
                                  It may be fine in some
                                  > domains for an object to exist and be persisted
                                  when that object is in
                                  > an invalid data state. I am faced with an issue
                                  in which I cannot
                                  > allow certain objects to ever be in an invalid state.
                                  >
                                  > In my domain I have PromoCode and Account. PromoCodes can be
                                  redeemed by
                                  > accounts, but there are rules regarding redemption. If any
                                  of these
                                  > rules are violated, redemption cannot succeed and the
                                  application must
                                  > prevent the redemption. These rule violations are not
                                  fatal and are to
                                  > be expected, however I must notify the user as to why
                                  the redemption did
                                  > not succeed. So my question is, what is the
                                  preferred way of
                                  > communicating business rule violations to the UI when
                                  an action cannot
                                  > be performed because it would put the object into an
                                  invalid state that
                                  > cannot be persisted?
                                  >
                                  > I think there
                                  are essentialy 4 ways:
                                  > 1) Throw an exception describing the first
                                  violation
                                  > 2) Use Notification pattern
                                  > <
                                  href="http://www.martinfowler.com/eaaDev/Notification.html">http://www.martinfo wler.com/ eaaDev/Notificat ion.html> to communicate
                                  > information about all violations.
                                  > 3) Throw an
                                  exception that encapsulates the Notification object as
                                  > described in
                                  Sergio's blog post, A Notification Strategy for Business
                                  > Errors
                                  > <
                                  href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html>
                                  >
                                  4) Provide a Check operation which returns a a boolean or a Notification
                                  > object such as /Notification CanRedeem(Account) ; /or /bool
                                  > CanRedeem(Account) ; /If the check operation returns any
                                  violations,
                                  > Redeem would throw an exception.
                                  >
                                  > The
                                  thought of throwing exceptions doesn't sit real well with me but it
                                  > is
                                  the easiest way to get the information to any interested parties
                                  >
                                  because they just have to try...catch it. The Notification pattern has
                                  >
                                  value but it seems more difficult to get the information to the
                                  >
                                  interested parties. Granted, the Redeem operation on PromoCode is a
                                  >
                                  void operation and I could just return a Notification object from that
                                  >
                                  call. However, in my research for this problem Im trying to comeup with
                                  >
                                  a solution that would also work with operations that had a return
                                  >
                                  value. #4 is an instersting option but im a little turned off by it
                                  >
                                  because the check would have to be called multiple times, once from the
                                  >
                                  client and once from the redeem operation. Here is a sample
                                  >
                                  >
                                  public class PromoCode{
                                  >
                                  > string code;
                                  > DateTime
                                  expirationDate;
                                  > bool isRedeemed;
                                  > bool isOnlyForNewAccount s;
                                  >
                                  > public Notification CanRedeem(Account account){
                                  >
                                  Notification violations = new Notification( );
                                  >
                                  >
                                  if(this.isRedeemed) {
                                  >
                                  violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                                  >
                                  }
                                  >
                                  > if(this.expirationD ate > DateTime.Now) {
                                  >
                                  violations.Add( PromoCodeViolati on.Expired) ;
                                  > }
                                  >
                                  > if(this.isOnlyForNe wAccounts && account.IsNewAccoun t
                                  == false){
                                  >
                                  violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                  >
                                  }
                                  >
                                  > return violations;
                                  > }
                                  >
                                  > public void
                                  Redeem(Account account){
                                  > Notification violations =
                                  this.CanRedeem( account);
                                  >
                                  >
                                  if(violations. HasErrors) {
                                  > throw new
                                  BusinessRuleExcepti on(violations) ;
                                  > }
                                  >
                                  >
                                  this.DoRedeem( account);
                                  > }
                                  >
                                  > protected void
                                  DoRedeem(Account account){
                                  > ...
                                  > }
                                  > }
                                  >
                                  >
                                  > public class PromoCodeTest{
                                  >
                                  > public void
                                  RunCanRedeem( ){
                                  >
                                  > Account testAccount =
                                  Mock.GetMock< Account>( );
                                  >
                                  > PromoCode code =
                                  CreateValidPromoCod e();
                                  >
                                  >
                                  if(code.CanRedeem( testAccount) .HasErrors == false){
                                  >
                                  code.Redeem( testAccount) ;
                                  >
                                  >
                                  Assert.IsTrue( code.IsRedeemed) ;
                                  > }
                                  > }
                                  > }
                                  >
                                  >
                                  >
                                  > Any thoughts or advice on this? Any ways to improve
                                  it? Or is the a
                                  > better strategy that I havent seen?
                                  >
                                  >
                                  Thanks,
                                  > Jesse
                                  >
                                  >
                                  >
                                  >

                                • saad rehmani
                                  What about languages that don t support checked exceptions? e.g., C#, Ruby I m used to being able to declare the exceptions that a method will throw as part of
                                  Message 16 of 26 , Jun 28 12:53 PM

                                    What about languages that don't support checked exceptions? e.g., C#, Ruby

                                    I'm used to being able to declare the exceptions that a method will throw as part of its signature, but in the absence of a declarative interface, a thrown exception becomes much less meaningful.

                                    Saad

                                    ----- Original Message ----
                                    From: Jeff Lowe <jlowe@...>
                                    To: domaindrivendesign@yahoogroups.com
                                    Sent: Thursday, June 28, 2007 8:52:17 AM
                                    Subject: RE: [domaindrivendesign] To throw or not to throw on Rule Violation

                                    Call me old fashioned, but I prefer simply throwing a checked exception.  The exception then becomes part of the method signature, which makes for a more expressive domain interface, e.g.:
                                     
                                    public redeem(Account account) throws PromotionRulesViolationException
                                     
                                    The exception can then encapsulate everything needed by the client (i.e. application) to communicate back to the user, including information about multiple rule violations. 
                                     
                                    >> The thought of throwing exceptions doesn't sit real well with me but ...
                                     
                                    I'm curious why it doesn't sit well.  Other folks have also expressed this.
                                     
                                     
                                    Thanks,
                                    -Jeff
                                     


                                    From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jesse Napier
                                    Sent: Wednesday, June 27, 2007 9:41 PM
                                    To: domaindrivendesign@yahoogroups.com
                                    Subject: [domaindrivendesign] To throw or not to throw on Rule Violation

                                    I have a question regarding business logic validation in my domain. Im not talking about validation in the sense of simple data validation such as checking for null values or specific data ranges.  These days it seems like most people are handling these types of validations with a validation framework and checking an IsValid operation or something similar.  I refer to these as data validations.  It may be fine in some domains for an object to exist and be persisted when that object is in an invalid data state.  I am faced with an issue in which I cannot allow certain objects to ever be in an invalid state. 
                                     
                                    In my domain I have PromoCode and Account. PromoCodes can be redeemed by accounts, but there are rules regarding redemption.  If any of these rules are violated, redemption cannot succeed and the application must prevent the redemption.  These rule violations are not fatal and are to be expected, however I must notify the user as to why the redemption did not succeed.  So my question is, what is the preferred way of communicating business rule violations to the UI when an action cannot be performed because it would put the object into an invalid state that cannot be persisted?
                                     
                                    I think there are essentialy 4 ways:
                                    1) Throw an exception describing the first violation
                                    2) Use Notification pattern to communicate information about all violations.
                                    3) Throw an exception that encapsulates the Notification object as described in Sergio's blog post, A Notification Strategy for Business Errors
                                    4) Provide a Check operation which returns a a boolean or a Notification object such as Notification CanRedeem(Account) ; or bool CanRedeem(Account) ;  If the check operation returns any violations, Redeem would throw an exception.
                                     
                                    The thought of throwing exceptions doesn't sit real well with me but it is the easiest way to get the information to any interested parties because they just have to try...catch it.  The Notification pattern has value but it seems more difficult to get the information to the interested parties.  Granted, the Redeem operation on PromoCode is a void operation and I could just return a Notification object from that call. However, in my research for this problem Im trying to comeup with a solution that would also work with operations that had a return value.  #4 is an instersting option but im a little turned off by it because the check would have to be called multiple times, once from the client and once from the redeem operation.  Here is a sample
                                     
                                    public class PromoCode{
                                     
                                        string code;
                                        DateTime expirationDate;
                                        bool isRedeemed;
                                        bool isOnlyForNewAccount s; 
                                       
                                        public Notification CanRedeem(Account account){
                                            Notification violations = new Notification( );
                                           
                                            if(this.isRedeemed) {
                                                violations.Add( PromoCodeViolati on.AlreadyRedeem ed);       
                                            }
                                     
                                            if(this.expirationD ate > DateTime.Now) {
                                                violations.Add( PromoCodeViolati on.Expired) ;
                                            }
                                     
                                            if(this.isOnlyForNe wAccounts && account.IsNewAccoun t == false){
                                               violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                            }
                                           
                                            return violations;
                                        }
                                       
                                        public void Redeem(Account account){
                                            Notification violations = this.CanRedeem( account);
                                           
                                            if(violations. HasErrors) {
                                                throw new BusinessRuleExcepti on(violations) ;
                                            }
                                     
                                            this.DoRedeem( account);
                                        } 
                                       
                                        protected void DoRedeem(Account account){
                                            ...
                                        }
                                    }
                                     
                                     
                                    public class PromoCodeTest{
                                     
                                        public void RunCanRedeem( ){
                                           
                                            Account testAccount = Mock.GetMock<Account>();
                                           
                                            PromoCode code = CreateValidPromoCod e();
                                     
                                            if(code.CanRedeem( testAccount) .HasErrors == false){
                                                code.Redeem( testAccount) ;
                                     
                                                Assert.IsTrue( code.IsRedeemed) ;
                                            }
                                        }
                                    }
                                     
                                     
                                     
                                    Any thoughts or advice on this?  Any ways to improve it?  Or is the a better strategy that I havent seen?
                                     
                                    Thanks,
                                    Jesse
                                     
                                     




                                    Don't be flakey. Get Yahoo! Mail for Mobile and
                                    always stay connected to friends.
                                  • Louis Richer
                                    Personally, treating contingency business cases as checked exceptions makes a ton of sense. That is the argument put forward, quite effectively in my opinion,
                                    Message 17 of 26 , Jun 28 1:04 PM
                                      Personally, treating contingency business cases as checked exceptions makes a ton of sense. That is the argument put forward, quite effectively in my opinion, in the Effective Java Exceptions 3 page article referenced in Chris Beams response on this thread.
                                       
                                      It would be very helpful to get a critique of the Effective Java Exceptions article from someone advocating a strict interpretation of exception (i.e. the mantra).


                                      Louis Richer


                                      From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jesse Napier
                                      Sent: Thursday, June 28, 2007 3:43 PM
                                      To: domaindrivendesign@yahoogroups.com
                                      Subject: RE: [domaindrivendesign] To throw or not to throw on Rule Violation

                                      Its so true that exceptional situations are very subjective.  I've found myself battling with that all the time.  In my case, it seems like an exceptional situation would be if more people redeemed the promo code than were allowed to.  Then Ive got problems.  So the business logic is in place to prevent that from occurring. 
                                       
                                      From reading other discussions on this forum and from the feedback I have recieved in regards to this post, it appears that there is alot of sentiment for not throwing exceptions in situations like this and I tend to agree.  So how do we get the validation errors to the caller in an elegant way?
                                       
                                      There has been some talk of events, but that doesnt really seem elegant to me.  It seems confusing for the client.
                                       
                                      Say im a a controller, I want to do this:
                                       
                                      string codeId = GetCodeFromRequest( );
                                       
                                      PromCode promoCode = promoRepository. FindByCode( codeId);
                                       
                                      promoCode.Redeem( account);
                                       
                                         //get validation errors from somewhere
                                         //and register them for the view to display
                                      }
                                       
                                      having some event handler in the controller to trap for redemption errors would be very hard to understand and follow if you ask me.  The code would read better if we handled any violations right next to the code that caused the violation.
                                       
                                      does this smell?
                                       
                                      INotification violations = INotificationFactor y.Create( );
                                       
                                      promoCode.Redeem( account, violations);
                                       
                                      if(violations. HasErrors) {
                                          //register error messages with the view
                                      }
                                       
                                       


                                      From: domaindrivendesign@ yahoogroups. com [mailto:domaindrive ndesign@yahoogro ups.com] On Behalf Of Jeff Lowe
                                      Sent: Thursday, June 28, 2007 7:46 AM
                                      To: domaindrivendesign@ yahoogroups. com
                                      Subject: RE: [domaindrivendesign ] To throw or not to throw on Rule Violation

                                      That's a cute mantra.  "exceptional situation" is certainly subjective.
                                       
                                      As Jesse stated, there's a difference between simple data validation, and the violation of business rules during a non-trivial operation in the domain.  I consider the latter to be an "exceptional situation".
                                       
                                       


                                      From: domaindrivendesign@ yahoogroups. com [mailto:domaindrive ndesign@yahoogro ups.com] On Behalf Of ARKBAN
                                      Sent: Thursday, June 28, 2007 10:10 AM
                                      To: domaindrivendesign@ yahoogroups. com
                                      Subject: Re: [domaindrivendesign ] To throw or not to throw on Rule Violation

                                      I think the concern revolves around the mantra "exceptions are for
                                      exceptional situations". Validation is most often not exceptional but
                                      expected; validation checks for situations that occur easily but can be
                                      easily corrected, which are not really exceptional.

                                      ARKBAN

                                      Jeff Lowe wrote:
                                      >
                                      >
                                      > Call me old fashioned, but I prefer simply throwing a
                                      > checked exception. The exception then becomes part of the method
                                      > signature, which makes for a more expressive domain interface, e.g.:
                                      >
                                      > public redeem(Account account) throws PromotionRulesViola tionException
                                      >
                                      > The exception can then encapsulate everything needed by the client (i.e.
                                      > application) to communicate back to the user, including information
                                      > about multiple rule violations.
                                      >
                                      >> > The thought of throwing exceptions doesn't sit real well with me but ...
                                      >
                                      > I'm curious why it doesn't sit well. Other folks have also expressed this.
                                      >
                                      >
                                      > Thanks,
                                      > -Jeff
                                      >
                                      >
                                      > ------------ --------- --------- --------- --------- --------- -
                                      > *From:* domaindrivendesign@ yahoogroups. com
                                      > [mailto:domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jesse Napier
                                      > *Sent:* Wednesday, June 27, 2007 9:41 PM
                                      > *To:* domaindrivendesign@ yahoogroups. com
                                      > *Subject:* [domaindrivendesign ] To throw or not to throw on Rule Violation
                                      >
                                      > I have a question regarding business logic validation in my domain. Im
                                      > not talking about validation in the sense of simple data validation such
                                      > as checking for null values or specific data ranges. These days it
                                      > seems like most people are handling these types of validations with a
                                      > validation framework and checking an IsValid operation or something
                                      > similar. I refer to these as data validations. It may be fine in some
                                      > domains for an object to exist and be persisted when that object is in
                                      > an invalid data state. I am faced with an issue in which I cannot
                                      > allow certain objects to ever be in an invalid state.
                                      >
                                      > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                                      > accounts, but there are rules regarding redemption. If any of these
                                      > rules are violated, redemption cannot succeed and the application must
                                      > prevent the redemption. These rule violations are not fatal and are to
                                      > be expected, however I must notify the user as to why the redemption did
                                      > not succeed. So my question is, what is the preferred way of
                                      > communicating business rule violations to the UI when an action cannot
                                      > be performed because it would put the object into an invalid state that
                                      > cannot be persisted?
                                      >
                                      > I think there are essentialy 4 ways:
                                      > 1) Throw an exception describing the first violation
                                      > 2) Use Notification pattern
                                      > <http://www.martinfo wler.com/ eaaDev/Notificat ion.html> to communicate
                                      > information about all violations.
                                      > 3) Throw an exception that encapsulates the Notification object as
                                      > described in Sergio's blog post, A Notification Strategy for Business
                                      > Errors
                                      > <http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html>
                                      > 4) Provide a Check operation which returns a a boolean or a Notification
                                      > object such as /Notification CanRedeem(Account) ; /or /bool
                                      > CanRedeem(Account) ; /If the check operation returns any violations,
                                      > Redeem would throw an exception.
                                      >
                                      > The thought of throwing exceptions doesn't sit real well with me but it
                                      > is the easiest way to get the information to any interested parties
                                      > because they just have to try...catch it. The Notification pattern has
                                      > value but it seems more difficult to get the information to the
                                      > interested parties. Granted, the Redeem operation on PromoCode is a
                                      > void operation and I could just return a Notification object from that
                                      > call. However, in my research for this problem Im trying to comeup with
                                      > a solution that would also work with operations that had a return
                                      > value. #4 is an instersting option but im a little turned off by it
                                      > because the check would have to be called multiple times, once from the
                                      > client and once from the redeem operation. Here is a sample
                                      >
                                      > public class PromoCode{
                                      >
                                      > string code;
                                      > DateTime expirationDate;
                                      > bool isRedeemed;
                                      > bool isOnlyForNewAccount s;
                                      >
                                      > public Notification CanRedeem(Account account){
                                      > Notification violations = new Notification( );
                                      >
                                      > if(this.isRedeemed) {
                                      > violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                                      > }
                                      >
                                      > if(this.expirationD ate > DateTime.Now) {
                                      > violations.Add( PromoCodeViolati on.Expired) ;
                                      > }
                                      >
                                      > if(this.isOnlyForNe wAccounts && account.IsNewAccoun t == false){
                                      > violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                      > }
                                      >
                                      > return violations;
                                      > }
                                      >
                                      > public void Redeem(Account account){
                                      > Notification violations = this.CanRedeem( account);
                                      >
                                      > if(violations. HasErrors) {
                                      > throw new BusinessRuleExcepti on(violations) ;
                                      > }
                                      >
                                      > this.DoRedeem( account);
                                      > }
                                      >
                                      > protected void DoRedeem(Account account){
                                      > ...
                                      > }
                                      > }
                                      >
                                      >
                                      > public class PromoCodeTest{
                                      >
                                      > public void RunCanRedeem( ){
                                      >
                                      > Account testAccount = Mock.GetMock< Account>( );
                                      >
                                      > PromoCode code = CreateValidPromoCod e();
                                      >
                                      > if(code.CanRedeem( testAccount) .HasErrors == false){
                                      > code.Redeem( testAccount) ;
                                      >
                                      > Assert.IsTrue( code.IsRedeemed) ;
                                      > }
                                      > }
                                      > }
                                      >
                                      >
                                      >
                                      > Any thoughts or advice on this? Any ways to improve it? Or is the a
                                      > better strategy that I havent seen?
                                      >
                                      > Thanks,
                                      > Jesse
                                      >
                                      >
                                      >
                                      >

                                    • Joe A. Reddy
                                      I like it. It makes it clear to anyone and everyone that when PromoCodes are redeemed they need to deal with Violations. This code would be hard to misuse. ...
                                      Message 18 of 26 , Jun 28 1:17 PM

                                        I like it.

                                        It makes it clear to anyone and everyone that when PromoCodes are redeemed they need to deal with Violations.

                                        This code would be hard to misuse.

                                         

                                         

                                        -----Original Message-----
                                        From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jesse Napier
                                        Sent: Thursday, June 28, 2007 2:43 PM
                                        To: domaindrivendesign@yahoogroups.com
                                        Subject: RE: [domaindrivendesign] To throw or not to throw on Rule Violation

                                         

                                        Its so true that exceptional situations are very subjective.  I've found myself battling with that all the time.  In my case, it seems like an exceptional situation would be if more people redeemed the promo code than were allowed to.  Then Ive got problems.  So the business logic is in place to prevent that from occurring. 

                                         

                                        From reading other discussions on this forum and from the feedback I have recieved in regards to this post, it appears that there is alot of sentiment for not throwing exceptions in situations like this and I tend to agree.  So how do we get the validation errors to the caller in an elegant way?

                                         

                                        There has been some talk of events, but that doesnt really seem elegant to me.  It seems confusing for the client.

                                         

                                        Say im a a controller, I want to do this:

                                         

                                        string codeId = GetCodeFromRequest( );

                                         

                                        PromCode promoCode = promoRepository. FindByCode( codeId);

                                         

                                        promoCode.Redeem( account);

                                         

                                           //get validation errors from somewhere

                                           //and register them for the view to display

                                        }

                                         

                                        having some event handler in the controller to trap for redemption errors would be very hard to understand and follow if you ask me.  The code would read better if we handled any violations right next to the code that caused the violation.

                                         

                                        does this smell?

                                         

                                        INotification violations = INotificationFactor y.Create( );

                                         

                                        promoCode.Redeem( account, violations);

                                         

                                        if(violations. HasErrors) {

                                            //register error messages with the view

                                        }

                                         

                                         

                                         


                                        From: domaindrivendesign@ yahoogroups. com [mailto:domaindrive ndesign@yahoogro ups.com] On Behalf Of Jeff Lowe
                                        Sent: Thursday, June 28, 2007 7:46 AM
                                        To: domaindrivendesign@ yahoogroups. com
                                        Subject: RE: [domaindrivendesign ] To throw or not to throw on Rule Violation

                                        That's a cute mantra.  "exceptional situation" is certainly subjective.

                                         

                                        As Jesse stated, there's a difference between simple data validation, and the violation of business rules during a non-trivial operation in the domain.  I consider the latter to be an "exceptional situation".

                                         

                                         

                                         


                                        From: domaindrivendesign@ yahoogroups. com [mailto:domaindrive ndesign@yahoogro ups.com] On Behalf Of ARKBAN
                                        Sent: Thursday, June 28, 2007 10:10 AM
                                        To: domaindrivendesign@ yahoogroups. com
                                        Subject: Re: [domaindrivendesign ] To throw or not to throw on Rule Violation

                                        I think the concern revolves around the mantra "exceptions are for
                                        exceptional situations". Validation is most often not exceptional but
                                        expected; validation checks for situations that occur easily but can be
                                        easily corrected, which are not really exceptional.

                                        ARKBAN

                                        Jeff Lowe wrote:

                                        >
                                        >
                                        > Call me old fashioned, but I prefer simply throwing a
                                        > checked exception. The exception then becomes part of the method
                                        > signature, which makes for a more expressive domain interface, e.g.:
                                        >
                                        > public redeem(Account account) throws PromotionRulesViola tionException
                                        >
                                        > The exception can then encapsulate everything needed by the client (i.e.
                                        > application) to communicate back to the user, including information
                                        > about multiple rule violations.
                                        >
                                        >> > The thought of throwing exceptions doesn't sit real well with me
                                        but ...
                                        >
                                        > I'm curious why it doesn't sit well. Other folks have also expressed this.
                                        >
                                        >
                                        > Thanks,
                                        > -Jeff
                                        >
                                        >
                                        > ------------ --------- --------- --------- --------- --------- -
                                        > *From:* domaindrivendesign@ yahoogroups. com
                                        > [mailto:domaindrivendesign@ yahoogroups. com]
                                        *On Behalf Of *Jesse Napier
                                        > *Sent:* Wednesday, June 27, 2007 9:41 PM
                                        > *To:* domaindrivendesign@ yahoogroups. com
                                        > *Subject:* [domaindrivendesign ] To throw or not to throw on Rule
                                        Violation
                                        >
                                        > I have a question regarding business logic validation in my domain. Im
                                        > not talking about validation in the sense of simple data validation such
                                        > as checking for null values or specific data ranges. These days it
                                        > seems like most people are handling these types of validations with a
                                        > validation framework and checking an IsValid operation or something
                                        > similar. I refer to these as data validations. It may be fine in some
                                        > domains for an object to exist and be persisted when that object is in
                                        > an invalid data state. I am faced with an issue in which I cannot
                                        > allow certain objects to ever be in an invalid state.
                                        >
                                        > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                                        > accounts, but there are rules regarding redemption. If any of these
                                        > rules are violated, redemption cannot succeed and the application must
                                        > prevent the redemption. These rule violations are not fatal and are to
                                        > be expected, however I must notify the user as to why the redemption did
                                        > not succeed. So my question is, what is the preferred way of
                                        > communicating business rule violations to the UI when an action cannot
                                        > be performed because it would put the object into an invalid state that
                                        > cannot be persisted?
                                        >
                                        > I think there are essentialy 4 ways:
                                        > 1) Throw an exception describing the first violation
                                        > 2) Use Notification pattern
                                        > <http://www.martinfo wler.com/ eaaDev/Notificat ion.html>
                                        to communicate
                                        > information about all violations.
                                        > 3) Throw an exception that encapsulates the Notification object as
                                        > described in Sergio's blog post, A Notification Strategy for Business
                                        > Errors
                                        > <
                                        href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html>
                                        > 4) Provide a Check operation which returns a a boolean or a Notification
                                        > object such as /Notification CanRedeem(Account) ; /or /bool
                                        > CanRedeem(Account) ; /If the check operation returns any violations,
                                        > Redeem would throw an exception.
                                        >
                                        > The thought of throwing exceptions doesn't sit real well with me but it
                                        > is the easiest way to get the information to any interested parties
                                        > because they just have to try...catch it. The Notification pattern has
                                        > value but it seems more difficult to get the information to the
                                        > interested parties. Granted, the Redeem operation on PromoCode is a
                                        > void operation and I could just return a Notification object from that
                                        > call. However, in my research for this problem Im trying to comeup with
                                        > a solution that would also work with operations that had a return
                                        > value. #4 is an instersting option but im a little turned off by it
                                        > because the check would have to be called multiple times, once from the
                                        > client and once from the redeem operation. Here is a sample
                                        >
                                        > public class PromoCode{
                                        >
                                        > string code;
                                        > DateTime expirationDate;
                                        > bool isRedeemed;
                                        > bool isOnlyForNewAccount s;
                                        >
                                        > public Notification CanRedeem(Account account){
                                        > Notification violations = new Notification( );
                                        >
                                        > if(this.isRedeemed) {
                                        > violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                                        > }
                                        >
                                        > if(this.expirationD ate > DateTime.Now) {
                                        > violations.Add( PromoCodeViolati on.Expired) ;
                                        > }
                                        >
                                        > if(this.isOnlyForNe wAccounts && account.IsNewAccoun t ==
                                        false){
                                        > violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                        > }
                                        >
                                        > return violations;
                                        > }
                                        >
                                        > public void Redeem(Account account){
                                        > Notification violations = this.CanRedeem( account);
                                        >
                                        > if(violations. HasErrors) {
                                        > throw new BusinessRuleExcepti on(violations) ;
                                        > }
                                        >
                                        > this.DoRedeem( account);
                                        > }
                                        >
                                        > protected void DoRedeem(Account account){
                                        > ...
                                        > }
                                        > }
                                        >
                                        >
                                        > public class PromoCodeTest{
                                        >
                                        > public void RunCanRedeem( ){
                                        >
                                        > Account testAccount = Mock.GetMock< Account>( );
                                        >
                                        > PromoCode code = CreateValidPromoCod e();
                                        >
                                        > if(code.CanRedeem( testAccount) .HasErrors == false){
                                        > code.Redeem( testAccount) ;
                                        >
                                        > Assert.IsTrue( code.IsRedeemed) ;
                                        > }
                                        > }
                                        > }
                                        >
                                        >
                                        >
                                        > Any thoughts or advice on this? Any ways to improve it? Or is the a
                                        > better strategy that I havent seen?
                                        >
                                        > Thanks,
                                        > Jesse
                                        >
                                        >
                                        >
                                        >

                                      • ARKBAN
                                        How are they forced to deal with violations in these code examples? In the first I could just not register a listener/event handler, and in the second I could
                                        Message 19 of 26 , Jun 28 1:29 PM
                                          How are they forced to deal with violations in these code examples? In
                                          the first I could just not register a listener/event handler, and in the
                                          second I could just not check for violations.

                                          Personally the second example to me looks very much like the old return
                                          code style error system used in C. Not inherently bad but requires
                                          consistency and mindfulness to always check for errors.

                                          ARKBAN

                                          Joe A. Reddy wrote:
                                          >
                                          >
                                          > I like it.
                                          >
                                          > It makes it clear to anyone and everyone that when PromoCodes are
                                          > redeemed they need to deal with Violations.
                                          >
                                          > This code would be hard to misuse.
                                          >
                                          >
                                          >
                                          >
                                          >
                                          > -----Original Message-----
                                          > *From:* domaindrivendesign@yahoogroups.com
                                          > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *Jesse Napier
                                          > *Sent:* Thursday, June 28, 2007 2:43 PM
                                          > *To:* domaindrivendesign@yahoogroups.com
                                          > *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule
                                          > Violation
                                          >
                                          >
                                          >
                                          > Its so true that exceptional situations are very subjective. I've found
                                          > myself battling with that all the time. In my case, it seems like an
                                          > exceptional situation would be if more people redeemed the promo code
                                          > than were allowed to. Then Ive got problems. So the business logic is
                                          > in place to prevent that from occurring.
                                          >
                                          >
                                          >
                                          > From reading other discussions on this forum and from the feedback I
                                          > have recieved in regards to this post, it appears that there is alot of
                                          > sentiment for not throwing exceptions in situations like this and I tend
                                          > to agree. So how do we get the validation errors to the caller in an
                                          > elegant way?
                                          >
                                          >
                                          >
                                          > There has been some talk of events, but that doesnt really seem elegant
                                          > to me. It seems confusing for the client.
                                          >
                                          >
                                          >
                                          > Say im a a controller, I want to do this:
                                          >
                                          >
                                          >
                                          > string codeId = GetCodeFromRequest();
                                          >
                                          >
                                          >
                                          > PromCode promoCode = promoRepository.FindByCode(codeId);
                                          >
                                          >
                                          >
                                          > promoCode.Redeem(account);
                                          >
                                          >
                                          >
                                          > //get validation errors from somewhere
                                          >
                                          > //and register them for the view to display
                                          >
                                          > }
                                          >
                                          >
                                          >
                                          > having some event handler in the controller to trap for redemption
                                          > errors would be very hard to understand and follow if you ask me. The
                                          > code would read better if we handled any violations right next to the
                                          > code that caused the violation.
                                          >
                                          >
                                          >
                                          > does this smell?
                                          >
                                          >
                                          >
                                          > INotification violations = INotificationFactory.Create();
                                          >
                                          >
                                          >
                                          > promoCode.Redeem(account, violations);
                                          >
                                          >
                                          >
                                          > if(violations.HasErrors){
                                          >
                                          > //register error messages with the view
                                          >
                                          > }
                                          >
                                          >
                                          >
                                          >
                                          >
                                          >
                                          >
                                          > ------------------------------------------------------------------------
                                          >
                                          > *From:* domaindrivendesign@yahoogroups.com
                                          > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *Jeff Lowe
                                          > *Sent:* Thursday, June 28, 2007 7:46 AM
                                          > *To:* domaindrivendesign@yahoogroups.com
                                          > *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule
                                          > Violation
                                          >
                                          > That's a cute mantra. "exceptional situation" is certainly subjective.
                                          >
                                          >
                                          >
                                          > As Jesse stated, there's a difference between simple data validation,
                                          > and the violation of business rules during a non-trivial operation in
                                          > the domain. I consider the latter to be an "exceptional situation".
                                          >
                                          >
                                          >
                                          >
                                          >
                                          >
                                          >
                                          > ------------------------------------------------------------------------
                                          >
                                          > *From:* domaindrivendesign@yahoogroups.com
                                          > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *ARKBAN
                                          > *Sent:* Thursday, June 28, 2007 10:10 AM
                                          > *To:* domaindrivendesign@yahoogroups.com
                                          > *Subject:* Re: [domaindrivendesign] To throw or not to throw on Rule
                                          > Violation
                                          >
                                          > I think the concern revolves around the mantra "exceptions are for
                                          > exceptional situations". Validation is most often not exceptional but
                                          > expected; validation checks for situations that occur easily but can be
                                          > easily corrected, which are not really exceptional.
                                          >
                                          > ARKBAN
                                          >
                                          > Jeff Lowe wrote:
                                          >>
                                          >>
                                          >> Call me old fashioned, but I prefer simply throwing a
                                          >> checked exception. The exception then becomes part of the method
                                          >> signature, which makes for a more expressive domain interface, e.g.:
                                          >>
                                          >> public redeem(Account account) throws PromotionRulesViolationException
                                          >>
                                          >> The exception can then encapsulate everything needed by the client (i.e.
                                          >> application) to communicate back to the user, including information
                                          >> about multiple rule violations.
                                          >>
                                          >> > > The thought of throwing exceptions doesn't sit real well with me
                                          > but ...
                                          >>
                                          >> I'm curious why it doesn't sit well. Other folks have also expressed this.
                                          >>
                                          >>
                                          >> Thanks,
                                          >> -Jeff
                                          >>
                                          >>
                                          >> ----------------------------------------------------------
                                          >> *From:* domaindrivendesign@yahoogroups.com
                                          > <mailto:domaindrivendesign%40yahoogroups.com>
                                          >> [mailto:domaindrivendesign@yahoogroups.com
                                          > <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jesse Napier
                                          >> *Sent:* Wednesday, June 27, 2007 9:41 PM
                                          >> *To:* domaindrivendesign@yahoogroups.com
                                          > <mailto:domaindrivendesign%40yahoogroups.com>
                                          >> *Subject:* [domaindrivendesign] To throw or not to throw on Rule Violation
                                          >>
                                          >> I have a question regarding business logic validation in my domain. Im
                                          >> not talking about validation in the sense of simple data validation such
                                          >> as checking for null values or specific data ranges. These days it
                                          >> seems like most people are handling these types of validations with a
                                          >> validation framework and checking an IsValid operation or something
                                          >> similar. I refer to these as data validations. It may be fine in some
                                          >> domains for an object to exist and be persisted when that object is in
                                          >> an invalid data state. I am faced with an issue in which I cannot
                                          >> allow certain objects to ever be in an invalid state.
                                          >>
                                          >> In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                                          >> accounts, but there are rules regarding redemption. If any of these
                                          >> rules are violated, redemption cannot succeed and the application must
                                          >> prevent the redemption. These rule violations are not fatal and are to
                                          >> be expected, however I must notify the user as to why the redemption did
                                          >> not succeed. So my question is, what is the preferred way of
                                          >> communicating business rule violations to the UI when an action cannot
                                          >> be performed because it would put the object into an invalid state that
                                          >> cannot be persisted?
                                          >>
                                          >> I think there are essentialy 4 ways:
                                          >> 1) Throw an exception describing the first violation
                                          >> 2) Use Notification pattern
                                          >> <http://www.martinfowler.com/eaaDev/Notification.html
                                          > <http://www.martinfowler.com/eaaDev/Notification.html>> to communicate
                                          >> information about all violations.
                                          >> 3) Throw an exception that encapsulates the Notification object as
                                          >> described in Sergio's blog post, A Notification Strategy for Business
                                          >> Errors
                                          >>
                                          > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html
                                          > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html>>
                                          >> 4) Provide a Check operation which returns a a boolean or a Notification
                                          >> object such as /Notification CanRedeem(Account); /or /bool
                                          >> CanRedeem(Account); /If the check operation returns any violations,
                                          >> Redeem would throw an exception.
                                          >>
                                          >> The thought of throwing exceptions doesn't sit real well with me but it
                                          >> is the easiest way to get the information to any interested parties
                                          >> because they just have to try...catch it. The Notification pattern has
                                          >> value but it seems more difficult to get the information to the
                                          >> interested parties. Granted, the Redeem operation on PromoCode is a
                                          >> void operation and I could just return a Notification object from that
                                          >> call. However, in my research for this problem Im trying to comeup with
                                          >> a solution that would also work with operations that had a return
                                          >> value. #4 is an instersting option but im a little turned off by it
                                          >> because the check would have to be called multiple times, once from the
                                          >> client and once from the redeem operation. Here is a sample
                                          >>
                                          >> public class PromoCode{
                                          >>
                                          >> string code;
                                          >> DateTime expirationDate;
                                          >> bool isRedeemed;
                                          >> bool isOnlyForNewAccounts;
                                          >>
                                          >> public Notification CanRedeem(Account account){
                                          >> Notification violations = new Notification();
                                          >>
                                          >> if(this.isRedeemed){
                                          >> violations.Add(PromoCodeViolation.AlreadyRedeemed);
                                          >> }
                                          >>
                                          >> if(this.expirationDate > DateTime.Now){
                                          >> violations.Add(PromoCodeViolation.Expired);
                                          >> }
                                          >>
                                          >> if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                                          >> violations.Add(PromoCodeViolation.NewAccountsOnly);
                                          >> }
                                          >>
                                          >> return violations;
                                          >> }
                                          >>
                                          >> public void Redeem(Account account){
                                          >> Notification violations = this.CanRedeem(account);
                                          >>
                                          >> if(violations.HasErrors){
                                          >> throw new BusinessRuleException(violations);
                                          >> }
                                          >>
                                          >> this.DoRedeem(account);
                                          >> }
                                          >>
                                          >> protected void DoRedeem(Account account){
                                          >> ...
                                          >> }
                                          >> }
                                          >>
                                          >>
                                          >> public class PromoCodeTest{
                                          >>
                                          >> public void RunCanRedeem(){
                                          >>
                                          >> Account testAccount = Mock.GetMock<Account>();
                                          >>
                                          >> PromoCode code = CreateValidPromoCode();
                                          >>
                                          >> if(code.CanRedeem(testAccount).HasErrors == false){
                                          >> code.Redeem(testAccount);
                                          >>
                                          >> Assert.IsTrue(code.IsRedeemed);
                                          >> }
                                          >> }
                                          >> }
                                          >>
                                          >>
                                          >>
                                          >> Any thoughts or advice on this? Any ways to improve it? Or is the a
                                          >> better strategy that I havent seen?
                                          >>
                                          >> Thanks,
                                          >> Jesse
                                          >>
                                          >>
                                          >>
                                          >>
                                          >
                                          >
                                        • Joe A. Reddy
                                          In C# when I type myPromo.Redeem( the IDE will tell me I will be passing into two arguments. One is an Account passed by value and the other is Violations
                                          Message 20 of 26 , Jun 28 1:38 PM

                                            In C# when I type myPromo.Redeem( the IDE will tell me I will be passing into two arguments. One is an Account passed by value and the other is Violations passed by reference and not initialized.

                                            This tells me that the routine will initialize Violations…something is happening…I have to go out of my way to ignore it.

                                             

                                            Note, I did not say forced, just hard to misuse, hard to ignore.

                                             

                                             

                                             

                                             

                                            -----Original Message-----
                                            From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of ARKBAN
                                            Sent: Thursday, June 28, 2007 3:29 PM
                                            To: domaindrivendesign@yahoogroups.com
                                            Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                                             

                                            How are they forced to deal with violations in these code examples? In
                                            the first I could just not register a listener/event handler, and in the
                                            second I could just not check for violations.

                                            Personally the second example to me looks very much like the old return
                                            code style error system used in C. Not inherently bad but requires
                                            consistency and mindfulness to always check for errors.

                                            ARKBAN

                                            Joe A. Reddy wrote:

                                            >
                                            >
                                            > I like it.
                                            >
                                            > It makes it clear to anyone and everyone that when PromoCodes are
                                            > redeemed they need to deal with Violations.
                                            >
                                            > This code would be hard to misuse.
                                            >
                                            >
                                            >
                                            >
                                            >
                                            > -----Original Message-----
                                            > *From:* domaindrivendesign@ yahoogroups. com
                                            > [mailto:domaindrivendesign@ yahoogroups. com]
                                            *On Behalf Of *Jesse Napier
                                            > *Sent:* Thursday, June 28, 2007 2:43 PM
                                            > *To:* domaindrivendesign@ yahoogroups. com
                                            > *Subject:* RE: [domaindrivendesign ] To throw or not to throw on Rule
                                            > Violation
                                            >
                                            >
                                            >
                                            > Its so true that exceptional situations are very subjective. I've found
                                            > myself battling with that all the time. In my case, it seems like an
                                            > exceptional situation would be if more people redeemed the promo code
                                            > than were allowed to. Then Ive got problems. So the business logic is
                                            > in place to prevent that from occurring.
                                            >
                                            >
                                            >
                                            > From reading other discussions on this forum and from the feedback I
                                            > have recieved in regards to this post, it appears that there is alot of
                                            > sentiment for not throwing exceptions in situations like this and I tend
                                            > to agree. So how do we get the validation errors to the caller in an
                                            > elegant way?
                                            >
                                            >
                                            >
                                            > There has been some talk of events, but that doesnt really seem elegant
                                            > to me. It seems confusing for the client.
                                            >
                                            >
                                            >
                                            > Say im a a controller, I want to do this:
                                            >
                                            >
                                            >
                                            > string codeId = GetCodeFromRequest( );
                                            >
                                            >
                                            >
                                            > PromCode promoCode = promoRepository. FindByCode( codeId);
                                            >
                                            >
                                            >
                                            > promoCode.Redeem( account);
                                            >
                                            >
                                            >
                                            > //get validation errors from somewhere
                                            >
                                            > //and register them for the view to display
                                            >
                                            > }
                                            >
                                            >
                                            >
                                            > having some event handler in the controller to trap for redemption
                                            > errors would be very hard to understand and follow if you ask me. The
                                            > code would read better if we handled any violations right next to the
                                            > code that caused the violation.
                                            >
                                            >
                                            >
                                            > does this smell?
                                            >
                                            >
                                            >
                                            > INotification violations = INotificationFactor y.Create( );
                                            >
                                            >
                                            >
                                            > promoCode.Redeem( account, violations);
                                            >
                                            >
                                            >
                                            > if(violations. HasErrors) {
                                            >
                                            > //register error messages with the view
                                            >
                                            > }
                                            >
                                            >
                                            >
                                            >
                                            >
                                            >
                                            >
                                            > ------------ --------- --------- --------- --------- --------- -
                                            >
                                            > *From:* domaindrivendesign@ yahoogroups. com
                                            > [mailto:domaindrivendesign@ yahoogroups. com]
                                            *On Behalf Of *Jeff Lowe
                                            > *Sent:* Thursday, June 28, 2007 7:46 AM
                                            > *To:* domaindrivendesign@ yahoogroups. com
                                            > *Subject:* RE: [domaindrivendesign ] To throw or not to throw on Rule
                                            > Violation
                                            >
                                            > That's a cute mantra. "exceptional situation" is certainly
                                            subjective.
                                            >
                                            >
                                            >
                                            > As Jesse stated, there's a difference between simple data validation,
                                            > and the violation of business rules during a non-trivial operation in
                                            > the domain. I consider the latter to be an "exceptional
                                            situation".
                                            >
                                            >
                                            >
                                            >
                                            >
                                            >
                                            >
                                            > ------------ --------- --------- --------- --------- --------- -
                                            >
                                            > *From:* domaindrivendesign@ yahoogroups. com
                                            > [mailto:domaindrivendesign@ yahoogroups. com]
                                            *On Behalf Of *ARKBAN
                                            > *Sent:* Thursday, June 28, 2007 10:10 AM
                                            > *To:* domaindrivendesign@ yahoogroups. com
                                            > *Subject:* Re: [domaindrivendesign ] To throw or not to throw on Rule
                                            > Violation
                                            >
                                            > I think the concern revolves around the mantra "exceptions are for
                                            > exceptional situations". Validation is most often not exceptional but
                                            > expected; validation checks for situations that occur easily but can be
                                            > easily corrected, which are not really exceptional.
                                            >
                                            > ARKBAN
                                            >
                                            > Jeff Lowe wrote:
                                            >>
                                            >>
                                            >> Call me old fashioned, but I prefer simply throwing a
                                            >> checked exception. The exception then becomes part of the method
                                            >> signature, which makes for a more expressive domain interface, e.g.:
                                            >>
                                            >> public redeem(Account account) throws PromotionRulesViola tionException
                                            >>
                                            >> The exception can then encapsulate everything needed by the client
                                            (i.e.
                                            >> application) to communicate back to the user, including information
                                            >> about multiple rule violations.
                                            >>
                                            >> > > The thought of throwing exceptions doesn't sit real well
                                            with me
                                            > but ...
                                            >>
                                            >> I'm curious why it doesn't sit well. Other folks have also expressed
                                            this.
                                            >>
                                            >>
                                            >> Thanks,
                                            >> -Jeff
                                            >>
                                            >>
                                            >> ------------ --------- --------- --------- --------- --------- -
                                            >> *From:* domaindrivendesign@ yahoogroups. com
                                            > <mailto:domaindrive ndesign%40yahoog roups.com>
                                            >> [mailto:domaindrivendesign@ yahoogroups. com
                                            > <mailto:domaindrive ndesign%40yahoog roups.com> ] *On
                                            Behalf Of *Jesse Napier
                                            >> *Sent:* Wednesday, June 27, 2007 9:41 PM
                                            >> *To:* domaindrivendesign@ yahoogroups. com
                                            > <mailto:domaindrive ndesign%40yahoog roups.com>
                                            >> *Subject:* [domaindrivendesign ] To throw or not to throw on Rule
                                            Violation
                                            >>
                                            >> I have a question regarding business logic validation in my domain. Im
                                            >> not talking about validation in the sense of simple data validation
                                            such
                                            >> as checking for null values or specific data ranges. These days it
                                            >> seems like most people are handling these types of validations with a
                                            >> validation framework and checking an IsValid operation or something
                                            >> similar. I refer to these as data validations. It may be fine in some
                                            >> domains for an object to exist and be persisted when that object is in
                                            >> an invalid data state. I am faced with an issue in which I cannot
                                            >> allow certain objects to ever be in an invalid state.
                                            >>
                                            >> In my domain I have PromoCode and Account. PromoCodes can be redeemed
                                            by
                                            >> accounts, but there are rules regarding redemption. If any of these
                                            >> rules are violated, redemption cannot succeed and the application must
                                            >> prevent the redemption. These rule violations are not fatal and are to
                                            >> be expected, however I must notify the user as to why the redemption
                                            did
                                            >> not succeed. So my question is, what is the preferred way of
                                            >> communicating business rule violations to the UI when an action cannot
                                            >> be performed because it would put the object into an invalid state
                                            that
                                            >> cannot be persisted?
                                            >>
                                            >> I think there are essentialy 4 ways:
                                            >> 1) Throw an exception describing the first violation
                                            >> 2) Use Notification pattern
                                            >> <http://www.martinfo wler.com/ eaaDev/Notificat ion.html
                                            > <http://www.martinfo wler.com/ eaaDev/Notificat ion.html>>
                                            to communicate
                                            >> information about all violations.
                                            >> 3) Throw an exception that encapsulates the Notification object as
                                            >> described in Sergio's blog post, A Notification Strategy for Business
                                            >> Errors
                                            >>
                                            > <
                                            href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html
                                            > <
                                            href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html>>
                                            >> 4) Provide a Check operation which returns a a boolean or a
                                            Notification
                                            >> object such as /Notification CanRedeem(Account) ; /or /bool
                                            >> CanRedeem(Account) ; /If the check operation returns any
                                            violations,
                                            >> Redeem would throw an exception.
                                            >>
                                            >> The thought of throwing exceptions doesn't sit real well with me but
                                            it
                                            >> is the easiest way to get the information to any interested parties
                                            >> because they just have to try...catch it. The Notification pattern has
                                            >> value but it seems more difficult to get the information to the
                                            >> interested parties. Granted, the Redeem operation on PromoCode is a
                                            >> void operation and I could just return a Notification object from that
                                            >> call. However, in my research for this problem Im trying to comeup
                                            with
                                            >> a solution that would also work with operations that had a return
                                            >> value. #4 is an instersting option but im a little turned off by it
                                            >> because the check would have to be called multiple times, once from
                                            the
                                            >> client and once from the redeem operation. Here is a sample
                                            >>
                                            >> public class PromoCode{
                                            >>
                                            >> string code;
                                            >> DateTime expirationDate;
                                            >> bool isRedeemed;
                                            >> bool isOnlyForNewAccount s;
                                            >>
                                            >> public Notification CanRedeem(Account account){
                                            >> Notification violations = new Notification( );
                                            >>
                                            >> if(this.isRedeemed) {
                                            >> violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                                            >> }
                                            >>
                                            >> if(this.expirationD ate > DateTime.Now) {
                                            >> violations.Add( PromoCodeViolati on.Expired) ;
                                            >> }
                                            >>
                                            >> if(this.isOnlyForNe wAccounts && account.IsNewAccoun t
                                            == false){
                                            >> violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                            >> }
                                            >>
                                            >> return violations;
                                            >> }
                                            >>
                                            >> public void Redeem(Account account){
                                            >> Notification violations = this.CanRedeem( account);
                                            >>
                                            >> if(violations. HasErrors) {
                                            >> throw new BusinessRuleExcepti on(violations) ;
                                            >> }
                                            >>
                                            >> this.DoRedeem( account);
                                            >> }
                                            >>
                                            >> protected void DoRedeem(Account account){
                                            >> ...
                                            >> }
                                            >> }
                                            >>
                                            >>
                                            >> public class PromoCodeTest{
                                            >>
                                            >> public void RunCanRedeem( ){
                                            >>
                                            >> Account testAccount = Mock.GetMock< Account>( );
                                            >>
                                            >> PromoCode code = CreateValidPromoCod e();
                                            >>
                                            >> if(code.CanRedeem( testAccount) .HasErrors == false){
                                            >> code.Redeem( testAccount) ;
                                            >>
                                            >> Assert.IsTrue( code.IsRedeemed) ;
                                            >> }
                                            >> }
                                            >> }
                                            >>
                                            >>
                                            >>
                                            >> Any thoughts or advice on this? Any ways to improve it? Or is the a
                                            >> better strategy that I havent seen?
                                            >>
                                            >> Thanks,
                                            >> Jesse
                                            >>
                                            >>
                                            >>
                                            >>
                                            >
                                            >

                                          • Louis Richer
                                            Personally, treating contingency business cases as checked exceptions makes a ton of sense. That is the argument put forward, quite effectively in my opinion,
                                            Message 21 of 26 , Jun 28 1:41 PM
                                              Personally, treating contingency business cases as checked exceptions
                                              makes a ton of sense. That is the argument put forward, quite
                                              effectively in my opinion, in the 3 page Effective Java Exceptions
                                              article referenced in Chris Beams response earlier on this topic.

                                              It would be helpful to get a critique of the Effective Java Exceptions
                                              article from someone advocating a strict interpretation of the use of
                                              exceptions (i.e. the mantra).

                                              louis

                                              --- In domaindrivendesign@yahoogroups.com, "Jesse Napier"
                                              <jnapier@...> wrote:
                                              >
                                              > Its so true that exceptional situations are very subjective. I've found
                                              > myself battling with that all the time. In my case, it seems like an
                                              > exceptional situation would be if more people redeemed the promo code
                                              > than were allowed to. Then Ive got problems. So the business logic is
                                              > in place to prevent that from occurring.
                                              >
                                              > From reading other discussions on this forum and from the feedback I
                                              > have recieved in regards to this post, it appears that there is alot of
                                              > sentiment for not throwing exceptions in situations like this and I tend
                                              > to agree. So how do we get the validation errors to the caller in an
                                              > elegant way?
                                              >
                                              > There has been some talk of events, but that doesnt really seem elegant
                                              > to me. It seems confusing for the client.
                                              >
                                              > Say im a a controller, I want to do this:
                                              >
                                              > string codeId = GetCodeFromRequest();
                                              >
                                              > PromCode promoCode = promoRepository.FindByCode(codeId);
                                              >
                                              > promoCode.Redeem(account);
                                              >
                                              > //get validation errors from somewhere
                                              > //and register them for the view to display
                                              > }
                                              >
                                              > having some event handler in the controller to trap for redemption
                                              > errors would be very hard to understand and follow if you ask me. The
                                              > code would read better if we handled any violations right next to the
                                              > code that caused the violation.
                                              >
                                              > does this smell?
                                              >
                                              > INotification violations = INotificationFactory.Create();
                                              >
                                              > promoCode.Redeem(account, violations);
                                              >
                                              > if(violations.HasErrors){
                                              > //register error messages with the view
                                              > }
                                              >
                                              >
                                              >
                                              > ________________________________
                                              >
                                              > From: domaindrivendesign@yahoogroups.com
                                              > [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Jeff Lowe
                                              > Sent: Thursday, June 28, 2007 7:46 AM
                                              > To: domaindrivendesign@yahoogroups.com
                                              > Subject: RE: [domaindrivendesign] To throw or not to throw on Rule
                                              > Violation
                                              >
                                              >
                                              >
                                              > That's a cute mantra. "exceptional situation" is certainly subjective.
                                              >
                                              > As Jesse stated, there's a difference between simple data validation,
                                              > and the violation of business rules during a non-trivial operation in
                                              > the domain. I consider the latter to be an "exceptional situation".
                                              >
                                              >
                                              >
                                              > ________________________________
                                              >
                                              > From: domaindrivendesign@yahoogroups.com
                                              > [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of ARKBAN
                                              > Sent: Thursday, June 28, 2007 10:10 AM
                                              > To: domaindrivendesign@yahoogroups.com
                                              > Subject: Re: [domaindrivendesign] To throw or not to throw on Rule
                                              > Violation
                                              >
                                              >
                                              >
                                              > I think the concern revolves around the mantra "exceptions are for
                                              > exceptional situations". Validation is most often not exceptional but
                                              > expected; validation checks for situations that occur easily but can be
                                              > easily corrected, which are not really exceptional.
                                              >
                                              > ARKBAN
                                              >
                                              > Jeff Lowe wrote:
                                              > >
                                              > >
                                              > > Call me old fashioned, but I prefer simply throwing a
                                              > > checked exception. The exception then becomes part of the method
                                              > > signature, which makes for a more expressive domain interface, e.g.:
                                              > >
                                              > > public redeem(Account account) throws PromotionRulesViolationException
                                              > >
                                              > > The exception can then encapsulate everything needed by the client
                                              > (i.e.
                                              > > application) to communicate back to the user, including information
                                              > > about multiple rule violations.
                                              > >
                                              > >> > The thought of throwing exceptions doesn't sit real well with me
                                              > but ...
                                              > >
                                              > > I'm curious why it doesn't sit well. Other folks have also expressed
                                              > this.
                                              > >
                                              > >
                                              > > Thanks,
                                              > > -Jeff
                                              > >
                                              > >
                                              > > ----------------------------------------------------------
                                              > > *From:* domaindrivendesign@yahoogroups.com
                                              > <mailto:domaindrivendesign%40yahoogroups.com>
                                              > > [mailto:domaindrivendesign@yahoogroups.com
                                              > <mailto:domaindrivendesign%40yahoogroups.com> ] *On Behalf Of *Jesse
                                              > Napier
                                              > > *Sent:* Wednesday, June 27, 2007 9:41 PM
                                              > > *To:* domaindrivendesign@yahoogroups.com
                                              > <mailto:domaindrivendesign%40yahoogroups.com>
                                              > > *Subject:* [domaindrivendesign] To throw or not to throw on Rule
                                              > Violation
                                              > >
                                              > > I have a question regarding business logic validation in my domain. Im
                                              >
                                              > > not talking about validation in the sense of simple data validation
                                              > such
                                              > > as checking for null values or specific data ranges. These days it
                                              > > seems like most people are handling these types of validations with a
                                              > > validation framework and checking an IsValid operation or something
                                              > > similar. I refer to these as data validations. It may be fine in some
                                              > > domains for an object to exist and be persisted when that object is in
                                              >
                                              > > an invalid data state. I am faced with an issue in which I cannot
                                              > > allow certain objects to ever be in an invalid state.
                                              > >
                                              > > In my domain I have PromoCode and Account. PromoCodes can be redeemed
                                              > by
                                              > > accounts, but there are rules regarding redemption. If any of these
                                              > > rules are violated, redemption cannot succeed and the application must
                                              >
                                              > > prevent the redemption. These rule violations are not fatal and are to
                                              >
                                              > > be expected, however I must notify the user as to why the redemption
                                              > did
                                              > > not succeed. So my question is, what is the preferred way of
                                              > > communicating business rule violations to the UI when an action cannot
                                              >
                                              > > be performed because it would put the object into an invalid state
                                              > that
                                              > > cannot be persisted?
                                              > >
                                              > > I think there are essentialy 4 ways:
                                              > > 1) Throw an exception describing the first violation
                                              > > 2) Use Notification pattern
                                              > > <http://www.martinfowler.com/eaaDev/Notification.html
                                              > <http://www.martinfowler.com/eaaDev/Notification.html> > to communicate
                                              > > information about all violations.
                                              > > 3) Throw an exception that encapsulates the Notification object as
                                              > > described in Sergio's blog post, A Notification Strategy for Business
                                              > > Errors
                                              > >
                                              > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busines
                                              > s.html
                                              > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busines
                                              > s.html> >
                                              > > 4) Provide a Check operation which returns a a boolean or a
                                              > Notification
                                              > > object such as /Notification CanRedeem(Account); /or /bool
                                              > > CanRedeem(Account); /If the check operation returns any violations,
                                              > > Redeem would throw an exception.
                                              > >
                                              > > The thought of throwing exceptions doesn't sit real well with me but
                                              > it
                                              > > is the easiest way to get the information to any interested parties
                                              > > because they just have to try...catch it. The Notification pattern has
                                              >
                                              > > value but it seems more difficult to get the information to the
                                              > > interested parties. Granted, the Redeem operation on PromoCode is a
                                              > > void operation and I could just return a Notification object from that
                                              >
                                              > > call. However, in my research for this problem Im trying to comeup
                                              > with
                                              > > a solution that would also work with operations that had a return
                                              > > value. #4 is an instersting option but im a little turned off by it
                                              > > because the check would have to be called multiple times, once from
                                              > the
                                              > > client and once from the redeem operation. Here is a sample
                                              > >
                                              > > public class PromoCode{
                                              > >
                                              > > string code;
                                              > > DateTime expirationDate;
                                              > > bool isRedeemed;
                                              > > bool isOnlyForNewAccounts;
                                              > >
                                              > > public Notification CanRedeem(Account account){
                                              > > Notification violations = new Notification();
                                              > >
                                              > > if(this.isRedeemed){
                                              > > violations.Add(PromoCodeViolation.AlreadyRedeemed);
                                              > > }
                                              > >
                                              > > if(this.expirationDate > DateTime.Now){
                                              > > violations.Add(PromoCodeViolation.Expired);
                                              > > }
                                              > >
                                              > > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                                              > > violations.Add(PromoCodeViolation.NewAccountsOnly);
                                              > > }
                                              > >
                                              > > return violations;
                                              > > }
                                              > >
                                              > > public void Redeem(Account account){
                                              > > Notification violations = this.CanRedeem(account);
                                              > >
                                              > > if(violations.HasErrors){
                                              > > throw new BusinessRuleException(violations);
                                              > > }
                                              > >
                                              > > this.DoRedeem(account);
                                              > > }
                                              > >
                                              > > protected void DoRedeem(Account account){
                                              > > ...
                                              > > }
                                              > > }
                                              > >
                                              > >
                                              > > public class PromoCodeTest{
                                              > >
                                              > > public void RunCanRedeem(){
                                              > >
                                              > > Account testAccount = Mock.GetMock<Account>();
                                              > >
                                              > > PromoCode code = CreateValidPromoCode();
                                              > >
                                              > > if(code.CanRedeem(testAccount).HasErrors == false){
                                              > > code.Redeem(testAccount);
                                              > >
                                              > > Assert.IsTrue(code.IsRedeemed);
                                              > > }
                                              > > }
                                              > > }
                                              > >
                                              > >
                                              > >
                                              > > Any thoughts or advice on this? Any ways to improve it? Or is the a
                                              > > better strategy that I havent seen?
                                              > >
                                              > > Thanks,
                                              > > Jesse
                                              > >
                                              > >
                                              > >
                                              > >
                                              >
                                            • Jesse Napier
                                              Arkban, its true, the client may not do anything with the violations. That doesnt change the fact that the PromoCode still did not get redeemed. If the client
                                              Message 22 of 26 , Jun 28 1:57 PM
                                                Arkban,
                                                its true, the client may not do anything with the violations.  That doesnt change the fact that the PromoCode still did not get redeemed.  If the client doesnt convey that properly then I guess we have a problem with the client.
                                                 
                                                I'm starting to actually lik the 2nd example as Joe as has mentioned.  It makes it quite clear that there could be notifications as a result of this operation.  I think this reads better:
                                                 
                                                if(promoCode.CanRedeem(account).HasErrors){
                                                    //register violations with view
                                                }else{
                                                    promoCode.Redeem(account);
                                                }
                                                 
                                                but the client could much easier fail to call CanRedeem and not realize that Redeem threw an exception as opposed to calling Redeem(account, violations). Its much more explicit that there can be violations from calling Redeem.  This may not look as pretty but it seems really clear.


                                                From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of ARKBAN
                                                Sent: Thursday, June 28, 2007 1:29 PM
                                                To: domaindrivendesign@yahoogroups.com
                                                Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                                                How are they forced to deal with violations in these code examples? In
                                                the first I could just not register a listener/event handler, and in the
                                                second I could just not check for violations.

                                                Personally the second example to me looks very much like the old return
                                                code style error system used in C. Not inherently bad but requires
                                                consistency and mindfulness to always check for errors.

                                                ARKBAN

                                                Joe A. Reddy wrote:

                                                >
                                                >
                                                > I like it.
                                                >
                                                > It makes it clear to anyone and
                                                everyone that when PromoCodes are
                                                > redeemed they need to deal with
                                                Violations.
                                                >
                                                > This code would be hard to misuse.
                                                >
                                                >
                                                >
                                                >
                                                >
                                                > -----Original Message-----
                                                > *From:*
                                                domaindrivendesign@ yahoogroups. com
                                                > [mailto:
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jesse Napier
                                                > *Sent:* Thursday, June 28, 2007 2:43
                                                PM
                                                > *To:*
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com
                                                >
                                                *Subject:* RE: [domaindrivendesign ] To throw or not to throw on Rule
                                                > Violation
                                                >
                                                >
                                                >
                                                > Its so true that
                                                exceptional situations are very subjective. I've found
                                                > myself battling
                                                with that all the time. In my case, it seems like an
                                                > exceptional
                                                situation would be if more people redeemed the promo code
                                                > than were
                                                allowed to. Then Ive got problems. So the business logic is
                                                > in place to
                                                prevent that from occurring.
                                                >
                                                >
                                                >
                                                > From reading
                                                other discussions on this forum and from the feedback I
                                                > have recieved
                                                in regards to this post, it appears that there is alot of
                                                > sentiment for
                                                not throwing exceptions in situations like this and I tend
                                                > to agree. So
                                                how do we get the validation errors to the caller in an
                                                > elegant
                                                way?
                                                >
                                                >
                                                >
                                                > There has been some talk of events, but
                                                that doesnt really seem elegant
                                                > to me. It seems confusing for the
                                                client.
                                                >
                                                >
                                                >
                                                > Say im a a controller, I want to do
                                                this:
                                                >
                                                >
                                                >
                                                > string codeId =
                                                GetCodeFromRequest( );
                                                >
                                                >
                                                >
                                                > PromCode promoCode
                                                = promoRepository. FindByCode( codeId);
                                                >
                                                >
                                                >
                                                > promoCode.Redeem( account);
                                                >
                                                >
                                                >
                                                >
                                                //get validation errors from somewhere
                                                >
                                                > //and register them for
                                                the view to display
                                                >
                                                > }
                                                >
                                                >
                                                >
                                                > having
                                                some event handler in the controller to trap for redemption
                                                > errors
                                                would be very hard to understand and follow if you ask me. The
                                                > code
                                                would read better if we handled any violations right next to the
                                                > code
                                                that caused the violation.
                                                >
                                                >
                                                >
                                                > does this
                                                smell?
                                                >
                                                >
                                                >
                                                > INotification violations =
                                                INotificationFactor y.Create( );
                                                >
                                                >
                                                >
                                                >
                                                promoCode.Redeem( account, violations);
                                                >
                                                >
                                                >
                                                >
                                                if(violations. HasErrors) {
                                                >
                                                > //register error messages
                                                with the view
                                                >
                                                > }
                                                >
                                                >
                                                >
                                                >
                                                >
                                                >
                                                >
                                                >
                                                ------------ --------- --------- --------- --------- --------- -
                                                >
                                                > *From:*
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com
                                                > [mailto:
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jeff Lowe
                                                > *Sent:* Thursday, June 28, 2007 7:46 AM
                                                >
                                                *To:* domaindrivendesign@ yahoogroups. com
                                                >
                                                *Subject:* RE: [domaindrivendesign ] To throw or not to throw on Rule
                                                > Violation
                                                >
                                                > That's a cute mantra. "exceptional
                                                situation" is certainly subjective.
                                                >
                                                >
                                                >
                                                > As Jesse
                                                stated, there's a difference between simple data validation,
                                                > and the
                                                violation of business rules during a non-trivial operation in
                                                > the
                                                domain. I consider the latter to be an "exceptional situation".
                                                >
                                                >
                                                >
                                                >
                                                >
                                                >
                                                >
                                                >
                                                ------------ --------- --------- --------- --------- --------- -
                                                >
                                                > *From:*
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com
                                                > [mailto:
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com] *On Behalf Of *ARKBAN
                                                > *Sent:* Thursday, June 28, 2007 10:10 AM
                                                >
                                                *To:* domaindrivendesign@ yahoogroups. com
                                                >
                                                *Subject:* Re: [domaindrivendesign ] To throw or not to throw on Rule
                                                > Violation
                                                >
                                                > I think the concern revolves around the
                                                mantra "exceptions are for
                                                > exceptional situations". Validation is most
                                                often not exceptional but
                                                > expected; validation checks for situations
                                                that occur easily but can be
                                                > easily corrected, which are not really
                                                exceptional.
                                                >
                                                > ARKBAN
                                                >
                                                > Jeff Lowe
                                                wrote:
                                                >>
                                                >>
                                                >> Call me old fashioned, but I prefer
                                                simply throwing a
                                                >> checked exception. The exception then becomes part
                                                of the method
                                                >> signature, which makes for a more expressive domain
                                                interface, e.g.:
                                                >>
                                                >> public redeem(Account account) throws
                                                PromotionRulesViola tionException
                                                >>
                                                >> The exception can
                                                then encapsulate everything needed by the client (i.e.
                                                >> application)
                                                to communicate back to the user, including information
                                                >> about
                                                multiple rule violations.
                                                >>
                                                >> > > The thought of
                                                throwing exceptions doesn't sit real well with me
                                                > but
                                                ...
                                                >>
                                                >> I'm curious why it doesn't sit well. Other folks
                                                have also expressed this.
                                                >>
                                                >>
                                                >>
                                                Thanks,
                                                >> -Jeff
                                                >>
                                                >>
                                                >>
                                                ------------ --------- --------- --------- --------- --------- -
                                                >>
                                                *From:* domaindrivendesign@ yahoogroups. com
                                                >
                                                <mailto:domaindrive ndesign%40yahoog roups.com>
                                                >>
                                                [mailto:domaindrivendesign@ yahoogroups. com
                                                > <mailto:domaindrive ndesign%40yahoog roups.com> ] *On
                                                Behalf Of *Jesse Napier
                                                >> *Sent:* Wednesday, June 27, 2007 9:41
                                                PM
                                                >> *To:*
                                                href="mailto:domaindrivendesign%40yahoogroups.com">domaindrivendesign@ yahoogroups. com
                                                >
                                                <mailto:domaindrive ndesign%40yahoog roups.com>
                                                >>
                                                *Subject:* [domaindrivendesign ] To throw or not to throw on Rule Violation
                                                >>
                                                >> I have a question regarding business logic
                                                validation in my domain. Im
                                                >> not talking about validation in the
                                                sense of simple data validation such
                                                >> as checking for null values or
                                                specific data ranges. These days it
                                                >> seems like most people are
                                                handling these types of validations with a
                                                >> validation framework and
                                                checking an IsValid operation or something
                                                >> similar. I refer to these
                                                as data validations. It may be fine in some
                                                >> domains for an object to
                                                exist and be persisted when that object is in
                                                >> an invalid data state.
                                                I am faced with an issue in which I cannot
                                                >> allow certain objects to
                                                ever be in an invalid state.
                                                >>
                                                >> In my domain I have
                                                PromoCode and Account. PromoCodes can be redeemed by
                                                >> accounts, but
                                                there are rules regarding redemption. If any of these
                                                >> rules are
                                                violated, redemption cannot succeed and the application must
                                                >> prevent
                                                the redemption. These rule violations are not fatal and are to
                                                >> be
                                                expected, however I must notify the user as to why the redemption did
                                                >> not succeed. So my question is, what is the preferred way
                                                of
                                                >> communicating business rule violations to the UI when an action
                                                cannot
                                                >> be performed because it would put the object into an invalid
                                                state that
                                                >> cannot be persisted?
                                                >>
                                                >> I think
                                                there are essentialy 4 ways:
                                                >> 1) Throw an exception describing the
                                                first violation
                                                >> 2) Use Notification pattern
                                                >> <
                                                href="http://www.martinfowler.com/eaaDev/Notification.html">http://www.martinfo wler.com/ eaaDev/Notificat ion.html
                                                > <
                                                href="http://www.martinfowler.com/eaaDev/Notification.html">http://www.martinfo wler.com/ eaaDev/Notificat ion.html>> to communicate
                                                >> information about all violations.
                                                >> 3)
                                                Throw an exception that encapsulates the Notification object as
                                                >>
                                                described in Sergio's blog post, A Notification Strategy for Business
                                                >> Errors
                                                >>
                                                > <
                                                href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html
                                                > <
                                                href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html>>
                                                >>
                                                4) Provide a Check operation which returns a a boolean or a Notification
                                                >> object such as /Notification CanRedeem(Account) ;
                                                /or /bool
                                                >> CanRedeem(Account) ; /If the check operation returns
                                                any violations,
                                                >> Redeem would throw an
                                                exception.
                                                >>
                                                >> The thought of throwing exceptions doesn't
                                                sit real well with me but it
                                                >> is the easiest way to get the
                                                information to any interested parties
                                                >> because they just have to
                                                try...catch it. The Notification pattern has
                                                >> value but it seems more
                                                difficult to get the information to the
                                                >> interested parties. Granted,
                                                the Redeem operation on PromoCode is a
                                                >> void operation and I could
                                                just return a Notification object from that
                                                >> call. However, in my
                                                research for this problem Im trying to comeup with
                                                >> a solution that
                                                would also work with operations that had a return
                                                >> value. #4 is an
                                                instersting option but im a little turned off by it
                                                >> because the
                                                check would have to be called multiple times, once from the
                                                >> client
                                                and once from the redeem operation. Here is a sample
                                                >>
                                                >>
                                                public class PromoCode{
                                                >>
                                                >> string code;
                                                >>
                                                DateTime expirationDate;
                                                >> bool isRedeemed;
                                                >> bool
                                                isOnlyForNewAccount s;
                                                >>
                                                >> public Notification
                                                CanRedeem(Account account){
                                                >> Notification violations = new
                                                Notification( );
                                                >>
                                                >>
                                                if(this.isRedeemed) {
                                                >>
                                                violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                                                >>
                                                }
                                                >>
                                                >> if(this.expirationD ate >
                                                DateTime.Now) {
                                                >>
                                                violations.Add( PromoCodeViolati on.Expired) ;
                                                >>
                                                }
                                                >>
                                                >> if(this.isOnlyForNe wAccounts &&
                                                account.IsNewAccoun t == false){
                                                >>
                                                violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                                >>
                                                }
                                                >>
                                                >> return violations;
                                                >>
                                                }
                                                >>
                                                >> public void Redeem(Account account){
                                                >>
                                                Notification violations = this.CanRedeem( account);
                                                >>
                                                >>
                                                if(violations. HasErrors) {
                                                >> throw new
                                                BusinessRuleExcepti on(violations) ;
                                                >>
                                                }
                                                >>
                                                >> this.DoRedeem( account);
                                                >>
                                                }
                                                >>
                                                >> protected void DoRedeem(Account account){
                                                >>
                                                ...
                                                >> }
                                                >> }
                                                >>
                                                >>
                                                >> public class
                                                PromoCodeTest{
                                                >>
                                                >> public void
                                                RunCanRedeem( ){
                                                >>
                                                >> Account testAccount =
                                                Mock.GetMock< Account>( );
                                                >>
                                                >> PromoCode code
                                                = CreateValidPromoCod e();
                                                >>
                                                >>
                                                if(code.CanRedeem( testAccount) .HasErrors == false){
                                                >>
                                                code.Redeem( testAccount) ;
                                                >>
                                                >>
                                                Assert.IsTrue( code.IsRedeemed) ;
                                                >> }
                                                >>
                                                }
                                                >> }
                                                >>
                                                >>
                                                >>
                                                >> Any thoughts or
                                                advice on this? Any ways to improve it? Or is the a
                                                >> better strategy
                                                that I havent seen?
                                                >>
                                                >> Thanks,
                                                >>
                                                Jesse
                                                >>
                                                >>
                                                >>
                                                >>
                                                >
                                                >

                                              • Greg Young
                                                I think you want out there not ref Joe (you method is taking control of the instantiation). INotificationCollection Notifications = null; //?
                                                Message 23 of 26 , Jun 28 3:21 PM
                                                  I think you want "out" there not ref Joe (you method is taking control of the instantiation).

                                                  INotificationCollection Notifications = null; //?
                                                  myPromo.Redeem(Account, ref Notifications);

                                                  vs

                                                  INotificationCollection Notifications;
                                                  myPromo.Redeem(Account, out Notifications);



                                                  Personally I prefer a slightly different mechanism .... I like to use commands to hold data for the change (i.e. build a message for the object and pass it as a whole) ... then I apply the command to which I give all errors at once through a normal notification pattern.

                                                  ex:

                                                  Customer has a field "CustomerType" ... instead of having a proeprty for this I have a changecustomertypecommand ... I can also key other things like work flows off of these commands if I persist them (they also come in really handy for my reporting database which is synchronized in near real time as I just take the commands and ship them over to the denormalization process which then selectively updates the reporting databse).

                                                  When it is time for me to save I can also persist the commands that were associated with the object as an audit.

                                                  Cheers,

                                                  Greg

                                                  On 6/28/07, Joe A. Reddy <jreddy@...> wrote:

                                                  In C# when I type myPromo.Redeem( the IDE will tell me I will be passing into two arguments. One is an Account passed by value and the other is Violations passed by reference and not initialized.

                                                  This tells me that the routine will initialize Violations…something is happening…I have to go out of my way to ignore it.

                                                   

                                                  Note, I did not say forced, just hard to misuse, hard to ignore.

                                                   

                                                   

                                                   

                                                   

                                                  -----Original Message-----
                                                  From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogro ups.com] On Behalf Of ARKBAN
                                                  Sent: Thursday, June 28, 2007 3:29 PM
                                                  To: domaindrivendesign@yahoogroups.com

                                                  Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                                                   

                                                  How are they forced to deal with violations in these code examples? In
                                                  the first I could just not register a listener/event handler, and in the
                                                  second I could just not check for violations.

                                                  Personally the second example to me looks very much like the old return
                                                  code style error system used in C. Not inherently bad but requires
                                                  consistency and mindfulness to always check for errors.

                                                  ARKBAN

                                                  Joe A. Reddy wrote:
                                                  >
                                                  >
                                                  > I like it.
                                                  >
                                                  > It makes it clear to anyone and everyone that when PromoCodes are
                                                  > redeemed they need to deal with Violations.
                                                  >
                                                  > This code would be hard to misuse.
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  > -----Original Message-----
                                                  > *From:* domaindrivendesign@yahoogroups.com
                                                  > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *Jesse Napier
                                                  > *Sent:* Thursday, June 28, 2007 2:43 PM
                                                  > *To:* domaindrivendesign@yahoogroups.com
                                                  > *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule
                                                  > Violation
                                                  >
                                                  >
                                                  >
                                                  > Its so true that exceptional situations are very subjective. I've found
                                                  > myself battling with that all the time. In my case, it seems like an
                                                  > exceptional situation would be if more people redeemed the promo code
                                                  > than were allowed to. Then Ive got problems. So the business logic is
                                                  > in place to prevent that from occurring.
                                                  >
                                                  >
                                                  >
                                                  > From reading other discussions on this forum and from the feedback I
                                                  > have recieved in regards to this post, it appears that there is alot of
                                                  > sentiment for not throwing exceptions in situations like this and I tend
                                                  > to agree. So how do we get the validation errors to the caller in an
                                                  > elegant way?
                                                  >
                                                  >
                                                  >
                                                  > There has been some talk of events, but that doesnt really seem elegant
                                                  > to me. It seems confusing for the client.
                                                  >
                                                  >
                                                  >
                                                  > Say im a a controller, I want to do this:
                                                  >
                                                  >
                                                  >
                                                  > string codeId = GetCodeFromRequest();
                                                  >
                                                  >
                                                  >
                                                  > PromCode promoCode = promoRepository.FindByCode(codeId);
                                                  >
                                                  >
                                                  >
                                                  > promoCode.Redeem(account);
                                                  >
                                                  >
                                                  >
                                                  > //get validation errors from somewhere
                                                  >
                                                  > //and register them for the view to display
                                                  >
                                                  > }
                                                  >
                                                  >
                                                  >
                                                  > having some event handler in the controller to trap for redemption
                                                  > errors would be very hard to understand and follow if you ask me. The
                                                  > code would read better if we handled any violations right next to the
                                                  > code that caused the violation.
                                                  >
                                                  >
                                                  >
                                                  > does this smell?
                                                  >
                                                  >
                                                  >
                                                  > INotification violations = INotificationFactory.Create();
                                                  >
                                                  >
                                                  >
                                                  > promoCode.Redeem(account, violations);
                                                  >
                                                  >
                                                  >
                                                  > if(violations.HasErrors){
                                                  >
                                                  > //register error messages with the view
                                                  >
                                                  > }
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  > ----------------------------------------------------------
                                                  >
                                                  > *From:* domaindrivendesign@yahoogroups.com
                                                  > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *Jeff Lowe
                                                  > *Sent:* Thursday, June 28, 2007 7:46 AM
                                                  > *To:* domaindrivendesign@yahoogroups.com
                                                  > *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule
                                                  > Violation
                                                  >
                                                  > That's a cute mantra. "exceptional situation" is certainly subjective.
                                                  >
                                                  >
                                                  >
                                                  > As Jesse stated, there's a difference between simple data validation,
                                                  > and the violation of business rules during a non-trivial operation in
                                                  > the domain. I consider the latter to be an "exceptional situation".
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  >
                                                  > ----------------------------------------------------------
                                                  >
                                                  > *From:* domaindrivendesign@yahoogroups.com
                                                  > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *ARKBAN
                                                  > *Sent:* Thursday, June 28, 2007 10:10 AM
                                                  > *To:* domaindrivendesign@yahoogroups.com
                                                  > *Subject:* Re: [domaindrivendesign] To throw or not to throw on Rule
                                                  > Violation
                                                  >
                                                  > I think the concern revolves around the mantra "exceptions are for
                                                  > exceptional situations". Validation is most often not exceptional but
                                                  > expected; validation checks for situations that occur easily but can be
                                                  > easily corrected, which are not really exceptional.
                                                  >
                                                  > ARKBAN
                                                  >
                                                  > Jeff Lowe wrote:
                                                  >>
                                                  >>
                                                  >> Call me old fashioned, but I prefer simply throwing a
                                                  >> checked exception. The exception then becomes part of the method
                                                  >> signature, which makes for a more expressive domain interface, e.g.:
                                                  >>
                                                  >> public redeem(Account account) throws PromotionRulesViolationException
                                                  >>
                                                  >> The exception can then encapsulate everything needed by the client (i.e.
                                                  >> application) to communicate back to the user, including information
                                                  >> about multiple rule violations.
                                                  >>
                                                  >> > > The thought of throwing exceptions doesn't sit real well with me
                                                  > but ...
                                                  >>
                                                  >> I'm curious why it doesn't sit well. Other folks have also expressed this.
                                                  >>
                                                  >>
                                                  >> Thanks,
                                                  >> -Jeff
                                                  >>
                                                  >>
                                                  >> ----------------------------------------------------------
                                                  >> *From:* domaindrivendesign@yahoogroups.com
                                                  > <mailto:domaindrivendesign%40yahoog roups.com>
                                                  >> [mailto:domaindrivendesign@yahoogroups.com
                                                  > <mailto:domaindrivendesign%40yahoog roups.com>] *On Behalf Of *Jesse Napier
                                                  >> *Sent:* Wednesday, June 27, 2007 9:41 PM
                                                  >> *To:* domaindrivendesign@yahoogroups.com
                                                  > <mailto:domaindrivendesign%40yahoog roups.com>
                                                  >> *Subject:* [domaindrivendesign] To throw or not to throw on Rule Violation
                                                  >>
                                                  >> I have a question regarding business logic validation in my domain. Im
                                                  >> not talking about validation in the sense of simple data validation such
                                                  >> as checking for null values or specific data ranges. These days it
                                                  >> seems like most people are handling these types of validations with a
                                                  >> validation framework and checking an IsValid operation or something
                                                  >> similar. I refer to these as data validations. It may be fine in some
                                                  >> domains for an object to exist and be persisted when that object is in
                                                  >> an invalid data state. I am faced with an issue in which I cannot
                                                  >> allow certain objects to ever be in an invalid state.
                                                  >>
                                                  >> In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                                                  >> accounts, but there are rules regarding redemption. If any of these
                                                  >> rules are violated, redemption cannot succeed and the application must
                                                  >> prevent the redemption. These rule violations are not fatal and are to
                                                  >> be expected, however I must notify the user as to why the redemption did
                                                  >> not succeed. So my question is, what is the preferred way of
                                                  >> communicating business rule violations to the UI when an action cannot
                                                  >> be performed because it would put the object into an invalid state that
                                                  >> cannot be persisted?
                                                  >>
                                                  >> I think there are essentialy 4 ways:
                                                  >> 1) Throw an exception describing the first violation
                                                  >> 2) Use Notification pattern
                                                  >> <http://www.martinfowler.com/eaaDev/Notification.html
                                                  > <http://www.martinfowler.com/eaaDev/Notification.html>> to communicate
                                                  >> information about all violations.
                                                  >> 3) Throw an exception that encapsulates the Notification object as
                                                  >> described in Sergio's blog post, A Notification Strategy for Business
                                                  >> Errors
                                                  >>
                                                  > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html
                                                  > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html >>
                                                  >> 4) Provide a Check operation which returns a a boolean or a Notification
                                                  >> object such as /Notification CanRedeem(Account); /or /bool
                                                  >> CanRedeem(Account); /If the check operation returns any violations,
                                                  >> Redeem would throw an exception.
                                                  >>
                                                  >> The thought of throwing exceptions doesn't sit real well with me but it
                                                  >> is the easiest way to get the information to any interested parties
                                                  >> because they just have to try...catch it. The Notification pattern has
                                                  >> value but it seems more difficult to get the information to the
                                                  >> interested parties. Granted, the Redeem operation on PromoCode is a
                                                  >> void operation and I could just return a Notification object from that
                                                  >> call. However, in my research for this problem Im trying to comeup with
                                                  >> a solution that would also work with operations that had a return
                                                  >> value. #4 is an instersting option but im a little turned off by it
                                                  >> because the check would have to be called multiple times, once from the
                                                  >> client and once from the redeem operation. Here is a sample
                                                  >>
                                                  >> public class PromoCode{
                                                  >>
                                                  >> string code;
                                                  >> DateTime expirationDate;
                                                  >> bool isRedeemed;
                                                  >> bool isOnlyForNewAccounts;
                                                  >>
                                                  >> public Notification CanRedeem(Account account){
                                                  >> Notification violations = new Notification();
                                                  >>
                                                  >> if(this.isRedeemed){
                                                  >> violations.Add(PromoCodeViolation.AlreadyRedeemed);
                                                  >> }
                                                  >>
                                                  >> if(this.expirationDate > DateTime.Now){
                                                  >> violations.Add(PromoCodeViolation.Expired);
                                                  >> }
                                                  >>
                                                  >> if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                                                  >> violations.Add(PromoCodeViolation.NewAccountsOnly);
                                                  >> }
                                                  >>
                                                  >> return violations;
                                                  >> }
                                                  >>
                                                  >> public void Redeem(Account account){
                                                  >> Notification violations = this.CanRedeem(account);
                                                  >>
                                                  >> if(violations.HasErrors){
                                                  >> throw new BusinessRuleException(violations);
                                                  >> }
                                                  >>
                                                  >> this.DoRedeem(account);
                                                  >> }
                                                  >>
                                                  >> protected void DoRedeem(Account account){
                                                  >> ...
                                                  >> }
                                                  >> }
                                                  >>
                                                  >>
                                                  >> public class PromoCodeTest{
                                                  >>
                                                  >> public void RunCanRedeem(){
                                                  >>
                                                  >> Account testAccount = Mock.GetMock<Account>();
                                                  >>
                                                  >> PromoCode code = CreateValidPromoCode();
                                                  >>
                                                  >> if(code.CanRedeem(testAccount).HasErrors == false){
                                                  >> code.Redeem(testAccount);
                                                  >>
                                                  >> Assert.IsTrue(code.IsRedeemed);
                                                  >> }
                                                  >> }
                                                  >> }
                                                  >>
                                                  >>
                                                  >>
                                                  >> Any thoughts or advice on this? Any ways to improve it? Or is the a
                                                  >> better strategy that I havent seen?
                                                  >>
                                                  >> Thanks,
                                                  >> Jesse
                                                  >>
                                                  >>
                                                  >>
                                                  >>
                                                  >
                                                  >




                                                  --
                                                  Studying for the Turing test
                                                • ARKBAN
                                                  With a method you are right this does work very well. Not to go off on a tangent but I think that s one of the pitfalls of C# Properties, they don t lend
                                                  Message 24 of 26 , Jun 28 6:00 PM
                                                    With a method you are right this does work very well. Not to go off on a
                                                    tangent but I think that's one of the pitfalls of C# Properties, they
                                                    don't lend themselves to more complex operations beyond simple get and
                                                    sets. I think it's a good idea to remember, to not use C# Properties and
                                                    only use methods when you have validation concerns.

                                                    ARKBAN

                                                    Joe A. Reddy wrote:
                                                    >
                                                    >
                                                    > In C# when I type myPromo.Redeem( the IDE will tell me I will be passing
                                                    > into two arguments. One is an Account passed by value and the other is
                                                    > Violations passed by reference and not initialized.
                                                    >
                                                    > This tells me that the routine will initialize Violations…something is
                                                    > happening…I have to go out of my way to ignore it.
                                                    >
                                                    >
                                                    >
                                                    > Note, I did not say forced, just hard to misuse, hard to ignore.
                                                    >
                                                    >
                                                    >
                                                    >
                                                    >
                                                    >
                                                    >
                                                    >
                                                    >
                                                    > -----Original Message-----
                                                    > *From:* domaindrivendesign@yahoogroups.com
                                                    > [mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *ARKBAN
                                                    > *Sent:* Thursday, June 28, 2007 3:29 PM
                                                    > *To:* domaindrivendesign@yahoogroups.com
                                                    > *Subject:* Re: [domaindrivendesign] To throw or not to throw on Rule
                                                    > Violation
                                                    >
                                                    >
                                                    >
                                                    > How are they forced to deal with violations in these code examples? In
                                                    > the first I could just not register a listener/event handler, and in the
                                                    > second I could just not check for violations.
                                                    >
                                                    > Personally the second example to me looks very much like the old return
                                                    > code style error system used in C. Not inherently bad but requires
                                                    > consistency and mindfulness to always check for errors.
                                                    >
                                                    > ARKBAN
                                                    >
                                                    > Joe A. Reddy wrote:
                                                    >>
                                                    >>
                                                    >> I like it.
                                                    >>
                                                    >> It makes it clear to anyone and everyone that when PromoCodes are
                                                    >> redeemed they need to deal with Violations.
                                                    >>
                                                    >> This code would be hard to misuse.
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >> -----Original Message-----
                                                    >> *From:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> [mailto:domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jesse Napier
                                                    >> *Sent:* Thursday, June 28, 2007 2:43 PM
                                                    >> *To:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule
                                                    >> Violation
                                                    >>
                                                    >>
                                                    >>
                                                    >> Its so true that exceptional situations are very subjective. I've found
                                                    >> myself battling with that all the time. In my case, it seems like an
                                                    >> exceptional situation would be if more people redeemed the promo code
                                                    >> than were allowed to. Then Ive got problems. So the business logic is
                                                    >> in place to prevent that from occurring.
                                                    >>
                                                    >>
                                                    >>
                                                    >> From reading other discussions on this forum and from the feedback I
                                                    >> have recieved in regards to this post, it appears that there is alot of
                                                    >> sentiment for not throwing exceptions in situations like this and I tend
                                                    >> to agree. So how do we get the validation errors to the caller in an
                                                    >> elegant way?
                                                    >>
                                                    >>
                                                    >>
                                                    >> There has been some talk of events, but that doesnt really seem elegant
                                                    >> to me. It seems confusing for the client.
                                                    >>
                                                    >>
                                                    >>
                                                    >> Say im a a controller, I want to do this:
                                                    >>
                                                    >>
                                                    >>
                                                    >> string codeId = GetCodeFromRequest();
                                                    >>
                                                    >>
                                                    >>
                                                    >> PromCode promoCode = promoRepository.FindByCode(codeId);
                                                    >>
                                                    >>
                                                    >>
                                                    >> promoCode.Redeem(account);
                                                    >>
                                                    >>
                                                    >>
                                                    >> //get validation errors from somewhere
                                                    >>
                                                    >> //and register them for the view to display
                                                    >>
                                                    >> }
                                                    >>
                                                    >>
                                                    >>
                                                    >> having some event handler in the controller to trap for redemption
                                                    >> errors would be very hard to understand and follow if you ask me. The
                                                    >> code would read better if we handled any violations right next to the
                                                    >> code that caused the violation.
                                                    >>
                                                    >>
                                                    >>
                                                    >> does this smell?
                                                    >>
                                                    >>
                                                    >>
                                                    >> INotification violations = INotificationFactory.Create();
                                                    >>
                                                    >>
                                                    >>
                                                    >> promoCode.Redeem(account, violations);
                                                    >>
                                                    >>
                                                    >>
                                                    >> if(violations.HasErrors){
                                                    >>
                                                    >> //register error messages with the view
                                                    >>
                                                    >> }
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >> ----------------------------------------------------------
                                                    >>
                                                    >> *From:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> [mailto:domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jeff Lowe
                                                    >> *Sent:* Thursday, June 28, 2007 7:46 AM
                                                    >> *To:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule
                                                    >> Violation
                                                    >>
                                                    >> That's a cute mantra. "exceptional situation" is certainly subjective.
                                                    >>
                                                    >>
                                                    >>
                                                    >> As Jesse stated, there's a difference between simple data validation,
                                                    >> and the violation of business rules during a non-trivial operation in
                                                    >> the domain. I consider the latter to be an "exceptional situation".
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >>
                                                    >> ----------------------------------------------------------
                                                    >>
                                                    >> *From:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> [mailto:domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *ARKBAN
                                                    >> *Sent:* Thursday, June 28, 2007 10:10 AM
                                                    >> *To:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> *Subject:* Re: [domaindrivendesign] To throw or not to throw on Rule
                                                    >> Violation
                                                    >>
                                                    >> I think the concern revolves around the mantra "exceptions are for
                                                    >> exceptional situations". Validation is most often not exceptional but
                                                    >> expected; validation checks for situations that occur easily but can be
                                                    >> easily corrected, which are not really exceptional.
                                                    >>
                                                    >> ARKBAN
                                                    >>
                                                    >> Jeff Lowe wrote:
                                                    >> >
                                                    >> >
                                                    >> > Call me old fashioned, but I prefer simply throwing a
                                                    >> > checked exception. The exception then becomes part of the method
                                                    >> > signature, which makes for a more expressive domain interface, e.g.:
                                                    >> >
                                                    >> > public redeem(Account account) throws PromotionRulesViolationException
                                                    >> >
                                                    >> > The exception can then encapsulate everything needed by the client (i.e.
                                                    >> > application) to communicate back to the user, including information
                                                    >> > about multiple rule violations.
                                                    >> >
                                                    >> > > > The thought of throwing exceptions doesn't sit real well with me
                                                    >> but ...
                                                    >> >
                                                    >> > I'm curious why it doesn't sit well. Other folks have also expressed
                                                    > this.
                                                    >> >
                                                    >> >
                                                    >> > Thanks,
                                                    >> > -Jeff
                                                    >> >
                                                    >> >
                                                    >> > ----------------------------------------------------------
                                                    >> > *From:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> > [mailto:domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jesse Napier
                                                    >> > *Sent:* Wednesday, June 27, 2007 9:41 PM
                                                    >> > *To:* domaindrivendesign@yahoogroups.com
                                                    > <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> <mailto:domaindrivendesign%40yahoogroups.com>
                                                    >> > *Subject:* [domaindrivendesign] To throw or not to throw on Rule
                                                    > Violation
                                                    >> >
                                                    >> > I have a question regarding business logic validation in my domain. Im
                                                    >> > not talking about validation in the sense of simple data validation such
                                                    >> > as checking for null values or specific data ranges. These days it
                                                    >> > seems like most people are handling these types of validations with a
                                                    >> > validation framework and checking an IsValid operation or something
                                                    >> > similar. I refer to these as data validations. It may be fine in some
                                                    >> > domains for an object to exist and be persisted when that object is in
                                                    >> > an invalid data state. I am faced with an issue in which I cannot
                                                    >> > allow certain objects to ever be in an invalid state.
                                                    >> >
                                                    >> > In my domain I have PromoCode and Account. PromoCodes can be redeemed by
                                                    >> > accounts, but there are rules regarding redemption. If any of these
                                                    >> > rules are violated, redemption cannot succeed and the application must
                                                    >> > prevent the redemption. These rule violations are not fatal and are to
                                                    >> > be expected, however I must notify the user as to why the redemption did
                                                    >> > not succeed. So my question is, what is the preferred way of
                                                    >> > communicating business rule violations to the UI when an action cannot
                                                    >> > be performed because it would put the object into an invalid state that
                                                    >> > cannot be persisted?
                                                    >> >
                                                    >> > I think there are essentialy 4 ways:
                                                    >> > 1) Throw an exception describing the first violation
                                                    >> > 2) Use Notification pattern
                                                    >> > <http://www.martinfowler.com/eaaDev/Notification.html
                                                    > <http://www.martinfowler.com/eaaDev/Notification.html>
                                                    >> <http://www.martinfowler.com/eaaDev/Notification.html
                                                    > <http://www.martinfowler.com/eaaDev/Notification.html>>> to communicate
                                                    >> > information about all violations.
                                                    >> > 3) Throw an exception that encapsulates the Notification object as
                                                    >> > described in Sergio's blog post, A Notification Strategy for Business
                                                    >> > Errors
                                                    >> >
                                                    >>
                                                    > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html
                                                    > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html>
                                                    >
                                                    >>
                                                    > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html
                                                    > <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html>>>
                                                    >> > 4) Provide a Check operation which returns a a boolean or a Notification
                                                    >> > object such as /Notification CanRedeem(Account); /or /bool
                                                    >> > CanRedeem(Account); /If the check operation returns any violations,
                                                    >> > Redeem would throw an exception.
                                                    >> >
                                                    >> > The thought of throwing exceptions doesn't sit real well with me but it
                                                    >> > is the easiest way to get the information to any interested parties
                                                    >> > because they just have to try...catch it. The Notification pattern has
                                                    >> > value but it seems more difficult to get the information to the
                                                    >> > interested parties. Granted, the Redeem operation on PromoCode is a
                                                    >> > void operation and I could just return a Notification object from that
                                                    >> > call. However, in my research for this problem Im trying to comeup with
                                                    >> > a solution that would also work with operations that had a return
                                                    >> > value. #4 is an instersting option but im a little turned off by it
                                                    >> > because the check would have to be called multiple times, once from the
                                                    >> > client and once from the redeem operation. Here is a sample
                                                    >> >
                                                    >> > public class PromoCode{
                                                    >> >
                                                    >> > string code;
                                                    >> > DateTime expirationDate;
                                                    >> > bool isRedeemed;
                                                    >> > bool isOnlyForNewAccounts;
                                                    >> >
                                                    >> > public Notification CanRedeem(Account account){
                                                    >> > Notification violations = new Notification();
                                                    >> >
                                                    >> > if(this.isRedeemed){
                                                    >> > violations.Add(PromoCodeViolation.AlreadyRedeemed);
                                                    >> > }
                                                    >> >
                                                    >> > if(this.expirationDate > DateTime.Now){
                                                    >> > violations.Add(PromoCodeViolation.Expired);
                                                    >> > }
                                                    >> >
                                                    >> > if(this.isOnlyForNewAccounts && account.IsNewAccount == false){
                                                    >> > violations.Add(PromoCodeViolation.NewAccountsOnly);
                                                    >> > }
                                                    >> >
                                                    >> > return violations;
                                                    >> > }
                                                    >> >
                                                    >> > public void Redeem(Account account){
                                                    >> > Notification violations = this.CanRedeem(account);
                                                    >> >
                                                    >> > if(violations.HasErrors){
                                                    >> > throw new BusinessRuleException(violations);
                                                    >> > }
                                                    >> >
                                                    >> > this.DoRedeem(account);
                                                    >> > }
                                                    >> >
                                                    >> > protected void DoRedeem(Account account){
                                                    >> > ...
                                                    >> > }
                                                    >> > }
                                                    >> >
                                                    >> >
                                                    >> > public class PromoCodeTest{
                                                    >> >
                                                    >> > public void RunCanRedeem(){
                                                    >> >
                                                    >> > Account testAccount = Mock.GetMock<Account>();
                                                    >> >
                                                    >> > PromoCode code = CreateValidPromoCode();
                                                    >> >
                                                    >> > if(code.CanRedeem(testAccount).HasErrors == false){
                                                    >> > code.Redeem(testAccount);
                                                    >> >
                                                    >> > Assert.IsTrue(code.IsRedeemed);
                                                    >> > }
                                                    >> > }
                                                    >> > }
                                                    >> >
                                                    >> >
                                                    >> >
                                                    >> > Any thoughts or advice on this? Any ways to improve it? Or is the a
                                                    >> > better strategy that I havent seen?
                                                    >> >
                                                    >> > Thanks,
                                                    >> > Jesse
                                                  • Jesse Napier
                                                    Arkban, That s a good point, this style wouldn t work very well for properties. Usually setting a property doesn t trigger a state change, so we would be fine
                                                    Message 25 of 26 , Jun 28 6:26 PM

                                                      Arkban,
                                                      That’s a good point, this style wouldn’t work very well for properties.  Usually setting a property doesn’t trigger a state change, so we would be fine with the the usual IsValid() check on the object. However, I usually try to use a method for setting a property if it changes the state of an object. I think using a method makes it much more explict that something bigger is happening than just setting a property.  For example, I would use

                                                      account.Close();

                                                      as opposed to

                                                      account.Status = AcountStatus.Closed;

                                                       
                                                       


                                                      -----Original Message-----
                                                      From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of ARKBAN
                                                      Sent: Thursday, June 28, 2007 6:00 PM
                                                      To: domaindrivendesign@yahoogroups.com
                                                      Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                                                      With a method you are right this does work very well. Not to go off on a tangent but I think that's one of the pitfalls of C# Properties, they don't lend themselves to more complex operations beyond simple get and sets. I think it's a good idea to remember, to not use C# Properties and only use methods when you have validation concerns.

                                                      ARKBAN

                                                      Joe A. Reddy wrote:

                                                      >
                                                      >
                                                      > In C#
                                                      when I type myPromo.Redeem( the IDE will tell me I will be
                                                      > passing into
                                                      two arguments. One is an Account passed by value and the
                                                      > other is
                                                      Violations passed by reference and not initialized.
                                                      >
                                                      > This tells
                                                      me that the routine will initialize Violations…something is
                                                      > happening…I
                                                      have to go out of my way to ignore it.
                                                      >

                                                      >
                                                      >
                                                      Note, I did not say forced, just hard to misuse, hard to ignore.
                                                      >

                                                      >

                                                      >

                                                      >

                                                      >
                                                      >
                                                      -----Original Message-----
                                                      > *From:*
                                                      domaindrivendesign@yahoogroups.com
                                                      > [
                                                      href="mailto:domaindrivendesign@yahoogroups.com">mailto:domaindrivendesign@yahoogroups.com] *On Behalf Of *ARKBAN
                                                      > *Sent:* Thursday, June 28, 2007 3:29 PM
                                                      >
                                                      *To:* domaindrivendesign@yahoogroups.com
                                                      > *Subject:* Re:
                                                      [domaindrivendesign] To throw or not to throw on Rule
                                                      >
                                                      Violation
                                                      >

                                                      >
                                                      > How are they forced to deal with
                                                      violations in these code examples? In
                                                      > the first I could just not
                                                      register a listener/event handler, and in
                                                      > the second I could just not
                                                      check for violations.
                                                      >
                                                      > Personally the second example to me looks
                                                      very much like the old
                                                      > return code style error system used in C. Not
                                                      inherently bad but
                                                      > requires consistency and mindfulness to always check
                                                      for errors.
                                                      >
                                                      > ARKBAN
                                                      >
                                                      > Joe A. Reddy
                                                      wrote:
                                                      >>
                                                      >>
                                                      >>  I like
                                                      it.
                                                      >>
                                                      >>  It makes it clear to anyone and everyone that
                                                      when PromoCodes are 
                                                      >> redeemed they need to deal with
                                                      Violations.
                                                      >>
                                                      >>  This code would be hard to
                                                      misuse.
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      -----Original Message-----
                                                      >>  *From:*
                                                      domaindrivendesign@yahoogroups.com
                                                      > <
                                                      href="mailto:domaindrivendesign%40yahoogroups.com">mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      [mailto:domaindrivendesign@yahoogroups.com
                                                      >
                                                      <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jesse
                                                      > Napier
                                                      >>  *Sent:* Thursday, June 28,
                                                      2007 2:43 PM
                                                      >>  *To:* domaindrivendesign@yahoogroups.com
                                                      >
                                                      <mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule 
                                                      >>
                                                      Violation
                                                      >>
                                                      >>
                                                      >>
                                                      >>  Its so true that
                                                      exceptional situations are very subjective. I've
                                                      >> found  myself
                                                      battling with that all the time. In my case, it seems
                                                      >> like an 
                                                      exceptional situation would be if more people redeemed the
                                                      >> promo
                                                      code  than were allowed to. Then Ive got problems. So the
                                                      >>
                                                      business logic is  in place to prevent that from occurring.
                                                      >>
                                                      >>
                                                      >>
                                                      >>  From reading
                                                      other discussions on this forum and from the feedback I 
                                                      >> have
                                                      recieved in regards to this post, it appears that there is alot
                                                      >>
                                                      of  sentiment for not throwing exceptions in situations like this and
                                                      >> I tend  to agree. So how do we get the validation errors to
                                                      the
                                                      >> caller in an  elegant
                                                      way?
                                                      >>
                                                      >>
                                                      >>
                                                      >>  There has been some
                                                      talk of events, but that doesnt really seem
                                                      >> elegant  to me. It
                                                      seems confusing for the client.
                                                      >>
                                                      >>
                                                      >>
                                                      >>  Say im a a
                                                      controller, I want to do this:
                                                      >>
                                                      >>
                                                      >>
                                                      >>  string codeId =
                                                      GetCodeFromRequest();
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      PromCode promoCode = promoRepository.FindByCode(codeId);
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      promoCode.Redeem(account);
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      //get validation errors from somewhere
                                                      >>
                                                      >>  //and
                                                      register them for the view to display
                                                      >>
                                                      >> 
                                                      }
                                                      >>
                                                      >>
                                                      >>
                                                      >>  having some event
                                                      handler in the controller to trap for redemption 
                                                      >> errors would
                                                      be very hard to understand and follow if you ask me. The 
                                                      >> code
                                                      would read better if we handled any violations right next to the 
                                                      >> code that caused the
                                                      violation.
                                                      >>
                                                      >>
                                                      >>
                                                      >>  does this
                                                      smell?
                                                      >>
                                                      >>
                                                      >>
                                                      >>  INotification
                                                      violations = INotificationFactory.Create();
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      promoCode.Redeem(account, violations);
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      if(violations.HasErrors){
                                                      >>
                                                      >>  //register error
                                                      messages with the view
                                                      >>
                                                      >> 
                                                      }
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      ----------------------------------------------------------
                                                      >>
                                                      >> 
                                                      *From:* domaindrivendesign@yahoogroups.com
                                                      > <
                                                      href="mailto:domaindrivendesign%40yahoogroups.com">mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      [mailto:domaindrivendesign@yahoogroups.com
                                                      >
                                                      <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jeff
                                                      > Lowe
                                                      >>  *Sent:* Thursday, June 28,
                                                      2007 7:46 AM
                                                      >>  *To:* domaindrivendesign@yahoogroups.com
                                                      >
                                                      <mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      *Subject:* RE: [domaindrivendesign] To throw or not to throw on Rule 
                                                      >> Violation
                                                      >>
                                                      >>  That's a cute
                                                      mantra. "exceptional situation" is certainly subjective.
                                                      >>
                                                      >>
                                                      >>
                                                      >>  As Jesse
                                                      stated, there's a difference between simple data
                                                      >> validation, 
                                                      and the violation of business rules during a non-trivial
                                                      >> operation
                                                      in  the domain. I consider the latter to be an "exceptional situation".
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >>
                                                      >> 
                                                      ----------------------------------------------------------
                                                      >>
                                                      >> 
                                                      *From:* domaindrivendesign@yahoogroups.com
                                                      > <
                                                      href="mailto:domaindrivendesign%40yahoogroups.com">mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      [mailto:domaindrivendesign@yahoogroups.com
                                                      >
                                                      <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *ARKBAN
                                                      >>  *Sent:* Thursday, June 28, 2007 10:10
                                                      AM
                                                      >>  *To:* domaindrivendesign@yahoogroups.com
                                                      > <
                                                      href="mailto:domaindrivendesign%40yahoogroups.com">mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      *Subject:* Re: [domaindrivendesign] To throw or not to throw on Rule 
                                                      >> Violation
                                                      >>
                                                      >>  I think the
                                                      concern revolves around the mantra "exceptions are for 
                                                      >>
                                                      exceptional situations". Validation is most often not exceptional but 
                                                      >> expected; validation checks for situations that occur
                                                      easily but can
                                                      >> be  easily corrected, which are not really
                                                      exceptional.
                                                      >>
                                                      >>  ARKBAN
                                                      >>
                                                      >> 
                                                      Jeff Lowe wrote:
                                                      >> >
                                                      >> >
                                                      >> > Call me old
                                                      fashioned, but I prefer simply throwing a checked
                                                      >> > exception.
                                                      The exception then becomes part of the method signature,
                                                      >> > which
                                                      makes for a more expressive domain interface, e.g.:
                                                      >> >
                                                      >> > public redeem(Account account) throws
                                                      >> >
                                                      PromotionRulesViolationException
                                                      >> >
                                                      >> > The exception
                                                      can then encapsulate everything needed by the client (i.e.
                                                      >> >
                                                      application) to communicate back to the user, including information
                                                      >> > about multiple rule violations.
                                                      >> >
                                                      >> > > >
                                                      The thought of throwing exceptions doesn't sit real well with
                                                      >> > > > me
                                                      >>  but ...
                                                      >> >
                                                      >> > I'm
                                                      curious why it doesn't sit well. Other folks have also
                                                      >> >
                                                      expressed
                                                      > this.
                                                      >> >
                                                      >> >
                                                      >> >
                                                      Thanks,
                                                      >> > -Jeff
                                                      >> >
                                                      >> >
                                                      >> > ----------------------------------------------------------
                                                      >> >
                                                      *From:* domaindrivendesign@yahoogroups.com
                                                      > <
                                                      href="mailto:domaindrivendesign%40yahoogroups.com">mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      <mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> > [
                                                      href="mailto:domaindrivendesign@yahoogroups.com">mailto:domaindrivendesign@yahoogroups.com
                                                      >
                                                      <mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      <mailto:domaindrivendesign%40yahoogroups.com>] *On Behalf Of *Jesse
                                                      >> Napier
                                                      >> > *Sent:* Wednesday, June
                                                      27, 2007 9:41 PM
                                                      >> > *To:*
                                                      domaindrivendesign@yahoogroups.com
                                                      > <
                                                      href="mailto:domaindrivendesign%40yahoogroups.com">mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> 
                                                      <mailto:domaindrivendesign%40yahoogroups.com>
                                                      >> > *Subject:* [domaindrivendesign] To throw or not to throw on Rule
                                                      >
                                                      Violation
                                                      >> >
                                                      >> > I have a question regarding business
                                                      logic validation in my domain.
                                                      >> > Im not talking about validation
                                                      in the sense of simple data
                                                      >> > validation such as checking for
                                                      null values or specific data
                                                      >> > ranges. These days it seems like
                                                      most people are handling these
                                                      >> > types of validations with a
                                                      validation framework and checking an
                                                      >> > IsValid operation or
                                                      something similar. I refer to these as data
                                                      >> > validations. It may
                                                      be fine in some domains for an object to exist
                                                      >> > and be persisted
                                                      when that object is in an invalid data state. I am
                                                      >> > faced with
                                                      an issue in which I cannot allow certain objects to ever be in an invalid state.
                                                      >> >
                                                      >> > In my domain I have PromoCode and
                                                      Account. PromoCodes can be
                                                      >> > redeemed by accounts, but there are
                                                      rules regarding redemption. If
                                                      >> > any of these rules are violated,
                                                      redemption cannot succeed and the
                                                      >> > application must prevent the
                                                      redemption. These rule violations are
                                                      >> > not fatal and are to be
                                                      expected, however I must notify the user as
                                                      >> > to why the
                                                      redemption did not succeed. So my question is, what is
                                                      >> > the
                                                      preferred way of communicating business rule violations to the
                                                      >> >
                                                      UI when an action cannot be performed because it would put the
                                                      >> >
                                                      object into an invalid state that cannot be persisted?
                                                      >> >
                                                      >> > I think there are essentialy 4 ways:
                                                      >> > 1)
                                                      Throw an exception describing the first violation
                                                      >> > 2) Use
                                                      Notification pattern
                                                      >> >
                                                      <http://www.martinfowler.com/eaaDev/Notification.html
                                                      > <
                                                      href="http://www.martinfowler.com/eaaDev/Notification.html">http://www.martinfowler.com/eaaDev/Notification.html>
                                                      >> 
                                                      <http://www.martinfowler.com/eaaDev/Notification.html
                                                      > <
                                                      href="http://www.martinfowler.com/eaaDev/Notification.html">http://www.martinfowler.com/eaaDev/Notification.html>>> to
                                                      > communicate
                                                      >> > information about all
                                                      violations.
                                                      >> > 3) Throw an exception that encapsulates the
                                                      Notification object as
                                                      >> > described in Sergio's blog post, A
                                                      Notification Strategy for
                                                      >> > Business Errors
                                                      >> >
                                                      >>
                                                      >
                                                      <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin
                                                      >
                                                      ess.html
                                                      >
                                                      <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin
                                                      >
                                                      ess.html>
                                                      >
                                                      >>
                                                      >
                                                      <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin
                                                      >
                                                      ess.html
                                                      >
                                                      <http://sbtourist.blogspot.com/2006/03/notification-strategy-for-busin
                                                      >
                                                      ess.html>>>
                                                      >> > 4) Provide a Check operation which returns
                                                      a a boolean or a
                                                      >> > Notification object such as /Notification
                                                      CanRedeem(Account); /or
                                                      >> > /bool CanRedeem(Account); /If the check
                                                      operation returns any
                                                      >> > violations, Redeem would throw an
                                                      exception.
                                                      >> >
                                                      >> > The thought of throwing exceptions
                                                      doesn't sit real well with me
                                                      >> > but it is the easiest way to get
                                                      the information to any interested
                                                      >> > parties because they just
                                                      have to try...catch it. The Notification
                                                      >> > pattern has value but
                                                      it seems more difficult to get the
                                                      >> > information to the
                                                      interested parties. Granted, the Redeem
                                                      >> > operation on PromoCode
                                                      is a void operation and I could just return
                                                      >> > a Notification
                                                      object from that call. However, in my research for
                                                      >> > this problem
                                                      Im trying to comeup with a solution that would also
                                                      >> > work with
                                                      operations that had a return value. #4 is an instersting
                                                      >> > option
                                                      but im a little turned off by it because the check would
                                                      >> > have
                                                      to be called multiple times, once from the client and once
                                                      >> > from
                                                      the redeem operation. Here is a sample
                                                      >> >
                                                      >> > public
                                                      class PromoCode{
                                                      >> >
                                                      >> > string code;
                                                      >> >
                                                      DateTime expirationDate;
                                                      >> > bool isRedeemed;
                                                      >> > bool
                                                      isOnlyForNewAccounts;
                                                      >> >
                                                      >> > public Notification
                                                      CanRedeem(Account account){ Notification
                                                      >> > violations = new
                                                      Notification();
                                                      >> >
                                                      >> >
                                                      if(this.isRedeemed){
                                                      >> >
                                                      violations.Add(PromoCodeViolation.AlreadyRedeemed);
                                                      >> >
                                                      }
                                                      >> >
                                                      >> > if(this.expirationDate >
                                                      DateTime.Now){
                                                      >> >
                                                      violations.Add(PromoCodeViolation.Expired);
                                                      >> > }
                                                      >> >
                                                      >> > if(this.isOnlyForNewAccounts &&
                                                      account.IsNewAccount == false){
                                                      >> >
                                                      violations.Add(PromoCodeViolation.NewAccountsOnly);
                                                      >> >
                                                      }
                                                      >> >
                                                      >> > return violations;
                                                      >> >
                                                      }
                                                      >> >
                                                      >> > public void Redeem(Account account){
                                                      Notification violations =
                                                      >> > this.CanRedeem(account);
                                                      >> >
                                                      >> > if(violations.HasErrors){
                                                      >> > throw new
                                                      BusinessRuleException(violations);
                                                      >> > }
                                                      >> >
                                                      >> > this.DoRedeem(account);
                                                      >> > }
                                                      >> >
                                                      >> > protected void DoRedeem(Account account){ ...
                                                      >> > }
                                                      >> > }
                                                      >> >
                                                      >> >
                                                      >> >
                                                      public class PromoCodeTest{
                                                      >> >
                                                      >> > public void
                                                      RunCanRedeem(){
                                                      >> >
                                                      >> > Account testAccount =
                                                      Mock.GetMock<Account>();
                                                      >> >
                                                      >> > PromoCode code
                                                      = CreateValidPromoCode();
                                                      >> >
                                                      >> >
                                                      if(code.CanRedeem(testAccount).HasErrors == false){
                                                      >> >
                                                      code.Redeem(testAccount);
                                                      >> >
                                                      >> >
                                                      Assert.IsTrue(code.IsRedeemed);
                                                      >> > }
                                                      >> >
                                                      }
                                                      >> > }
                                                      >> >
                                                      >> >
                                                      >> >
                                                      >> > Any thoughts or advice on this? Any ways to improve it? Or
                                                      is the a
                                                      >> > better strategy that I havent seen?
                                                      >> >
                                                      >> > Thanks,
                                                      >> > Jesse



                                                      Yahoo! Groups Links

                                                      <*> To visit your group on the web, go to:
                                                          http://groups.yahoo.com/group/domaindrivendesign/

                                                      <*> Your email settings:
                                                          Individual Email | Traditional

                                                      <*> To change settings online go to:
                                                          http://groups.yahoo.com/group/domaindrivendesign/join
                                                          (Yahoo! ID required)

                                                      <*> To change settings via email:
                                                          mailto:domaindrivendesign-digest@yahoogroups.com
                                                          mailto:domaindrivendesign-fullfeatured@yahoogroups.com

                                                      <*> To unsubscribe from this group, send an email to:
                                                          domaindrivendesign-unsubscribe@yahoogroups.com

                                                      <*> Your use of Yahoo! Groups is subject to:
                                                          http://docs.yahoo.com/info/terms/

                                                    • Joe A. Reddy
                                                      Yep, that s what I said... Violations passed by reference
                                                      Message 26 of 26 , Jun 29 7:11 AM

                                                        << I think you want "out" there not ref Joe (you method is taking control of the instantiation) .>>

                                                        Yep, that’s what I said…” Violations passed by reference and not initialized”

                                                        I just did not know if Java has the same concept so I specified “by reference and not initialized” which is what ‘out’ is doing.

                                                        Which leads me to a question, just out of curiosity; does Java have a way to do this?

                                                         

                                                        Thanks,

                                                        Joe

                                                         

                                                         

                                                         

                                                        -----Original Message-----
                                                        From: domaindrivendesign@yahoogroups.com [mailto:domaindrivendesign@yahoogroups.com] On Behalf Of Greg Young
                                                        Sent:
                                                        Thursday, June 28, 2007 5:21 PM
                                                        To: domaindrivendesign@yahoogroups.com
                                                        Subject: Re: [domaindrivendesign] To throw or not to throw on Rule Violation

                                                         

                                                        I think you want "out" there not ref Joe (you method is taking control of the instantiation) .

                                                        INotificationCollec tion Notifications = null; //?
                                                        myPromo.Redeem( Account, ref Notifications) ;

                                                        vs

                                                        INotificationCollec tion Notifications;
                                                        myPromo.Redeem( Account, out Notifications) ;



                                                        Personally I prefer a slightly different mechanism .... I like to use commands to hold data for the change (i.e. build a message for the object and pass it as a whole) ... then I apply the command to which I give all errors at once through a normal notification pattern.

                                                        ex:

                                                        Customer has a field "CustomerType" ... instead of having a proeprty for this I have a changecustomertypec ommand ... I can also key other things like work flows off of these commands if I persist them (they also come in really handy for my reporting database which is synchronized in near real time as I just take the commands and ship them over to the denormalization process which then selectively updates the reporting databse).

                                                        When it is time for me to save I can also persist the commands that were associated with the object as an audit.

                                                        Cheers,

                                                        Greg

                                                        On 6/28/07, Joe A. Reddy <jreddy@benefitfinan ce.com> wrote:

                                                        In C# when I type myPromo.Redeem( the IDE will tell me I will be passing into two arguments. One is an Account passed by value and the other is Violations passed by reference and not initialized.

                                                        This tells me that the routine will initialize Violations…something is happening…I have to go out of my way to ignore it.

                                                         

                                                        Note, I did not say forced, just hard to misuse, hard to ignore.

                                                         

                                                         

                                                         

                                                         

                                                        -----Original Message-----
                                                        From: domaindrivendesign@ yahoogroups. com [mailto:domaindrivendesign@yahoogro ups.com] On Behalf Of ARKBAN
                                                        Sent:
                                                        Thursday, June 28, 2007 3:29 PM
                                                        To: domaindrivendesign@ yahoogroups. com

                                                        Subject: Re: [domaindrivendesign ] To throw or not to throw on Rule Violation

                                                         

                                                        How are they forced to deal with violations in these code examples? In
                                                        the first I could just not register a listener/event handler, and in the
                                                        second I could just not check for violations.

                                                        Personally the second example to me looks very much like the old return
                                                        code style error system used in C. Not inherently bad but requires
                                                        consistency and mindfulness to always check for errors.

                                                        ARKBAN

                                                        Joe A. Reddy wrote:

                                                        >
                                                        >
                                                        > I like it.
                                                        >
                                                        > It makes it clear to anyone and everyone that when PromoCodes are
                                                        > redeemed they need to deal with Violations.
                                                        >
                                                        > This code would be hard to misuse.
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        > -----Original Message-----
                                                        > *From:*
                                                        target="_blank">domaindrivendesign@ yahoogroups. com
                                                        > [mailto:
                                                        target="_blank">domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jesse Napier
                                                        > *Sent:*
                                                        Thursday, June 28, 2007 2:43 PM
                                                        > *To:* domaindrivendesign@ yahoogroups. com
                                                        > *Subject:* RE: [domaindrivendesign ] To throw or not to throw on Rule
                                                        > Violation
                                                        >
                                                        >
                                                        >
                                                        > Its so true that exceptional situations are very subjective. I've found
                                                        > myself battling with that all the time. In my case, it seems like an
                                                        > exceptional situation would be if more people redeemed the promo code
                                                        > than were allowed to. Then Ive got problems. So the business logic is
                                                        > in place to prevent that from occurring.
                                                        >
                                                        >
                                                        >
                                                        > From reading other discussions on this forum and from the feedback I
                                                        > have recieved in regards to this post, it appears that there is alot of
                                                        > sentiment for not throwing exceptions in situations like this and I tend
                                                        > to agree. So how do we get the validation errors to the caller in an
                                                        > elegant way?
                                                        >
                                                        >
                                                        >
                                                        > There has been some talk of events, but that doesnt really seem elegant
                                                        > to me. It seems confusing for the client.
                                                        >
                                                        >
                                                        >
                                                        > Say im a a controller, I want to do this:
                                                        >
                                                        >
                                                        >
                                                        > string codeId = GetCodeFromRequest( );
                                                        >
                                                        >
                                                        >
                                                        > PromCode promoCode = promoRepository. FindByCode( codeId);
                                                        >
                                                        >
                                                        >
                                                        > promoCode.Redeem( account);
                                                        >
                                                        >
                                                        >
                                                        > //get validation errors from somewhere
                                                        >
                                                        > //and register them for the view to display
                                                        >
                                                        > }
                                                        >
                                                        >
                                                        >
                                                        > having some event handler in the controller to trap for redemption
                                                        > errors would be very hard to understand and follow if you ask me. The
                                                        > code would read better if we handled any violations right next to the
                                                        > code that caused the violation.
                                                        >
                                                        >
                                                        >
                                                        > does this smell?
                                                        >
                                                        >
                                                        >
                                                        > INotification violations = INotificationFactor y.Create( );
                                                        >
                                                        >
                                                        >
                                                        > promoCode.Redeem( account, violations);
                                                        >
                                                        >
                                                        >
                                                        > if(violations. HasErrors) {
                                                        >
                                                        > //register error messages with the view
                                                        >
                                                        > }
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        > ------------ --------- --------- --------- --------- --------- -
                                                        >
                                                        > *From:* target="_blank">domaindrivendesign@ yahoogroups. com
                                                        > [mailto:
                                                        target="_blank">domaindrivendesign@ yahoogroups. com] *On Behalf Of *Jeff Lowe
                                                        > *Sent:* Thursday, June 28, 2007 7:46 AM
                                                        > *To:* domaindrivendesign@ yahoogroups. com
                                                        > *Subject:* RE: [domaindrivendesign ] To throw or not to throw on Rule
                                                        > Violation
                                                        >
                                                        > That's a cute mantra. "exceptional situation" is certainly subjective.
                                                        >
                                                        >
                                                        >
                                                        > As Jesse stated, there's a difference between simple data validation,
                                                        > and the violation of business rules during a non-trivial operation in
                                                        > the domain. I consider the latter to be an "exceptional
                                                        situation".
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        >
                                                        > ------------ --------- --------- --------- --------- --------- -
                                                        >
                                                        > *From:*
                                                        target="_blank">domaindrivendesign@ yahoogroups. com
                                                        > [mailto:
                                                        target="_blank">domaindrivendesign@ yahoogroups. com] *On Behalf Of *ARKBAN
                                                        > *Sent:* Thursday, June 28, 2007 10:10 AM
                                                        > *To:* domaindrivendesign@ yahoogroups. com
                                                        > *Subject:* Re: [domaindrivendesign ] To throw or not to throw on Rule
                                                        > Violation
                                                        >
                                                        > I think the concern revolves around the mantra "exceptions are for
                                                        > exceptional situations". Validation is most often not exceptional but
                                                        > expected; validation checks for situations that occur easily but can be
                                                        > easily corrected, which are not really exceptional.
                                                        >
                                                        > ARKBAN
                                                        >
                                                        > Jeff Lowe wrote:
                                                        >>
                                                        >>
                                                        >> Call me old fashioned, but I prefer simply throwing a
                                                        >> checked exception. The exception then becomes part of the method
                                                        >> signature, which makes for a more expressive domain interface, e.g.:
                                                        >>
                                                        >> public redeem(Account account) throws PromotionRulesViola tionException
                                                        >>
                                                        >> The exception can then encapsulate everything needed by the client
                                                        (i.e.
                                                        >> application) to communicate back to the user, including information
                                                        >> about multiple rule violations.
                                                        >>
                                                        >> > > The thought of throwing exceptions doesn't sit real well
                                                        with me
                                                        > but ...
                                                        >>
                                                        >> I'm curious why it doesn't sit well. Other folks have also expressed
                                                        this.
                                                        >>
                                                        >>
                                                        >> Thanks,
                                                        >> -Jeff
                                                        >>
                                                        >>
                                                        >> ------------ --------- --------- --------- --------- --------- -
                                                        >> *From:*
                                                        target="_blank">domaindrivendesign@ yahoogroups. com
                                                        > <mailto:domaindrivendesign%40yahoog
                                                        href="http://roups.com" target="_blank"> roups.com>
                                                        >> [mailto:
                                                        target="_blank">domaindrivendesign@ yahoogroups. com
                                                        > <mailto:domaindrivendesign%40yahoog
                                                        href="http://roups.com" target="_blank"> roups.com>] *On Behalf Of *Jesse Napier
                                                        >> *Sent:* Wednesday, June 27, 2007 9:41 PM
                                                        >> *To:*
                                                        target="_blank">domaindrivendesign@ yahoogroups. com
                                                        > <mailto:domaindrivendesign%40yahoog
                                                        href="http://roups.com" target="_blank"> roups.com>
                                                        >> *Subject:* [domaindrivendesign ] To throw or not to throw on Rule
                                                        Violation
                                                        >>
                                                        >> I have a question regarding business logic validation in my domain. Im
                                                        >> not talking about validation in the sense of simple data validation
                                                        such
                                                        >> as checking for null values or specific data ranges. These days it
                                                        >> seems like most people are handling these types of validations with a
                                                        >> validation framework and checking an IsValid operation or something
                                                        >> similar. I refer to these as data validations. It may be fine in some
                                                        >> domains for an object to exist and be persisted when that object is in
                                                        >> an invalid data state. I am faced with an issue in which I cannot
                                                        >> allow certain objects to ever be in an invalid state.
                                                        >>
                                                        >> In my domain I have PromoCode and Account. PromoCodes can be redeemed
                                                        by
                                                        >> accounts, but there are rules regarding redemption. If any of these
                                                        >> rules are violated, redemption cannot succeed and the application must
                                                        >> prevent the redemption. These rule violations are not fatal and are to
                                                        >> be expected, however I must notify the user as to why the redemption
                                                        did
                                                        >> not succeed. So my question is, what is the preferred way of
                                                        >> communicating business rule violations to the UI when an action cannot
                                                        >> be performed because it would put the object into an invalid state
                                                        that
                                                        >> cannot be persisted?
                                                        >>
                                                        >> I think there are essentialy 4 ways:
                                                        >> 1) Throw an exception describing the first violation
                                                        >> 2) Use Notification pattern
                                                        >> <
                                                        target="_blank">http://www.martinfo wler.com/ eaaDev/Notificat ion.html
                                                        > <
                                                        target="_blank">http://www.martinfo wler.com/ eaaDev/Notificat ion.html>> to communicate
                                                        >> information about all violations.
                                                        >> 3) Throw an exception that encapsulates the Notification object as
                                                        >> described in Sergio's blog post, A Notification Strategy for Business
                                                        >> Errors
                                                        >>
                                                        > <
                                                        href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html" target="_blank">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html
                                                        > <
                                                        href="http://sbtourist.blogspot.com/2006/03/notification-strategy-for-business.html" target="_blank">http://sbtourist. blogspot. com/2006/ 03/notification- strategy- for-business. html
                                                        >>
                                                        >> 4) Provide a Check operation which returns a a boolean or a
                                                        Notification
                                                        >> object such as /Notification CanRedeem(Account) ; /or /bool
                                                        >> CanRedeem(Account) ; /If the check operation returns any
                                                        violations,
                                                        >> Redeem would throw an exception.
                                                        >>
                                                        >> The thought of throwing exceptions doesn't sit real well with me but
                                                        it
                                                        >> is the easiest way to get the information to any interested parties
                                                        >> because they just have to try...catch it. The Notification pattern has
                                                        >> value but it seems more difficult to get the information to the
                                                        >> interested parties. Granted, the Redeem operation on PromoCode is a
                                                        >> void operation and I could just return a Notification object from that
                                                        >> call. However, in my research for this problem Im trying to comeup
                                                        with
                                                        >> a solution that would also work with operations that had a return
                                                        >> value. #4 is an instersting option but im a little turned off by it
                                                        >> because the check would have to be called multiple times, once from
                                                        the
                                                        >> client and once from the redeem operation. Here is a sample
                                                        >>
                                                        >> public class PromoCode{
                                                        >>
                                                        >> string code;
                                                        >> DateTime expirationDate;
                                                        >> bool isRedeemed;
                                                        >> bool isOnlyForNewAccount s;
                                                        >>
                                                        >> public Notification CanRedeem(Account account){
                                                        >> Notification violations = new Notification( );
                                                        >>
                                                        >> if(this.isRedeemed) {
                                                        >> violations.Add( PromoCodeViolati on.AlreadyRedeem ed);
                                                        >> }
                                                        >>
                                                        >> if(this.expirationD ate > DateTime.Now) {
                                                        >> violations.Add( PromoCodeViolati on.Expired) ;
                                                        >> }
                                                        >>
                                                        >> if(this.isOnlyForNe wAccounts && account.IsNewAccoun t
                                                        == false){
                                                        >> violations.Add( PromoCodeViolati on.NewAccountsOn ly);
                                                        >> }
                                                        >>
                                                        >> return violations;
                                                        >> }
                                                        >>
                                                        >> public void Redeem(Account account){
                                                        >> Notification violations = this.CanRedeem( account);
                                                        >>
                                                        >> if(violations. HasErrors) {
                                                        >> throw new BusinessRuleExcepti on(violations) ;
                                                        >> }
                                                        >>
                                                        >> this.DoRedeem( account);
                                                        >> }
                                                        >>
                                                        >> protected void DoRedeem(Account account){
                                                        >> ...
                                                        >> }
                                                        >> }
                                                        >>
                                                        >>
                                                        >> public class PromoCodeTest{
                                                        >>
                                                        >> public void RunCanRedeem( ){
                                                        >>
                                                        >> Account testAccount = Mock.GetMock<Account>();
                                                        >>
                                                        >> PromoCode code = CreateValidPromoCod e();
                                                        >>
                                                        >> if(code.CanRedeem( testAccount) .HasErrors == false){
                                                        >> code.Redeem( testAccount) ;
                                                        >>
                                                        >> Assert.IsTrue( code.IsRedeemed) ;
                                                        >> }
                                                        >> }
                                                        >> }
                                                        >>
                                                        >>
                                                        >>
                                                        >> Any thoughts or advice on this? Any ways to improve it? Or is the a
                                                        >> better strategy that I havent seen?
                                                        >>
                                                        >> Thanks,
                                                        >> Jesse
                                                        >>
                                                        >>
                                                        >>
                                                        >>
                                                        >
                                                        >




                                                        --
                                                        Studying for the Turing test

                                                      Your message has been successfully submitted and would be delivered to recipients shortly.