Тёмный
No video :(

Master The L in SOLID 

Zoran Horvat
Подписаться 28 тыс.
Просмотров 7 тыс.
50% 1

Опубликовано:

 

22 авг 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 54   
@gornhoth
@gornhoth 5 месяцев назад
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 5 месяцев назад
Very good Zoran, nothing much to comment except it's starting to make sense.
@PedroPabloCalvoMorcillo
@PedroPabloCalvoMorcillo 5 месяцев назад
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 5 месяцев назад
Agreed.
@VincentYang024
@VincentYang024 5 месяцев назад
Absolutely agree, my head spins by just watching the video. I’m wondering and curious how other languages follow and implement the lsb principle😂
@danflemming3553
@danflemming3553 Месяц назад
Your solution of making an IStackable still breaks Liskov principle, because you cannot substitute it by an instance of Stack or UniqueStack. A simple test (which you also show) is calling Push(1) twice and calling Pop() twice, and the app will crash when using an instance of UniqueStack. Your example was good but the solution does not make sense, it does not solve the problem. Modelling the tests in a way which does not break Liskov is not also a solution.
@zoran-horvat
@zoran-horvat Месяц назад
@@danflemming3553 Yeah, attempting all that is a lost cause. Those two are just unrelated types.
@andersborum9267
@andersborum9267 Месяц назад
I think proper design it's about ensuring that your interfaces are as generic as possible, but in this case the interface is already as simple as it can be. It's still not evident from the video (again, my perspective) how you come about not violating LSP if a dependency (or method argument) is defined using the base interface (i.e. IStack), and you're assigning an specialized implementation (i.e. ProperStack or UniqueStack). As the consumer, all I care about is the contract of IStack, and not the specialized implementation. It's a real head scratcher and something that's easy to violate, yet rarely causes issues.
@CharlesBurnsPrime
@CharlesBurnsPrime 4 месяца назад
I've been designing software for decades, but I think your video made me feel the most confident about really grokking LSP.
@eugene5096
@eugene5096 4 месяца назад
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 4 месяца назад
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.
@TeoTube10
@TeoTube10 4 месяца назад
Very good understanding about using Liskov at design time!! Thanks!
@sunnypatel1045
@sunnypatel1045 5 месяцев назад
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 5 месяцев назад
Can I also add my request, property-based testing. (property in yet another sense of the word).
@David-id6jw
@David-id6jw 5 месяцев назад
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 5 месяцев назад
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.
@andersborum9267
@andersborum9267 Месяц назад
@@zoran-horvat but since the limited stack does implement the base interface, what's keeping the consumer from assigning a specialized (i.e. violating implementation) to the interface, or pass it to a consumer that accepts said interface? Is the simple answer in this case that the specialized implementation shouldn't implement the interface at all?
@piotrkozbial8753
@piotrkozbial8753 5 месяцев назад
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 5 месяцев назад
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 3 месяца назад
@@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 3 месяца назад
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 3 месяца назад
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 3 месяца назад
@@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?
@cyrusol
@cyrusol 4 месяца назад
Absolutely excellent!
@luc9volts
@luc9volts 5 месяцев назад
I like your implementations 👍🏻
@codingbloke
@codingbloke 5 месяцев назад
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 5 месяцев назад
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 5 месяцев назад
@@zoran-horvat Um, yup fair point. :)
@arghasen6535
@arghasen6535 5 месяцев назад
You never revealed the unit test class 😢
@zoran-horvat
@zoran-horvat 5 месяцев назад
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.
@ekhm
@ekhm 2 месяца назад
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 2 месяца назад
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 2 месяца назад
@@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.
@andersborum9267
@andersborum9267 Месяц назад
@@zoran-horvat Yes, that's the answer. The unique stack isn't a stack to the extent that it satisfies the initial requirements of the interface, and as such, shouldn't implement that interface, but define it's own unique stack interface and implement that (i.e. without any inheritance of the basic stack interface, as "it's not a basic stack", basically).
@adambickford8720
@adambickford8720 5 месяцев назад
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 5 месяцев назад
That's it! All it promises is that the element will be there, meaning that a subsequent get will succeed. Nothing else.
@adambickford8720
@adambickford8720 5 месяцев назад
@@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 😢
@mohammadtoficmohammad3594
@mohammadtoficmohammad3594 5 месяцев назад
Thank you very much 😊
@lettuceturnipthebeets790
@lettuceturnipthebeets790 5 месяцев назад
I still didn't get what you meant exactly...
@zoran-horvat
@zoran-horvat 5 месяцев назад
Then watch again ;)
@alfonsdeda8912
@alfonsdeda8912 5 месяцев назад
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 5 месяцев назад
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 5 месяцев назад
@@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 5 месяцев назад
@@alfonsdeda8912 Exactly.
@qorxmazmaharram8300
@qorxmazmaharram8300 5 месяцев назад
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 5 месяцев назад
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 5 месяцев назад
@@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 5 месяцев назад
@@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.
@ataadevs
@ataadevs 5 месяцев назад
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 5 месяцев назад
Didn't I just prove that unique stackable is not a specialization of stack? ;)
@ataadevs
@ataadevs 5 месяцев назад
@zoran-horvat Oh yes correct, thanks. Great video as always
@torrvic1156
@torrvic1156 4 месяца назад
I don’t get it but thanks anyway!
@zoran-horvat
@zoran-horvat 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.
Далее
Let C# Tuples Become Your Best Friends
11:51
Просмотров 9 тыс.
Avoid This Common Mistake in DDD Modeling
10:17
Просмотров 8 тыс.
Why I don't "using namespace std"
14:35
Просмотров 391 тыс.
Liskov: The Liskov Substitution Principle
4:23
Просмотров 21 тыс.
Why is C# Evolving This Way?
15:02
Просмотров 21 тыс.
Manage Nulls Like a Boss and Never Fail!
21:43
Просмотров 12 тыс.
SOLID Principles: Do You Really Understand Them?
7:04
Просмотров 159 тыс.
What is IO monad?
36:32
Просмотров 68 тыс.