Master the Fluent Builder Design Pattern in C#

Поділитися
Вставка
  • Опубліковано 11 січ 2025

КОМЕНТАРІ • 106

  • @MilanJovanovicTech
    @MilanJovanovicTech  7 місяців тому +5

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

  • @tattooineste
    @tattooineste 7 місяців тому +5

    If I "stay awesome", it's because I keep coming back for more Milan. Awesome... as ever.

  • @awright18
    @awright18 7 місяців тому +3

    I really like fluent builders. I typically have a private field of the type that is getting built. Then each fluent method sets it's properties with the build method returning that member, but this implementation works, too. Nice video!

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому +1

      That works from the outside, although it's not a proper builder unless you build in the last step.

  • @joergw
    @joergw 7 місяців тому +1

    Thanks 🤗

  • @ugochukwuumerie6378
    @ugochukwuumerie6378 7 місяців тому +3

    A useful video right there. Also glad you mentioned their use cases because that seems like a lot!

  • @TroyCSchmidt
    @TroyCSchmidt 7 місяців тому +1

    Great tutorial that gets straight to the point and jets me know if i want to watch or not. Definitely great video flow and great content as well!

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Glad you liked this. Experimenting with a new video format, so good to hear some feedback

  • @bartlomiejuminski
    @bartlomiejuminski 7 місяців тому +5

    More videos on real life design patterns like this please :)

  • @xNeoGenesis
    @xNeoGenesis 7 місяців тому +1

    Great video as always: useful, insightful, concise and straight to the point. Some months ago I started using this pattern and I really like how easy and seamless it can make instances creation and I found your tip to use Actions in methods really useful to improve what I've worked on.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Very cool. Do you use it for entity creation or some different objects?

    • @xNeoGenesis
      @xNeoGenesis 7 місяців тому +1

      @@MilanJovanovicTech Different objects, I've not had the need to use it for entity creation yet. Specifically, I made a library intended to make all kinds of Http requests and I use it to configure them, like the url, headers, cookies, method, download location if needed, post body, number of retries, etc. This allows it to be very flexible and extensible.
      Regarding entities, your DDD videos have been very useful recently to me to implement support for an external API with many entities and complex relations. As an amateur and hobbyist programmer I've been learning a lot with your content.

  • @mylesdavies9476
    @mylesdavies9476 7 місяців тому +1

    Great content, would like to see more like this, design patterns in practice 👌

  • @m31coding
    @m31coding 7 місяців тому

    Thank you very much for this awesome video, Milan! I’ve added your example to the M31.FluentAPI library, implementing it twice: once with an arbitrary call order for the builder methods and once with a forced order. The library uses source code generation to create the builder boilerplate.
    Happy coding!
    Kevin

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      That is an awesome library! 😁

    • @m31coding
      @m31coding 7 місяців тому

      @@MilanJovanovicTech Glad you found it useful! The first creator to make a video about it could get a lot of views 😉.

  • @danko_v3
    @danko_v3 7 місяців тому

    Builder pattern is really cool. There is interesting approach called stepwise builder, which also can be implemented with fluent api. This helps you provide validation where for example one property should be validated based on another property value or force developers specify values in a specific order

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      That's an excellent extension on top of this implementation

  • @pavfrang
    @pavfrang 7 місяців тому

    Thanks Milan, great content as always!

  • @samwalker5438
    @samwalker5438 7 місяців тому +3

    Question: what’s the point of Empty()? Build() is creating a new object at the end.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Returning the initial empty builder instance

    • @timur2887
      @timur2887 7 місяців тому +4

      @@MilanJovanovicTech why not just use new () instead?

  • @cuIo_
    @cuIo_ 5 місяців тому

    this helped a LOT, thank you!!

  • @Brendan2Alexander
    @Brendan2Alexander 7 місяців тому

    Very very nice video. Tips here are things I will implement immediately in my code. Thank u!

  • @christianmarpert3844
    @christianmarpert3844 5 місяців тому

    thks! great video and explanation! Still got one question, when using records, you could use the With syntax , along with Empty(), also getting immutability ... not sure if it is rather a preference (as this approach comes with ot of boilerplate) or has more advantages...
    Anyway, well explained, will add it to my tool box!

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 місяців тому +1

      The boilerplate also acts as a safeguard in what you can do. Using the records with expression you can do anything, and possibly something you shouldn't be allowed to. So there's a slight difference.

  • @empathetic24671
    @empathetic24671 5 місяців тому

    Thanks man. You're great

  • @ajaysingh-sc1qt
    @ajaysingh-sc1qt 7 місяців тому

    Great explanation with example !!

  • @PhilipDanielHayton
    @PhilipDanielHayton 7 місяців тому

    Nice video👍🏻 I love this pattern as a consumer

  • @EHBRod13
    @EHBRod13 5 місяців тому

    You’re such a baller! Thanks, bro!

  • @simoneesposito8447
    @simoneesposito8447 7 місяців тому

    Thank you very much for the great video!
    Could you tell me if there is a way to automate the creation of the builder from a DTO?
    Also, is it recommended to use FluentValidation to validate the object during the Building phase?

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      What do you mean by: "automate the creation of the builder from a DTO"

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

    Thx for this! I really got the idea but I do not see „enough“ PROs compared to CONRTA of writing much more code! I do not see me using this pattern

  • @pedrosilva1437
    @pedrosilva1437 7 місяців тому

    Very nice video! One question: how to do you recommend doing data validation in the builder pattern? For example, let's say the Address must have a Street property, but the user doesn't call the WithStreet method in the AddressBuilder. Would you check the required parameters in the Build method call and fail if the street member hasn't been set? And what about the format of the data, like the zip code format... would you validate that in the WithZipCode method, or with constraints validation in the Address constructor? Thanks.

    • @andreibicu5592
      @andreibicu5592 7 місяців тому +1

      I am also interested to know that. I'm thinking to combine it with the Result pattern, but don't know yet if it's a good approach.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      You can validate the format of fields as soon as you call the WithX method. And a great place to do validation is in the Build method. I would probably opt for throwing exceptions in the WithX method - or return a Result in the Build step.

    • @pedrosilva1437
      @pedrosilva1437 7 місяців тому

      @@MilanJovanovicTech That makes sense... I was thinking along these same lines.

  • @NahomKW
    @NahomKW 7 місяців тому

    Hey Milan, I've always wondered about the type of unique identifier big companies like Netflix, Amazon, etc., use and how they utilize these identifiers for querying entities. Could you shed some light on that as well?

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Will do some research, it's probably either a UUID (Guid) or some sort of timestamp based random ID like snowflakes or ULID

  • @sujitbhandarkar886
    @sujitbhandarkar886 7 місяців тому

    So what i think real use could be instead of extension method we can go for this builder pattern where same object reference is shared while in extension method not

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      How would it help?

    • @sujitbhandarkar886
      @sujitbhandarkar886 7 місяців тому

      @@MilanJovanovicTech hi, sorry my bad I thought the a different object reference or instance is passed on every extension method call but that's not the case with the class type which I performed a poc and checked. Below is the code. Thanks !
      MyClass myClass = new(5);
      Console.WriteLine("Hash Code before " + RuntimeHelpers.GetHashCode(myClass) + "
      ");
      var myClassResult = myClass.AddOne().AddDouble();
      Console.WriteLine("
      Hash Code after Result " + RuntimeHelpers.GetHashCode(myClassResult));
      Console.WriteLine(myClass.IsSameInstance(myClassResult));
      Console.ReadKey();
      public class MyClass
      {
      public int Value { get; set; }
      public MyClass(int value)
      {
      Value = value;
      }
      }
      public static class MyClassExtension
      {
      public static MyClass AddOne(this MyClass myClass)
      {
      Console.WriteLine("Hash Code before" + RuntimeHelpers.GetHashCode(myClass));
      myClass.Value += 1;
      Console.WriteLine("Hash Code After" + RuntimeHelpers.GetHashCode(myClass));
      return myClass;
      }
      public static MyClass AddDouble(this MyClass myClass)
      {
      Console.WriteLine("Hash Code before" + RuntimeHelpers.GetHashCode(myClass));
      myClass.Value *= 5;
      Console.WriteLine("Hash Code After" + RuntimeHelpers.GetHashCode(myClass));
      return myClass;
      }
      public static bool IsSameInstance(this MyClass instance, MyClass other)
      {
      return ReferenceEquals(instance, other);
      }
      }

  • @sunzhang-d9v
    @sunzhang-d9v 7 місяців тому

    Is the address sub-item of the order and the address maintained by the customer the same table?

  • @Kupnu4000
    @Kupnu4000 7 місяців тому +1

    The video is very useful, thank you! One minor thing - fully white screens are pretty painful for the eyes, especially when they go after the dark ones

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому +1

      Sorry about that! It wasn't entirely white, instead it's a shade of gray. I'll see how I can make this easier on the eyes in future videos.

    • @Kupnu4000
      @Kupnu4000 7 місяців тому

      @@MilanJovanovicTech Thank you sir!

  • @nucasspro1
    @nucasspro1 7 місяців тому

    thanks, I use this pattern when the class has a lot of properties and it hard see the code when creating an instance, to make the code readable. But not sure it is a good choice or not :)

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Is it only getters/setters? Probably overkill for that. If there is some logic inside, then it makes sense.

  • @intermixhector2902
    @intermixhector2902 6 місяців тому

    god god you out control love you love you love you

  • @PhobiaQQ
    @PhobiaQQ 7 місяців тому +1

    What if I have rich domain model and my business rules are validated inside the entity?

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Then you'll probably control the creation from the domain model?

  • @alexmel8448
    @alexmel8448 6 місяців тому

    Why does the empty method is static ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 місяців тому +1

      Just to start off the builder.
      Or you could do
      new OrderBuilder()
      ....

  • @sunzhang-d9v
    @sunzhang-d9v 7 місяців тому

    For example, in the order details table, it will not be too complicated to have too many fields

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      What do you mean?

    • @sunzhang-d9v
      @sunzhang-d9v 7 місяців тому +2

      @@MilanJovanovicTech If there are too many fields, will the use of builds be too large and not conducive to writing and maintenance?

  • @shabanelmogy7912
    @shabanelmogy7912 7 місяців тому

    we need big tutorial for blazor and whats your opinion in it ?

  • @Rick-mf3gh
    @Rick-mf3gh 7 місяців тому +1

    Nice clean and easy to follow video. 👍
    I can see how this would be good if there are only optional properties, like in the AuthenticationBuilder.
    But for POCOs, I find required+init to be less prone to mistakes, as the compiler tells you if you forget to set a mandatory property.
    e.g. public required string Name { get; init; }
    I prefer knowing that if (e.g.) I add an additional mandatory property then the code will not build unitl I have updated all the places I construct the class.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      What if you're deserializing?

    • @modernkennnern
      @modernkennnern 7 місяців тому +1

      ​​@@MilanJovanovicTechDepends on your serializer of course, but STJ supports required properties

    • @Rick-mf3gh
      @Rick-mf3gh 7 місяців тому

      @@MilanJovanovicTech I have not experienced any issues using 'required' nor 'init' when using either Newtonsoft or System.Text.Json.
      IIRC, both 'required' and 'init' are compiler-enforced constraints that have no effect during runtime.

  • @timur2887
    @timur2887 7 місяців тому

    Nice and fancy! But with double overhead...

  • @marcociaschini4616
    @marcociaschini4616 7 місяців тому +3

    I don't agree on this kind of use of the fluent builder pattern. Apart from the benefit of the fluent style, this is just an over complicated constructor. The main target of a constructor is to cleary define all mandatory dependencies of an object, and this approach seems to transform everything into optionals.
    In my opinion, the context where fluent builder really shines, is when it implements a kind of buidling workflow for complex object, where you have to plugin and configure various components at different steps of buidling flow.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Right, and showing this with a complex example would make the video too complicated. This is why I choose to showcase simple examples and discuss the concepts behind the pattern. You're welcome to make an improved version. 😁

  • @shadowsir
    @shadowsir 7 місяців тому +1

    You can go a little bit further still:
    If you have mandatory fields, you can create a "steps" builder. Suppose orderId is mandatory, and you don't want to set it up so the builder can generate one at random (trivial example to show what I mean):
    public class OrderBuilder
    {
    public OrderBuilderStep1 WithOrderId(string orderId) {
    return new OrderBuilderStep1(orderId);
    }
    public class OrderBuilderStep1(string orderId) {
    private string _addressLine1 = "";
    public OrderBuilderStep1 WithAddressLine1(string addressLine1)
    {
    _addressLine1 = addressLine1
    }
    public Order Build()
    {
    return new Order { OrderId = orderId, AddressLine1 = _addressLine1 };
    }
    }
    }
    This also makes it possible to create even more complex scenario's where, depending on the input, you can return a different next step.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому +2

      The steps builder is a beautiful approach! Didn't want to add too much in one video, but I might cover that in part 2.

    • @samwalker5438
      @samwalker5438 7 місяців тому

      Interfaces can be used here too to indicate the next available steps. I’ve seen another channel explaining that.

  • @eduardoandrescastilloperer4810
    @eduardoandrescastilloperer4810 7 місяців тому

    Wait, can you edit the code while it is RUNNING?

  • @rahulsheelavantar2110
    @rahulsheelavantar2110 7 місяців тому

    Nice one, but don't know where I should use it

  • @ajdinhusic2574
    @ajdinhusic2574 4 місяці тому

    What do you think about the importance of using immutability in builder patterns?

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

      Making each operation immutable? I think it's enough that we encapsulate state within the builder and only allow it to be modified through the builder methods. Returning a new builder instance for each operation would eat up a lot of memory. Did you have a different opinion on this?

    • @ajdinhusic2574
      @ajdinhusic2574 4 місяці тому

      @@MilanJovanovicTech Yes, you're correct that it depends on the use case of course.
      We used to have some bugs in the past because we used a builder pattern that mutates its internal state, but the builder had to reuse the configuration three times and then return three separate builder results, with slight changes.

  • @konarksharma6524
    @konarksharma6524 2 місяці тому

    Wow clappings।

  • @emfi8744
    @emfi8744 7 місяців тому +1

    Interesting, but it's not functional, as it contains an internal state

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 місяців тому

      Is there a way to build a builder without holding state?

    • @emfi8744
      @emfi8744 7 місяців тому

      @@MilanJovanovicTech Right, I was not clear: the builder you implemented is changing its internal state.
      To be functional, you should return a modified copy of the builder.
      For example, IServiceCollection follows your pattern, so I can write:
      services.AddTransient(x);
      services.AddTransient(y);
      And still services will have both dependendies.
      But let's not call it functional

    • @TroyCSchmidt
      @TroyCSchmidt 7 місяців тому

      So what would you change to be functional then? I'm not sure I'm following your point cause it still seems functional because it is composable by allowing the daisy chaining just like if you called services.AddTransient(x).Add transient(y)

    • @emfi8744
      @emfi8744 7 місяців тому

      @@TroyCSchmidt Every time you invoke WithXxx(""), you should return a new instance of the builder, with the updated value.
      Functional comes with immutability. As it is implemented now, if you pass it to a method, the method may change your builder.
      It's the same difference you have between List and IEnumerable. When you add an element, the List is modified, the IEnumerable returns a new instance of IEnumerable.
      Guess who invented Linq?

    • @emfi8744
      @emfi8744 7 місяців тому +1

      @@TroyCSchmidt Having a fluent syntax does not mean being functional

  • @orhanaliyev9774
    @orhanaliyev9774 7 місяців тому

    Мда я это проходил в универе в 2011 году ))