Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@tattooineste3 ай бұрын
If I "stay awesome", it's because I keep coming back for more Milan. Awesome... as ever.
@MilanJovanovicTech3 ай бұрын
Thanks a lot! :)
@awright183 ай бұрын
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!
@MilanJovanovicTech3 ай бұрын
That works from the outside, although it's not a proper builder unless you build in the last step.
@TroyCSchmidt3 ай бұрын
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!
@MilanJovanovicTech3 ай бұрын
Glad you liked this. Experimenting with a new video format, so good to hear some feedback
@ugochukwuumerie63783 ай бұрын
A useful video right there. Also glad you mentioned their use cases because that seems like a lot!
@MilanJovanovicTech3 ай бұрын
Glad it was helpful!
@samwalker54383 ай бұрын
Question: what’s the point of Empty()? Build() is creating a new object at the end.
@MilanJovanovicTech3 ай бұрын
Returning the initial empty builder instance
@timur28873 ай бұрын
@@MilanJovanovicTech why not just use new () instead?
@bartlomiejuminski3 ай бұрын
More videos on real life design patterns like this please :)
@MilanJovanovicTech3 ай бұрын
Will do! :)
@mylesdavies94763 ай бұрын
Great content, would like to see more like this, design patterns in practice 👌
@MilanJovanovicTech3 ай бұрын
More to come!
@xNeoGenesis3 ай бұрын
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.
@MilanJovanovicTech3 ай бұрын
Very cool. Do you use it for entity creation or some different objects?
@xNeoGenesis3 ай бұрын
@@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.
@m31coding2 ай бұрын
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
@MilanJovanovicTech2 ай бұрын
That is an awesome library! 😁
@m31coding2 ай бұрын
@@MilanJovanovicTech Glad you found it useful! The first creator to make a video about it could get a lot of views 😉.
@cuIo_Ай бұрын
this helped a LOT, thank you!!
@MilanJovanovicTechАй бұрын
Glad it helped!
@danko_v33 ай бұрын
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
@MilanJovanovicTech3 ай бұрын
That's an excellent extension on top of this implementation
@pavfrang2 ай бұрын
Thanks Milan, great content as always!
@MilanJovanovicTech2 ай бұрын
Much appreciated!
@EHBRod13Ай бұрын
You’re such a baller! Thanks, bro!
@MilanJovanovicTechАй бұрын
Happy to help!
@empathetic24671Ай бұрын
Thanks man. You're great
@MilanJovanovicTechАй бұрын
You're welcome!
@Brendan2Alexander3 ай бұрын
Very very nice video. Tips here are things I will implement immediately in my code. Thank u!
@MilanJovanovicTech3 ай бұрын
Glad it was helpful!
@intermixhector29022 ай бұрын
god god you out control love you love you love you
@MilanJovanovicTech2 ай бұрын
Thanks 😅
@PhilipDanielHayton3 ай бұрын
Nice video👍🏻 I love this pattern as a consumer
@MilanJovanovicTech3 ай бұрын
That's who it is meant for 😁
@marcociaschini46163 ай бұрын
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.
@MilanJovanovicTech3 ай бұрын
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-mf3gh3 ай бұрын
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.
@MilanJovanovicTech3 ай бұрын
What if you're deserializing?
@modernkennnern3 ай бұрын
@@MilanJovanovicTechDepends on your serializer of course, but STJ supports required properties
@Rick-mf3gh3 ай бұрын
@@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.
@timur28873 ай бұрын
Nice and fancy! But with double overhead...
@MilanJovanovicTech3 ай бұрын
True! But use the idea, not the example.
@ajaysingh-sc1qt3 ай бұрын
Great explanation with example !!
@MilanJovanovicTech3 ай бұрын
Glad you liked it!
@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Ай бұрын
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.
@Kupnu40003 ай бұрын
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
@MilanJovanovicTech3 ай бұрын
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.
@Kupnu40003 ай бұрын
@@MilanJovanovicTech Thank you sir!
@joergw3 ай бұрын
Thanks 🤗
@MilanJovanovicTech3 ай бұрын
Thanks a lot! And I'm glad you enjoyed the video :)
@user-px2oj3dg4c3 ай бұрын
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?
@MilanJovanovicTech3 ай бұрын
Will do some research, it's probably either a UUID (Guid) or some sort of timestamp based random ID like snowflakes or ULID
@shadowsir3 ай бұрын
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.
@MilanJovanovicTech3 ай бұрын
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.
@samwalker54383 ай бұрын
Interfaces can be used here too to indicate the next available steps. I’ve seen another channel explaining that.
@simoneesposito84473 ай бұрын
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?
@MilanJovanovicTech3 ай бұрын
What do you mean by: "automate the creation of the builder from a DTO"
@nucasspro13 ай бұрын
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 :)
@MilanJovanovicTech3 ай бұрын
Is it only getters/setters? Probably overkill for that. If there is some logic inside, then it makes sense.
@user-xm7sh3vw8o3 ай бұрын
For example, in the order details table, it will not be too complicated to have too many fields
@MilanJovanovicTech3 ай бұрын
What do you mean?
@user-xm7sh3vw8o3 ай бұрын
@@MilanJovanovicTech If there are too many fields, will the use of builds be too large and not conducive to writing and maintenance?
@pedrosilva14373 ай бұрын
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.
@andreibicu55923 ай бұрын
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.
@MilanJovanovicTech3 ай бұрын
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.
@pedrosilva14373 ай бұрын
@@MilanJovanovicTech That makes sense... I was thinking along these same lines.
@PhobiaQQ3 ай бұрын
What if I have rich domain model and my business rules are validated inside the entity?
@MilanJovanovicTech3 ай бұрын
Then you'll probably control the creation from the domain model?
@sujitbhandarkar8863 ай бұрын
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
@MilanJovanovicTech3 ай бұрын
How would it help?
@sujitbhandarkar8863 ай бұрын
@@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); } }
@shabanelmogy79123 ай бұрын
we need big tutorial for blazor and whats your opinion in it ?
@MilanJovanovicTech3 ай бұрын
I don't use it, but I like the tech
@alexmel84482 ай бұрын
Why does the empty method is static ?
@MilanJovanovicTech2 ай бұрын
Just to start off the builder. Or you could do new OrderBuilder() ....
@ajdinhusic257418 күн бұрын
What do you think about the importance of using immutability in builder patterns?
@MilanJovanovicTech18 күн бұрын
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?
@ajdinhusic257417 күн бұрын
@@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-xm7sh3vw8o3 ай бұрын
Is the address sub-item of the order and the address maintained by the customer the same table?
@MilanJovanovicTech3 ай бұрын
That's a persistence decision
@eduardoandrescastilloperer48102 ай бұрын
Wait, can you edit the code while it is RUNNING?
@MilanJovanovicTech2 ай бұрын
Yeah, with hot reload
@rahulsheelavantar21103 ай бұрын
Nice one, but don't know where I should use it
@MilanJovanovicTech3 ай бұрын
I shared a few use cases
@emfi87443 ай бұрын
Interesting, but it's not functional, as it contains an internal state
@MilanJovanovicTech3 ай бұрын
Is there a way to build a builder without holding state?
@emfi87443 ай бұрын
@@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
@TroyCSchmidt3 ай бұрын
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)
@emfi87443 ай бұрын
@@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?
@emfi87443 ай бұрын
@@TroyCSchmidt Having a fluent syntax does not mean being functional