Completely Get Rid of Exceptions Using This Technique

Поделиться
HTML-код
  • Опубликовано: 23 ноя 2024

Комментарии • 171

  • @MilanJovanovicTech
    @MilanJovanovicTech  5 месяцев назад +5

    Get the source code for this video for FREE → the-dotnet-weekly.ck.page/rop
    Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt

  • @antonmartyniuk
    @antonmartyniuk 5 месяцев назад +10

    This is a video made-in-heaven for all the functional programming lovers. Nicely done!

  • @abdushakoor0099
    @abdushakoor0099 5 месяцев назад +3

    two interesting things i learned from your videos.
    1. Vertical Slice architecture
    2. Railway-oriented programming

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 месяца назад +1

      Awesome, glad you're finding new ideas 😁

    • @abdushakoor0099
      @abdushakoor0099 4 месяца назад

      @@MilanJovanovicTech yes I've been working with Either monad in flutter. Keep up the good work

  • @eugene5096
    @eugene5096 5 месяцев назад +7

    I was using it and its a clean and nice way of doing complicated logic. Unfortunetly for most of the team this was not welcomed as considered too complicated. Its so hard to start thinking in functional way these days

    • @paarma1752
      @paarma1752 5 месяцев назад +2

      I have the same experience. ROP and other functional concepts are actually quite hard. Once dookie hits the fan and your team is under time pressure, devs start cutting corners and finding workarounds. The ROP model that was initially so beautiful and pure suddenly becomes everyone's nightmare full of nasty hacks. Imho this approach just doesn't stand time that well...

    • @gpzim981
      @gpzim981 5 месяцев назад

      Horrible. Mixing function and OO causes more problem and most of the times devs bringing it to the code base are literally trying to resolve problems that doesn’t exist.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      ​@@gpzim981the style it replaced wasn't even oo
      You're mixing that up with general flow of control

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +4

      Skill issue

    • @arunnair7584
      @arunnair7584 5 месяцев назад

      True. I had faced this problem too. But if I showed them an end-to-end example of this, they usually accepted this approach.

  • @r0bertdenir0
    @r0bertdenir0 4 месяца назад

    The problem with using the Result pattern in C# is that the language doesn't give us the syntax to enforce it.
    Historically C# reference types have been "weak" in the sense that a string could be a (string or null).
    That has been fixed with nullable reference types.
    Now a value that could be null must be explicitly defined as being nullable (string?).
    But functions are still "weak" contracts. A function that returns a string can either (return a string OR raise an exception).
    Result doesn't change that.
    A function that returns Result can still (return Result or raise an exception).
    We need some mechanism at the language level where the caller knows that when a function returns Result, there is no possibility of an exception.
    That would be a "strong" contract.
    "async" kind of does this for "Task".
    An async Task function will only raise the exception when it is awaited.
    Unfortunately, a caller can't be confident that a function that returns Task is an async function that won't raise an exception.
    Only the async keyword creates the state machine to wrap the exception, but a function can return Task without using async, which could raise an exception directly.
    Perhaps this might be done with source generators or IL weaving?
    Are there any Result implementations that provide this functionality of "strong" contracts?

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 месяца назад

      I don't think you will find what you're looking for in the open source world. Best we can do is accept that exception "can" happen, and we can deal with them accordingly.

    • @r0bertdenir0
      @r0bertdenir0 4 месяца назад

      ​@@MilanJovanovicTech I do like the Result pattern & think it's a better way to explicitly declare that a function may return a Error, rather than the goto-ish behaviour of Exceptions.
      But currently it feels "ugly" in C#.
      Standard C# functions could (return value OR raise Exception.
      Using Result leads to functions that could ((return T OR Exception) OR raise Exception)
      Is that really an improvement?

    • @r0bertdenir0
      @r0bertdenir0 4 месяца назад

      If we follow the principle that functions are opaque, and we only interact with them via the contract of their signature (inputs -> outputs), then we must carry on wrapping everything in try...catch even when we have a functional pipeline, because we don't know if any of those functions in the pipeline will raise an exception instead of wrapping the exception in a Result.

  • @adambickford8720
    @adambickford8720 5 месяцев назад +1

    It's nice once you get used to it. Everything is immutable and in your tiny scope, so you don't have to keep as many 'moving parts' in your head. Each 'prefix' gives you an idea of what to expect: `Tap` will be a side effect, `bind` could short circuit, etc.
    It's not like imperative programming where "oh boy, we just set a boolean up above to be consumed down below... maybe".

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +2

      Definitely there's a learning curve here. Although I didn't find it too difficult. I first worked with RxJs in Angular a while back, before discovering ROP. And it's almost identical.

    • @sushantkhare8467
      @sushantkhare8467 5 месяцев назад

      @@MilanJovanovicTech exactly, it reminded me of RxJs. I love declarative programming, but it looks like C# wasn't designed for it?

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад +1

      @@sushantkhare8467 why are so many people saying c# is not designed for it? Are you talking about the current generation of junior devs not having the cognitive capacity to understand that you don't need a strict approach? Go benchmark it if the structure irks you. This is literally how you set up your host, DI container, chaining linq calls, and don't get me started on generating expression trees.
      This is a common look in many implements of c# programs.
      What you mean is, c# can do this, but nobody does it because they aren't thinking of ways to leverage code.

    • @user-jc6pe2bp1y
      @user-jc6pe2bp1y 5 месяцев назад

      @sushantkhare8476 what do you mean c# wasn’t designed for it? It looks like LINQ lambda notation to me. You know - the syntax that c# introduced

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      @@user-jc6pe2bp1y they have to have just started a course in programming with morons for professors thats the only way people are coming up with these statements

  • @TheScriptPunk
    @TheScriptPunk 5 месяцев назад +1

    My suggestion is to add some sort of container that is passed to each call so the intermediate functions are able to write to that container, such as their error, like failed validation.
    That way, you can couple the error with the call within the same parameter set or something.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Have a suggestion for the method signature for that?

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад +1

      @@MilanJovanovicTech yeah, similar to builder pattern that passes down the object with a this reference, or something along those lines.

    • @arunnair7584
      @arunnair7584 5 месяцев назад

      If there is any error thrown by any method, processing the rest may not be good in most cases. I implemented a fluent monad years ago that checks if an exception or error has already occurred. If yes, the method does not execute rest of the statements. This is done inside the monad, so the method using this, has to check if the exception flag is turned on, at the end and then fetch the error.

    • @arunnair7584
      @arunnair7584 5 месяцев назад

      Yes, this is exactly what I used to do.

  • @damianradinoiu4314
    @damianradinoiu4314 5 месяцев назад

    I would say this pattern is more suitable for algorithm procedure implementations rather than structure. Keeping the OOP paradigm for structural code and FP paradigm for implementations code is my goto approach

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      What would you consider structural code and implementation code?

    • @damianradinoiu4314
      @damianradinoiu4314 5 месяцев назад

      @@MilanJovanovicTech structural code would be the design of the abstractions interactions themselves (object behaviour patterns) while implementations would be the private state that goes into those abstractions (the procedure themselves). The reasoning behind my idea is because most of the time you want to keep abstractions simple enough in terms of maintainability whereas procedures can grow very complex and this "railroad" approach basically removes the technical complexity from the business one therefore allowing one to focus only on the business logic. Let me know your thoughts as well.

  • @chrisbaker5284
    @chrisbaker5284 Месяц назад

    I use a simplified implementation of an Either class in my code (more for returning errors rather than throwing exception). I don't believe either way around, in your example, is more or less readable, I do believe there is more complexity in the final result, but that's just my opinion. I think what you have done is great. What perplexes me more though is that we need to consider pushing an OO language into a functional paradigm in the first place. It's no better, it's just a different approach. There are programming languages that already work functionally, if that's what is required, then perhaps use one of those instead, even MS has one that can be used in VS - F#.
    Yes, I know you're going to use the LINQ argument, and yes it is functional, but that's basically just extensions over IEnumerable and no reason to try and force everything else into that functional way of thinking. It sounds like I'm disagreeing with your approach, that's not my intent, I think what you've done is good and useful to some, not really for me, and, I simply don't agree that it should be introduced into an OO language.

    • @MilanJovanovicTech
      @MilanJovanovicTech  Месяц назад

      Result and Either are pretty much the same, a way to express a success/failure of something

    • @chrisbaker5284
      @chrisbaker5284 Месяц назад

      @@MilanJovanovicTech I understand that, that wasn't really my point. My point was that while I use some functional paradigms in my code (albeit simplified versions), I don't agree that incorporating functional styles inside an OOP language is necessarily a good idea.

  • @haroldpepete
    @haroldpepete 5 месяцев назад +4

    great video, thanks, can you do a video about the differences between task and valuetask? when use one of them?

  • @mtsLeal
    @mtsLeal 24 дня назад

    Thanks for this video!
    I just think that is missing an async example of this approach

    • @MilanJovanovicTech
      @MilanJovanovicTech  23 дня назад +1

      The code looks the same, you just create a bunch of async overloads that accept and return Task

    • @mtsLeal
      @mtsLeal 23 дня назад

      ​@@MilanJovanovicTech
      Something like that?
      public static async Task ExecuteAsync(this Result result, Func executor) where TResult : Result
      {
      return result.IsSuccess ? await executor(result.Value) : result.Value as TResult;
      }
      I'm wondering if there's a nicest way to do that and use in the middle of the flow, in that way the async have to be the last in execution stack.

  • @dragannikolic568
    @dragannikolic568 5 месяцев назад

    Thx for the source code.
    I am doing everything from the scratch and put everything together when possible.
    That way I can check if I did everything right or if I'm missing something.
    Thx. again.

  • @barrysphone
    @barrysphone 5 месяцев назад +2

    Very interesting video. I use result types with implicit operators for success/error types and use match but had not seen bind or tap before. 👍

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +2

      So you're probably not doing ROP, but still utilizing Result 👌

    • @barrysphone
      @barrysphone 5 месяцев назад

      @@MilanJovanovicTech yeah, this is the first I've heard of it. I'll have to give it a go. Thanks for the video.

  • @DavidSmith-ef4eh
    @DavidSmith-ef4eh 4 месяца назад

    cool and all, but you had to write 3 funciton definitons, besides the extension methods. I'll just keep using guard clauses and thorwing. I could get used to it though, if I had to, for example in rust.

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 месяца назад

      You could also use a NuGet package with these abstractions built in

    • @DavidSmith-ef4eh
      @DavidSmith-ef4eh 4 месяца назад

      @@MilanJovanovicTech no, I meant the first three functions you wrote besides the extension methods. It's a nice way to program for sure, but it makes it harder readable for most devs (including me). And you also said it's slower because of extra allocations, so.. I am just learning about it to not get left behidn if this trend catches on :D

  • @eugene5096
    @eugene5096 5 месяцев назад +5

    Milan how you think we can mitigate need to use DI inside extension method, do you think it will be poissble in next c# with new extensions operator ?

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      What does this mean

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Just pass it as an argument?

    • @eugene5096
      @eugene5096 5 месяцев назад

      @@MilanJovanovicTech will it look much uglier if we pass all dependencies as arguments when chaining methods. Imagine you will pass logger in all of them

  • @benjsoft
    @benjsoft 5 месяцев назад

    Feels like programming with RxJs in Angular :D

  • @iliyan-kulishev
    @iliyan-kulishev 5 месяцев назад

    I've seen you previous videos on the topic and I love this. And I'm yet to find a convincing argument against it - either at work or in this comment section.
    Here's a question: why you have all these functions on Result as extension methods and not just part of the Result class ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      I find it more flexible to organize with extension methods. It starts making even more sense with a Result and Result object, which is how I usually do it.
      Most folks against this approach are unfamiliar with FP paradigm, so it feels strange. 😅

    • @TazG2000
      @TazG2000 5 месяцев назад +1

      The case against it is where the scope of error handling is wider than a single layer and there are several levels of the call stack separating the error from the handler. This pattern is useful, but as with any pattern, trying to fit it into every scenario becomes unwieldy. In general, it isn't worth reinventing the wheel just to "get rid of" alternatives that already fit the purpose.

  • @vijayarajan-bt5fk
    @vijayarajan-bt5fk Месяц назад

    If anybody cannot understand this code please wait and watch previous video also

  • @pedrosilva1437
    @pedrosilva1437 5 месяцев назад +1

    I personally don't like the Bind, TryCatch, and Tap methods. They complicate code in this ROP. I prefer how LINQ works where you call .Select, .Where, .OrderBy directly... I think that's more readable rather than introducing functions like Bind. Would that be possible in your ROP example?
    But I appreciate the video... It's always good to see new concepts, even if you decide they're not for you. Thanks!

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Fair enough!

    • @pedrosilva1437
      @pedrosilva1437 5 месяцев назад

      @@MilanJovanovicTech So do you think there's a way to make your example work more like LINQ? I'm curious if that could be possible, but they always return a list, even if it's empty, and throw exceptions out for failures.

    • @David-id6jw
      @David-id6jw 5 месяцев назад

      @@pedrosilva1437 Well, his custom methods are basically the same thing as LINQ functions, but operating on a different data type. LINQ works on IEnumerables (including things like List, which implements IEnumerable). Milan's functions mostly operate on a single value, his Result type.
      The main difference is in the naming. For example, Select() in LINQ is basically Bind(). It takes one type as input, and generates a (usually) different type as output. There's also Map(), which is what Python uses rather than Select().
      The name "Bind" comes from functional logic, and I always found to be a horrible name for programming purposes. You could, however, simply change the name of the extension method from Bind() to Select(). Since the extension method is bound to the specific designated data type (in this case, Result), it won't conflict with LINQ's version as long as Result never implements IEnumerable.
      There's no equivalent in LINQ to the Tap() function. List itself does actually implement a ForEach() function which is equivalent, but it's not part of the broader LINQ, and isn't an appropriate name for a non-collection type. I would probably rename it Process(), but that's a subjective choice.
      TryCatch() is basically Bind/Select with exception handling. The bind and func function parameters in Bind() and TryCatch() are basically the same thing, except one returns TOut and the other returns Result. You can adjust so that they both use the same signature, and then the entire thing collapses into a single function. I'd merge them together.
      And then Match() just splits the OK and Error results apart to generate the final return value. That's fine as is.

  • @LeotrimJusufi
    @LeotrimJusufi 5 месяцев назад

    How do you handle if you need a variable from two previous functions? Say that in the fourth call, you need a value from the second? If you understand what i mean.

  • @spreadandexpandknowledge
    @spreadandexpandknowledge 5 месяцев назад

    Great video! Could you cover generic exception handling in the repository pattern in clean architecture without using the Result type? I'm keen to learn how to handle exceptions cleanly in .NET applications. if you have already video then share the link here. Thanks in advance!

  • @simonklein2335
    @simonklein2335 5 месяцев назад

    I wonder if that is a production ready code or a well known approach. We are using Hellang Middleware for handling web requests, that way we can return error codes from the Application Layer to the Web layer and then return a formatted error response. To me this looks like a lot of work to put together and the benefits are quite small.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      I wouldn't say this is near production-ready. More showcasing an example.

  • @ugochukwuumerie6378
    @ugochukwuumerie6378 5 месяцев назад

    Awesome. Is there a way to globally detect and handle result failure in the asp net middleware?

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Yes, you could come up with something. I used to do it with a MediatR pipeline behavior

  • @Naton
    @Naton 5 месяцев назад +9

    I'll do this only if there are no interns in my company. But then again I rather use F#

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +2

      I think it should be a team-level agreement on if you'd use this. I'm not saying force this down everyone's throat. I find it a very interesting alternative to the "traditional" imperative paradigm.

    • @donarnold8811
      @donarnold8811 5 месяцев назад +1

      ROP is so much cleaner in F#.

    • @obinnaokafor6252
      @obinnaokafor6252 5 месяцев назад

      use f# to do what exactly

    • @Andy01010
      @Andy01010 5 месяцев назад

      Yeah good luck switching to F#… I’d like too see how your management takes it

    • @paarma1752
      @paarma1752 5 месяцев назад

      There may be interns in your company in the future.

  • @Rodrick.
    @Rodrick. 5 месяцев назад

    I loved programming like this in Angular with RxJs, but it feels weird in C#, can't explain it better, maybe it's my brain is constantly going "this goes against every uni book you read".
    Would be interesting to see performance metrics for the original method vs ROP. Allocations don't matter as much to me as performance.
    Also would be interesting comparing the same implementation in F#, I could never fully get into it.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Yes, this is very similar to RxJs so it felt pretty natural to me. There's also Rx.NET 😁

  • @pawel131657
    @pawel131657 5 месяцев назад

    I'm wandering how this would look if the db and related services functions would have proper async/await implemenations.
    And would need to be awaited before proceeding to next function in the pipeline.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      The function chains would be the same, you'd just have one await at the front, so:
      await ValidateLineItems()
      .Bind(...)
      .TryCatch(...)
      .Tap()
      .Tap()
      .Match();
      The trick is just to create the async overloads for each method, that can accept and return a Task

    • @timur2887
      @timur2887 21 день назад

      @@MilanJovanovicTech debugging will be hell)

  • @lodevijk
    @lodevijk 3 месяца назад

    I like the result type but converting everything into extension methods makes this very unreadable and hard to debug.

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 месяца назад

      Looks like we might be getting a Result type in C# soon :)

  • @joga_bonito_aro
    @joga_bonito_aro 5 месяцев назад +3

    I prefer the follow errorhandling styles (in order):
    1. Result pattern
    2. obj | err tuple return values (golang style)
    3. exceptions (but I try to avoid it like a cat avoids water)
    The problem with exceptions is that they can happen anywhere down the path and they may, or may not be handled. If you don't handle them, they will explode higher up the call chain and then good friggin luck catching them all like these stupid pokemons. If you use solution 1 or 2, you force yourself handling the error immediately.
    Once you've gone Result pattern, you'll never go back.
    PS: The explanation with the drawbacks in the end was awesome as hell! Much appreciated!

  • @mostafachronic1874
    @mostafachronic1874 3 месяца назад

    Can I get your courses from my country (Iran)?

  • @cas818028
    @cas818028 5 месяцев назад +3

    I understand this completely. But maybe I am just to simple minded this seems like deeply excessive over engineering to solve a very simple problem that is very humans readable that pretty much any c# dev can eyeball in 10 seconds and figure exactly what it’s doing.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Well, I laid out the pros and cons the way I see them. So everyone can decide what works for them 😁

  • @matswessling6600
    @matswessling6600 5 месяцев назад +15

    too complicated.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      If you say so

    • @matswessling6600
      @matswessling6600 5 месяцев назад

      @@MilanJovanovicTech it contsins an embryo to agood idea but I feel that it is too invasive.

    • @icewolf1911
      @icewolf1911 5 месяцев назад +2

      Ah, not that complicated… it’s like the builder pattern to the next level. It’s fine and looks pretty cool.

    • @matswessling6600
      @matswessling6600 5 месяцев назад +2

      @@icewolf1911 "its fine and it looks cool". yes I agree its cool and that is what makes it unreadable for most programmers.

    • @icewolf1911
      @icewolf1911 5 месяцев назад +1

      @@matswessling6600 Sounds like a skills issue then. That is pretty readable, but I've been doing this for two decades now.

  • @thibaultlesuisse8650
    @thibaultlesuisse8650 5 месяцев назад

    I get it, it looks like functional programming but why use C# instead of F# if you end up doing C# like this?

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Because I can still use C# and the ecosystem I know well

    • @thibaultlesuisse8650
      @thibaultlesuisse8650 5 месяцев назад

      @@MilanJovanovicTech true! Thanks for the video anyway! Nice to see new styles like this

  • @ryan-heath
    @ryan-heath 5 месяцев назад +11

    I really dislike this style of programming (in c#)
    Just use a global execration handler that is smart enough to know what to return to the customer.
    Move validation into some global handlers too.
    Just implement your api like a happy path (mostly).
    Yeah I hear you 😅 I am flaming this style in the comments hahaha

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Do you also dislike LINQ? 😁
      Of course I expected some heat around this topic. As was the case when I previously discussed it. What's your stance on functional programming in C# (in general)?

    • @paarma1752
      @paarma1752 5 месяцев назад +2

      100% agreed. Being imperative is so much better when your code can branch (e.g. exceptions can happen). You can actually step through it without the control flow bouncing all over the place due to some declarative magic logic and without having to put breakpoints inside callbacks (ugh). I use LINQ all the time, but only if there's no branching, i.e. there are no junctions in my railroad, e.g. when projecting a data structure or when querying with EF.
      Exceptions and occasional result objects ftw!

    • @ryan-heath
      @ryan-heath 5 месяцев назад

      @@MilanJovanovicTech I do like linq a lot.
      I think the main difference with linq is that its domain is well defined.
      That is set oriented selection methods.
      ROP seems to be all over the place. I don’t like to tie everything together into one long fluent syntax.
      Reads fine now, but how about 3 months from now?
      Also it is not immediately obvious where to put or add new functionality opposed to simpler transaction script style.
      FP in c# seems fun at start or in a green field project, but maintainers are going to hate you for it.
      You might even curse your younger self because he wrote some FP code that barely fitted the bill but he went ahead with it anyway because it looked cool. But 3 months from now it looks like a piece of mud … 😅

    • @HenrikElkjrHagen
      @HenrikElkjrHagen 4 месяца назад

      This will very quickly lead to highly coupled code, with business logic sprinkled all over the place.

  • @roberteru25
    @roberteru25 5 месяцев назад

    The Golang way 😂😂😂

  • @arunnair7584
    @arunnair7584 5 месяцев назад +1

    This is quite an old technique.

  • @novalogic1265
    @novalogic1265 19 дней назад

    @MilanJovanovicTech what if email_service or payment_service is async? some example?

  • @MyFuzzyAfterlife
    @MyFuzzyAfterlife 5 месяцев назад +4

    I recently joined a team where a pipeline like this was used. The problem was , the whole "old" team had left, so everyone in the team is new. This means that nobody knows what "Bind" or "Tap" means any more, and there is no documentation. This makes this code, very frustrating to maintain. We are in the process of replacing this with simpler "normal" program flow.
    I like the idea of this, but there are big danger flags around it, that makes me avoid it like the plague.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад +2

      The issue is your team doesn't have the competence to be engineers.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +1

      Well, they're all simple functions. Tap = no side effect. Bind = could fail. Map = like LINQ Select. What made this hard to figure out?

    • @MyFuzzyAfterlife
      @MyFuzzyAfterlife 5 месяцев назад

      @@MilanJovanovicTech I gave those as examples, they are not hard to figure out, but they are not descriptive either. Tap does not tell you what it does. But again, I just used your example, in our case they were equally weirdly named, plus were then highly generic. It makes it difficult to debug, and difficult to parse. People may say it's a bad team, but I would counter that with code should be easy to parse on reading.
      They TryCatch is a great example, I see that method, I know exactly what it does and what it is intended for. I see Tap, I have no clue what that means, do I really have to go delve into the methods to figure out what it does. Yes, your methods are simple, ours were not. Again, I'm not attacking anything that was presented, just my experience with these pipelines.

    • @Eltin123456
      @Eltin123456 5 месяцев назад +3

      @TheScriptPunk Your opinion suggests a punk that no one would like to work with. Firstly, if the team can handle rewriting such code and then dealing with business tasks, they are competent enough to do their job. Secondly, the code was done in some niche way (in the C# world) and it is proven by many that it is hard to follow (we write code for people, not for our ego). Thirdly, this code does not solve anything.
      I use the functional approach where it solves the problem, so I use 25% functional and 75% OOP. This was using some functional approach just to use a functional approach- not to solve the problem in a much simpler way. The only good thing from this video is that viewers can familiarize themselves with the functional approach, which is not the default way in C#.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      @@Eltin123456 sure ok.
      Still has nothing to do with oop

  • @99aabbccddeeff
    @99aabbccddeeff 5 месяцев назад +6

    I would avoid exceptions in some places only if I have to write high performant code or in some cases where it is really needed or more appropriate than throwing an exception. Just avoiding exceptions without any significant reason doesn't make code better at all.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      So, you just put "throw" in your code rather than passing data?

    • @another_random_video_channel
      @another_random_video_channel 5 месяцев назад

      totally agreed. Checking result is so 1970. it makes your codebase bloat. There is a reason why .net introduced exception as an alternative. I perfer to use exception for readability then optimise to use result pattern in hot paths

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +2

      How about avoiding exceptions because you know what the failure is, and you know how to handle it? (If you're thinking that's not exceptional, maybe we're onto something here).

    • @99aabbccddeeff
      @99aabbccddeeff 5 месяцев назад

      ​@@MilanJovanovicTech Right, if I know how to handle some situations in code I won't throw an exception of course. Exceptions is a good tool in right hands and it is only for exception situations. If you take a look at GO lang code, you can see, in some libraries, code turns into if-hell, instead of have one place to handling errors. I don't want to say that we should use exceptions whenever where possible, it is just about they are really helpful and make your code much cleaner, if use them right.
      It's like talking about "goto", many people hate it, but it is also really helpful if it is used right and it is even used in some places in .Net to improve performance, instead of creating additional overhead with flag variables, etc.

  • @nepalxplorer
    @nepalxplorer 5 месяцев назад +2

    I'd rather implement Result with Service and handle everything in service. looks too complicated for me. coz need to introduce so many functions (btw no need to add custom methods in LINQ, they comes built in)

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +1

      You can write the functions "in place" also. This was just my way of structuring it to lead into the solution.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      Testability in those functions 100% absolute win when working with devs that are lazy. You can go behind and write the tests for them.

  • @copterbuddy
    @copterbuddy 5 месяцев назад

    Interesting

  • @giullianosep
    @giullianosep 5 месяцев назад

    I think this is great, but C# is too verbose, it's a lot nicer in F#.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      Lemme guess, you're a sr dev that should actually be starting as mid level instead, and don't actually code outside of work because you got your foot in the door?

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      I agree that this looks better in F#, since it's a functional language. But I also like to stay in C# for other reasons.

  • @rohit704
    @rohit704 5 месяцев назад

    Have you worked on event sourcing pattern ? I found it most complex pattern.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Event sourcing is fundamentally simple. It's the "maintaining an ES system" that's the hard part

  • @TheScriptPunk
    @TheScriptPunk 5 месяцев назад

    Them: I don't like this approach
    You: might be a matter of unfamiliarity
    Them: let me find reasons having nothing to do with the approach to justify unfamiliarity.
    😂
    😂

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +1

      I've heard these arguments in the past when talking about ROP 😅 So I expected as much. But still, I think it's worth talking about "different" ways to do things. Someone out there might see this, and it could really help them.

  • @jd-chnl
    @jd-chnl 5 месяцев назад

    it seems you reinvented 'monad'))

  • @ilushkinz4424
    @ilushkinz4424 5 месяцев назад +1

    Please, just stop doing things in C# non idiomatically. The problem with Option/Result monads in C#, is that you just don't have the support from language, to use them without a pain (like in Rust or F#). And the code becames just insanely convoluted.
    If you want to express Option in C#, you can use NRT. If you need to do another way of error handling, just use exceptions.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад +1

      | you just don't have the support from language
      So we add it with some extension methods?

    • @ilushkinz4424
      @ilushkinz4424 5 месяцев назад +1

      ​@@MilanJovanovicTech that's not the point. The point is that it is not idiomatic and it's not providing that much benefit. You basically need to pattern match every result/option, regardles if you need just to return the failed result and handle happy path (which is like 95%+ of the cases when you're using these monads).
      You also can use panic in go for exception-like error handling. But should you?​

    • @BeauFortLv
      @BeauFortLv 5 месяцев назад

      @@ilushkinz4424 Some confusion here about expected and unexpected exceptions. This approach allows you to handle the expected cleanly using the capabilities that C# currently has. The readability, comes with experience, allows the developers to focus on the business rather than the infrastructure.

    • @RavinduNanayakkara
      @RavinduNanayakkara 2 месяца назад

      Idiomatic C# is anyway heading in this direction with the upcoming Discriminated Unions with Option and Result monads. So doesn't hurt to familiarize yourself with the concept.

  • @gpzim981
    @gpzim981 5 месяцев назад +2

    Horrible. Mixing function and OO causes more problem and most of the times devs bringing it to the code base are literally trying to resolve problems that doesn’t exist.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      Makes your conditionals actually testable

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 месяцев назад

      Did you ever try this approach in practice and you're speaking from experience?

    • @arunnair7584
      @arunnair7584 5 месяцев назад

      I have mixed OO with functional, did not face any issues, except in the beginning, but I chalk that upto the learning curve.

    • @TheScriptPunk
      @TheScriptPunk 5 месяцев назад

      @@arunnair7584 you've been using functional the whole time.
      Oo is when you encapsulate data in an object.
      Flow of control, var assignment, property accessing is not oo.

    • @arunnair7584
      @arunnair7584 5 месяцев назад

      @@TheScriptPunk Nope. I have been using OO since 1999. Functional since around 2018 or so. I avoid getters and setters in OO too.