5

I have a project implemented by Onion Architecture, and it is similar to Ordering. I need to handle validation errors in the all layers. As far as I know, there are generally two following approaches to do handle the errors:

1- Throwing exception

2- Returning Operation Result

In your view, which one is the best?

1- Throwing exception

This is my approach. As you can see in ValidatorBehavior, I have used ValidatorBehavior to handle validation errors related to validate my commands like this. FluentValidation is used to validate input command and errors are cached in Handle method in ValidatorBehavior.

One of the issues is FluentValidation throw exception if command isn't valid. This exception could be cached in HttpGlobalExceptionFilter in the web API.

Some people said exception is for unexpected case, but in this scenario (Validation), we know the result of validation phase and we implemented some business rules by throw exception.

Another one is using throwing exception in Domain Layer like StatusChangeException. So there is no doubt, we need throwing exception in other layers.

2- Returning Operation Result

In the second approach suggested by some of my friends, we can use handle errors for showing these errors to end users by an object named OperationResult. In performance viewpoint, it seems to be better because throwing exceptions is more expensive than first approach.

What do you think about these two approach? I am wondering if you share your idea to make the best decision.

Ali Soltani
  • 9,589
  • 5
  • 30
  • 55
  • It depends on business task, specific project, context, architecture etc. There is no 'rule of thumb' however after you have chosen one of these options it's better to stick to it and do all your error handling in the same fashion. Both have their pros and cons. I personally prefer the 2nd approach – Fabjan Sep 15 '19 at 11:57

2 Answers2

2

After personally designing and introducing an implementation of the Operation Result pattern to my company and having used it extensively for the last 3 years, on 3 different projects with 3 different customers, I've formed a pretty strong opinion on the topic.

TLDR: Go with the Exception based approach.

Performance: Exception-based is 10 times more expensive in failure scenarios, while Operation Result is 3 times more expensive in success scenarios. You could argue that success scenarios, statistically, are way more likely than exceptional scenarios, so we end up making our app 3 times slower so that, one out of 100 requests executes 10 times faster.

Complexity: All the examples you'll see about Operation Result uses only 2 levels of nesting, i.e.: A method fails an operation and the caller method checks whether the result is a success or a failure. In practice, you have to make these checks on every single method call, on every level of nesting. So, if you have a method, that calls 3 methods in sequence, each of which calls 3 more methods in sequence, you end up with between 8 and 12 if/else mandatory blocks. This is required for every single scenario, even if you don't care about handling failures.

On the Exception based side, we pretty much have the same amount of required code (try/catch Vs. if/else with a remediation block in the catch). The big difference is that we only use try/catch if we need to explicitly handle the exception. In most cases you won't, you'd like the exception to bubble up to your global handler. Ex.: An API POST operation, if, 3 levels down the SQL INSERT commands fail, I'm OK with the whole API failing with a 500.

Learning Curve: I'm a consultant, so my main priority is to provide a solution that my customers can maintain when I'm not around. The Operation Result Pattern is not mainstream, or at least, I cannot expect a job post to have it listed as a skill requirement and developers meeting it. I've found that, on average, it takes 6 months for developers unfamiliar with the concept to get used to it. Exceptions, on the other hand, are expected to be even taught at schools and there's plenty of available documentation on standards and best practices.

mdarefull
  • 829
  • 2
  • 14
  • 24
  • This. I don't really get everyone hyping up the Result-based approach and talking down on exceptions. Exceptions are a great way of keeping your code simple, since you more or less only should handle them at the top level (unless you have a good reason not to). The only thing I wish we had with exceptions is a way to tag them... I may want to handle an ArgumentException way differently if it's thrown in my code vs a third-party module. The performance is a non-issue, since successful executions are *way* more common than fails. – Andreas Forslöw Jan 25 '23 at 11:00
0

For exceptional errors, I typically throw exceptions from within all layers, which are handled in a global exception handler. This allows my application and domain code to remain 'clean', with that I mean, it can focus on the normal flow instead of handling exceptions. After all, exceptions are exceptional, not part of the normal flow, so to me they should not pullute your 'normal' logic.

As for your performance remark, I don't think this matters as your are talking about micro-optimization here, so basically, not a real problem.

L-Four
  • 13,345
  • 9
  • 65
  • 109