Exceptions Are Extremely Expensive… Do This Instead

แชร์
ฝัง
  • เผยแพร่เมื่อ 21 พ.ย. 2024

ความคิดเห็น • 183

  • @MilanJovanovicTech
    @MilanJovanovicTech  4 หลายเดือนก่อน +5

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

  • @br3nto
    @br3nto 4 หลายเดือนก่อน +27

    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 4 หลายเดือนก่อน

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

    • @br3nto
      @br3nto 4 หลายเดือนก่อน +3

      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  4 หลายเดือนก่อน +3

      "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 4 หลายเดือนก่อน

      @@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 4 หลายเดือนก่อน +4

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

  • @mohammedelrasheed8498
    @mohammedelrasheed8498 4 หลายเดือนก่อน +4

    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

  • @daneel_olivaw
    @daneel_olivaw 3 หลายเดือนก่อน +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  3 หลายเดือนก่อน +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.

  • @vunder84
    @vunder84 3 หลายเดือนก่อน +3

    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  3 หลายเดือนก่อน

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

  • @reginaldo8597
    @reginaldo8597 3 หลายเดือนก่อน +9

    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  3 หลายเดือนก่อน +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 3 หลายเดือนก่อน

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

    • @poneciak57
      @poneciak57 3 หลายเดือนก่อน

      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
      @mionel237 27 วันที่ผ่านมา

      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

  • @bogella2225
    @bogella2225 4 หลายเดือนก่อน +3

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

  • @gfantin88
    @gfantin88 4 หลายเดือนก่อน +6

    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  4 หลายเดือนก่อน

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

  • @ajdinhusic2574
    @ajdinhusic2574 4 หลายเดือนก่อน +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  4 หลายเดือนก่อน +3

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

    • @ajdinhusic2574
      @ajdinhusic2574 4 หลายเดือนก่อน

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

  • @chanep1
    @chanep1 3 หลายเดือนก่อน +1

    Well done, exposing real pors and cons

  • @anton-ivanchenko
    @anton-ivanchenko 4 หลายเดือนก่อน +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  4 หลายเดือนก่อน

      Makes sense ☝️

    • @adolfomartin5456
      @adolfomartin5456 4 หลายเดือนก่อน +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 4 หลายเดือนก่อน

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

  • @Rizkiaqa
    @Rizkiaqa 4 หลายเดือนก่อน +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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน +1

      Agreed 😁

    • @kyreehenry9202
      @kyreehenry9202 3 หลายเดือนก่อน

      @Rizkiaqa Spoken like a true software developer 😅

    • @Rizkiaqa
      @Rizkiaqa 3 หลายเดือนก่อน

      @@kyreehenry9202 yeah. :D

  • @sokka7460
    @sokka7460 3 หลายเดือนก่อน +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

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 หลายเดือนก่อน +2

      Or you'll keep getting a 500 response?

  • @CreativeB34ST
    @CreativeB34ST 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

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

  • @krccmsitp2884
    @krccmsitp2884 4 หลายเดือนก่อน

    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 4 หลายเดือนก่อน +2

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

    • @krccmsitp2884
      @krccmsitp2884 4 หลายเดือนก่อน +1

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

    • @DanWalshTV
      @DanWalshTV 4 หลายเดือนก่อน +1

      That's the standard approach in Golang

    • @krccmsitp2884
      @krccmsitp2884 4 หลายเดือนก่อน

      @@DanWalshTV never used that, but good to know

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

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

  • @juniorzucareli
    @juniorzucareli 4 หลายเดือนก่อน +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  4 หลายเดือนก่อน +3

      I can work with that ☝️

    • @CesarDemi81
      @CesarDemi81 4 หลายเดือนก่อน +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 4 หลายเดือนก่อน +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 4 หลายเดือนก่อน +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 4 หลายเดือนก่อน

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

  • @pedroferreira9234
    @pedroferreira9234 4 หลายเดือนก่อน +43

    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  4 หลายเดือนก่อน +23

      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 4 หลายเดือนก่อน +9

      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 4 หลายเดือนก่อน +2

      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 4 หลายเดือนก่อน

      ​@@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 4 หลายเดือนก่อน +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

  • @SXsoft99
    @SXsoft99 3 หลายเดือนก่อน

    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"

  • @yatsuk
    @yatsuk 3 หลายเดือนก่อน

    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  3 หลายเดือนก่อน

      Not the only reason to use Result: th-cam.com/video/WCCkEe_Hy2Y/w-d-xo.html

    • @yatsuk
      @yatsuk 3 หลายเดือนก่อน

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

  • @janjoska2549
    @janjoska2549 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

      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.

  • @higoramorim85
    @higoramorim85 3 หลายเดือนก่อน

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

  • @eu.jeanoliveira
    @eu.jeanoliveira 4 หลายเดือนก่อน +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  4 หลายเดือนก่อน +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 4 หลายเดือนก่อน +1

      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.

  • @botyironcastle
    @botyironcastle 4 หลายเดือนก่อน +1

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

  • @davidtaylor3771
    @davidtaylor3771 4 หลายเดือนก่อน

    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 หลายเดือนก่อน +4

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

  • @Rick-mf3gh
    @Rick-mf3gh 4 หลายเดือนก่อน +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  4 หลายเดือนก่อน

      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 4 หลายเดือนก่อน

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

    • @Rick-mf3gh
      @Rick-mf3gh 4 หลายเดือนก่อน

      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 4 หลายเดือนก่อน

      @@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 4 หลายเดือนก่อน

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

  • @ASUSVOLT
    @ASUSVOLT 4 หลายเดือนก่อน

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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน +1

      Check out some of my other videos on the Result pattern

  • @oshastitko
    @oshastitko 3 หลายเดือนก่อน

    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  3 หลายเดือนก่อน +1

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

    • @oshastitko
      @oshastitko 3 หลายเดือนก่อน +1

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

    • @marko5734
      @marko5734 2 หลายเดือนก่อน

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

  • @kyreehenry9202
    @kyreehenry9202 3 หลายเดือนก่อน

    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  3 หลายเดือนก่อน

      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 3 หลายเดือนก่อน

      @@MilanJovanovicTech I like yours better

  • @user-rp9iis1en6h
    @user-rp9iis1en6h 4 หลายเดือนก่อน

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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

      Yes, it's best to code everything from scratch

  • @helshabini
    @helshabini 4 หลายเดือนก่อน +2

    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  4 หลายเดือนก่อน +1

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

  • @pinyorungoral6037
    @pinyorungoral6037 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน +3

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

  • @tiagomabango
    @tiagomabango 4 หลายเดือนก่อน +1

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

  • @DanielOpitz
    @DanielOpitz 4 หลายเดือนก่อน +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  4 หลายเดือนก่อน

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

  • @БорисСлавков-д3ш
    @БорисСлавков-д3ш 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

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

  • @CRBarchager
    @CRBarchager 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

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

  • @omineirotech
    @omineirotech 3 หลายเดือนก่อน

    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.

  • @vintage8
    @vintage8 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

      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 4 หลายเดือนก่อน

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

  • @Koshala123
    @Koshala123 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

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

  • @rohit704
    @rohit704 4 หลายเดือนก่อน

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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

      What does messaging have to do with this? 🤔

  • @peeetee6012
    @peeetee6012 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

      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.

  • @dionismendanha4649
    @dionismendanha4649 4 หลายเดือนก่อน

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

    • @LordOfCoding
      @LordOfCoding 4 หลายเดือนก่อน

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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

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

  • @beyaz1404
    @beyaz1404 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

      What's wrong with this solution?

    • @beyaz1404
      @beyaz1404 4 หลายเดือนก่อน

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

  • @patfre
    @patfre 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน

      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.

  • @alexmotaufc3871
    @alexmotaufc3871 4 หลายเดือนก่อน

    With this the "stack trace" would be lost ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

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

    • @MaciejLisCK
      @MaciejLisCK 4 หลายเดือนก่อน

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

  • @necromancer151
    @necromancer151 หลายเดือนก่อน

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  หลายเดือนก่อน

      I respectfully disagree. But what content do you suggest I make? What do you consider useful? I'm dying to know.

    • @necromancer151
      @necromancer151 หลายเดือนก่อน

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

  • @pawesydorow933
    @pawesydorow933 4 หลายเดือนก่อน

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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

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

  • @thanhnguyenduy78
    @thanhnguyenduy78 2 หลายเดือนก่อน

    How can I get source code of this

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 หลายเดือนก่อน

      For this, Patreon: www.patreon.com/milanjovanovic

  • @fcoder1
    @fcoder1 4 หลายเดือนก่อน

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

  • @tomtoups
    @tomtoups 4 หลายเดือนก่อน

    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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

      The other reasons are what's more important

  • @redcrafterlppa303
    @redcrafterlppa303 4 หลายเดือนก่อน

    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.

  • @MAUIMS-m4g
    @MAUIMS-m4g 4 หลายเดือนก่อน

    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 ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

      Looks like you got just CRUD

    • @MAUIMS-m4g
      @MAUIMS-m4g 4 หลายเดือนก่อน

      @@MilanJovanovicTech
      API is CRUD !!!
      Post Get Put Delete

  • @compman73
    @compman73 4 หลายเดือนก่อน

    Awesome same always

  • @portusdelphini
    @portusdelphini 4 หลายเดือนก่อน

    Absolutely true for c++ thou

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน

      Haven't used C++ in ages (can't say I miss it)

  • @rafaspimenta
    @rafaspimenta 4 หลายเดือนก่อน +6

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

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 หลายเดือนก่อน +4

      Even MSFT doesn't recommend using exceptions for flow control

    • @99aabbccddeeff
      @99aabbccddeeff 4 หลายเดือนก่อน +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 4 หลายเดือนก่อน +2

      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 4 หลายเดือนก่อน +1

      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 4 หลายเดือนก่อน +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 4 หลายเดือนก่อน

    Valeu!

  • @enricoroselino7557
    @enricoroselino7557 4 หลายเดือนก่อน

    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 ❤

  • @egozMaster
    @egozMaster 3 หลายเดือนก่อน

    oh just your opinion, and I think you dont work for any company

  • @tehwabbbit
    @tehwabbbit 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน +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 4 หลายเดือนก่อน

      @@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 4 หลายเดือนก่อน

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