17

I know it is expensive but (IMO) I believe it is a very good practice. I'm talking about rules like say, you can't save an Invoice if you are not a sales person... so in that case throwing an exception saying 'your are not authorized' or such...

Another approach it would be having objects with a status or something like that

Is there any other approach? how do you feel about it?

6 Answers 6

15

If you mean representing individual business rule checks with exceptions, then I don't think it's a very good idea. Many times you have to report more than one failed condition, and not stop on the first one.

On the other hand, I do believe that checking for all rules and then throwing an exception with the summary is a good practice.

6
  • 1
    That's exactly how I handle it in my apps. Using FluentValidation to make my life easy, and ValidateAndThrow method saves my day. Oct 29, 2010 at 14:55
  • In a UI app I agree completely, but in a service tier app I would generate an exception if I was passed an object that does not comply with business rules. If you are using the two in combination then sometimes you and up adding a validation function or a complex error as matiasha describes in the last sentence.
    – Bill
    Oct 29, 2010 at 15:09
  • 8
    Throw a domain specific exception. This allows you to separate between ours and not-ours up higher.
    – user1249
    Nov 18, 2010 at 21:08
  • @Thorbjørn Ravn Andersen +1 "domain specific" great addition Jun 21, 2011 at 15:14
  • 1
    @JamesPoulson it may be enough to create JamesPoulsonException as a subclass of RuntimeException and then provide the original exception as the cause. You can then simply say if (exception instanceof JamesPoulsonException)... to differentiate. Use the getCause() method to reach the original exception.
    – user1249
    May 14, 2012 at 7:36
9

In the example you've given us I think that raising an exception is a bad idea. If you know that the user is not authorized before they start working and you still allow them to do some function and then smack them with an message AFTER they've already completed the task, that's just a bad design.

Using exceptions to enforce business rules is not a good design.

5
  • What I understand of what you said, is that you don't agree with the UI. I'm ok with that. I agree with you that a much more friendly UI wouldn't let you try to update something you're not allowed. But that doesn't mean that the validation and exception check in the business core is unnecessary. By the contrary, I believe they are a must. You need them to ensure that a badly programmed UI doesn't allow a BL misuse.
    – Fede
    Oct 29, 2010 at 15:15
  • 8
    @Fede: it's a question of separation of concerns. The UI is responsible for gathering the user's intentions and reporting feedback from the business layer. The business layer's job is analyzing the information gathered by the UI, analyzing it and either reporting back to the UI and/or asking the data layer to persist some data. There should only be loose coupling between these layers. Exceptions are a poor, poor approach to loose-coupling. Not only does it mean sharing actual classes between the layers but it also invokes a mechanism that is meant to handle unexpected failures. Oct 29, 2010 at 15:24
  • @Adam - Well said and exactly on point.
    – Walter
    Oct 29, 2010 at 16:11
  • 2
    @Adam - Don't follow you with the separation of concerns issues. I don't expect anyone in the UI to handle a CustomerNameInLowercaseException (please, I also hope that exception doesn't even exist!). You can just handle a generic ValidationException. Besides, I'm 100% with you that the UI should only gather information, and all that thig. What I said before is that no matter what you do in the UI, the BL shouldn't assume that every input is ok. It's just some defensive programing.
    – Fede
    Oct 29, 2010 at 17:44
  • @Fede: it is the Business Layer's job to assure that every input is OK. If the UI is doing it then it is implementing business logic. Now, if it is the case that an input field is restricted to digits and the BL sees alpha characters, by all means throw an exception. Whenever a component recieves invalid inputs from another component, throwing an exception is logical and right. The interface has been broken, and the system is broken. However, validating inputs is very different than executing business logic. Two very different things. Oct 29, 2010 at 18:23
5

I don't see what value throwing an Exception has in creating good business logic. There are dozens of approaches to handling business logic that do not involve using a system that is meant for addressing unexpected conditions in the operation of a system.

It is expected that in business logic, conditions will not be met; that's the reason for having it in the first place, and you don't want to piggyback on the same mechanism that handles unexpected I/O failures, out of memory errors and null references. Those are failures of the system, but detecting unmet business conditions is the successful operation of the system.

Additionally, it is a system that is ripe for unintended consequences. Because an exception has to be caught at some point, you run the risk of having a new business rule exception ened up being caught somewhere that it's not intended or you chance having the code that looks for business rules catching exceptions that aren't actually meant for it. Yes, these conditions can be accounted for with good coding practices, but in any non-trivial system on which more than one developer is working, mistakes will happen, and you just have to hope that they won't be costly mistakes.

1
  • 2
    I agree, exceptions are called exceptions because they are not expected to happen. On the other hand, enforcing business rules in your service tier with an exception is not necessarily wrong. You don't expect it to be used, you expect the client to only invoke operations and only submit data that meet valid conditions; but you want to build in a layer of protection because you know mistakes can happen in the client coding too. Sort of like using foreign key constraints in a database: you expect people insert and update data correctly but know they could fail due to a programming error.
    – Jeremy
    Oct 29, 2010 at 15:54
2

expressing business rules is one thing, implementing them is another

think about the user experience; if the user is not a salesperson, why give them a button that says 'create invoice' at all?

2
  • 2
    Just because you don't give a button, that doesn't mean they won't send you the message to do something anyway. Think how easy security rules would be if that was all it took..
    – jmoreno
    May 25, 2012 at 3:58
  • 1
    If the user isn't allowed to do X, don't give them a button that says "Do X". The best security is ignorance - don't tell the user about things they cannot do ;) May 28, 2012 at 20:10
1

That depends entirely on what's being done.

First, what is the actual behavior you want? If somebody is entering their own information, then a rejection and a dialog box saying, essentially, "You can't do that" is probably correct. If this is a data entry person, working from a pile of forms, a dialog box is probably also good, and the data entry person can put the invalid forms in a special pile. If you're doing batch processing, you don't want to bring things to a halt, but flag it and move to the next.

Once you have the behavior, you need to decide how you're going to implement it. Having a business rules checker that throws an exception is probably a good idea. Returning an return code and having it passed along is something else that can go wrong, and you certainly don't want the erroneous entries getting further.

Don't worry about performance expense. In the case of an individual entering data, it's trivial compared to the other times involved. Typically, the human will take the most time in that system. In the case of a batch job, if exceptions are a performance problem, you're entering far too many bad records, and in reality handling and re-entering all of those is going to be more of a problem than the exceptions.

0

Having a robust and well designed exception API that is consistent is very appropriate. Using this to enforce business rules can also be appropriate. In fact in my experience, the more complicated the business rule the more likely that it will end up being handled this way. It's often just as easy if not easier to write a system where exceptions are expected than to write authoritative branching logic.

This is to say that simple rules that can be described in a single sentence generally should be implemented in a preventative or authoritative manner depending on which it is. However if you have a rule that is multi-dimensional and requires more than three or four factors (especially if the selection of these factors is based on one or more of the other factors) then exception coding may be more maintainable. Often in these cases the logic path will have many precursor exceptions that need to be thrown, (checks for why the action cannot be performed) then (or vice-versa) there is a fall through to security (to check that the action is authorized), sometimes there will be some authoritative accumulation logic that needs to be checked (descendant/ancestor availability, precursor states that objects must be put into, etc. ) then the logic will fall through to the actual process which may include the more direct authoritative logic checks directly pertinent to the process.

One benefit that derives from this type of exception throwing is that it allows you to separate out and reuse the precursor exceptions across multiple areas of your project. (This is the essence of Aspect Oriented Programming.) By doing this you are encapsulating one particular aspect of your general business rules in a self contained and maintainable component. In general these components will correspond 1-1 with the error messages thrown. (Although sometimes you will have one component that throws several different exceptions, you should almost never have the same exception thrown from multiple components.)

In my opinion it is more difficult to design systems that are exception based the and the initial development time is longer since you have to build the exception process across all N levels. However these system generally end up being much more stable. While it is never possible to design a system that 'will not fail' the benefit of exception based design is that you are always anticipating failure. For most people the process can be counter-intuitive. It's like asking for directions and having someone tell you all the streets that you shouldn't turn on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.