Solid Programming Single Responsibility, Liskov, Interface, Dependency Inversion

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi in the next five minutes I'm going to talk to you about five principles that will make your programming better solid programming technique now solid programming comes from five words Sol I D stands for single responsibility of a method your method should do one job the second is open closed systems so that when you design a class always extend it rather than going back to modify it if you need to change it now the Liskov substitution is about taking descendents and making them work with other methods that your parent was already designed to work with and then the interface segregation is a principle that states don't make your users rely on interfaces that they don't need and then finally dependency inversion makes your program more flexible by making things swappable and so we're going to look at each one of these five with some examples here to make you a better programmer so let's start with number one a class should only have a single responsibility and so the Swiss Army knife is obviously the real example when you're trying to bring up your code for example let's say we have a program method called move player updates score and check for winner this is a pretty obvious error we should have three methods that do these things so don't try to shove everything into one method the second example here would be maybe not in video games but something like this we're logging in and registering we have a method called create account and send email now you might want to do both of those things when somebody registers but let's set them into two separate methods so don't combine things if you don't have to now an object has a single purpose so some objects are designed to hold data for example the person object don't try to make the person object do things if its main job is just to hold data classes are designed to control events for example on Form submit so the cement form may have lots of things inside of it but his main job is to read the form fields validate their data save it somewhere else and let somebody else take care of the data once you've read the form how about this one coordinate a process so checkout cart might be a complex process but we want to keep it short you shouldn't have a thousand lines of code in one method instead checkout cart probably relies on helper methods that have purposes of their own so you might want to read to the database right to the database you might want to send an email you might want to clear the cart all those things are going to be required but checkout cart his main job is to coordinate what other methods do you might have a service so for example a database access object is a good example of a service DB get order by date his only job is to get you one item so don't try to notify don't try to send information around don't try to update the order just get the order and do what you're told so an object usually has a single purpose and that's a great principle to follow number two is a principle called the open closed principle so here's the in words it says methods should be open for extension but closed for modification so think of a blueprint and once you've cemented your house into place you're not going to go and bust up the foundation to change it you're going to add to it maybe if you need a new living room but you're not going to modify the internals now you could in a physical world without any problem because you only have one house well let's say you have a program where you have people depending on things that you've built before what you need then instead is called an extension method an extension method allows you to extend a program without breaking the original let's give you a couple examples of where this would come into play so here's a cartoon where the guy says I'm dude there's a problem with the ape yeah yeah that makes sense it's because we deployed a new version and all the end points have changed are you kidding and when were you going to tell us I was planning to tell you really when right now right now I'm telling you now about right now now go make your changes now that's obviously annoying we don't want to do that to our users and if you're a programmer creating services you do have customers you do have users so instead of making your API break or making your program method break you might want to think about extensions instead so here's an example called int extensions you can see the URL from where I got this below so if you want to change the behavior of the integer class in c-sharp you're not going to go and modify the code in the integer class you better not because every application in the world is depending on that integer class to work as it was originally designed however if you want to add a new method called is greater then you can do that and so here's an example of it in use so we create an integer and we name them number 10 high equals 10 and then we have a method called is greater than 100 and it returns a result and so IDOT is greater than 100 will exist in this program only but we didn't go in and modify the integer class to make it happen we added an extension so that this class for some reason needs to have this method let's look at the example of API versions again so returning to api's so the first example of the API and the left here shows us that we have a book service version one of the API says I want to get the book by ID and here is book number 104 now if I want to get a newer version of my API I might change the URL and the version 1.6 is what I have on the right side and then you can eventually tell your users that version 1 is going out of service as deprecated and you have until December 31st of this year to get on the new version otherwise your service will break so for instance we are planning to remove pages 5 23 no longer valid instead we're going to have a new version of pages that includes the index and so if you decide to remove something from the API you're gonna annoy your users here's some other examples of how you could avoid making your API go out of date so you could change the version number and just force people to change their code or here's another way that might be more flexible you could just modify the API and not break the old version so it's still backward compatible here's version 1 on the left and version 2 on the right what we've done in version 2 though is a little different we've kept the original three data points title pages and pub date but we've exam as existing but we've added some new guys so we've added the publisher in category in the new content now if we want to we can have two versions of the page number we can replace the content and still keep the original content so pages with index exists right alongside of pages and so the people that are still on the old version that was built five years ago still get to use their API even though your newer API has more data in it so we haven't modified the existing things we've just augmented it the third principle is called a Liskov substitution this one is similar to backwards compatibility we want to avoid errors like this you've ever got this that says the document you're trying to open was created in a new version of the application please pay the upgrade fee and try again yeah I'm looking at you Adobe I'm thinking that you don't want to do this to your users you want them to have backward compatibility in your software here's how its stated in a sentence that any method that takes care of class a or takes class a as a parameter must be able to work with any subclasses of a now I know that probably doesn't make any sense unless you think about it and see some examples so let's take a look at one so let's say I have a method called give haircut and the parameter that is sent to that method is an animal a inside of the method we have haircut so we're gonna change the length of the hair to be hair length divided by two now that works great when you have your fuzzy dog and your cat but as soon as you have another animal that doesn't have any hair the snake he might just cause an exception so animal dot or a dot hair length is not going to function well with snake and so this violates the principle that animal can't have a more restrictive version of it like snake as a subclass and so we would have to either take hair lengths and make it not part of the parent or just not use that animal a as a parameter now Barbara Liskov is the person behind the name of the Liskov principle so she's a professor at MIT one of the first women to get a PhD in computer science and she gets her name on the list gogh principle here's another example of what you might think of is passing a parameter down that is not compatible with the method so putting the drive is my method and we expect a vehicle to be sent as a parameter so vehicle V so the car works great truck works great the convertible works great helicopter not so much so make sure that vehicle has its children as workable or compatible with a method called put into drive here's a little bit more wordy example of the Liskov principle objects of a superclass should be replaceable with objects of its subclasses without breaking the application and the example that you probably find if you google this Liskov substitution principle is the example of the rectangle and the square now as you know rectangles and squares are very related all squares are rectangles but not all rectangles are squares because a square must have the equal length and the equal width width as it's one of its requirements so an overridden method of a subclass needs to accept the same input parameter values as the superclass you are allowed to implement less restrictive validation rules but you are not allowed to enforce stricter ones in your subclass for the example in the square class the more restrictive requirement is that the width and the length be the same here's some strategies to make sure that you are following the Liskov substitution principle top-down design make sure you do it well if you're thinking about subclasses make sure that you don't have more restrictive methods in your children designed by contract is another way to avoid this problem so you can think of interfaces usually as designed by contract so use object inheritance with caution now you can't just avoid it altogether some people would recommend that you never use inheritance and just stick with interfaces all the time you can if you design it right so use them with caution the fourth principle is what we're going to call interface segregation so the phrase is clients should not be forced to rely on interfaces that they do not use for example here's an example of two workers in a factory and a bad design so Joe implements the interface called AI worker and the robot also implements I worker obviously there are differences between the two workers but the computer program are designed the AI worker class to include everything they can sign in fix things solve problems charge batteries take a lunch break upgrade firmware assemble the thing and go home some of these apply to the robot and some just to Joe for example charge batteries is obviously a robot thing upgrade firmware robot thing but we want to do fix things we're not going to give it to the robot Joe is a lot smarter at fixing things and matter of fact Joe can solve problems isn't that nice that's why we keep hiring Joe how unfortunately though Joe takes lunch breaks and Joe goes home the robot just keeps working here's a good design though if we were to implement two interfaces for each of these people then you would have a better design so you can see that Joe implements I worker but he also has another interface now in this version called I human and the same with the robot he has AI worker in AI robot so I worker gets things that they both compared to they have sign-in start work assemble thing and sign out however Joe gets to be the guy that says I can do a method called fix solve take a break and go home the robot he has update charge and system check and so those are two different classes for each of these objects and that makes a much better program design here's a physical world example of what I'm talking about clients should not be forced to rely on interfaces they do not use we've probably all bought these octopus looking charger cords there's going to be one cord on there that you actually need but it's kind of nice to have all eight of well not really you can actually take your scissors and cut off seven of them and probably never miss them so we don't want to have to do that to our programming make your users only in implement the interfaces that they need multiple interfaces are usually better than one general-purpose interface also large interfaces make it more difficult to extend smaller parts to the system let's think about a video game here all the pieces on the game so you got Mario you got mushrooms you got question marks you got coins all these things and each of them probably should have an interface to describe its properties can you control the object then give it AI controlled can you kill the object then give it I kill a ball is an enemy give it AI enemy so there might be many enemies or many killable things but they all have the one thing in common that makes that interface apply to them the last principle of solid is what we're going to call dependency inversion or sometimes called dependency injection now you know that you've violated this principle if you can say when knowing how things work becomes a burden for example you get up in the morning and you're grumpy all you need is a cup of coffee I want my coffee to be ready after I click the green button and I fill it with water and then I wait I don't have to think about what voltage that the coils are working at I don't have to worry about the plumbing I don't have to worry about how the alarm goes off or how it senses that the coffee is ready I just want it to work and so we don't care if it's a simple coffeemaker or a complex one in our code we want the user to be able to just use the method without knowing the internals of it here's another example of why dependency injection is good modules can be swappable and probably the best example is the dremel tool that's a great power tool it can be a drill it can be a saw it can be a sander and I don't know what else you can do but there's a maybe 20 or 30 different things that you can see here now you can't automatically switch them from one to the other you have to shut the Machine off you have to swap out something and then turn it back on but in just a short time it's turned in from a drill to a sander now the same thing happens in your code if you have dependency injection with one change of a code you can swap out one database system for another you can make a new change to go from production to a database server that is in in development you can you can make quick changes in one line of code and so dependency injection allows your program to be more flexible think about this the ultimate interface is the interface on your wall for your electricity so you know that this is a 110 outlet in North America and of course if you're trying to work with your stove in the kitchen you're going to have a very different interface to plug into just imagine if you require the users to every time they plug in is to have a connection of physical wires they'd have to make sure that they had the right voltage that they were plugged into the right frequency to the right power plant that they didn't have a some kind of a transformer issue it would be complete disaster and so the interface is allowing us to just mindlessly plug it in and know that it's going to work dependency inversion principle works like this that instead of the lower level modules driving the game or running the show they don't tell the higher modules what to do it's the reverse the high level modules define the interface and then the lower level modules must implement so hopefully anytime you worked with an interface you've already done this kind of principle we're trying to do this because your applications should be ready for changes we want it to be resilient so you don't do this for every part of your application think of the parts that are likely to change so one example that usually comes up in a system like this is working with a database suppose you just want data to come and go you might want to connect it to a Microsoft sequel server or my sequel or even might attach to a no sequel database like but in any case we want our DB object to implement all of the things such as get a user save a user check a user register all those things we don't want to have to go in and find out how the actual database did this work now the opposite of these solid principles you might call it is the stupid principles don't be stupid all right don't use Singleton's too often tight coupling the exact opposite of the dependency injection are untested bility probably related to the idea that you're creating too many goals for one method so testability works best if you have one job per method premature optimization so don't make your code extremely complex in the hopes of making your algorithm a little bit more efficient focus on a good algorithm of course but just let the compiler do its job it's probably going to do just fine in descriptive naming so don't name everything in your program the letter X for a variable you know go ahead and use descriptive names whenever you define a variable and then duplication of code so that means if you're copying and pasting code from one method to another without any changes at all you're doing it wrong there's going to be a better way so dry is don't repeat yourself and that's kind of the duplication stupid principle here so don't be stupid we want to be smart we want to be solid so think of the single responsibility of each method we want to think about the open/closed idea where you can extend a module but don't go change the original we want to be able to use the Liskov substitution so that children can behave well when the methods that their parents use we want to be able to make interfaces that are segregated so don't force your user to inherit or implement an interface that they don't care about and then finally dependency inversion which means that your program can have hot-swappable parts that are easily maintainable and makes your program more flexible so be a solid programmer and think of s oli D when you're doing your programming
Info
Channel: Programming w/ Professor Sluiter
Views: 2,906
Rating: undefined out of 5
Keywords: solid programming, design principles, solid design principles, programming, design patterns, c#, computer programming, software development, javascript, liskov substitution principle, liskov substitution principle c#, solid programming skills, solid programming explained, solid design, solid design explained, open closed, solid principles, single responsibility principle, solid design patterns in c#, solid design pattern in java, solid design patterns, liskov
Id: kMyosdBxKPU
Channel Id: undefined
Length: 20min 53sec (1253 seconds)
Published: Wed Apr 15 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.