Master The L in SOLID

Sdílet
Vložit
  • čas přidán 15. 06. 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
  • Věda a technologie

Komentáře • 48

  • @gornhoth
    @gornhoth Před 3 měsíci +8

    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 Před 3 měsíci +6

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

  • @PedroPabloCalvoMorcillo
    @PedroPabloCalvoMorcillo Před 3 měsíci +8

    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  Před 3 měsíci +1

      Agreed.

    • @VincentYang024
      @VincentYang024 Před 2 měsíci +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 Před měsícem +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 Před 2 měsíci +1

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

  • @eugene5096
    @eugene5096 Před 2 měsíci +2

    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  Před 2 měsíci

      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.

  • @sunnypatel1045
    @sunnypatel1045 Před 3 měsíci +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 Před 3 měsíci +1

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

  • @luc9volts
    @luc9volts Před 2 měsíci +1

    I like your implementations 👍🏻

  • @cyrusol
    @cyrusol Před 2 měsíci +1

    Absolutely excellent!

  • @mohammadtoficmohammad3594
    @mohammadtoficmohammad3594 Před 3 měsíci +1

    Thank you very much 😊

  • @David-id6jw
    @David-id6jw Před 3 měsíci +2

    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  Před 3 měsíci

      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.

  • @alfonsdeda8912
    @alfonsdeda8912 Před 3 měsíci

    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  Před 3 měsíci

      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 Před 3 měsíci +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  Před 3 měsíci +1

      @@alfonsdeda8912 Exactly.

  • @piotrkozbial8753
    @piotrkozbial8753 Před 2 měsíci +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  Před 2 měsíci +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 Před měsícem

      @@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 Před měsícem

      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 Před měsícem

      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  Před měsícem

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

  • @ekhm
    @ekhm Před 8 dny

    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 Před 8 dny

      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  Před 8 dny

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

  • @ataadevs
    @ataadevs Před 3 měsíci

    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  Před 3 měsíci +2

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

    • @ataadevs
      @ataadevs Před 3 měsíci

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

  • @arghasen6535
    @arghasen6535 Před 2 měsíci +1

    You never revealed the unit test class 😢

    • @zoran-horvat
      @zoran-horvat  Před 2 měsíci

      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 Před 3 měsíci +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  Před 3 měsíci +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 Před 3 měsíci +1

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

  • @adambickford8720
    @adambickford8720 Před 3 měsíci

    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  Před 3 měsíci

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

    • @adambickford8720
      @adambickford8720 Před 3 měsíci

      @@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 Před 3 měsíci

    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  Před 3 měsíci

      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 Před 3 měsíci

      @@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  Před 3 měsíci +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 Před 3 měsíci +1

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

  • @torrvic1156
    @torrvic1156 Před 2 měsíci +1

    I don’t get it but thanks anyway!

    • @zoran-horvat
      @zoran-horvat  Před 2 měsíci +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.