Keep an Eye on SRP - That Might Just Save Your Broken Code Base

แชร์
ฝัง
  • เผยแพร่เมื่อ 9 ก.ค. 2024
  • Become a patron and download the source code: / zoranhorvat
    Ever felt overwhelmed looking at a Swiss Army knife of a class in your code? We've all seen them - those classes that juggle functionalities, often coming that way without an up-front plan. They just happen!
    At first glance, they might appear efficient. The allure of a one-stop shop can be tempting. However, they often lead to unforeseen challenges down the line. Picture this: Classes that cover multiple responsibilities do not combine well - soon enough, we won't be able to implement a larger feature because there is no combination of existing classes that does what is asked for! The inability to implement new features without pulling apart the existing structure can lead to lost opportunities and frustrated clients.
    There is hope in the form of the Single Responsibility Principle (SRP). Instead of that all-in-one chaos, envision an orchestra: Each musician is a master of their instrument, coming together to produce a harmonious symphony. With SRP, each class focuses on one small responsibility and does it exceptionally well. It brings clarity, making it easier to identify and resolve issues. Moreover, it offers flexibility - each piece can be adjusted or replaced without disturbing the entire ensemble.
    The final touch comes in the form of object composition. It is through composing objects into larger wholes that we can effectively implement features of great complexity, especially those governed by multiple interconnected business rules.
    This video is meant to teach you the virtue of the Single Responsibility Principle applied to domain classes, combined with object composition in addressing and resolving the issues we see when original classes are implementing multiple responsibilities each.
    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 #dotnet #objectorientedprogramming
  • วิทยาศาสตร์และเทคโนโลยี

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

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

    Download the source code from Patreon: www.patreon.com/posts/source-code-for-88367914
    Learn more from the video course *Beginning Object-Oriented Programming with C#* ► codinghelmet.com/go/beginning-oop-with-csharp
    Learn from related videos:
    Clean Code Tip: Remove Messy Constructor Calls ► th-cam.com/video/6g4ggpOxxCc/w-d-xo.html
    Remove Separate Concerns From a Class and Make It Favor SRP Again ► th-cam.com/video/5CU7137IWf4/w-d-xo.html
    Avoid Returning Null From Methods - There Is a Better Way To Write Them! ► th-cam.com/video/HRLdcMil7Ec/w-d-xo.html

  • @codingbloke
    @codingbloke 10 หลายเดือนก่อน +14

    I think one of the difficulties of SRP is just accepting that a "responsibility" can be very very small. Its easy to conflate a set of small responsibilities into what you imagine is a "single" one but it is not. I can't tell you the number of times I have come across code that largely duplicates logic because the developer (which admittedly is often me) couldn't bring themselves to separate out the responsibilities. A very, very valuable video, thank you!

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

      The worst part of SRP is that it is subjective. None of the SOLID principles has verifiable rules when and how to apply it. I believe if I left this video for a year and watched it then I wouldn't agree with myself in half of the decisions I made today.

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

      @@zoran-horvat that's both upsetting and completely relatable

  • @bonchodikov6248
    @bonchodikov6248 10 หลายเดือนก่อน +4

    Sir, years after I have watched one of your many courses in plural site I am still getting amazed from your deep logic and simplicity of your code. Thank you very much, definitely you are pushing me to be a better dev. Thank you and please don't stop sharing your skill for the rest of us.

  • @julealgon
    @julealgon 10 หลายเดือนก่อน +6

    Always interesting to see more people pushing for the extremely powerful decorator pattern.
    The restricted discount could also leverage the specification pattern for more complex conditions as needed.
    I'd like to see you tackle potentially 2 distinct things on top of this model though:
    1. How would you persist these composite discounts (say, in a database) and transfer them through an API
    2. What would you propose to isolate the "UI representation" concern of the discount object (formatting into a label/string) from the rest of its implementation.

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

      You have asked two perfect questions for this model.
      1. Hierarchical structures like the one from my demo are best persisted and transferred as a document (e.g. a JSON document). This structure is not suitable for relational databases. I would start from serialization/deserialization to JSON.
      2. You are right about that. I didn't want to extend the talk further, but yes, any transformation of the domain object into whatever other form belongs to the place that produces that other form. In this case, turning the domain object into labels certainly belongs to the UI layer. There are several reasons for that, one being internationalization - the UI might require something other than a plain string to represent labels so that they can be translated depending on the output language. That responsibility certainly does not belong to where the domain model is defined.

  • @martins.8349
    @martins.8349 9 หลายเดือนก่อน +1

    your videos are impressively good
    everyone always talks about fancy patterns but never explains what to do with them
    you nailed that and use simple words in a slow manner so anyone can understand them

  • @marko_losonc
    @marko_losonc 10 หลายเดือนก่อน +1

    What I like the most with this approach is that the entire logic in DemoDiscountServer class is soooo descriptive that it could easily be understood by almost anyone, even non-programmers.

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

      There will be an entire video on that coding style. I find it critically important in classes with complex logic.

    • @marko_losonc
      @marko_losonc 10 หลายเดือนก่อน

      @@zoran-horvat I'm looking forward to it.

  • @AlexUkrop
    @AlexUkrop 10 หลายเดือนก่อน +1

    Very cool functional programming at the end. Thanks

  • @nishiths9228
    @nishiths9228 9 หลายเดือนก่อน

    wonderful

  • @RiversJ
    @RiversJ 6 หลายเดือนก่อน

    I would've solved this with a class that takes in a collection of conditions and generic math discount operands that would allow multiple discounts to apply with a deterministic order of operations.
    Would probably be a bit more complex but allow very high extensibility. Can definitely see the value in this as well, method chaining to compose the discount would be very easy for a new developer arriving at this class system.

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

    Thank you

  • @adambickford8720
    @adambickford8720 10 หลายเดือนก่อน

    SRP: the 'No true Scotsman' of software engineering. If it didn't work, you didn't use enough!
    One of the things I like about FP is it really encourages SRP. Your `map`, `filter`, etc, by definition, are expected to do only thing. You're even encouraged to keep them as small '1 liners'. I find loops to be the root of this kind of complexity.

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

      Everything you said also stands for OOP.
      Moreover, for every functional program there is an isomorphic object-oriented program. If it is good, then it is good in OOP, too. Therefore, it is not the coding paradigm that makes the difference, but coding practices applied by ones or the others. Don't forget functional programmers who write monstrously large imperative functions, still believing they made functional code!
      The fact that it is less likely you will encounter bad FP code is due to having less bad coders there, which is the result of FP posing a much higher entry threshold for programmers.
      In other words: we need more expertise among programmers, no matter the paradigm.

    • @adambickford8720
      @adambickford8720 10 หลายเดือนก่อน

      @@zoran-horvat Sure, but getting there in OOP is much, much more difficult. IME OOP has too much 'art' to it. Even when done well, its maintainers often compromise it. The upside is its lower barrier to entry means it's likely 'good enough', even if you botch it.
      FP devs are 'better' than OOP ones for the same reasons linux users are usually more capable than windows users; they have to be ;)

  • @rustamhajiyev
    @rustamhajiyev 10 หลายเดือนก่อน +1

    I rest my case - the mic drops 🫳🎤
    Awesome episode! 😎🥰

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

      Many programmers only see object composition through its intrinsic complexity. The complexity is real. Debugging is hard. All that is true.
      But what they fail to see so often is that object composition is a necessity. It is impossible to develop a large application with great numbers of rules, often contending ones, without composition.

    • @rustamhajiyev
      @rustamhajiyev 10 หลายเดือนก่อน

      @@zoran-horvat Can't agree more

  • @SteveNgaiCheeWeng
    @SteveNgaiCheeWeng 10 หลายเดือนก่อน

    I think in real-life e-commerce system, the business rules are complicated (i.e. different countries could have different rules), and dynamic (they keep changing and i.e. special rules to be applied during a campaign period only,). Is it better that we store the business rules in the database and have one generic class that covers all the business rules dynamically instead of creating many classes with business rules in the class? With the rules in the database, it is also easier for the admin to make changes to the business rules from the UI. What are your thoughts on this?

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

      The Demo class is what its name is suggesting - a demonstration. In a real system, all those small classes could be instantiated and combined based on some document which could vary based on the use case.

  • @pickle1987
    @pickle1987 10 หลายเดือนก่อน

    SRP = single line in each class

  • @tonyyip1969
    @tonyyip1969 10 หลายเดือนก่อน

    Thanks for the awesome video. Could decorator pattern able to achieve the same result?

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

      A few of those classes are indeed decorators, but not all of them.

  • @LordErnie
    @LordErnie 10 หลายเดือนก่อน +1

    Great episode for sure. I never thought about something like a simple mathematical operation as something that is, from the domain standpoint, something that should be calculated within its own seperate unit that carries responsibility for that calculation. An eye opener for sure. But this is one of those cases where OOP loses me a bit. I still study informatics and software engineering, so please don't take any offense. The usage of decorators (are they? It's an estimated guess) and wrapping classes is a bit confusing. I'm losing track of what goes before what and why. The code, to me, doesn't speak for itself and I would need a chart or map of some sort that would show me the flow and what objects belong where inside of that flow. The scenarios where these types of solutions are applicable are higher up in the industry. It's a solution for a very big application, or at least one that needs to give a developer very fine-grained control over every single step of a process. If you need this much control over a discounting system, I would say that this is something that would almost be at the level where you define a completely separate pipeline for it. I'm probably wrong half the time here, but taking SRP this far is something that still obliviates me a bit. How does one understand the wrapping and the combining of classes like you do here? It's wild but confusing.

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

      I see the source of your confusion, and I even plan to make a separate video on that issue. It is a common problem, especially in young programmers and I would argue that understanding that single point is the critical understanding required to become a senior programmer.
      The problem you are facing in trying to see the order of execution is real. It is there. But it is not substantial. The true problem you are facing is **wanting** to see the order of execution. That is irrelevant! It is established once the composition is created.
      Now, that leaves a huge gap that must be filled. What **does** count then? It is the contract of the interface or a method. The promise of a type or a call. If the call returns IDiscount, then it is the contract of IDiscount that matters to you and nothing else. Trying to see beyond the interface is to break its encapsulation, and that is just wrong. The interface doesn't promise anything with respect to the issues you have listed, so why ask? Now try to watch this demo from that angle and you will begin to understand it.

    • @marklord7614
      @marklord7614 10 หลายเดือนก่อน

      I relate to the criticizm. As a casual programmer, I developed a habit of trying to understand the order of execution of new code and, in this case, it leads me down a rabbit hole. However, I will take the advise of backing off and pay more attention to method signatures instead and treat the two ways of looking at code separately. @@zoran-horvat

    • @ClickOkYT
      @ClickOkYT 10 หลายเดือนก่อน

      @@zoran-horvat I totally relate to this *wanting to see the order of execution* thing. I am a developer for +25 years, so I "born" in procedural world, then was painful to follow things in deep hierarchy in OOP, but chains of functional coding burn the brain cells too... I found really easier, for example, newline anything after a dot in Linq because that. Tips about that kind of thing will really be amazing!

  • @ivandrofly
    @ivandrofly 10 หลายเดือนก่อน

    One question the extension method .WhenBookAuthoredBy(Person) is just returning a new instance of BookAuthorDiscount class?
    19:31

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

      Yes, but the one that wraps the discount to which the extension method is applied.

    • @ivandrofly
      @ivandrofly 10 หลายเดือนก่อน

      Thanks for the reply.
      What is the name of that discount? Can I have a peak on the .WhenBookAuthoredBy(Person) maybe I will be able to understand
      Thanks in advance

    • @ivandrofly
      @ivandrofly 10 หลายเดือนก่อน

      Is this the product of calling `WhenBookAuthorBy(Person)` extension method (see below)?
      .WhenBookAuthorBy(Person) -> WhenBookAuthorBy(this Discount discount, Person person) => new BookAuthorDiscount(person, discount) @@zoran-horvat

  • @muhammadumair9074
    @muhammadumair9074 10 หลายเดือนก่อน

    Hi Zoran, Great videos and I am amazed how you sync yourself with the code screen on Visual Studio. It will be great if you make a video on how you create/record your videos. -Umair

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

      Guess what: I will! There is plan for that in the near future.

    • @muhammadumair9074
      @muhammadumair9074 10 หลายเดือนก่อน

      @@zoran-horvat Great. Thanks for that.

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

    If you have a discount based on a name, you quickly go in the rabbit hole of localization. Some books are translated in other languages, so, in reality your book model need a category or tags to set discount based on tags. This would be my solution to this specific problem.

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

      Don't get this example too literally. The purpose of the demo is to show a specific situation where the execution of a method (i.e. filtering out a call) depends on a piece of data that is not available at instantiation time. Try to view the demo through those lenses and you will see the difficulty that the class alone cannot address.

  • @vbachris
    @vbachris 10 หลายเดือนก่อน +1

    everyone is going to patreon, why doesn't youtube have it's own sponsorship system?

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

      TH-cam does have its sponsorship system, but the capabilities end at controlling access to videos. TH-cam does not support sharing files with sponsors - and that is precisely what we, programmers need. I believe that is the reason why so many programming channels opt to use an external platform to distribute files with sponsors, where TH-cam platform would be a natural choice.

    • @ClickOkYT
      @ClickOkYT 10 หลายเดือนก่อน

      TH-cam is unstable, it can block/demonetize/etc by lots of random reasons.

    • @evancombs5159
      @evancombs5159 7 หลายเดือนก่อน +1

      ​@@ClickOkYTto be fair the same can be said about Patreon or any other platform. Usually I would say the best method is to not be loyal to a single site, and use multiple sites. The downside being duplicate work.

  • @rezakaaccount
    @rezakaaccount 10 หลายเดือนก่อน

    All those extension methods introduce what I call hard-implicit-dependencies. These violate dependency inversion. I agree that the readability is enhanced but good luck testing the methods/classes that use extension methods specially when they contain business logic.

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

      This comment has too many misconceptions to clear them all with another comment, but I will still try.
      All extension methods demonstrated in the video are factory methods. One cannot mix them up with static utility methods, such as DateTime.Now or Random.Next. Moreover, the only method in the demo that consumes them is a factory method itself! One rarely injects factories into other factories, when a more direct solution exists in the form of injecting their products instead - that is precisely how this system of factory methods in the demo works, each factory method receiving one or more products of another, unknown factory.
      DIP is very well observed in the demo at the place where it belongs, i.e. where the factory's product is required. That is, in particular, the page model, which only depends on the product, injected by the IoC framework.
      Testing static factory methods is as easy as any other, as they allow method injection of subordinate products. We normally apply contract testing and structural inspection to the product returned.

    • @Alguem387
      @Alguem387 9 หลายเดือนก่อน

      'Using int.MaxValue creates a hard implicit dependency what of I want to mock Int32 for unit testing'
      You sound like this