diff --git a/README.md b/README.md index 7d094ea..3aa4099 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,9 @@ See the [API documentation](https://mrdave1999.github.io/SimpleResults/api/Simpl - [Operation Result Pattern](#operation-result-pattern) - [Why did I make this library?](#why-did-i-make-this-library) - [Why don't I use exceptions?](#why-dont-i-use-exceptions) + - [Differences between an expected and unexpected error](#differences-between-an-expected-and-unexpected-error) - [Anecdote](#anecdote) + - [What happens if I use exceptions for all cases?](#what-happens-if-i-use-exceptions-for-all-cases) - [Interesting resource about exceptions](#interesting-resource-about-exceptions) - [Installation](#installation) - [Overview](#overview) @@ -86,6 +88,8 @@ And there are many more examples of errors caused by the end user: the email is I only throw exceptions for unexpected errors otherwise, I create **result objects** and use return statements in my methods to terminate execution immediately when an expected error occurs. +### Differences between an expected and unexpected error + It is necessary to understand the differences between an expected and unexpected error in order to know when to throw exceptions. In fact, in practice, third-party dependencies are responsible for reporting unexpected errors, so the developer only has to worry about identifying the expected errors of his business application. - **Expected errors** are those that are expected to occur, and we tend to recover them. They are also known as recoverable errors or declared errors. @@ -110,6 +114,39 @@ This was a surprise to me! I didn't know! I was expecting an exception but it wa > If I had thrown an exception, I would have found the error very quickly, just by looking at the stack trace. In this case, it is very useful the exception object, for me and other developers and yes, divide by zero is an **unexpected error**, an exception should be thrown. +### What happens if I use exceptions for all cases? + +Your application will work for sure but some things will happen: + +- New maintainers of your application will learn that it is okay to throw exceptions in all situations. This is bad for their learning, since they don't really understand what exceptions in C# were designed for. + +- You make your code confusing, since you do not respect the official definition of what an exception is. + +- You need to create custom classes that inherit from the Exception type, otherwise you end up using the Exception type in many places, making your code not explicit, that is, the Exception type does not mean anything, it does not express anything to the developer. + +- You need to document those methods that throw exceptions, otherwise the consumer will not know which exceptions to handle, and will end up reviewing the source code of the method. + +- Performance. Yes, throwing exceptions is very expensive. Although in many applications there may not be any impact, it is not a justification for wasting resources unnecessarily. In other words, if you have an alternative to exceptions, why not use it? + - You can read more about it [here](https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/botr/intro-to-clr.md#exceptions). + +- If your application is a web application, you will have to find a mechanism to translate the exception object to HTTP status code, so you will have to create base classes like InvalidDataException to catch it from a global exception handler. + - For example: `DuplicateEmailException` inherits from `InvalidDataException` and in turn, it inherits from `Exception`. So you must think well in the hierarchy of types using inheritance. + +- You make your code not explicit, so it affects readability. Let's take a look at this example code: [RegisterCustomerUseCase](https://github.com/olafthielke/CleanArchitecture/blob/c18586b8b9a76bb1b9473693afc1cdc94f5e53e3/BusinessLogic/UseCases/RegisterCustomerUseCase.cs#L6C1-L41C2). + - This code is not explicit: + ```cs + public async Task RegisterCustomer(CustomerRegistration reg) + { + // What is this??? + await Validate(reg); + var customer = reg.ToCustomer(); + await Repository.SaveCustomer(customer); + await Notifier.SendWelcomeMessage(customer); + return customer; + } + ``` + That line is confusing because I don't know if that line of code was added on purpose or if someone forgot to handle the error with `try-catch`. As you will see, that line of code does not express its intention. + ### Interesting resource about exceptions - [Exceptions for flow control in C# by Vladimir Khorikov](https://enterprisecraftsmanship.com/posts/exceptions-for-flow-control)