Wish To Remove Primitive Obsession? Try This Effective Technique!

แชร์
ฝัง
  • เผยแพร่เมื่อ 13 ก.ค. 2023
  • Download the source code for this demo at Patreon: / source-code-for-86061899
    Primitive obsession - it's a silent killer of complex applications. With an infatuation for basic, unstructured types like strings, ints, and decimals, applications often fall prey to unwieldy bugs and the inability to develop intricate features. This obsession stifles potential and curtails robustness.
    In this video, we are showing an effective technique for removing primitive obsession by carefully substituting primitive types with appropriate domain classes.
    Proper domain classes have the power to enrich applications with features and capabilities far beyond the reach of primitive types. However, the transition needs to be safe. We can't afford to disrupt application functionality or introduce bugs while implementing a new feature.
    Therefore, in the technique demonstrated in this video, we are first augmenting primitive types and then transforming them into more sophisticated domain classes. As you will witness, this gradual process is safe and controlled and, at the end of it, you will have your detailed domain implemented and prior primitive types fully eradicated.
    This might sound complex, but it's a journey well worth taking. Over time, the domain model evolves to serve the needs of the business better. It offers depth, structure, and clarity that primitive types can't deliver. The path to better application design and development is right before you. Let's embark on this journey together and reimagine the possibilities of what our domain models can achieve.
    Thank you so much for watching! Please like, comment & share this video as it helps me a ton!! Don't forget to subscribe to my channel for more amazing videos and make sure to hit the bell icon to never miss any updates.🔥❤️
    ✅🔔 Become a patron ► / zoranhorvat
    ✅🔔 Subscribe ► / @zoran-horvat
    ⭐ Learn more from video courses:
    Beginning Object-oriented Programming with C# ► codinghelmet.com/go/beginning...
    ⭐ Collections and Generics in C# ► codinghelmet.com/go/collectio...
    ⭐ Making Your C# Code More Object-oriented ► codinghelmet.com/go/making-yo...
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⭐ CONNECT WITH ME 📱👨
    🌐Become a patron ► / zoranhorvat
    🌐Buy me a Coffee ► ko-fi.com/zoranhorvat
    🗳 Pluralsight Courses ► codinghelmet.com/go/pluralsight
    📸 Udemy Courses ► codinghelmet.com/go/udemy
    📸 Join me on Twitter ► / zoranh75
    🌐 Read my Articles ► codinghelmet.com/articles
    📸 Join me on LinkedIn ► / zoran-horvat
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    👨 About Me 👨
    Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my TH-cam channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⚡️RIGHT NOTICE:
    The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorized to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
    ⭐For copyright or any inquiries, please contact us at zh@codinghelmet.com
    #csharp #objectorientedprogramming #dotnet
  • วิทยาศาสตร์และเทคโนโลยี

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

  • @zebcode
    @zebcode ปีที่แล้ว +13

    Where has this video been all my life? 🎉

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +8

      In my drawer :)

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

      @zoran-horvat I think there were two good lessons in this video.
      1) Don't obsess over primate types for structured data.
      2) Small changes, otherwise you end up in a mess and can't remember what problem you're even tying to solve.

  • @JamesWHurst
    @JamesWHurst 11 หลายเดือนก่อน +6

    I only recently discovered your channel, Mr Horvat, but I must say -- I believe you are already my fav developer-instructor. Your content is higher-level but pragmatic, and you are EXCELENT with your presentation. You do have a strong accent which, in your case -- actually enhances your clarity. Or perhaps you are taking great care to speak deliberately and clearly? Regardless, I love how you present your topics, I appreciate the work you put into these and THANK YOU for sharing this excellent instruction and advice.

  • @makemeafirewall
    @makemeafirewall 2 หลายเดือนก่อน +2

    It shows that you are a real professional

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

    I'm glad TH-cam suggested your videos. Instant subscribe

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

    I'm very excited for the next video. Subscribed!

  • @Peter-wd3fq
    @Peter-wd3fq ปีที่แล้ว +5

    Really love your content!

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

    Excellent video. Looking forward to the next one. String especially can be painful. A lot of "strings" are actually "html strings", hence a + b should not necessarily be a simple concatenation. So many urls are often stored in strings, instead of a Uri. There many, many "types" of string and not understanding how to combine "types" of string is huge cause of bugs and even security issues (see "SQL strings").

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

    As always, great video. One thing that might be a good content for the future video is to use more strict access modifiers for classes to communicate with a dev more clearly about the intentions but also provide some encapsulation so that classes like Citation cannot be used in, let say, Infrastructure layer.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      I am not a fan of hiding models. What would be the reason not to allow persisting Citation instances, for example?
      When I want to indicate that some models are better used indirectly, I place them into a nested namespace. The parent namespace then provides all the means necessary to declare and create instances, but the models themselves are public like any other. That for one thing dismisses the question of how to test them.

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

    Great content, better than most other c# channels :) , The only small suggestion or conern I have is the usage of implict operator for Citation instead of proper static factory method, but I also understand, this is the most obvious way to not break any existing code

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      That was precisely the idea - to try not to cause any change in any other class before that step ends and we verify that nothing is broken. The final goal is to delete the conversion operator when the entire redesign is over.

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

    This is great advice, and given the context of a c# application with buisness logic this seems like a good default practice in most cases. Your point about the inflexibility of them is well taken. However if applied more generally I would say primitives have some advantages depending on the circumstances. 1, Depending on the language using primitives versus objects can have performance implications (stack/heap allocations, string copying, etc). 2, Primitives are standard in the language and understood without needing to reading specific implementation details (although for a counterpoint, primitives can be more vauge - what is this string doing exactly?). 3, And they can have a less pronounced benefit in other use cases /programming paradigms (a struct of one primitive versus a primitive in a data driven application where the logic in not contained in the object). I think one could argue the addition of primitives to that struct could be anologous to extending a class but I think the main point is are you returning a value/object that is extensible to your needs. Just thought I'd share some ideas, I work on predominantly low level c++ code so that's where I'm coming from.

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

    The most annoying thing with rich domain modelling is that it almost immediately hits the wall with EF. It's much better these days compared to what we had before, but still lacking some critical features. And then we have a choice either to introduce conversion layer from domain entities to db DTOs, or constrain ourselves to what is supported.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +3

      True, it is really demotivating ...

  • @ivandrofly
    @ivandrofly 11 หลายเดือนก่อน +1

    Thanks :)

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

    I am curious about what should qualify as a "domain model", and what is adding additional unnecessary complexity to the code.
    By way of example; Let's say that I have a Fraction class that takes in two integer values, a Nominator and Denominator. Of course, I need the Denominator to be a non-zero value, otherwise we'll end up dividing by zero!
    Now, I could use a smart constructor to perform the validation on the denominator value, but I wonder if it would be more appropriate to instead have a NonZeroInt (or in C# 11+, NonZero where T : INumber, using an instance of NonZero) class, which itself has a smart constructor and performs that validation, which allows me to simply pass a normal integer value for the numerator and a NonZeroInt in the denominator.
    Is this approach overkill? Because I'm not sure if there is necessarily anything domain worthy about a numerical value not being equal to zero, but it would allow me to abstract away a lot of instances where I would otherwise be performing the same validation checks in other parts of the code.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +2

      Domain model is the model of the problem domain - a projection of reality to a finite set of dimensions.
      Anything that has a place in customer's requirements is almost certainly qualified to be part of the domain model.
      DDD is going one step further and introduces ubiquitous language, requesting both customers and code to name things the same.

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

      @@zoran-horvat thank you kindly for your input.
      From your response, am I heading in completely the wrong direction with my example?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      @@metallixbrother Not necessarily - if what you are saying is the domain requirement, then it should be implemented as a domain type. Namely, if there is importance in a certain number never being zero, then that is a candidate for an explicit model.

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

    I like the pragmatic way you've approached this problem. However, when you were splitting into segments, I would have made the backward compatible string constructor split on commas rather than treat the entire list as a single segment. Treating it all as a single segment seems prone to create UI-visible bugs if not all the sources of string initialization have been addressed.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +2

      That is the next step. I tend to make steps as small as possible, so that at every step it is more than obvious that the code before and after the change will produce the same effects. Every discrepancy means that the last change - usually no more than a couple of lines of code - is to blame.
      Let me give you a hint how that can help. The first time I split into multiple segments in this demo, there appeared strange white spaces in the UI. It turned out that the browser rendered whitespace around spans unless they are glued together in the HTML. I only do frontend when I must (which turns out to be in videos only...) and then I make subtle mistakes like that one. However the very fact that the only thing I did since the last time application looked fine, was to generate spans for individual segments. That helped me pinpoint the problem in a second, literally.

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

    Zoran, why do you not use pattern matching with switch expressions instead of nested ternaries?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      If it looks like a chain of Boolean tests, then I prefer a chain of ternary operators. A personal preference. I have nothing against using switch expressions in the same situation, especially because switch expressions are matching cases in order of appearance, as documented.

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

    From now on we should add this in every application by default 🤣

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

    Thank you, an interesting lesson. But I would like to see the work of the new class (Citation class) not in a ready-made application, but in unit tests written for it. I would like to see the use of unit tests as a class design tool.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      There will be a similar video soon, where I plan to show the technique of testing class postconditions.
      In the meanwhile, you may watch the previous video where tests are constructed against the class's contract, avoiding to depend on its implementation: th-cam.com/video/po9ziMcnAWg/w-d-xo.html

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

      @@zoran-horvat Thanks.

  • @7th_CAV_Trooper
    @7th_CAV_Trooper 4 หลายเดือนก่อน

    I advocate this approach, but it can create issues with serializing JSON input/output in aspnet apps. Nothing that can't be overcome, but extra work is required.

    • @zoran-horvat
      @zoran-horvat  4 หลายเดือนก่อน

      Serialization should not be performed to and from domain models. Simply, the models have other, way more complex responsibilities to think about. Lift is much simpler if you do serialization from DTOs.

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

    Why not readonly record struct CitationSegment?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      The primary reason is that there are going to be multiple variants later (that is already a certainty) and therefore it cannot be a struct.
      Otherwise, if this were the only variant with only a single reference inside, then declaring it as a record struct would indeed be a viable performance optimization.

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

    I still don't get the whole primitive obsession thing. It's a string. What's wrong with a string? If you want to know what it is, give it a proper name and documentation, right? The only reason why you make a new data structure is when you have values paired with behaviors or if there are some values that belong together.
    There is nothing wrong with primitives. There is something wrong with devs writing helper classes to infinity, not properly documenting stuff, treating values with implicit behavioral magic. Your example uses a citation. Well, by the looks of it it's not just string. You contain segments, so it can't just be a string looking at the structure of the data.
    I think people are to obsessed with making everything a wrapper just to get rid of primitives. Sometimes a name is a string, and age an unsigned short (for the love of Code Jesus, use date of birth). It's when you attach behaviors or rules to the value that makes it a candidate for its own type. This, however, introduces the problem of not letting data just be data. It also raises questions about stuff like validation. What logic should be in a primitive wrapper, and what shouldn't?
    Devs are obsessed with primitive obsession. The term is used in places where it doesn't make sense. People who just learned that a primitive should be wrapped, and that's it. Those people are wrong. What you do in the video, however, is a perfect example of proper primitive obsession and how to solve it. But I still don't get what choices you made logically outside of what I mentioned in this post. Maybe you can help me out?
    Disclaimer, I'm still a student, so don't take anything I say for granted.

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

      Your experience might be skewed by being a student and/or watching a lot of videos like this. In my experience in the industry, 90% of code is way too primitive obsessed. You can for sure go too far in the other direction but I think this is less common

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +7

      Thank you for this detailed analysis. I think you are right that it should not be the goal to just wrap the primitive types - and it is not.
      With this video, I have tried to emphasize the importance of domain modeling. When modeling is done right, primitive types will stand in the place where they belong. You will see primitive obsession when there is domain-related behavior implemented at the place where a primitive type is used. Another typical symptom is when a developer introduces ad hoc DTOs to pass multiple values together, failing to give them higher meaning.
      As I said in the video, there are two major consequences of misusing primitive types in a domain model. One is bugs, usually coming from a mismatched assignment or misinterpretation of a primitive value. The other is inability to implement a feature because other accompanying values were lost in the process. One should also not forget that implementing behavior at the calling site is the source of the whole range of other problems - code duplication, unwanted dependencies, rigidness and outright bugs.
      The bottom line is that primitive obsession is a real thing. It does happen, and it does cause damage in application development.

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

      You are absolutely 💯 right

    • @chris-pee
      @chris-pee ปีที่แล้ว

      @@zoran-horvat "One is bugs, usually coming from a mismatched assignment or misinterpretation of a primitive value"
      I think that's why you shouldn't implement the implicit operator on your Citation, it's too easy to pass any string when a Citation is expected.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +4

      @@chris-pee That operator is an intermediate step while the feature is being fitted in. Once all consumers are transformed to not use strings, we remove that operator.
      That technique is part of iterative coding and I will explain it in greater depth in the follow-up video.

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

    Joke's on you, strings aren't primitive in my language

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      Don't be too literal. Any type that has no structure is primitive from the modeling point of view. Conversely, even a seemingly primitive type that does have a structure is not primitive. In that light, string is primitive and date is not, even though their representation might indicate the opposite.