Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@mohammedelrasheed84985 ай бұрын
00:02 Exceptions are meant for exceptional situations 02:06 Instead of exceptions, consider using the result pattern for error handling 04:07 Handling validation errors with exceptions 06:10 Handling exceptions using an IExceptionHandler interface in .NET 8. 08:03 Performance test using k6 for API requests 10:02 Implement alternative error handling method without throwing exceptions 12:05 Utilize existing libraries or create custom abstractions for handling exceptions efficiently 14:10 Using result pattern is faster than exceptions for flow control 16:12 Consider using result object instead of exceptions for performance
@MilanJovanovicTech5 ай бұрын
Thanks!
@br3nto5 ай бұрын
Like everything, exceptions are a trade-off. In one codebase, we went from Exceptions to success/failure wrappers, then back to Exceptions after about 2 years. Exceptions were waaaay simpler, and the code was drastically reduced when we removed the success/failure wrappers. The code was easier to follow and find bugs when we used exception because there was less of/else/switch control flow, and the return types were simpler. The apps were also easier to debug because breakpoints, and stepping through code was simpler when using exceptions as there was less indirection.
@br3nto5 ай бұрын
To be fair we were also using Dapper which was adding an annoying amount of unnecessary indirection.
@br3nto5 ай бұрын
Another point is that most of the time, your request should be going through the success state rather than the failure state. Usually the failure state is identified early, where as the success state has the expensive operations after all the failure states have been identified.
@MilanJovanovicTech5 ай бұрын
"stepping through code was simpler when using exceptions as there was less indirection" - isn't this counterintuitive, since exceptions will essentially throw you to an entirely different part of the code (indirection)? Whereas with a return statement, you go back to where you called the current method from.
@br3nto5 ай бұрын
@@MilanJovanovicTech maybe at the start… but then extra abstractions start getting added to make handling different and similar responses consistent, and more and more things eventually get layered on top. Exceptions handlers were easy because there was a single place where exceptions got mapped to error responses and response codes. Again, I think having other libraries like Dapper mixed in exacerbated the problem. Our code never looked like your example. We had thin controller actions.
@br3nto5 ай бұрын
@@MilanJovanovicTech it just occurred to me that returning errors as part of your return type is the same conceptually as checked exceptions in Java. Different syntax obviously, but the same type of patterns emerge. Any caller must handle your error, return it, or wrap and return it. In that sense it’s also like the “coloured function” problem that the Primagen talked about when using async; the pattern spreads. It’s hard to contain and isolate its usage. It’s almost like an all or nothing. So that’s another reason why I like exceptions over returning error values. There’s just less code.
@reginaldo85974 ай бұрын
I think the gained performance won't matter as much in a real world enterprise solution and I'll explain why. The selected premise is invalid, it sets up an application to fail hundreds of thousands of times per minute in order to be true. I understand that was done to highlight how expensive they are, but an application is not expected to fail like that. We generaly see a couple of exceptions once in a while, just like you said, they are for exceptional cases. If the application is failing like that, it means something is wrong with the caller or the application. Adding so much boilerplate for that is not worth it and will only polute the code.
@MilanJovanovicTech4 ай бұрын
Balanced argument, makes sense. It was never about performance for me (but I did want to make this video, though) - I much prefer the explicitness of Result pattern. With discriminated unions coming to C#, I think this approach will only become more popular.
@reginaldo85974 ай бұрын
@@MilanJovanovicTech fair enough, it was a good video, I didn't know it was so expensive. I personally feel pain having to use wrappers everywhere, makes the code more complex to maintain, specially for junior developers. Java pulled something similar with the Optional return types. I wish they did something like Typescript union types, rather than adding a wrapper for that. If C# adds something similar to Typescript, then I would have to agree that it will only become more popular.
@poneciak573 ай бұрын
After throwing an exception non garbage collected languages like C++ for example needs to do something with memory (garbage collected too) so they perform what is called "stack unwinding" and it can lead to some errors like memory leaks because pointers will get unwinded from the stack. Like its easy to say that you should watch out for this but thats why we have the Result pattern (or whatever it is called)
@mionel237Ай бұрын
you're wrong. too tired to explain but you can try saying the same thing while looking into mirror. keep up the good work milan, stay awesome
@HombrexGSP14 күн бұрын
Excellent video, this is actually common practice in functional languages, where typed errors are preferred over exceptions! Of course the latter have its uses but this is actually a really good demonstration of why things like the Result type exists in the first place. Good one!
@MilanJovanovicTech14 күн бұрын
Functional languages got it right
@daneel_olivaw4 ай бұрын
As you mentioned in your final remarks if we are doing client-side validation, the number of server-side exceptions should be minimal. With result objects, we have 1. Arguably less readable/maintainable code. Having result checks on each layer is way less fun than having a middleware that handles all exceptions in one place and returns the appropriate result to the user. 2. More memory allocations, since ALL happy paths are now boxed with the Result object. Try testing with a 5% failure rate, and compare memory allocations. In my benchmark, using ErrorOr, resulted in 10x memory allocations. 3. Lost stack trace
@MilanJovanovicTech4 ай бұрын
1. I don't find it less readable, but that'll be a personal opinion. I agree that layering exacerbates the problem, so the obvious solution is not to have many layers - which is doable. 2. Yes, that's expected. 3. We can add the stack trace to the result at time of creation.
@vunder844 ай бұрын
The biggest problem of this video is that the author misleads the audience that "you should not use exceptions because they slow down your app". This completely incorrect statement! Exceptions cost a lot, but the result in k6 depends on your app arch+tech solutions. In the same way I can prove that the SIMD instructions slow down your app by testing app using double and SIMD to sum and mul numbers in the "calculator app" It is important to tell what solution/technique is better to use in which cases/scenarios
@MilanJovanovicTech4 ай бұрын
You're right, there are far more important reasons not to use exceptions
@pedroferreira92345 ай бұрын
and how many applications go behond 1k request a second? Does the applications you built do 1/2k/s? Be pragmatic and default to exception handling first. There are many other ways (infrastructure) to increase request/s very cheaply , and if, somehow, this really gets to be a problem, then c# was probably a bad choice.
@MilanJovanovicTech5 ай бұрын
I still don't recommend using exceptions for flow control. Exceptions are for exceptional situations. Use result pattern (or similar) for expected and common errors. Going with exceptions ends up with dozens or hundreds of custom exception classes. Using generic exceptions ends up with lots of duplication. With errors as types, you can group them in a single file with much less ceremony than creating a new exception class.
@sameerband29335 ай бұрын
I would partially agree with you both. I would use the result pattern when it's a business case. For example user not found but I would use exception for something unexpected. For example dB connection, network, stream, anything related to communication, etc because exception would give me something more that I can later use may be to retry or change the approach
@patfre5 ай бұрын
Exception should only be used when something has actually gone wrong. Like when you try and access memory that isn’t the programs memory. Having a user not it exist doesn’t need to have an exception since the server doesn’t need it anyway it’s only the one requesting it and since it’s slower to do it it’s just worse. Besides the more you use it and the deeper the call stack the worse the penalty. No company will see the exception spam and think this is a qualified programmer because they don’t know simple optimization. The method also have benefits such as being simpler to understand the intent. Using exception will just lead to the server crashing needlessly because someone forgot a catch statement somewhere after a new exception was put in or changed and that’s expensive for a company because it could take hours to fix it all while no money is being made. So only if the server absolutely requires something it can’t get or do what it should do then it should throw an exception otherwise no.
@jamesbarrow5 ай бұрын
@@sameerband2933agreed. Result for application concerns, exception for infrastructure concerns. If an infrastructure concern becomes an application concern, then mapping to a result makes sense
@antonmartyniuk5 ай бұрын
When using exceptions your Service interface doesn't tell you that UserNotFoundException may be thrown. You could include this in code summary, but it can be quickly become outdated and not all devs write the code summary (and that's bad). With a result pattern your interface is explicit that you gonna have errors in this method
@gfantin885 ай бұрын
Great video! In my case, most applications I write are in a controlled environment, so exceptions are really exceptions and a tiny portion of our responses. So, in my case, I find it hard to defend using results in every method on the chain.
@MilanJovanovicTech5 ай бұрын
That's perfectly acceptable. What do you do for errors (e.g., validation)?
@ajdinhusic25745 ай бұрын
Great video! however one thing to note: All these stats about requests per hour (800,000 vs 15 million) are still not realistic in a real-world scenario, because this means that ALL these requests fail. In a true setting though, a percentage of requests might fail, and some will succeed. Therefore the gap between the two situations isn't as big as we think in the first place, and the 800,000 r/s might be more toward a few-million r/s (depending on the api consumer behavior of course).
@MilanJovanovicTech5 ай бұрын
I kind of tried to summarize that in my closing remarks, appreciate your comment though.
@ajdinhusic25745 ай бұрын
@@MilanJovanovicTech I appreciate your videos too! Really good job, Milan!
@bogella22255 ай бұрын
Im not sure where I saw it, but congrats on being MVP again.
@MilanJovanovicTech5 ай бұрын
Thank you!
@anton-ivanchenko5 ай бұрын
I use exceptions in most of my methods. If an action needs to be attempted without throwing an exception, then I create a separate "Try..." method. I don't see the point of using the Result type everywhere, as it adds dozens of checks to the code after each operation. But I agree that an exception should not control the flow of execution. When an exception occurs, it should reach the top of the call stack and return the result to the user (if possible).
@MilanJovanovicTech5 ай бұрын
Makes sense ☝️
@adolfomartin54565 ай бұрын
This is a functional solution, that you are using in other places: I usually program in JavaScript and Promises is like Result, they can be resolved or rejected, the if/else logic you said is somehow hidden with Promises.
@anton-ivanchenko5 ай бұрын
@@adolfomartin5456 In C#, tasks can be used in a similar way to promises in JavaScript. But then there is the problem of large nesting of the code, and a lot of inconvenience. In JavaScript, you can also put await before promises and in that case you will still need a type similar to "Result". If you need to do a dozen asynchronous operations sequentially, then your approach will require a dozen levels of nesting.
@oshastitko4 ай бұрын
What about the Open/Closed Principle in the Result Pattern? If we need to add one more result option, we have to modify a class used by the Result Pattern....
@MilanJovanovicTech4 ай бұрын
Nah, we'd have a Result and Result in reality. That takes care of both cases.
@oshastitko4 ай бұрын
@@MilanJovanovicTech The class should be closed for modification and open for extension. For example, if a subclass of our class introduces additional result options, and if T is an enum or something similar (which we can't inherit), how does this fit with the Open/Closed Principle?
@marko57343 ай бұрын
@@oshastitkoYou just exposed the flaws of inheritance. The derived class lose flexibility beacuse it's obligated to use parameters from the base constructor which doesn't need, so it cannot override. So the only option is to introduce new parameters in the base constructor and make most the parameters nullable, or you add new abstract void method, which again as you pointed out will break ocp. Maybe inheritance is not the best option here beacuse result pattern can be so diverse, and instead, object composition should be used?
@janjoska25495 ай бұрын
I would like to know what are the criteria for your decision to use result pattern in certain parts of your software. For example, a method allocates 1MB array. This operation can clearly fail as there might not be enough memory available. Will you use Result pattern for this? What will you do when you clearly cannot perform your intended operation? How will you interrupt work that cannot be finished. Will you place Result return object to basicly every method in call chain up to the entry point of your application? What if you forget to evaluate the result somewhere, system will throw null reference exceptions someplace else.
@MilanJovanovicTech5 ай бұрын
Wouldn't that throw an OutOfMemoryException anyway? "What will you do when you clearly cannot perform your intended operation?" - Can I return a meaningful error to the user? If yes, return an error. If not throw an exception. "Will you place Result return object to basicly every method in call chain up to the entry point of your application?" - Yes, that's what will happen. "What if you forget to evaluate the result somewhere, system will throw null reference exceptions someplace else." - Write a test so you don't forget.
@chanep14 ай бұрын
Well done, exposing real pors and cons
@MilanJovanovicTech4 ай бұрын
Thanks!
@Rizkiaqa5 ай бұрын
Great Video ! Almost my code using Exception to bypass all code after error occurs, then handle it by try..catch . We don't consider receiving request speed because the number of users arenot so many. Now the code is live production. Better not touching it anymore as long as it is not broke :D
@MilanJovanovicTech5 ай бұрын
Agreed 😁
@kyreehenry92024 ай бұрын
@Rizkiaqa Spoken like a true software developer 😅
@Rizkiaqa4 ай бұрын
@@kyreehenry9202 yeah. :D
@eu.jeanoliveira5 ай бұрын
Hi, Milan Jovanović. What is your opinion about exceptions in parameter validation during object initialization? Since there is a trend that says you should not create an object with an invalid state. By not using the exceptions approach, you would have to use something like FluentValidation. Which, in short, creates an object with a possible invalid state and then checks whether or not it is invalid.
@MilanJovanovicTech5 ай бұрын
You could also expose a factory method, that returns a failure Result/Error in case some of the input arguments are invalid
@arunnair75844 ай бұрын
Yes. I never create an object in an invalid state. All parameters are checked before creating the object. If any attributerequires a change, a new object is created. There are no setters or getters in the object. Immutable objects are the norm. Saves you a lot of headaches especially in products that have to be maintained for years.
@CreativeB34ST5 ай бұрын
I would love to see a follow up video on this that goes deeper into using exceptions for handling invariants and other validation checks in a DDD Domain Layer. In this case I prefer exceptions because I don't want to dirty my whole domain layer return types with a Result type. DDD states that the domain layer should use domain objects as arguments and return types. So in my eyes, (domain) exceptions are the only way to go.
@MilanJovanovicTech5 ай бұрын
"DDD states that the domain layer should use domain objects as arguments and return types" - where does it state it? I don't recall reading something like this.
@pinyorungoral60375 ай бұрын
How you handle flow when your code nested call service layer 3-4 level? And did you try disable log and test again?
@MilanJovanovicTech5 ай бұрын
Using exceptions there's typically a top-level handler. With Result pattern, you'd short-circuit the failure from level 3 upward.
@misters645113 күн бұрын
Thank you for this video. But what is Error structure?
@MilanJovanovicTech12 күн бұрын
record Error(string Code, string Description, ErrorType Type);
@sokka74604 ай бұрын
No, exceptions are for what they are, they bubble up to ensure some one catch and manages the exception. Result pattern doesn't. Exceptions for everything that needs to be handled or the application crahses
@MilanJovanovicTech4 ай бұрын
Or you'll keep getting a 500 response?
@Koshala1235 ай бұрын
Asking just to polish up my knowledge , imagine we are using a try catch block. Inside the catch block we are not throwing an exception but returning an int value or something Is that bad too. Does that fall under the same category as this
@MilanJovanovicTech5 ай бұрын
@@Koshala123 Not really. You catch an exception, know how to handle it, and return a meaningful response
@krccmsitp28845 ай бұрын
A simple alternative to a Result type might be to return a tuple like (T? Value, string? Error) where either of the elements is null. This can be simply checked with a switch expression and pattern matching.
@tehwabbbit5 ай бұрын
Honestly, just use the exception type as that's what it's designed for. This video is not good advice.
@krccmsitp28845 ай бұрын
@@tehwabbbit exceptions are for exceptional situations, not for business rules.
@DanWalshTV5 ай бұрын
That's the standard approach in Golang
@krccmsitp28845 ай бұрын
@@DanWalshTV never used that, but good to know
@MilanJovanovicTech5 ай бұрын
How do we maintain consistency with a Tuple, though? In a large team, devs can do weird things.
@rohit7045 ай бұрын
I am just thinking , who will result pattern will work with Que and DLQ ? If errors comes it should stop the process.
@MilanJovanovicTech5 ай бұрын
What does messaging have to do with this? 🤔
@beyaz14045 ай бұрын
Realy great video! Clear explanation ! I wnt to ask question. In this functional error handling; how to manage response checks? .. .. .. var result = callX(); if(result.Sucess) { return result.ErrorMessage; } .. .. in this case 5 time call generates 20 line of error check. is there any good solution for this problem? espacially c# language
@MilanJovanovicTech5 ай бұрын
What's wrong with this solution?
@beyaz14045 ай бұрын
@@MilanJovanovicTech - Code sizes growing very fast, many call generates extra 5 line code for error check. this reduce readability. - occurs complex variable names like userNameResult & userName
@tiagomabango5 ай бұрын
You are the best, very nice. Thanks for the content, I love that!
@MilanJovanovicTech5 ай бұрын
@@tiagomabango You bet! 😁
@DanielOpitz5 ай бұрын
I'm not sure if that minimal performance gain for very rare cases is worth the effort and extra dependency. Also logging will become complexer with the shown concept.
@MilanJovanovicTech5 ай бұрын
@@DanielOpitz Some will find the real value in this, good enough for me
@helshabini5 ай бұрын
Great video. I've always known that exceptions were expensive, but never imagined the difference would be that huge. What are your views on Tuples (containing an error) as simple return types rather than the complexity of Result types? Similar to Go's error handling methodology?
@MilanJovanovicTech5 ай бұрын
Result standardizes the response from your methods. Tuples are awesome, but I'm afraid of maintaining consistency in a large team.
@БорисСлавков-д3ш5 ай бұрын
I've never seen someone using exceptions as a result code, yes there is more work to be done, but what would say about ppl using a b c for naming their variables... Naming a variable properly is also a lot of work...
@MilanJovanovicTech5 ай бұрын
Not sure if you've been lucky not to see this in use, or... It's almost a standard, I'm afraid 😅
@higoramorim854 ай бұрын
Amusing concepts, I saw something like this with Kotlin and Ruby, uses exceptions when it really needs, best regards
@MilanJovanovicTech4 ай бұрын
Thanks!
@botyironcastle5 ай бұрын
use a functional language if you want to use the result pattern , c# is not meant for that
@MilanJovanovicTech5 ай бұрын
I'll stick with C#
@pawesydorow9335 ай бұрын
How it's should work with DDD when we have rich domain with many rules, and method return some value for us?
@MilanJovanovicTech5 ай бұрын
Errors are a good approach here to describe possible failure scenarios, if that makes sense for your use case.
@juniorzucareli5 ай бұрын
For this example in the video, I totally agree with not using exceptions, but for domain classes, I'm totally against using result, for me it has to be exception. If used for domain classes, the consumer of the class will have to do ifs all the time, this is hell, and I think it's unnecessary, normally input validations are done in higher layers, like controllers for web api. If you reached the domain class, it is understood that the inputs are ok, and if for some reason, the inputs arrived at the domain class with invalid data, an exception must be thrown, this applies to the class constructor, the methods within and etc...
@MilanJovanovicTech5 ай бұрын
I can work with that ☝️
@CesarDemi815 ай бұрын
Totally agree. Domain classes are actually the only place where it's justified to throw exceptions because, as you stated, that really IS an exception. A previous validator should have catched an incorrect value and the domain validations are the last line of defense prior to save data in an inconsistent state. The rest of things, like validating input from an endpoint or checking whether the item you're trying to edit or delete actually exist, then a results-based flow should be followed.
@juniorzucareli5 ай бұрын
Yes!! I have an example that may cause problems with returning result from the domain class: Imagine that you have a method called calculateAmount within the order class, and this method receives, for example, items and a discount coupon to calculate the value, if the values passed by parameter are invalid, and the method returns a result, forcing the consumer of the class method put an if to check, if the if is not done, and then there is a save in the database, this is a silent bug that can cause a lot of problems... (the example I gave was stupid, but the idea is valid and has happened to me several times)
@CesarDemi815 ай бұрын
@@juniorzucareli yeah, in that area, the convoluted work that brings along doesn't really add much value in exchange of all the effort that requires to handle it. At that point it's much more useful to throw as that never should have happened.
@matthewrossee5 ай бұрын
"if you reached the domain class, it is understood that the inputs are ok" why do you think so? a genuine question
@kyreehenry92024 ай бұрын
The result pattern feels cumbersome to me. Consider an application using a repository pattern, where the repository is standard and doesn’t involve use cases. In this setup, you have an abstraction layer-let's call it "services." This service layer interacts with repositories, handles validation, and, crucially, manages the conversion between DTOs and entity models. Using the result pattern in this context makes the code more complex and less readable. I've shifted from the result pattern to using exception handling instead.
@MilanJovanovicTech4 ай бұрын
The problem here is more about too many layers of indirection rather than the result pattern. But I get your point of view, and trust you've made the right decision. Do you have a global exception handler now?
@kyreehenry92024 ай бұрын
@@MilanJovanovicTech I like yours better
@yatsuk4 ай бұрын
If your service in 99% of time returns bad responses than yes - do not use exceptions. Otherwise there is no point to spend a time for fighting with exception because it is a rare case and performance issues will be in some another places - like slow db requests, caching, pools etc. And better to spend your time there.
@MilanJovanovicTech4 ай бұрын
Not the only reason to use Result: kzbin.info/www/bejne/jXSmnHiblK2saLs
@yatsuk4 ай бұрын
@@MilanJovanovicTech validation issue is still issue - in majority cases requests contain a proper json and validation does not fail.
@dionismendanha46495 ай бұрын
how to deal with trace in logs when not using exceptions?
@LordOfCoding5 ай бұрын
From the "Error" state back to the call state, you always add your call signature to a stack in the Result
@MilanJovanovicTech5 ай бұрын
You can log details from the Error, and even append a stack trace to the Result
@davidtaylor37715 ай бұрын
For years I have been doing what I refer to as "Exception driven development", where I model the core architecture via exception flows. This video has been a revelation that I might be doing something wrong.
@MilanJovanovicTech5 ай бұрын
I also believe in "if it ain't broke, don't fix it" 😁
@ASUSVOLT5 ай бұрын
Need to think about it... Thanks for video.
@MilanJovanovicTech5 ай бұрын
Check out some of my other videos on the Result pattern
@alexmotaufc38715 ай бұрын
With this the "stack trace" would be lost ?
@MilanJovanovicTech5 ай бұрын
You can always add it when creating the Result using Environment.StackTrace
@MaciejLisCK5 ай бұрын
@@MilanJovanovicTech But may make both solutions run at same time.
@omineirotech4 ай бұрын
I don’t think it was a trustable test, since it turns a exceptional situation (UserNotFound) into a situation that happens multiple times sequentially. Internally cache of the machine will change the results here… besides that, it is not usual thing at all.
@MilanJovanovicTech4 ай бұрын
How would you have structured it?
@MAUIMS-m4g5 ай бұрын
please sir, regarding DDD and aggregate like Order and OrderItems all methods for adding , updating and removing occurs on Frontend then sent back to backend as a patch to persist in database ,so DDD logic will be in Front-end not Back-end right? i.e DDD logic will be in JS or TS in case of react or angular. or C# but in DTOs in case of Blazor. Right ? or i misunderstood ?
@MilanJovanovicTech5 ай бұрын
Looks like you got just CRUD
@MAUIMS-m4g5 ай бұрын
@@MilanJovanovicTech API is CRUD !!! Post Get Put Delete
@SXsoft994 ай бұрын
programing is like food "ow that's not good for you, that's not good for you either, that affects you in that way, you should eat this and that, etc" same is with programing "ow that is a performance hog, ow that's an anti-patern, ow that is that"
@MilanJovanovicTech4 ай бұрын
What's your takeaway here?
@CRBarchager5 ай бұрын
Awesome video, Milan. I've surprised by the performance hit exception has. I knew they were slow but not by this much. I'm definately going to have rethink some of our solutions namely one that throws 100.000+ exceptions a day.
@MilanJovanovicTech5 ай бұрын
I'll do another benchmark with a remote server, to see how much of a difference it makes. Will post an update here.
@thanhnguyenduy783 ай бұрын
How can I get source code of this
@MilanJovanovicTech3 ай бұрын
For this, Patreon: www.patreon.com/milanjovanovic
@Rick-mf3gh5 ай бұрын
After all the work of cascading the Result result up and down the call stack, you still have to handle exceptions being thrown. And having used this technique in an enterprise level app, I can't express how much of a PITA it was. Extra code, complexityand risk with zero tangible benefits.
@MilanJovanovicTech5 ай бұрын
Handle exceptions as low-level as possible, if you know how to handle them. Unhandled exceptions (and caught by a global handler) aren't relevant since you don't know how to handle them. What did the rest of your team think of this approach? Someone had to introduce it.
@Rick-mf3gh5 ай бұрын
@@MilanJovanovicTech When I try to post a reply containing links to dotnetfiddle, my posts are not saved. 😥
@Rick-mf3gh5 ай бұрын
When I said "handle exceptions" I was referring to a global exception handler. 👍 As for what the team thought: We rapidly grew to hate it. But the guy that introduced it was not capable of admitting his mistakes. For example: Imagine a class used in multiple places in the codebase: dotnetfiddle id: wffxQD You then add validation: dotnetfiddle id: J5112m This code builds without warnings, but it is actually broken. To apply this change could require a significant cascading refactor due to ClassUsedByDozensOfOtherClasses now possibly returning a failure. And the compiler will not identify if you have missed handling a possible Failure. Accidentally missing a failure could have disastrous results. (I had to only post the dotnetfiddle ids because youtube appears to block posts with links.)
@Rick-mf3gh5 ай бұрын
@@MilanJovanovicTech When I said "handle exceptions" I was referring to a global exception handler. 👍 As for what the team thought: We rapidly grew to hate it. But the guy that introduced it was not capable of admitting his mistakes. For example: Imagine a class used in multiple places in the codebase: dotnetfiddle id: wffxQD You then add validation: dotnetfiddle id: J5112m This code builds without warnings, but it is actually broken. To apply this change could require a significant cascading refactor due to ClassUsedByDozensOfOtherClasses now possibly returning a failure. And the compiler will not identify if you have missed handling a possible Failure. Accidentally missing a failure could have disastrous results. (You'll have to create your own dotnetfiddle links based on the ids provided due to youtube seeming to block posts with links.)
@Rick-mf3gh5 ай бұрын
@@MilanJovanovicTech When I said "handle exceptions" I was referring to a global exception handler. 👍 As for what the team thought: We rapidly grew to hate it. But the guy that introduced it was not capable of admitting his mistakes.
@isacribeiro30715 ай бұрын
Valeu!
@MilanJovanovicTech5 ай бұрын
Much appreciated! 😁🍀
@vintage85 ай бұрын
It's becoming popular not throwing exceptions nowadays. Why do you expect that many exceptions to be thrown in the first place? Aren't you gonna handle exceptions that might occur in the front-end? Or are you worried that users might go into the javascript and modify it so that your back-end throws exceptions to decrease performance for other users?
@MilanJovanovicTech5 ай бұрын
Popular? I'm pretty much the only one advocating for using a Result object or similar. That doesn't mean not using exceptions (as explained in the video).
@vintage85 ай бұрын
@@MilanJovanovicTech KZbin always recommends me something about exceptions and I see that you didn’t respond to any of the questions I asked. Edit: forgot to add ErrorOr (@amantinband which also says the same thing about you), OneOf or any other packages does the same thing right? or am I mistaken? If these does not correlate to your video then my apologies.
@peeetee60125 ай бұрын
The tests have a weak point - they run locally. If you add real network latency, even just 5ms, the impact of exceptions expensiveness becomes less important. Returning of result object instead of throwing an exception looks ok when the code is trivial, but it becomes nightmare when the code is complex and deep.
@MilanJovanovicTech5 ай бұрын
1) Will do the same benchmark with a remote service, and post an update 2) Regarding deep call chains - I agree. Which is why I keep it as shallow as possible. Typically I have an endpoint-handler-entity. Comes out to passing the result 3x at most. The entity could also return void.
@patfre5 ай бұрын
I noticed you use “sealed” a lot and I will just want to let you know this is not the best thing to do. According to Microsoft themselves you should only ever use sealed if and only if there’s an inherent security risk to not this might be classes that are unsafe in nature or handle sensitive information. They also directly say that the performance gain you gain from it is not good enough of a reason to do it as someone might need to extend it later.
@MilanJovanovicTech5 ай бұрын
When they need to extend it, they can remove sealed. Just coding style, I like using it. Not forcing it up any one's throat.
@tomtoups5 ай бұрын
in modern processors, the context switch to Ring 0 or Kernel mode that happens when an exception is thrown is not as expensive as it used to be. For example, on x64 processors, the SYSCALL op code was added for this transition rather than the software interrupt op code. In many cases the exception doesn't even make a context switch at all. Now that doesn't mean you should be throwing or catching exceptions willy nilly, because that's bad for other reasons
@MilanJovanovicTech5 ай бұрын
The other reasons are what's more important
@redcrafterlppa3035 ай бұрын
I prefer the split rust does way better. In situations the application can't recover. The application simply terminates with a message set at the location the application fails. For everything requiring more graceful handling it uses the result type to let the calling function handle that condition. This as well provides the fail fast strategy as you can return a failing result in your guard clauses. With provided syntax to get the successful value with just 1 character of source code it's quite easy to continue with the happy path without any thought about the error.
@MilanJovanovicTech5 ай бұрын
A pragmatic approach
@necromancer1512 ай бұрын
just hint for all dev evangelist. Stop solve problems what nto a problems and make code simplier. We have bigger issues with our codes than db optimization to milliseconds or hanting down exceptions proper handling. it's like hanting down for extra ";" in code. Just stop it and do something useful instead. PS removing exceptions from code must be condier as antipattern due to increase code quantity and code quality
@MilanJovanovicTech2 ай бұрын
I respectfully disagree. But what content do you suggest I make? What do you consider useful? I'm dying to know.
@necromancer1512 ай бұрын
@@MilanJovanovicTech maybe something from real life? architectural design? maybe new features from java or edge cases? Review of common patterns/antipatterns? Database design best practices? tools overview... a lot.. let me know if you need more suggestions :P
@portusdelphini5 ай бұрын
Absolutely true for c++ thou
@MilanJovanovicTech5 ай бұрын
Haven't used C++ in ages (can't say I miss it)
@compman735 ай бұрын
Awesome same always
@MilanJovanovicTech5 ай бұрын
@@compman73 Thanks!
@fcoder15 ай бұрын
This is just a bs. If exceptions are too expensive for you, you should consider another language like rust or c
@MilanJovanovicTech5 ай бұрын
Watch the video again
@enricoroselino75575 ай бұрын
i prefer using manual result pattern, i also use it in flutter so i dont need to use dartz Either package... thank you for the benchmark ❤
@MilanJovanovicTech5 ай бұрын
Glad it was helpful!
@rafaspimenta5 ай бұрын
For me, exceptions should be the default approach. Only use results when performance becomes an issue
@MilanJovanovicTech5 ай бұрын
Even MSFT doesn't recommend using exceptions for flow control
@99aabbccddeeff5 ай бұрын
Agreed. If it is really needed, go with a result approach. Using the result approach everywhere, it's like avoiding LINQ because it is slower than usual iteration over collections.
@vmia1595 ай бұрын
Agreed. Throwing exception and catch with exception handler introduced in dotnet 8 just made the code looks cleaner as you can return error response anywhere and stop the execution. To me result pattern is just like props drilling in React where you pass the error from the bottom layer by layer until you reach the top.
@CesarDemi815 ай бұрын
That's terrible advice. It even makes the code harder to follow and understand since you have to track what catches it and how it handles it. Not even getting started on how to debug that.
@gabrielalejandrobernalpere30185 ай бұрын
Void is a most bigger lie in a software development. Any function, in a mathematical context, must be return a value. Void is a misconception introduced by POO, an bigger mistake. Also, the truly problem are the layers that only increases the change costs in effort terms. If you need make a change and it's necessary to review many layers, it's a problem, not by errors handling, rather than layers. And a exception, as their name it indicates, represent a truly exceptional behavior, is not for any error. The exception is a very poor control-flow mechanism because encourages break the main flow.
@egozMaster4 ай бұрын
oh just your opinion, and I think you dont work for any company
@MilanJovanovicTech4 ай бұрын
Carry on
@tehwabbbit5 ай бұрын
Do not do this... It goes against clean code, it adds complexity to a part of the system that os supposed to be clear, and the consuming code has to follow a different pattern. This is dangerous advice imo. Its a good thought exercise, but thats all
@MilanJovanovicTech5 ай бұрын
@@tehwabbbit If anything, exceptions go against clean code. They make a method dishonest. The caller doesn't know from the method signature if a method can throw an exception
@tehwabbbit5 ай бұрын
@@MilanJovanovicTech this is what XmlDoc comments are for in method headers, read by all IDEs automatically and standard practice in enterprise (and in many nuget packages), and if it's an endpoint utilising the data annotations that can feed into an OpenApi spec to state the possible returns. The only scenario it doesn't fulfil is a JS call to the backend catching the exception with the .fail() but arguably if you catch all exceptions on the server and return an error array in your DTO that's much cleaner for the consumer anyway.
@iliyan-kulishev5 ай бұрын
@@MilanJovanovicTech Unless you mention that in the method summary. But then how do you do this for, let's say, a particular implementation of a given abstraction ?
@user-rp9iis1en6h5 ай бұрын
When you will grow as a senior developer, you will learn mostly how to set up the project keeping third party libraries minimal.