Master the Fluent Builder Design Pattern in C#

  Рет қаралды 26,460

Milan Jovanović

Milan Jovanović

Күн бұрын

Пікірлер: 102
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@tattooineste
@tattooineste 3 ай бұрын
If I "stay awesome", it's because I keep coming back for more Milan. Awesome... as ever.
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Thanks a lot! :)
@awright18
@awright18 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 3 ай бұрын
That works from the outside, although it's not a proper builder unless you build in the last step.
@TroyCSchmidt
@TroyCSchmidt 3 ай бұрын
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 3 ай бұрын
Glad you liked this. Experimenting with a new video format, so good to hear some feedback
@ugochukwuumerie6378
@ugochukwuumerie6378 3 ай бұрын
A useful video right there. Also glad you mentioned their use cases because that seems like a lot!
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Glad it was helpful!
@samwalker5438
@samwalker5438 3 ай бұрын
Question: what’s the point of Empty()? Build() is creating a new object at the end.
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Returning the initial empty builder instance
@timur2887
@timur2887 3 ай бұрын
@@MilanJovanovicTech why not just use new () instead?
@bartlomiejuminski
@bartlomiejuminski 3 ай бұрын
More videos on real life design patterns like this please :)
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Will do! :)
@mylesdavies9476
@mylesdavies9476 3 ай бұрын
Great content, would like to see more like this, design patterns in practice 👌
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
More to come!
@xNeoGenesis
@xNeoGenesis 3 ай бұрын
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 3 ай бұрын
Very cool. Do you use it for entity creation or some different objects?
@xNeoGenesis
@xNeoGenesis 3 ай бұрын
@@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.
@m31coding
@m31coding 2 ай бұрын
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 2 ай бұрын
That is an awesome library! 😁
@m31coding
@m31coding 2 ай бұрын
@@MilanJovanovicTech Glad you found it useful! The first creator to make a video about it could get a lot of views 😉.
@cuIo_
@cuIo_ Ай бұрын
this helped a LOT, thank you!!
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
Glad it helped!
@danko_v3
@danko_v3 3 ай бұрын
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 3 ай бұрын
That's an excellent extension on top of this implementation
@pavfrang
@pavfrang 2 ай бұрын
Thanks Milan, great content as always!
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Much appreciated!
@EHBRod13
@EHBRod13 Ай бұрын
You’re such a baller! Thanks, bro!
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
Happy to help!
@empathetic24671
@empathetic24671 Ай бұрын
Thanks man. You're great
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
You're welcome!
@Brendan2Alexander
@Brendan2Alexander 3 ай бұрын
Very very nice video. Tips here are things I will implement immediately in my code. Thank u!
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Glad it was helpful!
@intermixhector2902
@intermixhector2902 2 ай бұрын
god god you out control love you love you love you
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Thanks 😅
@PhilipDanielHayton
@PhilipDanielHayton 3 ай бұрын
Nice video👍🏻 I love this pattern as a consumer
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
That's who it is meant for 😁
@marcociaschini4616
@marcociaschini4616 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 3 ай бұрын
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. 😁
@Rick-mf3gh
@Rick-mf3gh 3 ай бұрын
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 3 ай бұрын
What if you're deserializing?
@modernkennnern
@modernkennnern 3 ай бұрын
​​@@MilanJovanovicTechDepends on your serializer of course, but STJ supports required properties
@Rick-mf3gh
@Rick-mf3gh 3 ай бұрын
@@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 3 ай бұрын
Nice and fancy! But with double overhead...
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
True! But use the idea, not the example.
@ajaysingh-sc1qt
@ajaysingh-sc1qt 3 ай бұрын
Great explanation with example !!
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Glad you liked it!
@christianmarpert3844
@christianmarpert3844 Ай бұрын
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 Ай бұрын
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.
@Kupnu4000
@Kupnu4000 3 ай бұрын
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 3 ай бұрын
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 3 ай бұрын
@@MilanJovanovicTech Thank you sir!
@joergw
@joergw 3 ай бұрын
Thanks 🤗
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Thanks a lot! And I'm glad you enjoyed the video :)
@user-px2oj3dg4c
@user-px2oj3dg4c 3 ай бұрын
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 3 ай бұрын
Will do some research, it's probably either a UUID (Guid) or some sort of timestamp based random ID like snowflakes or ULID
@shadowsir
@shadowsir 3 ай бұрын
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 3 ай бұрын
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 3 ай бұрын
Interfaces can be used here too to indicate the next available steps. I’ve seen another channel explaining that.
@simoneesposito8447
@simoneesposito8447 3 ай бұрын
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 3 ай бұрын
What do you mean by: "automate the creation of the builder from a DTO"
@nucasspro1
@nucasspro1 3 ай бұрын
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 3 ай бұрын
Is it only getters/setters? Probably overkill for that. If there is some logic inside, then it makes sense.
@user-xm7sh3vw8o
@user-xm7sh3vw8o 3 ай бұрын
For example, in the order details table, it will not be too complicated to have too many fields
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
What do you mean?
@user-xm7sh3vw8o
@user-xm7sh3vw8o 3 ай бұрын
@@MilanJovanovicTech If there are too many fields, will the use of builds be too large and not conducive to writing and maintenance?
@pedrosilva1437
@pedrosilva1437 3 ай бұрын
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 3 ай бұрын
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 3 ай бұрын
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 3 ай бұрын
@@MilanJovanovicTech That makes sense... I was thinking along these same lines.
@PhobiaQQ
@PhobiaQQ 3 ай бұрын
What if I have rich domain model and my business rules are validated inside the entity?
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Then you'll probably control the creation from the domain model?
@sujitbhandarkar886
@sujitbhandarkar886 3 ай бұрын
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 3 ай бұрын
How would it help?
@sujitbhandarkar886
@sujitbhandarkar886 3 ай бұрын
@@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); } }
@shabanelmogy7912
@shabanelmogy7912 3 ай бұрын
we need big tutorial for blazor and whats your opinion in it ?
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
I don't use it, but I like the tech
@alexmel8448
@alexmel8448 2 ай бұрын
Why does the empty method is static ?
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Just to start off the builder. Or you could do new OrderBuilder() ....
@ajdinhusic2574
@ajdinhusic2574 18 күн бұрын
What do you think about the importance of using immutability in builder patterns?
@MilanJovanovicTech
@MilanJovanovicTech 18 күн бұрын
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 17 күн бұрын
@@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.
@user-xm7sh3vw8o
@user-xm7sh3vw8o 3 ай бұрын
Is the address sub-item of the order and the address maintained by the customer the same table?
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
That's a persistence decision
@eduardoandrescastilloperer4810
@eduardoandrescastilloperer4810 2 ай бұрын
Wait, can you edit the code while it is RUNNING?
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Yeah, with hot reload
@rahulsheelavantar2110
@rahulsheelavantar2110 3 ай бұрын
Nice one, but don't know where I should use it
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
I shared a few use cases
@emfi8744
@emfi8744 3 ай бұрын
Interesting, but it's not functional, as it contains an internal state
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Is there a way to build a builder without holding state?
@emfi8744
@emfi8744 3 ай бұрын
@@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 3 ай бұрын
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 3 ай бұрын
@@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 3 ай бұрын
@@TroyCSchmidt Having a fluent syntax does not mean being functional
@orhanaliyev9774
@orhanaliyev9774 3 ай бұрын
Мда я это проходил в универе в 2011 году ))
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Yes. it's a classic design pattern
A Step-by-Step Guide for the Cache-Aside Pattern + Stampede Protection
19:29
REPR (Request-Endpoint-Response) Pattern Will Make Your APIs Clean
16:10
Milan Jovanović
Рет қаралды 22 М.
So Cute 🥰
00:17
dednahype
Рет қаралды 45 МЛН
王子原来是假正经#艾莎
00:39
在逃的公主
Рет қаралды 25 МЛН
5 Design Patterns That Are ACTUALLY Used By Developers
9:27
Alex Hyett
Рет қаралды 263 М.
Building Fluent Interfaces in TypeScript
16:15
Andrew Burgess
Рет қаралды 15 М.
HTTP Polling vs SSE vs WebSocket vs WebHooks
22:22
ByteVigor
Рет қаралды 5 М.
How to create your own Fluent API in C#
11:12
Nick Chapsas
Рет қаралды 52 М.
If Your Code Looks Like This... You're A GOOD Programmer
16:39
Continuous Delivery
Рет қаралды 67 М.
C# Builder Строитель | Design Patterns
30:04
codaza
Рет қаралды 29 М.
"I Hate Agile!" | Allen Holub On Why He Thinks Agile And Scrum Are Broken
8:33
Forget Controllers and Minimal APIs in .NET!
14:07
Nick Chapsas
Рет қаралды 67 М.
Implementing the Transactional Outbox pattern with Hangfire
14:28
Milan Jovanović
Рет қаралды 11 М.
.NET and C# are in trouble. Here is what I'd do.
10:57
Ed Andersen
Рет қаралды 57 М.