Це відео не доступне.
Перепрошуємо.

Exceptions Are Extremely Expensive… Do This Instead

Поділитися
Вставка
  • Опубліковано 17 сер 2024
  • Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
    Join a community of 1000+ .NET developers: / milanjovanovic
    How should you handle errors in your code? This has been a topic of many discussions, and I want to share my opinion. One school of thought suggests using exceptions for flow control. This is not a good approach because it makes the code harder to reason about. The caller must know the implementation details and which exceptions to handle. Exceptions are for exceptional situations. Exceptions are also costly and degrade performance. If you don't believe me, we'll prove it in this video.
    GitHub thread: github.com/dot...
    Functional Error Handling in .NET With the Result Pattern
    www.milanjovan...
    Check out my courses:
    www.milanjovan...
    Read my Blog here:
    www.milanjovan...
    Join my weekly .NET newsletter:
    www.milanjovan...
    Chapters
    0:00 Are exceptions expensive?
    3:14 Exceptions for flow control
    7:38 Performance testing exceptions
    10:23 Handling errors with Result pattern
    14:11 Performance testing Result pattern
    15:30 Result pattern drawbacks

КОМЕНТАРІ • 172

  • @MilanJovanovicTech
    @MilanJovanovicTech  Місяць тому +5

    Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt

  • @daneel_olivaw
    @daneel_olivaw 9 днів тому +1

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  8 днів тому +2

      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.

  • @br3nto
    @br3nto Місяць тому +15

    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.

    • @br3nto
      @br3nto Місяць тому

      To be fair we were also using Dapper which was adding an annoying amount of unnecessary indirection.

    • @br3nto
      @br3nto Місяць тому +2

      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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +2

      "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.

    • @br3nto
      @br3nto Місяць тому

      @@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.

    • @br3nto
      @br3nto 28 днів тому +1

      @@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.

  • @gfantin88
    @gfantin88 Місяць тому +5

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      That's perfectly acceptable. What do you do for errors (e.g., validation)?

  • @ajdinhusic2574
    @ajdinhusic2574 Місяць тому +8

    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).

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +3

      I kind of tried to summarize that in my closing remarks, appreciate your comment though.

    • @ajdinhusic2574
      @ajdinhusic2574 Місяць тому

      @@MilanJovanovicTech I appreciate your videos too! Really good job, Milan!

  • @anton-ivanchenko
    @anton-ivanchenko Місяць тому +7

    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).

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      Makes sense ☝️

    • @adolfomartin5456
      @adolfomartin5456 Місяць тому +1

      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-ivanchenko
      @anton-ivanchenko Місяць тому

      @@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.

  • @pedroferreira9234
    @pedroferreira9234 Місяць тому +34

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +22

      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.

    • @sameerband2933
      @sameerband2933 Місяць тому +7

      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

    • @patfre
      @patfre Місяць тому

      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.

    • @jamesbarrow
      @jamesbarrow Місяць тому

      ​@@sameerband2933agreed. Result for application concerns, exception for infrastructure concerns. If an infrastructure concern becomes an application concern, then mapping to a result makes sense

    • @antonmartyniuk
      @antonmartyniuk Місяць тому +1

      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

  • @bogella2225
    @bogella2225 Місяць тому +3

    Im not sure where I saw it, but congrats on being MVP again.

  • @mohammedelrasheed8498
    @mohammedelrasheed8498 29 днів тому +1

    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

  • @sokka7460
    @sokka7460 21 день тому +3

    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

  • @juniorzucareli
    @juniorzucareli Місяць тому +11

    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...

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +3

      I can work with that ☝️

    • @CesarDemi81
      @CesarDemi81 Місяць тому +3

      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.

    • @juniorzucareli
      @juniorzucareli Місяць тому +1

      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)

    • @CesarDemi81
      @CesarDemi81 Місяць тому +1

      @@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.

    • @matthewrossee
      @matthewrossee Місяць тому

      "if you reached the domain class, it is understood that the inputs are ok" why do you think so? a genuine question

  • @Rizkiaqa
    @Rizkiaqa Місяць тому +3

    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

  • @reginaldo8597
    @reginaldo8597 17 днів тому +1

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  17 днів тому +2

      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.

    • @reginaldo8597
      @reginaldo8597 17 днів тому

      ​@@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.

  • @yatsuk
    @yatsuk 10 днів тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  10 днів тому

      Not the only reason to use Result: ua-cam.com/video/WCCkEe_Hy2Y/v-deo.html

    • @yatsuk
      @yatsuk 10 днів тому

      @@MilanJovanovicTech validation issue is still issue - in majority cases requests contain a proper json and validation does not fail.

  • @eu.jeanoliveira
    @eu.jeanoliveira Місяць тому +1

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +1

      You could also expose a factory method, that returns a failure Result/Error in case some of the input arguments are invalid

    • @arunnair7584
      @arunnair7584 26 днів тому

      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.

  • @CreativeB34ST
    @CreativeB34ST Місяць тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      "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.

  • @chanep1
    @chanep1 9 днів тому

    Well done, exposing real pors and cons

  • @oshastitko
    @oshastitko 12 днів тому

    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....

    • @MilanJovanovicTech
      @MilanJovanovicTech  12 днів тому

      Nah, we'd have a Result and Result in reality. That takes care of both cases.

    • @oshastitko
      @oshastitko 12 днів тому

      ​@@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?

  • @janjoska2549
    @janjoska2549 Місяць тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      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.

  • @DanielOpitz
    @DanielOpitz Місяць тому +4

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      @@DanielOpitz Some will find the real value in this, good enough for me

  • @kyreehenry9202
    @kyreehenry9202 23 дні тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  22 дні тому

      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?

    • @kyreehenry9202
      @kyreehenry9202 22 дні тому

      @@MilanJovanovicTech I like yours better

  • @botyironcastle
    @botyironcastle Місяць тому +1

    use a functional language if you want to use the result pattern , c# is not meant for that

  • @higoramorim85
    @higoramorim85 11 днів тому

    Amusing concepts, I saw something like this with Kotlin and Ruby, uses exceptions when it really needs, best regards

  • @vunder84
    @vunder84 12 днів тому

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  12 днів тому

      You're right, there are far more important reasons not to use exceptions

  • @krccmsitp2884
    @krccmsitp2884 Місяць тому

    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.

    • @tehwabbbit
      @tehwabbbit Місяць тому +1

      Honestly, just use the exception type as that's what it's designed for. This video is not good advice.

    • @krccmsitp2884
      @krccmsitp2884 Місяць тому +1

      @@tehwabbbit exceptions are for exceptional situations, not for business rules.

    • @DanWalshTV
      @DanWalshTV Місяць тому +1

      That's the standard approach in Golang

    • @krccmsitp2884
      @krccmsitp2884 Місяць тому

      @@DanWalshTV never used that, but good to know

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      How do we maintain consistency with a Tuple, though? In a large team, devs can do weird things.

  • @pinyorungoral6037
    @pinyorungoral6037 Місяць тому

    How you handle flow when your code nested call service layer 3-4 level? And did you try disable log and test again?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +3

      Using exceptions there's typically a top-level handler.
      With Result pattern, you'd short-circuit the failure from level 3 upward.

  • @CRBarchager
    @CRBarchager Місяць тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      I'll do another benchmark with a remote server, to see how much of a difference it makes. Will post an update here.

  • @SXsoft99
    @SXsoft99 18 днів тому

    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"

  • @Koshala123
    @Koshala123 Місяць тому

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      @@Koshala123 Not really. You catch an exception, know how to handle it, and return a meaningful response

  • @user-lp3jn7cz5o
    @user-lp3jn7cz5o Місяць тому

    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...

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      Not sure if you've been lucky not to see this in use, or...
      It's almost a standard, I'm afraid 😅

  • @rohit704
    @rohit704 29 днів тому

    I am just thinking , who will result pattern will work with Que and DLQ ? If errors comes it should stop the process.

  • @helshabini
    @helshabini Місяць тому +1

    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?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +1

      Result standardizes the response from your methods. Tuples are awesome, but I'm afraid of maintaining consistency in a large team.

  • @omineirotech
    @omineirotech 12 днів тому

    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.

  • @ASUSVOLT
    @ASUSVOLT Місяць тому

    Need to think about it... Thanks for video.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +1

      Check out some of my other videos on the Result pattern

  • @davidtaylor3771
    @davidtaylor3771 Місяць тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +4

      I also believe in "if it ain't broke, don't fix it" 😁

  • @tiagomabango
    @tiagomabango Місяць тому +1

    You are the best, very nice. Thanks for the content, I love that!

  • @Rick-mf3gh
    @Rick-mf3gh Місяць тому +3

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      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-mf3gh
      @Rick-mf3gh Місяць тому

      @@MilanJovanovicTech When I try to post a reply containing links to dotnetfiddle, my posts are not saved. 😥

    • @Rick-mf3gh
      @Rick-mf3gh Місяць тому

      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-mf3gh
      @Rick-mf3gh Місяць тому

      @@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-mf3gh
      @Rick-mf3gh Місяць тому

      @@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.

  • @pawesydorow933
    @pawesydorow933 Місяць тому

    How it's should work with DDD when we have rich domain with many rules, and method return some value for us?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      Errors are a good approach here to describe possible failure scenarios, if that makes sense for your use case.

  • @beyaz1404
    @beyaz1404 Місяць тому

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      What's wrong with this solution?

    • @beyaz1404
      @beyaz1404 Місяць тому

      @@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

  • @vintage8
    @vintage8 Місяць тому

    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?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      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).

    • @vintage8
      @vintage8 Місяць тому

      @@MilanJovanovicTech UA-cam 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.

  • @tomtoups
    @tomtoups Місяць тому

    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

  • @alexmotaufc3871
    @alexmotaufc3871 Місяць тому

    With this the "stack trace" would be lost ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      You can always add it when creating the Result using Environment.StackTrace

    • @MaciejLisCK
      @MaciejLisCK Місяць тому

      @@MilanJovanovicTech But may make both solutions run at same time.

  • @dionismendanha4649
    @dionismendanha4649 Місяць тому

    how to deal with trace in logs when not using exceptions?

    • @LordOfCoding
      @LordOfCoding Місяць тому

      From the "Error" state back to the call state, you always add your call signature to a stack in the Result

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      You can log details from the Error, and even append a stack trace to the Result

  • @peeetee6012
    @peeetee6012 Місяць тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      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.

  • @redcrafterlppa303
    @redcrafterlppa303 Місяць тому

    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.

  • @user-ls1ge5jd9g
    @user-ls1ge5jd9g Місяць тому

    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 ?

  • @patfre
    @patfre Місяць тому

    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.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому

      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.

  • @enricoroselino7557
    @enricoroselino7557 Місяць тому

    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 ❤

  • @romy4romy4
    @romy4romy4 Місяць тому

    Absolutely true for c++ thou

  • @compman73
    @compman73 Місяць тому

    Awesome same always

  • @fcoder1
    @fcoder1 Місяць тому

    This is just a bs. If exceptions are too expensive for you, you should consider another language like rust or c

  • @rafaspimenta
    @rafaspimenta Місяць тому +6

    For me, exceptions should be the default approach. Only use results when performance becomes an issue

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +3

      Even MSFT doesn't recommend using exceptions for flow control

    • @99aabbccddeeff
      @99aabbccddeeff Місяць тому +2

      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.

    • @vmia159
      @vmia159 Місяць тому +1

      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.

    • @CesarDemi81
      @CesarDemi81 Місяць тому

      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.

    • @gabrielalejandrobernalpere3018
      @gabrielalejandrobernalpere3018 Місяць тому +2

      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.

  • @isacribeiro3071
    @isacribeiro3071 Місяць тому

    Valeu!

  • @tehwabbbit
    @tehwabbbit Місяць тому

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  Місяць тому +3

      @@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

    • @tehwabbbit
      @tehwabbbit Місяць тому

      @@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-kulishev
      @iliyan-kulishev Місяць тому

      @@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 ?

  • @dfytq
    @dfytq Місяць тому

    When you will grow as a senior developer, you will learn mostly how to set up the project keeping third party libraries minimal.