Thanks a lot for your video. I agree that readability is the main advantage of the result pattern or monad. Exception can be see as a Go To. A good video on this topic is "Throw Exceptions Out of Your Codebase" by Guillaume Faas. However, performance should not be the deciding factor. I conducted a benchmark and found that the difference is not significant.
Performance is not the main reason. Can you share your benchmark? I and others have done exactly that already and came up to exactly the opposite conclusion. I would love to take a look.
More If else conditions at callers -> More test cases for all these additional if else conditions. No thanks. I practically refactored from Result patterns to exceptions patters making code lean and simpler. A lot of tests became redundant with this change and reduced maintenance efforts. There will be impact in performance. Well, we are not building software for rockets 😁😁.
To be fair I'm not a fan of this pattern. In most large applications you will have multiple layers responsible for different things and handling return type may add a lot of code. I would really like to have a way to break execution without huge impact on performance and with little amount of code. This is what exceptions do and in case of web development you can catch those and handle as you want in higher layers. The problem is usually impact on performance ( mainly stack trace which you can disable but it is still way slower than soft handling ). This pattern seams like tradeoff where you get boost in performance but you need a lot more code to handle it. Please give us a way to break the circuit without performance loss.
Result Pattern, Result Pattern, but remember it is not a solution for all issues. If you have complex logic, multiple level of call hierarchy, and any issue in the code will break the whole execution, there is no need to use Result Pattern and mess your code with thousands of if(result.Success) but it is much better just to throw an exception, catch and handle in global exception, and keep your code clean and readable
Instead of checking result.Success, you can introduce Result.Map and Result.MapError functions, and it's clear that you handle the successful or unsuccessful case. And helpers / implicit operators to help with repetitive error cases. Check out railway oriented programming, if you are curious.
Isn't that the best use case for the result pattern? In a multiple level of hierarchy you don't want to always throw exception beacuse based on some response type you don't want to stop the flow of the program.
Good explanation thanks. How can I identify the real problem for ex. an exception is throwed and I want to log it? Aren't we ignore valueable exception data by using Result pattern?
The idea is that you only replace exceptions that are not that “exceptional”. That means that you have the Result pattern on the expected paths. You can still produce telemetry there. The difference is that doesn't come from a bulky exception. But, do I need something like the stack trace for an expected case?!
This - I have my own implementation (unfortunately) in company code base but it fulfills the goals of don’t throw if you can return error The only unsolved problem due to time constraints is what if want to have different behavior based on error code (rn it is ugly if statement in a few places) To be satisfied with result type in .NET you need to add a little bit of ext method on Task type also you can chain them if you want to
I tend to adopt solid libraries. I prefer to contribute to the ecosystem than build myself. However, if bringing a new library is friction, for such a small feature, I would build my simple version of it.
Might just be me, but I do not see the point of wrapping the result of a task in a result object, when the class `Tast` is already a result container. From what I can tell, tasks, futures and promises are all implementations of the result pattern on operations that are supposed to return a value in the future and for which we want to process differentiated treatment if it completed successfully or if it errored out. Tasks do not need to run asynchronously neither, though it should be assumed that they could, but one can always not « await » them and just work with the result type itself.
So the industry gave up on checked exceptions and then realized that code can fail without the caller knowing about the potential failure points. Now we're coming up with an entire new concept (that BTW loses the stack trace information), all to avoid just using checked exceptions that the language supports by design?
The results pattern is fucking idiotic. Just use exceptions for exception cases and then your response types aren't polluted with worthless structures. Maybe in rare occasions it is suitable, but newbies throwing it everywhere is infuriating.
I like how you talk about the pros and the cons, this honestly seems situational but not really scalable
I would say it's harder in big teams.
i Always use Result and my implementation have methods like Rust(map, bind,unwrap and so on). I love It, but i can t use It with my team 😢
You are not alone 😔
This video is proof that my studies and thoughts are on the right track. I managed to have the same idea, the same conclusion as an MVP star.
Where's the star? 🤓
I love the fact that great ideas tend to naturally emerge with experience.
Great tutorial thanks!
Glad you enjoyed it!
Thanks a lot for your video.
I agree that readability is the main advantage of the result pattern or monad.
Exception can be see as a Go To.
A good video on this topic is "Throw Exceptions Out of Your Codebase" by Guillaume Faas.
However, performance should not be the deciding factor.
I conducted a benchmark and found that the difference is not significant.
Performance is not the main reason. Can you share your benchmark? I and others have done exactly that already and came up to exactly the opposite conclusion. I would love to take a look.
@@gui.ferreira hello I try to respond to your comment but look like something is not compilant with youtube.
I don't know how to share the repos ...
More If else conditions at callers -> More test cases for all these additional if else conditions. No thanks. I practically refactored from Result patterns to exceptions patters making code lean and simpler. A lot of tests became redundant with this change and reduced maintenance efforts. There will be impact in performance. Well, we are not building software for rockets 😁😁.
To be fair I'm not a fan of this pattern. In most large applications you will have multiple layers responsible for different things and handling return type may add a lot of code. I would really like to have a way to break execution without huge impact on performance and with little amount of code. This is what exceptions do and in case of web development you can catch those and handle as you want in higher layers. The problem is usually impact on performance ( mainly stack trace which you can disable but it is still way slower than soft handling ). This pattern seams like tradeoff where you get boost in performance but you need a lot more code to handle it. Please give us a way to break the circuit without performance loss.
As you said exceptions impose a penalty. It is a tradeoff between performance and readability vs convenience
Ah, and we are back in days whene in C we return 1 for success and 0 for failure.
Result Pattern, Result Pattern, but remember it is not a solution for all issues. If you have complex logic, multiple level of call hierarchy, and any issue in the code will break the whole execution, there is no need to use Result Pattern and mess your code with thousands of if(result.Success) but it is much better just to throw an exception, catch and handle in global exception, and keep your code clean and readable
just don't write nested messy code, and your problem is solved 👍
Instead of checking result.Success, you can introduce Result.Map and Result.MapError functions, and it's clear that you handle the successful or unsuccessful case. And helpers / implicit operators to help with repetitive error cases. Check out railway oriented programming, if you are curious.
And the post titled "Against Railway-Oriented Programming" for a full picture!
Isn't that the best use case for the result pattern? In a multiple level of hierarchy you don't want to always throw exception beacuse based on some response type you don't want to stop the flow of the program.
Good explanation thanks. How can I identify the real problem for ex. an exception is throwed and I want to log it? Aren't we ignore valueable exception data by using Result pattern?
The idea is that you only replace exceptions that are not that “exceptional”.
That means that you have the Result pattern on the expected paths. You can still produce telemetry there. The difference is that doesn't come from a bulky exception. But, do I need something like the stack trace for an expected case?!
@@gui.ferreira Right, maybe we need bulky exceptions in the first phases of the project but not in the final product. Thanks.
This - I have my own implementation (unfortunately) in company code base but it fulfills the goals of don’t throw if you can return error
The only unsolved problem due to time constraints is what if want to have different behavior based on error code (rn it is ugly if statement in a few places)
To be satisfied with result type in .NET you need to add a little bit of ext method on Task type also you can chain them if you want to
Exactly. Maybe with discriminated unions, it will be easier 🤞
¿Why do you recommend using a library? Because that is the approach i want to take but it´s hard to pitch it to the team.
I tend to adopt solid libraries. I prefer to contribute to the ecosystem than build myself.
However, if bringing a new library is friction, for such a small feature, I would build my simple version of it.
Might just be me, but I do not see the point of wrapping the result of a task in a result object, when the class `Tast` is already a result container.
From what I can tell, tasks, futures and promises are all implementations of the result pattern on operations that are supposed to return a value in the future and for which we want to process differentiated treatment if it completed successfully or if it errored out. Tasks do not need to run asynchronously neither, though it should be assumed that they could, but one can always not « await » them and just work with the result type itself.
+1 for result pattern
Rust influencing C# as well? 👍
It's good to absorb what others do right 😉
@@gui.ferreiraCouldn't agree more.
So the industry gave up on checked exceptions and then realized that code can fail without the caller knowing about the potential failure points. Now we're coming up with an entire new concept (that BTW loses the stack trace information), all to avoid just using checked exceptions that the language supports by design?
Not really… there's a place for exceptions. I have a video on it here
th-cam.com/video/cKa6nCuh7cc/w-d-xo.html
Exceptions should only be thrown for faulthy code, not expectable behavior. For those the Result pattern exists.
The results pattern is fucking idiotic. Just use exceptions for exception cases and then your response types aren't polluted with worthless structures.
Maybe in rare occasions it is suitable, but newbies throwing it everywhere is infuriating.
please dont
Great content! Thanks like always!
My pleasure!