Eventuous / dotnet-sample

Sample application using Eventuous .NET
38 stars 11 forks source link

Performance question: is a good idea use DomainExceptions #1

Closed AlbertoLeon closed 1 year ago

AlbertoLeon commented 2 years ago

We can see if (!roomAvailable) throw new DomainException("Room not available"); and I remember that guideline from .Net Framework Design Guidelines: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exception-throwing

image

Is it a good idea use exceptions? Maybe it's better having allways some kind of response from each operation? I guess this kind of questions are natively solved in F# as it forces always an output from all operations.

LockTar commented 1 year ago

Do you have a better solution in this case?

alexeyzimarev commented 1 year ago

I don't know how to bubble up errors without throwing exceptions without adding lots of complexity. If C# would have DU types it could be quite easy, but otherwise it will be tuples everywhere.

LockTar commented 1 year ago

I don't know how to bubble up errors without throwing exceptions without adding lots of complexity.

I agree with this. I don't think this is wrong in this case.

Frikki commented 1 year ago

An exception should be thrown when a function experiences a failure, i.e., an error.

A function is a unit of work, and failures should be viewed as errors or otherwise based on their impact on functions. Within a function f, a failure is an error if and only if it prevents f from meeting any of its callee’s preconditions, achieving any of f’s own postconditions, or reestablishing any invariant that f shares responsibility for maintaining.

There are three different kinds of errors:

a condition that prevents the function from meeting a precondition (e.g., a parameter restriction) of another function that must be called; a condition that prevents the function from establishing one of its own postconditions (e.g., producing a valid return value is a postcondition); and a condition that prevents the function from re-establishing an invariant that it is responsible for maintaining. This is a special kind of postcondition that applies particularly to member functions. An essential postcondition of every non-private member function is re-establishing its class’s invariants. Any other condition is not an error and should not be reported as an error.

Report an error wherever a function detects an error that it cannot deal with itself, preventing it from continuing in any form of normal or intended operation.

Handle the error in places with sufficient knowledge to handle the error, translate it, or enforce boundaries defined in the error policy, such as on main or thread mainlines.

Source: C++ Coding Standards: 101 Rules, Guidelines, and Best Practices

alexeyzimarev commented 1 year ago

Not sure how that helps.

By the way, I was discussing this issue with some people, in particular with Jérémie Chassaing. He lives in a functional world, and, to my surprise, the Decider pattern proposed by Jérémie, doesn't have a switch back to return an error result. When I asked him about it he said "I just throw an exception". Using similar arguments like "it's a normal flow, etc" I tried to convince him otherwise. His answer was "It is a bug in your app. Command handling should not fail. All the preconditions can be checked upfront, and failing in the domain model is the last resort".

In the case of my sample app, there are two ways to avoid the exception: