Hi. When software is good, it's good by design. But what does it mean to say that software is good? In this video, we'll try and understand what it means to say that software is good. Before we can talk about the quality of software, I want you to think about what software is, what that term means. This is the topic of one of our discussion questions and you should provide your own definition as well as read the definitions of some other learners in the course. Take some time and ponder this question or even switch over and participate in the discussion now and come back to finish the video in a bit. Any discussion of software quality has to start with a discussion of the software quality attributes. These attributes describe a variety of ways that we think about good software. Good software is performant, it responds to our input quickly. Good software is secure. It will not serve as malware or otherwise steal our information. Good software is modifiable. All software has bugs, and that set usually expands after launch. In both cases, we want the software to be in a state where it's easy for us to modify it. Modifiability is also the first of what we call the "-ilities". You can see a couple more here. Among the readings we will post are two resources for more comprehensive lists and discussions about the "-ilities", including some honorary "-ilities" like Performance and Security. Much like software quality attributes seek to describe characteristics of quality software, quality criteria seek to assess that quality. Let's look at each one to get a better understanding of what I mean here. Low coupling, high cohesion. You may have already heard this mantra. It's been around for a long time and many developers are aware of this goal, but most stopped there with a very opaque understanding of what it really means to have low or high coupling. We'll tackle both coupling and cohesion in other lectures. This is an expression of what it means that we should not be changing the preconditions of a method. If T has a method which accepts two parameters, the method in type S, which is a subclass of T, shouldn't require three parameters for the same method. That way, you can always replace an instance of T with an instance of S. That's the purpose of polymorphism, the ability to have a unifying type like T so you can define actions of client code in terms of that higher understanding from the parent class, from that base class and merely use an instance of the derived class, child class, subclass, in its place to do the work for each variation. Liskov's Substitution Principle is one of five design principles that are collectively referred to by the initialism SOLID. You can see the others here. To call out one or more principle here, the O in SOLID stands for Open/closed principle. Completed code should be open to extension, but closed to modification. I should be able to extend my code through inheritance, proper delegation, etc. without having to modify the existing code. This is another way you can't do this perfectly. It's a place where you should take care in your design, to design for change, to make the extension easier, and to minimize the necessary code modification. The idea that you should only have knowledge of closely related units, only talk to friends and really only talk to immediate friends, is known as the Law of Demeter. This is a little bit of an abstract concept until you think of a specific example. What can't you do? One example, think of object P. P contains an array of objects of type Q, and P is a parameter of our method M. If we need to know about Q objects, we can do one of two things. We can call method N on object P. It's a method that investigates the Q objects and returns the information sought when it was called by M, or we can ask P to give us the Q objects themselves and then our M method will work on those to produce the desired information. The latter option is a violation of the Law of Demeter. Asking P to get Qs means that O needs to know about how P works to call that method, and how Q works once we get those back. If P has a set of Q objects, it already knows about Q. Let P do its job. O knows about P. This, like all things, has exceptions. Sometimes you're given a payload of some kind where it's primarily just a vehicle for delivering data. There are other quality attributes and criteria that might be favored over following the Law of Demeter in that case, but when you see violations of Demeter, it's not necessarily a bad thing, it's just a section that you should be sure it's designed well and it's working as intended. Considering design quality takes significant care, there are no rules here without exception. Each is merely a guide, a reminder to think critically about the code you're writing or have written and make decisions which reflect careful engineering process.