Master The L in SOLID

Поділитися
Вставка
  • Опубліковано 8 чер 2024
  • Download source code ► / zoranhorvat
    Join the C# Discord server ► codinghelmet.com/go/discord
    Enroll course Beginning Object-Oriented Programming with C# ► codinghelmet.com/go/beginning...
    Subscribe ► / @zoran-horvat
    Have you noticed how everyone has an opinion about LSP - usually the strong one - yet hardly anyone can explain it clearly? It would sound even stranger if I told you that you can automate the verification of the Liskov Substitution Principle. That is how clear it is!
    Let me change that unfavorable situation by drawing you back to the fundamental principles of OOP. I will teach you how to formalize the definition of a type, either a class or an interface, to define the rules every subtype must satisfy. That will be the Liskov principle at work.
    With the abstract properties defined, every implementation of an interface and every subclass will always produce objects that are substitutable for objects of their parent type - just as the LSP would define them.
    ⌚ 00:00 Intro
    ⌚ 01:05 Defining Class Attributes
    ⌚ 06:43 Detecting LSP Violations
    ⌚ 08:54 Designing Interfaces with LSP
    ⌚ 12:29 Implementing Concrete Classes
    ⌚ 15:03 Outro
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⚡️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.
    #csharp #dotnet #objectorientedprogramming
  • Наука та технологія

КОМЕНТАРІ • 48

  • @gornhoth
    @gornhoth 2 місяці тому +7

    For the first time i properly understood what the LSP actually refers to and how to apply it, thanks for this great video!

  • @nickbarton3191
    @nickbarton3191 2 місяці тому +5

    Very good Zoran, nothing much to comment except it's starting to make sense.

  • @PedroPabloCalvoMorcillo
    @PedroPabloCalvoMorcillo 2 місяці тому +7

    It's not a casual video at all. I'll have to watch it in front of my computer and do the exercises myself in order to grasp entirely LSP.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      Agreed.

    • @VincentYang024
      @VincentYang024 2 місяці тому +1

      Absolutely agree, my head spins by just watching the video. I’m wondering and curious how other languages follow and implement the lsb principle😂

  • @CharlesBurnsPrime
    @CharlesBurnsPrime Місяць тому +1

    I've been designing software for decades, but I think your video made me feel the most confident about really grokking LSP.

  • @TeoTube10
    @TeoTube10 2 місяці тому +1

    Very good understanding about using Liskov at design time!! Thanks!

  • @sunnypatel1045
    @sunnypatel1045 2 місяці тому +2

    Thank you for all your amazing video mentor! Can you do a video on unit testing strategies like fake vs mock lib etc

    • @nickbarton3191
      @nickbarton3191 2 місяці тому +1

      Can I also add my request, property-based testing.
      (property in yet another sense of the word).

  • @luc9volts
    @luc9volts 2 місяці тому +1

    I like your implementations 👍🏻

  • @cyrusol
    @cyrusol 2 місяці тому +1

    Absolutely excellent!

  • @mohammadtoficmohammad3594
    @mohammadtoficmohammad3594 2 місяці тому +1

    Thank you very much 😊

  • @eugene5096
    @eugene5096 Місяць тому +1

    gpt-4 completelly did not get a problem and was soooo bad in the solution. Friends we still can hold our jobs !!!

    • @zoran-horvat
      @zoran-horvat  Місяць тому

      Exactly! The generative tools are still incapable of addressing design issues. There are many reasons for that and it looks like this generation of AI tools will never crack that problem. We need something else.

  • @alfonsdeda8912
    @alfonsdeda8912 2 місяці тому

    Hi Zoran, very great video!
    Correct me if I am wrong, so the lsp indicate that you shouldn't derived classes if all operations and conditions of base class are met in derived class too, so with interface we know only the operations to implement and not the base implementation?

    • @zoran-horvat
      @zoran-horvat  2 місяці тому

      LSP defines properties that both base and derived types must possess. It doesn't matter what those types are: classes, interfaces, an interface and a class, a covariant/contravariant generic class, a class with an implicit or explicit conversion operator to another class...

    • @alfonsdeda8912
      @alfonsdeda8912 2 місяці тому +1

      @@zoran-horvat Thank you for response, so to implement an interface and one of the implementation methods use the throw new Notimplementedexception Is considered breaking the lsp and I should divide that interface in more interfaces?

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      @@alfonsdeda8912 Exactly.

  • @piotrkozbial8753
    @piotrkozbial8753 2 місяці тому +1

    I don't know why people complicate these things, invent "principles" and other buzzwords.
    There is only one "principle" in software development - everything must be specified and work as specified. Then, when it comes to OOP, the deal is simple: a subclass must fulfill the specification of its superclass, period.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +2

      And how would you write a test, then?
      Needless to say that you have forgotten that the subclass can relax preconditions, therefore the claim that the subclass must fulfill the specification of its superclass is elementary untrue. Pity you didn't get it along the way.

    • @karlmehltretter2677
      @karlmehltretter2677 Місяць тому

      @@zoran-horvat Checking Liskov Substition Principal is undecidable. I.e. if the language in which to write down the properties ("behaviour") is powerful enough, the compiler cannot check it automatically.

    • @karlmehltretter2677
      @karlmehltretter2677 Місяць тому

      One example is the obvious desirable property "pop() should eventually return an element and not loop forever" (totality / termination). If I do a really stupid implementation of the stack that loops on some input values, the compiler may fail to catch the error (halting problem).

    • @karlmehltretter2677
      @karlmehltretter2677 Місяць тому

      So showing that something is violating LSP is "easy", proving that something is not violating LSP is "very hard". LSP in the extreme pretty much says "don't change a working implementation, you can never be sure that you break something" :)

    • @zoran-horvat
      @zoran-horvat  Місяць тому

      @@karlmehltretter2677 What is the purpose of this deliberation? I know the theory pretty well, I have a CS degree, and I have also been developing software for more than 25 years. Yet, the halting problem never popped up in my work. Did it ever cause a consequence in your work?

  • @David-id6jw
    @David-id6jw 2 місяці тому +1

    I've always heard of the LSP as applying at the argument-parameter boundary (or the return value boundary). Covariance and Contravariance. If B inherits from A, then pretty much by definition it has all the methods and properties of A. But this seems to take it a bit further. Going back to wiki, these seem to be only the most basic requirements of the principle.
    Part of what bothers me is that there's no obvious clarification of the contract you are agreeing to with each interface. This is most likely just the lack of documentation headers for a simple demo project, given you also have tests that are designed to clarify exactly how each interface should behave. Or maybe it's the naming. What is a "proper" stack supposed to be? Nitpicky stuff that's only tangential to the topic.
    However, suppose we add a third type of stack. Say, a stack with a limited size (eg: cannot add more than 10 items). It's not going to pass either of the other set of tests once you go beyond the size limit. So now do you have to create a third interface in order to create a third set of tests? And if you're just creating one interface per implementation, what is even the point of the interfaces? And does it belong at the bottom of the hierarchy or at the top? Or is it a V shape?
    It seems like every addition to a class hierarchy has the potential to require a complete overhaul of the entire hierarchy structure in order to retain compliance with the LSP. For example, with the demo, if you had only started with the basic stack, and then later added the unique stack, you're having to create an entirely new base class (or interface) that the original now derives from. But that has the potential to completely screw with naming conventions and API compatibility.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому

      Your example with the limited stack is what I meant when I asked if throwing an exception is violating LSP. If the base type does not indicate that the call might fall, then yes it does. The limited stack would violate the stack interface's contact in that case and you should not assign it to the stack interface.

  • @ataadevs
    @ataadevs 2 місяці тому

    What if we reverse the interfaces in a way that IStackable is implemented in Stack classe, but the IUniqueStackable (istead of using IProperStack interface) is implemented in UniqueStack class

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +2

      Didn't I just prove that unique stackable is not a specialization of stack? ;)

    • @ataadevs
      @ataadevs 2 місяці тому

      @zoran-horvat Oh yes correct, thanks. Great video as always

  • @ekhm
    @ekhm День тому

    hmmm, UniqueStack will not work for Push(1, 2), Push(1), Pop() == 1. And as it was said in test method Stackable should just return last pushed value. In this example it will return value 2 not 1. Or am I wrong?

    • @ekhm
      @ekhm День тому

      And I see something weird. In code you wrote test for Stackable with rule "Pop decrements stack size". Then in result there's no this test for Stackable, only for Stack. EDIT: ok, I assume it was just typo when copying code. Test should be for Stack.

    • @zoran-horvat
      @zoran-horvat  День тому

      @@ekhm The ultimate conclusion I came to in the video after going through all those pains was that the unique stack is not a stack no matter how hard I twisted the logic.

  • @arghasen6535
    @arghasen6535 2 місяці тому +1

    You never revealed the unit test class 😢

    • @zoran-horvat
      @zoran-horvat  2 місяці тому

      It is just a utility class which you can write in a dozen ways. It is not important for the story.
      By the way, in a proper project, you would use proper unit tests.

  • @codingbloke
    @codingbloke 2 місяці тому +1

    I think LSP is an important step in quality code could reduce bugs. It does seem to require quite a bit of a discipline.
    Consider a developer writes code against an IStackable interface. However, they have written code that depends on properties not guaranteed by the IStackable interface (e.g, pushing twice causes count to be >= 2.) How could they know? The IDE and Compiler isn't helping them. They could read the documentation for the interface but that just declares what properties are true, it doesn't provide an infinite list of properties NOT guaranteed. From a common sense point of view the code seems perfectly valid. It takes quite a bit of discernment to notice the code is relying on what is not actually guaranteed.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +2

      You are right. But isn't that true for any design? We are left to documentation, clear naming, and unit testing - each helping reduce a chance for misunderstandings, but not removing it entirely.

    • @codingbloke
      @codingbloke 2 місяці тому +1

      @@zoran-horvat Um, yup fair point. :)

  • @adambickford8720
    @adambickford8720 2 місяці тому

    I learned the hard way it all depends on the contract. For example, in java the 'Collection.add' operation's contract is... whatever the implementation does! So, you can't mutate it because it might be immutable and throw an exception, but you can't just hang onto it either, because... maybe it *is* mutable and someone else has a reference. But hey, we met the contract.
    boolean add(E e)
    Ensures that this collection contains the specified element (optional operation).

    • @zoran-horvat
      @zoran-horvat  2 місяці тому

      That's it! All it promises is that the element will be there, meaning that a subsequent get will succeed. Nothing else.

    • @adambickford8720
      @adambickford8720 2 місяці тому

      @@zoran-horvat That's the problem; it does not state even that. It says it *might* work, depending on the implementation, by declaring it an "optional operation" in the 'contract'.
      void foo(List list)
      You do not know if you can add to this list, or if some *other* reference can either! But they did avoid having to split im/mutable apis out.
      To throw salt into the wound, for years the only good factory method for creating a `List` created the immutable kind 😢

  • @qorxmazmaharram8300
    @qorxmazmaharram8300 2 місяці тому

    The second approach worked as expected but definition of different interfaces means different comcrete lass implementation. Its prone to code duplication.. as I understood LSP puts more restrictions during base-child class relation. I thinkg LSP definition does not match on real common cases all the times, rule required seperate class at all

    • @zoran-horvat
      @zoran-horvat  2 місяці тому

      LSP fits very well in object-oriented design. The problem is usually in programmers who prefer less formal design, writing code fast and then patching it when it doesn't work. In other words, it is the lack of knowledge, not shortcomings of the SOLID principles that we are facing in practice.

    • @qorxmazmaharram8300
      @qorxmazmaharram8300 2 місяці тому

      @@zoran-horvat If LSP fit so well into OOP, it wouldn't be such a controversial and incomprehensible topic. That's why most programmers can misperceive it for different purposes. Knowledge is resolved through experience, as long as its source is accurate.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      @@qorxmazmaharram8300 LSP is not controversial. It is rather that our industry is full of hotheaded half-baked programmers who didn't learn the basics but that doesn't stop them from teaching others the lesson.
      There are plenty of comments on my earlier videos saying I have violated LSP here, violated there, and those comments repeat all day long. And all those comments share one constant: those who posted them had no clue what they said. LSP is one of the cleanest and best documented principles in programming.

  • @lettuceturnipthebeets790
    @lettuceturnipthebeets790 2 місяці тому +1

    I still didn't get what you meant exactly...

  • @torrvic1156
    @torrvic1156 2 місяці тому +1

    I don’t get it but thanks anyway!

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +4

      That is an essential principle in programming, so I would suggest you to come back to it after a while and figure it out. That will change the way you see programming, trust me.