Treating Primitive Obsession with ValueObjects | DDD in .NET

Become a Patreon and get source code access: / nickchapsas
Check out my courses: dometrain.com
Hello everybody I'm Nick and in this video I will explain what Primitive Obsession is and how you can treat it by using something called ValueObjects. This is a DDD specific concept but understanding it can benefit any developer.
ValueOf on GitHub: github.com/mcintyre321/ValueOf
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
#dotnet #csharp #ddd

Пікірлер: 167

  • @codewkarim
    @codewkarim2 жыл бұрын

    "A double can have a wide variety of number, from Plus a lot to Minus a lot" - Nick Chapsas, 2021

  • @skerdi5822
    @skerdi58223 жыл бұрын

    Please make a whole series on DDD! You’re great, keep it up!

  • @adekunlealugbin4120

    @adekunlealugbin4120

    3 жыл бұрын

    Would love to see it too

  • @nilpunch2

    @nilpunch2

    3 жыл бұрын

    Absolutely thumb up

  • @klajdikume4082

    @klajdikume4082

    3 жыл бұрын

    Thumb Up

  • @ferooref7614

    @ferooref7614

    3 жыл бұрын

    yes pleeease

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    You know what? What's a pretty good idea

  • @strawhenge5007
    @strawhenge50073 жыл бұрын

    I wish more people were open to this kind of idea. So many developers are content validating the same string over and over, at every step in their application. A common response would be "Is it worth making a class just for Celcius?". Yes. Yes, it is.

  • @georget10i

    @georget10i

    3 жыл бұрын

    I watched the whole video (excellent video), but your comment actually made me understand ValueObjects. Interesting how that works. Thanks!

  • @pauldaulby260

    @pauldaulby260

    2 жыл бұрын

    People tend to be happy when they have 2 uuids floating around that can now never be confused in code because you did this

  • @UrzaRage778
    @UrzaRage7782 жыл бұрын

    I LOVE this! We had an issue w/ postal codes at some point because we're handling them as strings, and this sort of design decision would have been a HUGE help in preventing the massive time waste of looking for where things went wrong. Thank you so much for all of your videos, they're definitely helping add to my "Good ways to program" folder.

  • @toastybowl
    @toastybowl3 жыл бұрын

    Looking this video up again because someone recently showed me some code with tons of primitives + implicit mutations in its control flow & they had asked me to find a bug, but I couldn't explain in a short time the full implication I felt went into the refactorings. It's tough to tell sometimes whether another person shares one's understanding without properly scoped reference materials, & that is for sure what brings me back to the channel. Thanks again buddy. Def going to check out value of + one of later

  • @robertmrobo8954
    @robertmrobo89543 жыл бұрын

    It's almost three months now I'm trying to get my head around DDD with no success. Please make a whole series on DDD! The way you are good in explaining difficult things, I'm very confident I will be a guru in next to no time. Thanks for the great work up to so far. thanks.

  • @IvanArdillo

    @IvanArdillo

    3 жыл бұрын

    I'm kinda in the same struggle, but luckily for just a week. I feel like this whole DDD/Clean Architecture stuff is the must-know that would enable me to finally tackle software engineering from a very high quality point of view. In fact, I asked above about some resources such as books, online courses and videos that could bring me a very comprehensive view, in order to study it seriously.

  • @IvanArdillo

    @IvanArdillo

    3 жыл бұрын

    @Nickolai Paromov Thank you very very much for the info! I'm taking a look at his stuff, reviews on his books and people look like very happy with his work. I have a question: do you think that is approach to teaching and explaining is similar to the Nick Chapsas's one? Because I often see that even if some mentor explains the same concepts, patterns and shows some code about it, some of them present much hand-written code, so for me it's more difficult to follow, while others tend to keep things more easily understandable by using Nuget packages, like Nick does, such as Automapper, MediatR and stuff and concentrating on higher level concepts.

  • @IvanArdillo

    @IvanArdillo

    3 жыл бұрын

    @Nickolai Paromov ok I get it! Thank you very much!

  • @MMMM-vc5oi
    @MMMM-vc5oi2 жыл бұрын

    Perfect Nick, your channel is awesome In my opinion, for these short lived small value objects, structs are better or records. Temperature, Vector, etc. If we should not use structs for small immutable value objects, where should we utilize structs? Maybe, it is useful to talk about that in a video, I mean where you employ structs

  • @IvanArdillo
    @IvanArdillo3 жыл бұрын

    Hi Nick, I'm so grateful for your content! You're opening my eyes on a bigger vision about software development, because I'm not an advanced developer and I'm alone at my company taking challenging decisions. You're DDD approach and the video about Clean Architecture are opening a new world of possibilities: can you give me some information where I can study all the necessary content about this kind of development? Online courses, books and videos, any kind of structured content. I love your work and you're my light, keep working!! 🚀🚀🚀

  • @branislavpetrovic7486
    @branislavpetrovic74863 жыл бұрын

    Very simple explanation of Value Objects in DDD! Thanks

  • @mastermati773
    @mastermati7733 жыл бұрын

    Thank you for the video. Small note: My lead would assassinate me for direct comparing doubles for equality xD.

  • @bogdanpanchuk296

    @bogdanpanchuk296

    2 жыл бұрын

    As far as I understand comparing ValueOf doubles compares doubles under the hood so any of the usual problems associated with that still remain.

  • @vitaliidolotov4226
    @vitaliidolotov42262 жыл бұрын

    Such a nice explanation, thank you!

  • @meirkr
    @meirkr3 жыл бұрын

    One of the best lectures. Tx!

  • @michaelganzer3684
    @michaelganzer36843 жыл бұрын

    Wonderful explanation of ValueOf. But I strongly suggest to refrain from using the unit of temperature as the type name. This definition error leads to 'Celsius' being the magnitude holder, when it should be 'TemperatureInCelsius'. Please trust me on that one. The moment you have to convert from one to the other unit within ISQ scope, you will find yourself rewriting all your code. The presented code contains 'Celsius' as a convention, known to the developer only. It could have been 'Bob' as well. ;)

  • @michaelganzer3684

    @michaelganzer3684

    Жыл бұрын

    @@milanstevic8424 You did not get my point at all. Please consider that you may have totally misinterpreted my comment by inducing your level of knowledge on a topic that requires a deeper understanding. You've questioned the wrong things, based on your understanding. Try not to throw types, instances, properties, behaviour and naming into one big container, which you may stir vigorously. Degrees Celsius (°C) is a derived unit without any magnitude, so it's neither a quantity nor a measure itself. I suggested the type to be called 'TemperatureInCelsius' as a more understandable quantization compared to naming the type 'Celsius'. See how you proved my point already by totally mixing up things. But have a look at the definitions by yourself, please: en.wikipedia.org/wiki/International_System_of_Units

  • @v0id_d3m0n
    @v0id_d3m0n2 жыл бұрын

    this is so clever... i never thought of this. i will definitely start doing it in my code!!

  • @noblenetdk
    @noblenetdk2 жыл бұрын

    These videos are pure gold nuggets. Let me know if you ever start as a teacher on skillshare - keep up the good work

  • @gigik64
    @gigik643 жыл бұрын

    That's what I always try to explain to people. If you're writing data validation services thay you then inject into your application there's one or both of these problems: 1) You misconfigured the DB, so your engine is not validating the right stuff when you're persisting data 2) You misdesigned the domain, or maybe you didn't misdesign it, but it's still anemic

  • @jandvorak3535
    @jandvorak35352 жыл бұрын

    Your mileage may vary, but basically at beginning I thought this is really a nice idea, so I used it at one medium-size project with DDD, event sourcing and all the jazz. After a while my opinion is that the merits does not out-weight the negatives. Negatives being an explosion of types "converters" around serialization, deserialization and AutoMapper, which are needed for translation back and forth of those value type objects to scalar values, which serializers do understand. In short, they look and work quite nice in domain model and suck everywhere else.

  • @AnythingGodamnit

    @AnythingGodamnit

    Жыл бұрын

    Yep, works in the small using C#, works in the large using F#

  • @znefas

    @znefas

    Жыл бұрын

    @@AnythingGodamnit Never looked at F# much as a C# student. What makes it so great for you to say that DDD works well everywhere in F#?

  • @stephenraphael6911
    @stephenraphael69113 жыл бұрын

    Hi Nick, really cool video , hope you'll continue explore this approach(DDD) futher

  • @RichardONeil
    @RichardONeil3 жыл бұрын

    Perfect! I love these videos!

  • @clearlyunwell
    @clearlyunwell3 жыл бұрын

    This is really useful, thanks 🙏

  • @adriano.digiere
    @adriano.digiere3 жыл бұрын

    Great video. I hope you explore DDD in new videos. Thanks.

  • @matheusjahnke8643
    @matheusjahnke86439 ай бұрын

    One rabbit hole which ValueObject might make you stumble: operations over them... Should Celsius have a addition operation? A subtraction operation? A multiplication, a division? For the ones you said yes, which type should be the return? The same type, a raw float, something else entirely? TL,DR: We can only subtract and weighted averages. And for subtraction the result is a class CelsiusDifference which can get get below -273.15ºC and it can have all the 4 operations(addition and subtraction with other Celsius differences, multiplication and division with raw floats). Read more about that by searching for"affine space". Temperatures are actually a nice example to explain it. The mathy name for this kind of structure is an affine space... Addition over temperatures kinda breaks logic: 0ºC + 0ºC = 0ºC But 0ºC = 273.15 K... so 0ºC = 0ºC + 0ºC = 273.15 K + 273.15 K = 546.3 K = 273.15ºC Which is an absurd.... hence addition here is absurd.... this happens to affine spaces because they don't have a "special" 0... in particular, the 0 in Celsius is not the 0 in Kelvin... so addition on both scales give different result(a.k.a. the absurd math I did). On a similar argument you could argue multiplication and division are nonsensical. But, somehow, we still can calculate means... (0ºC + 0ºC) / 2= (0ºC)/2=0ºC (273.15 K + 273.15 K) / 2 = (546.3 K)/2=273.15 K This happens because the means are midpoints... And we still can calculate midpoints. Instead of thinking "(a+b)/2", think: start at "a", then find the vector from "a" to "b", then divide by 2 and apply to "a" a + (b-a)/2... which you check out the math to get (a+b)/2... you can even check that if we flipped "a" and "b", we would have gotten the same result. But note we are using subtraction and division... And here is the hope: we can use subtraction. When we subtract temperatures... the result is not a temperature of an object, but a temperature *difference*, which isn't bound by the same restrictions: you can have an object go from 1000ºC to 0ºC... resulting in a temperature difference which is below the -273.15ºC which would be the absolute 0. Here, the 0 actually has a meaning: no temperature difference, the 2 temperatures compared are the same. So a 0K difference is a 0ºC difference, but 0K temperature is -273.15ºC temperature. Another point which is important to note is that affine differences can be multiplied and divided without breaking logic... And, *sometimes*, they can be added to an element of the affine space to get another element of the affine space: Like I did before: A and B are affine objects B-A and (B-A)/2 are affine differences So A + (B - A)/2... or (A+B)/2 is an affine object... If the coefficients add 1(a.k.a. we have a weighted average), then this is guaranteed to work. Else we are in a wild territory.

  • @craigmunday3707
    @craigmunday37073 жыл бұрын

    I like the practice of creating these domain specific primitives, but shouldn't value objects be created as a struct instead of a class so it doesn't need to get allocated on the heap?

  • @Miggleness

    @Miggleness

    2 жыл бұрын

    how and where something is allocated should not affect your decision making for value objects. use classes (or even better, records) unless you have specific reasons for using structs. Id only use structs if I have something that NEEDS optimisation by “locality” of data.

  • @matthewcollings3387
    @matthewcollings33873 жыл бұрын

    Love your videos. If I am making an API with MediatR and FluentValidation, should I still use value objects for things like postcode. If so, should I have a static Validate method to us from the vlaidator instead of getting an exception from the constructor when I map the Command to domain object?

  • @Huebeiro
    @Huebeiro3 жыл бұрын

    Great video!

  • @7th_CAV_Trooper
    @7th_CAV_Trooper Жыл бұрын

    This is going to save me a lot of time.

  • @astralpowers
    @astralpowers3 жыл бұрын

    I love that trick with generics where you have the derived class as one of the generic parameter of the base class. I learned that when I was doing business objects in the .NET Framework 2.0 days, and I thought it looked weird at the time.

  • @diopistacchio5037
    @diopistacchio50373 жыл бұрын

    Love your videos 😁✌️

  • @qniken8770
    @qniken87703 жыл бұрын

    Shit man, Nick. Just discovered your vids. They're great!

  • @fedorarefyev5839
    @fedorarefyev58392 жыл бұрын

    Technically you could have made Celsius a struct and have validation inside getter / setter of Temperature property. It will also be more performant option if used in big collections because there will be no boxing/unboxing performance penalty. What do you think, are we not reinventing the wheel at this point?

  • @fuchsfarbe7660

    @fuchsfarbe7660

    Жыл бұрын

    I had the same thought, honestly. I know this is an example, but don't you want to typically avoid throwing exceptions for stuff like this as well? Because exceptions have to be dealt with, but returning a minimum -253 avoids the client having to deal with it.

  • @temp50
    @temp503 жыл бұрын

    How should business objects propagated between for example an SPA backend and frontend code? The backend is in C# but the frontend is a nodejs app (angular + ts). So if I wanna have the exactly same validation logic on both side, what is the recommended way to do so?

  • @StileLiberoSud
    @StileLiberoSud2 жыл бұрын

    Great !

  • @HistoireDuViolet
    @HistoireDuViolet3 жыл бұрын

    Is there any way to use oneOf with a validation using MediatR's pipeline behaviors?

  • @akhilbandari629
    @akhilbandari629 Жыл бұрын

    Hi, @Nick Chapsas Thanks for sharing the information. What if the Primitive types do not contain any validation? Example: Accepting any Positive number (uint) Public Class Test { public uint Id {get; init;} } Will it be a good idea to move "Id" own class (ValueOf) ?

  • @feelingeverfine
    @feelingeverfine3 жыл бұрын

    You can use records instead of a ValueObject class pretty easily. Love this new feature

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    Yeah records make it very easy to use and implement ValueObjects, that's actually exactly what I'm doing since C# 9. I wanted to show the concept to people that might not be familiar with it using a libary that streamlines it.

  • @MrBestard

    @MrBestard

    3 жыл бұрын

    How's the entity framework support for record? I would like to move away from enums

  • @feelingeverfine

    @feelingeverfine

    3 жыл бұрын

    @@MrBestard works perfectly. Just know that change tracking doesn't work with copied values

  • @haydensprogramming6766

    @haydensprogramming6766

    3 жыл бұрын

    I will say that with records, there may be a use case for having the value as a collection, which in that case, Microsoft's implementation is best docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/implement-value-objects

  • @andreibicu5592
    @andreibicu55922 жыл бұрын

    Hi Nick. Great videos here! About the exceptions, don't you think using a Result would be better than throwing an exception? I've seen cases with long computation time, where the performance is bad because of the exceptions.

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    It really depends on your application. Usually services that use DDD in that capacitiy are bigger and performance isn't the absolute number one priority, so for those services it makes sense to use something like this. I personally work with performance being a feature so for me, this isn't something I can use.

  • @pdevito
    @pdevito3 жыл бұрын

    Nice! Any particular method you recommend when you want the property to play nice with EF migrations? Not immediately apparent how EF would know how to map that to a particular field type in SQL.

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    ValueOf has explicit and implicit operators so it should treat it as the primitive that is backing it up but EF to me is the data layer and it doesn’t have to know about domain specific concerns like Celsius for example

  • @pdevito

    @pdevito

    3 жыл бұрын

    @@nickchapsas So you'd be adding these valueof props to your dtos versus the core data entity that represents the db table?

  • @jducobu
    @jducobu Жыл бұрын

    Hi Nick, since the introduction of the record, the valueof nuget package is obsolete right?

  • @abdelhaleemalfreihat7261
    @abdelhaleemalfreihat72613 жыл бұрын

    You are amazing

  • @modernkennnern
    @modernkennnern2 жыл бұрын

    I watched this video when you released it. I understood it back then, but I didn't really understand how important it was. Since then I got my first job, and realized just how bad some codebases are when it comes to this. More or less our entire backend database is strings(even for numbers :| ) - some ints, but almost nowhere were any structs or similar used. It's better now that I've started working on it, but still a lot of shit

  • @christophbornhardt7888
    @christophbornhardt78883 жыл бұрын

    Hi. I understand the pros of using the ValueOf library, but why don't use structs insteead of classes for that? Isn't that why the concept of structs were made? Btw, I just discovered your channel 2 weeks ago. I love it and have learned a lot. Thank you.

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    Structs have conceptual issues with the encapsulation required for ValueObjects. Records actually solve those concerns and come with all the necessary equality check overriding done for you out of the box, so if you are familiar with the concept I would recommend them over ValueOf and structs. Structs were not made to represent value objects though, no.

  • @viktorhh

    @viktorhh

    3 жыл бұрын

    @@nickchapsas could you please expand on this? I'm using older version of .Net (no records available) and I use structs for this purpose. Great videos, I like your style of coding

  • @arcowo
    @arcowo Жыл бұрын

    Since you can overload the == operator in C#, how do you check for reference equality?

  • @ricardovicentini
    @ricardovicentini3 жыл бұрын

    Hi Nick, greate video! Could you explain the advatages of using ValueOf over Record in c# 9? And about the validation that you implemented for Ceucius ValueObject woudn't it be better implement a notification technic instead of throwing an exception? Thank you very much!

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    The common pattern with ValueObjects is to throw on validation because notification based erroring messes up the flow. Tha being said, you can do whatever works for you. The core concept is wrapping the primitives with obejcts to represent them, not the validation. About Record, yeah I'm using records to do this personally but the counter arguement is that sometimes, not all properties need to be taken into account for equality purposes so it gets a bit more complicated. It's a rare thing but it can happen.

  • @ermanafacan
    @ermanafacan3 жыл бұрын

    I know it might not be necessery for the purpose of the video but the TemperatureBelowAbsoluteZeroException class should be [serialisabile] and the best practice is to implement additional constructor with the inner exception.

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    Yeah that's 100% true. Originally I wouldn't make this exception at all when I first scripted the video but as I was on it i realised that I could talk about domain specific exceptions instead of the generic ArgumentException, which is why I didn't "properly" do it.

  • @Maritims
    @Maritims3 жыл бұрын

    Lovely video Nick! Primitive obsession is not something I was aware of before watching this, but trying to combat it makes a lot of sense. Gonna keep this in mind :D

  • @isnotnull
    @isnotnull3 жыл бұрын

    Hi Is it possible to use ValueOf directly in the http request? For instance, I have a POST controller method: public async Task SaveTheWeather(WeatherForecast weather) { } Does the framework correctly bind a value got from http payload to Celsius field?

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    It is possible but you should do it. The donation layer should not leak through the Api layer. You should map it to a version api response contract instead

  • @silkfire
    @silkfire Жыл бұрын

    How do you handle the exception in the controller so elegantly? Are you catching exceptions in your Startup class? And how do you map the Validation errors specifically to a BadRequest response?

  • @sampleuser7727
    @sampleuser77272 жыл бұрын

    But a single property used as a value object doesn't easily wire up to EF 6, EF Core. Not as I could find it. The solution works well in a vacuum.

  • @malcolmchambers4934
    @malcolmchambers49343 жыл бұрын

    The other big advantage to this approach is related to conversions if you have a temperature in Celcius and another in Farnihite then it stops you from adding two temperatures that have differing scales. unless you create the required conversion code so in Celcius class you can have a method to do the conversion from a Farnihite temp so that addition / subtraction works etc. You can also block other math that does not make sense IE you cannot multiple two temperatures together, but it still makes sense to double for example a tempature

  • @christopherneese7578

    @christopherneese7578

    3 жыл бұрын

    The ValueOf library will implicitly convert Celcius to a double, so this is not a benefit in this example. If you use a C# 9.0 record, none of the arithmetic operators are overloaded automatically; the compiler is primarily concerned with equality. Furthermore, if you try to flesh out the example, as soon as you overload the minus operator, you have a problem since a temperature delta can be negative on the Kelvin scale.

  • @swedev
    @swedev3 жыл бұрын

    Hi Nick( or anyone), quick question. Should the below Absolute Zero exception, display the value of Absolute Zero?

  • @v0id_d3m0n

    @v0id_d3m0n

    2 жыл бұрын

    I assume the answer would be "if you want it to"

  • @denis-suleimanov
    @denis-suleimanov3 жыл бұрын

    What about orm and code first approach? For example: we have an Person type with property CardNumber as string and now we decide to use custom type CardNumber instead of primitive string. If I understand correctly we have an option like "value object" or records, right? So... how we should configure entities (ef core) properly?

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    This has nothing to do with a database and these objects would not be saved in a db. This is about the domain layer which is about 2 layers away from the database.

  • @berylliosis5250
    @berylliosis52503 жыл бұрын

    A note on postal codes - they shouldn't be stored as a string ValueObject, they should be a class of two enums and an int (in the UK). Stringly typed systems are still stringly typed if you add encapsulation. General rule for avoiding stuff like that is that strings generated by code should not be consumed by code, and anytime you're creating a postal code without user input you would break that rule.

  • @ragavendrannatarajan1381
    @ragavendrannatarajan13813 жыл бұрын

    Hi Nick, do we have any session on design patters

  • @awadosman1475
    @awadosman1475 Жыл бұрын

    Can we just override casting to double with implicit operator for example and get rid of the Celsius.From ?

  • @igorthelight
    @igorthelight3 жыл бұрын

    11:33 - You also may say "if you care about small decrease in performance - why would you use a language that uses JIT in the first place? Use C++ and manage memory by yourself or use C and almost never touch the Heap!" ;-)

  • @EspenSkaufel

    @EspenSkaufel

    2 жыл бұрын

    This is just plain wrong...

  • @igorthelight

    @igorthelight

    2 жыл бұрын

    @@EspenSkaufel Please elaborate :-)

  • @EspenSkaufel

    @EspenSkaufel

    2 жыл бұрын

    @@igorthelight The idea that you can solve something as complex as software optimization with don't use jit and don't use heap is at best naive. The topic is a lot more complex than you give it credit. Jit languages use precompiled machine-specific libraries, and they can compile machine-specific instructions. AOT code has to branch to support hardware-specific features, and it can never take advantage of hardware optimizations (not all CPUs are the same) that were not implemented in the compiler when it was built. AOT will outperform JIT for short-lived applications, but shot-lived is not the typical use case, and short-lived hardly needs optimization (except for showing off in benchmarks). There is no inherent reason AOT should be faster except for the startup time. The stack vs. heap (want speed? pass by value) is oversimplified again. What is most performant depends on the size and access pattern of the data. A large class or struct object would require a copy of the data; primitives are much faster when passed as values. At least, that is what my education taught me.

  • @igorthelight

    @igorthelight

    2 жыл бұрын

    @@EspenSkaufel Fair points!

  • @diligencehumility6971
    @diligencehumility69712 жыл бұрын

    Would you also create a table in DB for each value object? Or would you convert the Celsius class to a double - and if so, how?

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    These are just in-code objects they wouldn't translate to db objects. In DB you would use their actual value and that's done with implicit operators which will automatically convert them to their backing primitive

  • @bonaoenchelcha
    @bonaoenchelcha3 жыл бұрын

    If you create a course on DDD would not hesitate to buy it

  • @richardhaughton9633
    @richardhaughton96333 жыл бұрын

    Hi, I've been struggling to do a simple thing with this library. Let's say I wan't to enforce Uppercase when I new up my value object. In this case I should use the VO.From(s) but I have no way to override the from method. Am I doing something wrong? thanks for your help.

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    You don’t need to override the from method. Override the Validate method and add the validation logic there

  • @richardhaughton9633

    @richardhaughton9633

    3 жыл бұрын

    @@nickchapsas Thanks for your quick response Nick. I don't want to validate it. I just want to transform my values, give lowercase strings to the From method store them as uppercase. In a constructor I would simply ToUppercase my strings before assigning them to private fields.

  • @richardhaughton9633

    @richardhaughton9633

    3 жыл бұрын

    In other words just apply a transformation to my values. Let's say for an integer you would want to multiply it by 2 for whatever reason.

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    @@richardhaughton9633 It's not the responsibility of the ValueObejct to mutate the data. It's it's responsibility to validate that the data used fit specific criteria .

  • @Raffix394
    @Raffix3943 жыл бұрын

    Do you still need them in C# 9 or are records the better choice there?

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    Records can be used but there isn't really a "better" choice but rather what type of implementation of ValueObejct you wanna go with. ValueOf comes with a lot out of the box and it will do a lot of stuff that records will do for you, but you can re-implement it in records and you will be fine

  • @bogdan.p
    @bogdan.p3 жыл бұрын

    Why wouldn't we use the same validation logic in the Celsius class constructor, but without using ValueOf nuget package? I see it simpler this way. The only thing that will not be the same will be the equality check, but that's not like an advantage, but more like a difference. What do you think?

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    The equality check is way more important of an element for ValueObjects than the validation. Immutability and equality are the building by blocks of the concept. As long as you honour them, the rest is implementation details.

  • @mattia558
    @mattia5583 жыл бұрын

    is there a similar library for java?

  • @ricosaupe
    @ricosaupe2 жыл бұрын

    You've got a lot of very interesting videos. Keep going. One question though. I am trying to combine valueof and mapster and doesnt seem to be working. I tried with that model. public class Birthday:ValueOf Mapster then always wants to new up Birthday but cannot do because the Value property is protected. It should Birthday.From instead. Is there any trick to achieve that? Birthday = p1.Birthday == null ? null : new Birthday() {Value = p1.Birthday.Value} should do the following Birthday = p1.Birthday == null ? null : Birthday.From(p1.Birthday.Value)

  • @void_star_void
    @void_star_void3 жыл бұрын

    Idea for next vid: usage with ef

  • @LCTesla
    @LCTesla2 жыл бұрын

    my boss and a bunch of people around him actually thinks the opposite of this... keep telling me "don't use date objects, use strings instead"... the justification is supposedly that timezones keep messing things up, but imo the solution is to just handle localization as intended... I ask myself every day why I still work for them.

  • @ayalamac
    @ayalamac Жыл бұрын

    Hey, it's been a year since you posted this. I've seen that ValueOf is not being updated anymore. Can you provide some insights about mixing FluentValidation with Value Objects? (using current version of Valueof of or any other library)? Thank you for all of your amazing content.

  • @juliansegura5507

    @juliansegura5507

    Жыл бұрын

    You can try with records. They have these functionality build in by default.

  • @klaxxon__
    @klaxxon__2 жыл бұрын

    My biggest issue with wrapping of primitives is that they are purely spefic to your application and nothing else supports them. Database entities, serializers, UI libraries and other things need their values in a an actually primitive format. You might be able to make adapters for some cases (eg. Newtonsoft JSON definitely allows you to make those), but that just adds an unnecessary amount of conjured complexity and library lock-in (good luck switching serialization library or DB library if you have invested into a whole bunch of adapters...). And if the bulk of your application is just shifting values between external interfaces and database (as many are), wrapped primitives are a complete overkill. Another constraint is that you must not particularly care about performance of your code throughout the bulk of your application. I could see using these in eg. a game, since those tend to have a lot of logic, complexity of which could be potentially by having clearly marked values such as Damage or Health (and relationships between those being coded into the wrappers), but then you start coding some basic AI and discover that you lose a % of your FPS to peddling these wrappers. Not that something like Unity would particularly encourage you to introduce novel ways to represent numbers...

  • @L-E-son
    @L-E-son2 жыл бұрын

    At 3:15 he mentions a domain project and a "dot contracts project". I've done quite a bit of googling but I cannot determine what that is. Can anyone provide me with a little more information please?

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    Hey John. I'm refering to the project names here. The Domain and Contracts folders would be projects themselves instead of being in the PrimitiveObsession.Api project. The names I was referring to are the final names of those projects which would be PrimitiveObsession.Domain and PrimitiveObsession.Contracts

  • @zedmagdy
    @zedmagdy3 жыл бұрын

    how to deal with VO in EFCore?

  • @corruptmind7

    @corruptmind7

    3 жыл бұрын

    Owned types, denormalized database may work ?

  • @venkateshk2732
    @venkateshk27322 жыл бұрын

    How to you deal with serialization of ValueOf object. It doesn't seems to serialize to the primitive type.

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    It does. There is serialisation support

  • @christopherneese7578
    @christopherneese75783 жыл бұрын

    ValueObjects are very useful, but I think the Celcius class is a poor example. The Celcius class seems like an attempt to use a custom ValueObject type to compensate for C#'s (and the CLR's) lack of a units-of-measure feature like the one in F#. In the scientific computing domain, I would strongly suggest using a double here. Otherwise one can't do any math on the value without overloading additional operators or converting back and forth between the primiative type and the custom type. It is worth noting that the ValueOf class will implictly convert to the underlying primative, so adding two Celcius objects will result in a double not a new Celcius object (which would be the domain-based expectation).

  • @kabal911
    @kabal9113 жыл бұрын

    Maybe I missed it, but how is the API response unwrapping the value object? I.e it returns ‘“temp”: 30’ and not ‘“temp”: { “value”: 30}’

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    The API response is a contract so things like the valueobject don't matter. It will be mapped to a double to be returned to the client. That being said ValueOf is implementing implicit and expicit operators so it would do the conversion for you.

  • @kabal911

    @kabal911

    3 жыл бұрын

    Ahh ok, the implicit operator stopped you getting a compilation error in your mapper 👍🏻

  • @ch47

    @ch47

    2 жыл бұрын

    The implicit operator in ValueOf has been removed, so perhaps a different approach may yield better results. Change the WeatherForecast class and add a constructor, accepting a Celsius value. Expose a readonly property TemperatureC, which just returns the Value of the Celsius object. e.g. public class WeatherForecast { private readonly Celsius _celsius; public WeatherForecast(Celsius celsius) { _celsius = celsius; } public DateTime Date { get; set; } public double TemperatureC => _celsius.Value; public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string Summary { get; set; } } The action method in the controller would also require a minor change: [HttpGet] public IEnumerable Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast(Celsius.From(rng.Next(-20, 55))) { Date = DateTime.Now.AddDays(index), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); } I hope this helps 😃

  • @bonaoenchelcha
    @bonaoenchelcha3 жыл бұрын

    te amo

  • @corinnarust

    @corinnarust

    2 жыл бұрын

    eu tbm

  • @heathbaron2277
    @heathbaron22773 жыл бұрын

    Are you not worried about using a random package as such an important dependency?

  • @KenB782
    @KenB7829 ай бұрын

    How to map this with entityframework

  • @tenshizer0
    @tenshizer09 ай бұрын

    isn't better to use struct for this specific scenario?

  • @DrHeinzDoofenshmirtz
    @DrHeinzDoofenshmirtz3 жыл бұрын

    Hi Nick. What is your opinion on using Value Objects for everything, including Id fields etc.? Please tag me if you respond :) else I don’t get a notification.

  • @alexisfibonacci
    @alexisfibonacci2 жыл бұрын

    I think F# espouses this cure for primitive obsession. It is a language feature.

  • @bimsherwood7006
    @bimsherwood70063 жыл бұрын

    You can make the type system work for you: It can prevent you from passing a postcode when you meant to pass a phone number.

  • @ChazAllenUK
    @ChazAllenUK3 жыл бұрын

    I'm surprised by the comment about performance. Doesn't the compiler replace your ValueObject with the primitive + a static method for validate?!

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    Not if it’s a class no

  • @hanspetervollhorst1
    @hanspetervollhorst13 жыл бұрын

    would you mind sharing that little project on github?

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    The source code for my videos is available on GitHub for my Patreons

  • @lee45283
    @lee452833 жыл бұрын

    Why not just use struct’s?

  • @BlueRaja
    @BlueRaja2 жыл бұрын

    Shouldn't the domain type here be "Temperature", not "Celsius"?

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    It should be Celsius, inheriting from Temperature but I skipped that part since it’s the only temp measurement in the video

  • @syriuszb8611
    @syriuszb86112 жыл бұрын

    Wouldn't the ValueOf be just better as a struct? You don't change the value, just instantiate it every time, and you don't compare references but values. If I would see it in the wild, but without the knowledge how it works, I suspect it would confuse me.

  • @portlyoldman
    @portlyoldman3 жыл бұрын

    I can only hear the words “primitive obsession” in Vladimir Khorikov’s voice…

  • @felixp535
    @felixp5352 жыл бұрын

    I would use a struct in this case, and not use ValueOf. Allocating all variables on the heap doesn't sound acceptable to me

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    This is actually mostly false. Properties will be allocated on the heap along with their parent class, no matter whether they are a reference of a value type. Also passing value types around is way more expensive than passing reference types around. Also the whole idea of the value object is that it's created in a very controlled way and structs don't lend themselves for such a usecase due to their initializaiton contraints. At this point your best bet in C# for a value object is a record.

  • @felixp535

    @felixp535

    2 жыл бұрын

    ​@@nickchapsas Yes, I see what you mean. I personally don't like this inheritance, as I prefer having control over how things flow, and inheriting from ValueOf everytime makes me indirectly lose control over the creation process of the object. I would prefer rewriting GetHashCode and .Equals everytime (it's not that annoying and a lot clearer to me). I tend to limit inheritance as much as possible, and only use it when it actually makes sense for things to inherit from another. Storing everything on the heap makes me quite worried about garbage collection (working in the video game industry, I absolutely need to have the least amount of garbage created to avoid frametime issues when the GC is triggered).

  • @veljkoradovic9884
    @veljkoradovic98843 жыл бұрын

    -273,15 C°

  • @jonohiggs
    @jonohiggs3 жыл бұрын

    I really like using domain objects but not sure how I feel about adding an entire package for a 95 line class, it feel like we didn't learn the lessons of trivial packages from . Also, looks like it is a class rather than a struct, so anything more than trivial usage is likely to start tanking performance

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    Tanking is a strong word. If newing up objects is your performance bottleneck then you must be wrtting really optimized code. ValueOf is not everyone's cuppa but it's a perfect introduction to the concept. Structs don't play nicely with ValueObjects due to their encapsulation caveats.

  • @jonohiggs

    @jonohiggs

    3 жыл бұрын

    @@nickchapsas It wouldn't be newing them but accessing them off the heap that would be slow. I think a solution that uses source generators would be the best; no need to write the boiler plate code and it would allow nice optimal structs that don't have heap allocations and calls

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    @@jonohiggs I run some benchmarks out of curiosity to get the actual performance degradation on this. Turns out that the hit is on average 16.5 nanoseconds in terms of speed (from 1.8ns without ValueOf) and double the original allocated memory for the underlying type. If you bake validation logic in there then it hits 4ns which is still 4.5 times faster than Value of but we are talking nanoseconds so feels more like premature optimization to me to tell someone who is just starting with the concept to not use this library due to performance issues.

  • @jonohiggs

    @jonohiggs

    3 жыл бұрын

    @@nickchapsas I'd be curious to see the differences between a primative, a struct and the ValueOf, I suspect a struct would have some overhead and the class to have more. Thing with a simple benchmark is that it will probably be able to have all bit of memory in L1 cache at the same time, so in a larger system when accessing the value from somewhere else on the heap result in a cache miss would have a much higher perf penalty

  • @fat-freeoliveoil6553
    @fat-freeoliveoil65532 жыл бұрын

    If only we could inherit from structs then this performance issue wouldn't exist... I get why structs vs classes were designed the way they were in .NET but come on, let the developers do what they want. If we want a value-based class, let us have it.

  • @dandoescode
    @dandoescode2 жыл бұрын

    Could you not do the same with a record (so that you get immutability and equality) and use properties with backing fields so that you can add validation within the property setters?

  • @nickchapsas

    @nickchapsas

    2 жыл бұрын

    Sure but a record is still a struct or a class. You'd be reinventing the wheel at that point

  • @ThiagoCamposdeOliveira
    @ThiagoCamposdeOliveira3 жыл бұрын

    Hi Nick. After watching this video, I looked at the source code of this library and I was not happy. So a friend and I wrote a library, and then we wrote a second one that extends the first, but uses FluentValidation to perform the validations. We publish both libraries on Nuget. Both are open-source. This is the repository of our project: github.com/ThiagoAcam/ValueOf If you can, please give us an opinion. Thanks

  • @Myself0094
    @Myself00943 жыл бұрын

    Why not to use structures this way? Usage is quite the same, performance is a bit better

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    This was addressed in another comment. Stucts have issues when used in this concept because of their encapsulation capabilities. The recommended approach, if you don't wanna use ValueOf IMO is to use a Record since it comes with a lot of the ValueObject concepts out of the box (immutability, equality based on values etc)

  • @corruptmind7

    @corruptmind7

    3 жыл бұрын

    One thing I think is if you want to have a base value object class having some common behaviour for equality comparer or any other behaviour, than you can not use inheritance in structures (you can implement interface though but, u may not want to repeat same logic on every value object declaration) ,I am also on learning curve so if I have misunderstood this ,please do let me know.

  • @Myself0094

    @Myself0094

    3 жыл бұрын

    @@nickchapsas Hm, thanks for reply. Should dig deeper into records features.

  • @hector5851
    @hector58512 жыл бұрын

    I see more and more projects bloated with tons of string wrappers.

  • @BonBaisers
    @BonBaisers3 жыл бұрын

    I am very sorry but I won't ask my domains to handle exceptions during "implicit" convertions. In fact, in my humble opinion, domain and application layers should never deal with nulls and exceptions.

  • @nickchapsas

    @nickchapsas

    3 жыл бұрын

    The domain throws exceptions it doesn't handle them. By definition they are domain specific exceptions. If you wanna get your ValueObjects to validate in a different way you are more than welcome to do it, but traditionally, this is how it works.

  • @BonBaisers

    @BonBaisers

    3 жыл бұрын

    @@nickchapsas There is no real truth only (some) experience and opinion here. If we get a step back, values that need their parsing/conversion to be validated comes from an external source. In DDD, that source is responsable of that. If it's from UI or any datasource, external service, etc... the implementation layer should deal with that kind of issues. I tend to have my domain do only business logic. It deals only with Either (yes, functional) failures, domain models and abstracted infrastucture services. Thank you very much Nick for your great content and amazing quality of your videos.

  • @Layarion
    @Layarion2 жыл бұрын

    2 minutes in and the plosives are everywhere, popping my ears. ffs, please stop.

  • @nishudar
    @nishudar Жыл бұрын

    Why when I try to serialize it I get additional {"Value" : "{realValue}"}. I try not to write any converter. I used JsonSerializer.Serialize