Exceptions are evil. This is what I do instead.

preview_player
Показать описание
In today's video we'll talk about why exceptions are evil and why you should probably stop throwing exceptions for flow control.

Not throwing exceptions will make your code faster, simpler, faster to debug, and easier to maintain.

We'll also see the alternative flow control approach which is the result pattern. The result pattern will be demonstrated using ErrorOr, and we'll see how the ErrorOr library can be used to elegantly return errors instead of throwing exceptions.

Connect with me on 'em socials:

Thanks for watching, don't forget to like & comment & subscribe! ❤️ 💻

00:00. Intro
01:17. Exceptions suck #1 - Messy
03:45. Exceptions suck #2 - Complex
08:40. Exceptions suck #3 - Heavy
09:46. Exceptions suck #4 - Privacy
14:12. Exceptions suck #5 - Monitoring
17:19. The Result Pattern
17:58. ErrorOr
20:15. Result Pattern ftw #1
21:42. Result Pattern ftw #2
23:39. ErrorOr 2.0
24:17. Outro
Рекомендации по теме
Комментарии
Автор

You are absolutely right.
If you ask me, I use exceptions in exceptional cases only.😊

nirajjoshi
Автор

Sometimes exceptions are good, it doesn't turn code into if-hell after every method call. But they are for exception situations and the main problem is not exceptions, it's how people use them.

aabbccddeeff
Автор

In theory it's the same procedure as in Go but slightly worse. For me it's the complete opposite of what you say. It a.) becomes a burden, because you have to explicitly do error handling on every caller. b.) because of that it's getting really fast really messy and last but not least c.) I have to pollute my code with (in this case) an external dependency. Throwing domain specific exceptions, catching them separate if necessary or globally is in my opinion a cleaner way - but I guess this is subjective. For me another benefit of throwing domain specific exceptions is, that you know already by the name of the exception where the underlying problem most probably occurred.

B..N
Автор

There is a lot of divide on this topic and I love it. That said, the main reason why I like this approach is because I like the separation between Business Logic Expected Errors and Exceptions.

johalternate
Автор

The main problem presented is the fact that a global exception handler is responsible for handling all types of failure cases. This is bad, but I disagree that disallowing exceptions is the solution. Regardless, we need to move the responsibility where it belongs. Whichever component is aware of the failure case and decides the result of it, is the one that should actually be handling it (whether that is by catching exceptions or by checking a result object). I'm still concerned that the guidance here seems to be "exceptions are bad, never throw exceptions" when in reality different solutions are appropriate for different problems.

Basically this is looking at two extreme cases: Errors that flow up the entire dependency tree to a global handler (which should be avoided unless they are truly unexpected), and ones that are handled directly by the calling component. However, there are plenty of cases in between. It makes sense to use the result pattern if we know that the caller will usually be responsible for handling failure states. But otherwise, what is the value in forcing callers to collect errors and pass them through the tree? All we are doing then is manually re-implementing what exceptions already give us for free, and polluting all the layers in between with details they should not be concerned with.

On the point about privacy: This is also something that we need to handle regardless. At the end of the day, even if we refactor all of our own components to never deliberately throw exceptions, we will still have unhandled exceptions that need to be reported somehow, that we will want to be able to debug. I agree that the general solution here is that your public interface should only use error codes and descriptions that you control - but disagree that *replacing* exceptions with your own construct is the only way to do so. This information can be included with exceptions (either by using your own exception class, or some way of attaching metadata to existing exceptions). Then, the global handler should be designed to only output the public information publicly, but still be able to log the actual exceptions and/or display them when running in a development environment. This also allows us to freely throw our own unhandled exceptions for unexpected cases - that we will be able to debug if they do happen - without worrying about what the stack trace or inner exceptions might expose, because we know they are still never going to be displayed to the user anyway.

TazG
Автор

Here's my prediction, 30 seconds in:: You experienced working in projects that were messy because of engineers conflating 3 different concepts:

1. validation
2. completion status
3. exceptions

My take: If you always use exceptions to implement the first two cases, then you're going to have a bad time. If you go all the way and refuse to use any exceptions even in the third case, because you decided they were "evil", you're also going to have a bad time.

TazG
Автор

Thank you so much, Amichai. I love ErrorOr and am eagerly awaiting the next video about ErrorOr introduction. See you then!

hoangsangnguyen
Автор

Should have named the library ErrOr, as "orOr" is redundant - although it would be impossible to distinguish it while searching for "error" in a search engine.

StevenHartgers
Автор

I tried ErrorOr in one small part of my project. I had the following problems

1. To make the controller code short I needed a relatively complex generic extension method to convert the ErrorOr to the ActionResult. This is OK if you use it everywhere but it was annoying when I tried to use it in a single controller experimentally

2. I needed more results than Error or result and also inline way to define errors.

Basically I want union types that can be declared inline like string | int but also named if need be.

BTW when I use exceptions if I need to catch them anywhere but in the global handler I immediately switch to some form of results even if it is the most primitive.

Eirenarch
Автор

I am already using your ErrorOr library ever since I learned about it from the DDD series, and I like it a lot, with two exceptions: 1. sometimes, it can feel overwhelming to have to introduce "if checks-error returns" after every method call 2. I think it would have been nice if you explained in the video how do you handle stack traces when using discriminated union-like constructs, because sometimes, when looking in logs, a stack trace is really helpful, when the flow path that led to the exception is complex and long

ciprianhoreanu
Автор

The way you've described the global handling in #2 (3:45) makes it look like it's hard to think of the control flow when using exceptions. However, it's not a global handling logic that sometimes the component would propagate the exception to and sometimes won't. It's an extra layer on the surface of your application stack. Each layer/component would throw an exception that's understandable by the upper layer, and each layer has the choice to propagate that exception, convert it, or swallow it. The global error handling is always done at the top layer. And unless you're intercepting the exception on its way propagating to that global error handling it won't be affected.

mazenamria
Автор

c# is not designed to use the result pattern, your dependencies won't use it, you get a mess. If you want the kinda monadic discriminated union approach instead of exceptions then go with GO or languages which are designed to that. I would be happy if java and c# wouldn't be the mess they are, because I hate GO but have to admit it's a better overall design.

botyironcastle
Автор

This video is even more exciting than Game of Thrones episodes. I dont know how happened but he convinced me😅Waiting for the next episode. Thanks!

hamitkarahan
Автор

This is also my favourite Result pattern library. I was using OneOf before and I was slightly disappointed with it because of Matching and need to create empty classes for errors that didn't have any details.

I first have seen this library in your DDD course, I guess. And I liked it more then any other library.

Looking forward to seeing a error-or 2.0 video

antonmartyniuk
Автор

At the first section of the video you mention that many exceptions may bring a mess in our project, but at the 22:50 creating a folder with other business exceptions classes don't take us to the same problem?

moacir
Автор

Firstly, exceptions being heavy doesn't matter. You should not have exceptions thrown in production code, and if this does happen you fix it. Exceptions do not exist as a "general" application feature so assuming it's supposed to be anything like that is bad.
Secondly, privacy doesn't matter because of the first point. Exceptions should not be thrown. In the event an API throws an exception it has build in features to redact any sensitive information.

The result pattern is great, but it can't replace exceptions. For some reason you think it can. The whole point is throwing an error that is delegated to the first instance catching it, effectively ending code that can't handle the result that would otherwise be given. If you have the result pattern, your code clearly knows how to handle the issue. If you implement it just to end the method with another Result, you are wasting your time doing something an exception could have done in a more readable way.

Don't reinvent the wheel with something that doesn't work as well. These videos are just going to confuse developers into using something that works worse, and have them end up having to refactor it.

fusedqyou
Автор

In my experience, when you don’t use global handlers and exceptions as your default error handling mechanism, the code becomes a lot more complex, you would just write a ton of meaningless code just to propagate the error up the call stack - exactly what exceptions do when you forget about error handling, and you get a nice stacktrace in that case so you can find the cause of your error easily. Once you do, you can add adjust the error handling. That’s much better than relying on programmers always doing a correct handling and adding all the context info after each function call. That’s not naive approach, that’s very practical approach

alexgoncharov
Автор

Yeah, i remember 25 years ago we had those error codes, but at least there was a reason for that. Inventing new layer of error handing when you Can use standard exceptions looks to me really wrong.
The author just took an example of misusing exceptions and solved that with an approach i would never use in my code.

uuuummm
Автор

I'm a beginner with C# and I have been doing this manually for every endpoint in my project😅, I'm gonna give your library a try!

Stoney_Eagle
Автор

I use the result pattern; your solution is much cooler than mine

HaimBell
visit shbcf.ru