Treating Primitive Obsession with ValueObjects | DDD in .NET

แชร์
ฝัง
  • เผยแพร่เมื่อ 7 พ.ย. 2024

ความคิดเห็น • 167

  • @skerdi5822
    @skerdi5822 3 ปีที่แล้ว +110

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

  • @strawhenge5007
    @strawhenge5007 3 ปีที่แล้ว +47

    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 ปีที่แล้ว +5

      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

  • @matheusjahnke8643
    @matheusjahnke8643 ปีที่แล้ว +1

    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.

  • @codewkarim
    @codewkarim 2 ปีที่แล้ว +15

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

  • @UrzaRage778
    @UrzaRage778 2 ปีที่แล้ว +3

    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.

  • @robertmrobo8954
    @robertmrobo8954 3 ปีที่แล้ว +8

    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 ปีที่แล้ว +1

      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-vc5oi 3 ปีที่แล้ว +14

    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

  • @toastybowl
    @toastybowl 3 ปีที่แล้ว

    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

  • @IvanArdillo
    @IvanArdillo 3 ปีที่แล้ว +5

    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!! 🚀🚀🚀

  • @jandvorak3535
    @jandvorak3535 2 ปีที่แล้ว +4

    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 2 ปีที่แล้ว

      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#?

  • @matthewcollings3387
    @matthewcollings3387 3 ปีที่แล้ว +3

    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?

  • @craigmunday3707
    @craigmunday3707 3 ปีที่แล้ว +10

    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.

  • @vitaliidolotov4226
    @vitaliidolotov4226 2 ปีที่แล้ว +1

    Such a nice explanation, thank you!

  • @michaelganzer3684
    @michaelganzer3684 3 ปีที่แล้ว +3

    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

  • @branislavpetrovic7486
    @branislavpetrovic7486 3 ปีที่แล้ว

    Very simple explanation of Value Objects in DDD!
    Thanks

  • @v0id_d3m0n
    @v0id_d3m0n 2 ปีที่แล้ว

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

  • @akhilbandari629
    @akhilbandari629 2 ปีที่แล้ว +1

    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) ?

  • @mastermati773
    @mastermati773 3 ปีที่แล้ว +11

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

    • @bogdanpanchuk296
      @bogdanpanchuk296 3 ปีที่แล้ว

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

  • @pdevito
    @pdevito 3 ปีที่แล้ว +2

    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 ปีที่แล้ว +2

      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?

  • @astralpowers
    @astralpowers 3 ปีที่แล้ว +4

    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.

  • @noblenetdk
    @noblenetdk 3 ปีที่แล้ว

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

  • @meirkr
    @meirkr 3 ปีที่แล้ว

    One of the best lectures. Tx!

  • @gigik64
    @gigik64 3 ปีที่แล้ว +2

    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

  • @fedorarefyev5839
    @fedorarefyev5839 2 ปีที่แล้ว +2

    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.

  • @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?

  • @christophbornhardt7888
    @christophbornhardt7888 3 ปีที่แล้ว +4

    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 ปีที่แล้ว +4

      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

  • @andreibicu5592
    @andreibicu5592 2 ปีที่แล้ว +1

    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 ปีที่แล้ว +1

      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.

  • @modernkennnern
    @modernkennnern 2 ปีที่แล้ว +3

    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

  • @ricardovicentini
    @ricardovicentini 3 ปีที่แล้ว +1

    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 ปีที่แล้ว +2

      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.

  • @7th_CAV_Trooper
    @7th_CAV_Trooper ปีที่แล้ว

    This is going to save me a lot of time.

  • @ragavendrannatarajan1381
    @ragavendrannatarajan1381 3 ปีที่แล้ว

    Hi Nick, do we have any session on design patters

  • @feelingeverfine
    @feelingeverfine 3 ปีที่แล้ว +2

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

    • @nickchapsas
      @nickchapsas  3 ปีที่แล้ว +4

      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 ปีที่แล้ว +1

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

    • @haydensprogramming6766
      @haydensprogramming6766 3 ปีที่แล้ว +1

      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

  • @adriano.digiere
    @adriano.digiere 3 ปีที่แล้ว

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

  • @swedev
    @swedev 3 ปีที่แล้ว +1

    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"

  • @sampleuser7727
    @sampleuser7727 3 ปีที่แล้ว +1

    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.

  • @bogdan.p
    @bogdan.p 3 ปีที่แล้ว +1

    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 ปีที่แล้ว +1

      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.

  • @ermanafacan
    @ermanafacan 3 ปีที่แล้ว +1

    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 ปีที่แล้ว +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.

  • @arcowo
    @arcowo ปีที่แล้ว

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

  • @temp50
    @temp50 3 ปีที่แล้ว

    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?

  • @malcolmchambers4934
    @malcolmchambers4934 3 ปีที่แล้ว

    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.

  • @igorthelight
    @igorthelight 3 ปีที่แล้ว +2

    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!

  • @stephenraphael6911
    @stephenraphael6911 3 ปีที่แล้ว

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

  • @awadosman1475
    @awadosman1475 ปีที่แล้ว

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

  • @qniken8770
    @qniken8770 3 ปีที่แล้ว +3

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

  • @clearlyunwell
    @clearlyunwell 3 ปีที่แล้ว

    This is really useful, thanks 🙏

  • @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 ปีที่แล้ว +1

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

  • @heathbaron2277
    @heathbaron2277 3 ปีที่แล้ว

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

  • @RichardONeil
    @RichardONeil 3 ปีที่แล้ว

    Perfect! I love these videos!

  • @berylliosis5250
    @berylliosis5250 3 ปีที่แล้ว

    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.

  • @denis-suleimanov
    @denis-suleimanov 3 ปีที่แล้ว

    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.

  • @ricosaupe
    @ricosaupe 2 ปีที่แล้ว

    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)

  • @StileLiberoSud
    @StileLiberoSud 2 ปีที่แล้ว

    Great !

  • @diligencehumility6971
    @diligencehumility6971 3 ปีที่แล้ว

    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  3 ปีที่แล้ว +1

      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

  • @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...

  • @isnotnull
    @isnotnull 3 ปีที่แล้ว

    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

  • @tenshizer0
    @tenshizer0 ปีที่แล้ว

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

  • @diopistacchio5037
    @diopistacchio5037 3 ปีที่แล้ว

    Love your videos 😁✌️

  • @Raffix394
    @Raffix394 3 ปีที่แล้ว

    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

  • @zedmagdy
    @zedmagdy 3 ปีที่แล้ว +3

    how to deal with VO in EFCore?

    • @corruptmind7
      @corruptmind7 3 ปีที่แล้ว

      Owned types, denormalized database may work ?

  • @LCTesla
    @LCTesla 2 ปีที่แล้ว

    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.

  • @christopherneese7578
    @christopherneese7578 3 ปีที่แล้ว

    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).

  • @HistoireDuViolet
    @HistoireDuViolet 3 ปีที่แล้ว

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

  • @bonaoenchelcha
    @bonaoenchelcha 3 ปีที่แล้ว +2

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

  • @richardhaughton9633
    @richardhaughton9633 3 ปีที่แล้ว

    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 .

  • @venkateshk2732
    @venkateshk2732 2 ปีที่แล้ว

    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

  • @BlueRaja
    @BlueRaja 2 ปีที่แล้ว

    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

  • @abdelhaleemalfreihat7261
    @abdelhaleemalfreihat7261 3 ปีที่แล้ว

    You are amazing

  • @alexisfibonacci
    @alexisfibonacci 3 ปีที่แล้ว

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

  • @L-E-son
    @L-E-son 2 ปีที่แล้ว

    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 ปีที่แล้ว +1

      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

  • @KenB782
    @KenB782 ปีที่แล้ว

    How to map this with entityframework

  • @void_star_void
    @void_star_void 3 ปีที่แล้ว

    Idea for next vid: usage with ef

  • @DrHeinzDoofenshmirtz
    @DrHeinzDoofenshmirtz 3 ปีที่แล้ว

    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.

  • @mattia558
    @mattia558 3 ปีที่แล้ว

    is there a similar library for java?

  • @ChazAllenUK
    @ChazAllenUK 3 ปีที่แล้ว

    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

  • @Maritims
    @Maritims 3 ปีที่แล้ว

    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

  • @kabal911
    @kabal911 3 ปีที่แล้ว

    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 ปีที่แล้ว +1

      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 3 ปีที่แล้ว +1

      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 😃

  • @syriuszb8611
    @syriuszb8611 2 ปีที่แล้ว

    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.

  • @lee45283
    @lee45283 3 ปีที่แล้ว

    Why not just use struct’s?

  • @bonaoenchelcha
    @bonaoenchelcha 3 ปีที่แล้ว

    te amo

  • @hanspetervollhorst1
    @hanspetervollhorst1 3 ปีที่แล้ว

    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

  • @bimsherwood7006
    @bimsherwood7006 3 ปีที่แล้ว +2

    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.

  • @felixp535
    @felixp535 3 ปีที่แล้ว +1

    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  3 ปีที่แล้ว

      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 3 ปีที่แล้ว

      ​@@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).

  • @fat-freeoliveoil6553
    @fat-freeoliveoil6553 2 ปีที่แล้ว

    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.

  • @portlyoldman
    @portlyoldman 3 ปีที่แล้ว

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

  • @dandoescode
    @dandoescode 2 ปีที่แล้ว

    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

  • @veljkoradovic9884
    @veljkoradovic9884 3 ปีที่แล้ว

    -273,15 C°

  • @Myself0094
    @Myself0094 3 ปีที่แล้ว

    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.

  • @ThiagoCamposdeOliveira
    @ThiagoCamposdeOliveira 3 ปีที่แล้ว +1

    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

  • @jonohiggs
    @jonohiggs 3 ปีที่แล้ว

    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

  • @hector5851
    @hector5851 3 ปีที่แล้ว

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

  • @Layarion
    @Layarion 3 ปีที่แล้ว

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

  • @BonBaisers
    @BonBaisers 3 ปีที่แล้ว

    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.

  • @nishudar
    @nishudar 2 ปีที่แล้ว +1

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