Design Patterns: Single Responsibility Principle Explained Practically in C# (The S in SOLID)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
when you are writing code are you doing it right that's the question that worries a lot of people and should probably at least be something that every developer thinks through design patterns are best practice concepts that we can implement into our code to make it better in some way think of them as guardrails to keep our codes safe in today's video we're going to look at the first entry in the famous solid principle that s stands for single responsibility principle we're going to dive into what that means how I should change our programming practices and how far we should take it for those of you who don't know me my name is Tim quarry and it's my goal to clear up the confusion and frustration around learning c-sharp because learning software development shouldn't be so hard if that's selling something that would interest you I think you'd benefit from subscribing to my channel you probably also benefit from join my mailing list will get exclusive content insider access that link is the description below so let's start the conversation on the single responsibility principle which we'll call SRP from now on by looking at some code I could do a nifty PowerPoint for you and show you fun pictures that try to represent this issue but I find best to look at this in a practical manner here I have a project I created in Visual Studio in c-sharp now the principles of this video will actually apply to any software development language but since this channel focuses primarily on c-sharp that's the language will use the code I have here is rather simple I have a console application that asks for users first and last name it validates both names it then generates a user name for that user pretty simple stuff the problem is application is that it violates SRP so now we have some code in front of us let's talk about SRP SRP states that a class should only have one responsibility or another way of putting that is they should only have one reason to change in this code if we decide to change how we talk to the user to welcome them or a tell them we're done we have change the class we also have to change the same class if we need to change how he capture the first and last name if we decide to change how he validate names this class has to change and if we decide change how we generate user names again this class has to change see all the different changes that could affect this class SRP says there she only one reason to change per class let's look at how we could do that and then we'll discuss the limitations of SRP and how to can apply to more than just classes let's start with a standard message we show the user right here we have console dot write line welcome to my application which is pre standard pretty simple stuff and since we're using console application that's how you print it out that's great but again if we have to make a change this that's probably only change which would make this class which we know you have other things to do the other thing is we have return statement here or return statement here both with counsel read line beforehand and then just a console rely at the end that's really another message a standard message to the user think about this way what if I said you know what it doesn't make sense just to have a console red line that blinking cursor let's do a console dot right first that says press any you know press the Enter key to continue or close and then dot dot dot well I need to add that before this line before this line and before this line and again I am now changing this program dot CS file again so the first thing should probably do is look at see if we can't eliminate just standard messages now this is gonna get a little tricky here and I want you to at least take the SRP principle and think it through that's really what design patterns are meant to do to get you to think about your code so if we follow SRP to its full conclusion that a class should only change for one reason it would make sense that we have a welcome message class and a I'm done class or a closeout class or something like that because each of these messages is different that seems to me to be overkill and again this is gonna be where it comes down to these are principles not requirements okay so it's a principle see you have to figure out how in your best effort to apply his principles to your code so what I would do is I would probably create a new class and I would call this class something like standard messages and these would be standard messages that we give the user make it public and I would create a standard message for the welcome message so public and I'll create static later on in our solid principles we'll probably we'll see how we don't necessarily want to use static here maybe when I use a full class instance but until I get to a special especially the dependency inversion I I don't want to cover it yet and so static is fine and so if you're looking at this and you've already gotten kind of gone through the solid principles you look at this and go well is there's more you can do here and yes there is but I want to cover one thing at a time instead of trying to kind of pile them all together because you'll find us out as we go the solid principles and other design patterns kind of all blend together and they really work best when you don't just implement one but you implement multiple or or most of them but for now we're gonna create a public static method and we'll call that just play static void and will depend the console and that's one of those things again where we could totally abstract it from the console but for this demo for SRP we're gonna rely on the console so we'll just say say our welcome message like so so this is a public static void welcome message and we'll just take this right here the console dot write line that's what I'm saying about depayne a console this method now depends on the console being available which again it's OK for our application but if I was abstract this out I might say yeah let's see if we can't break that depends C and how it has returned this message and then may have programmed ICS actually read it to the console so but for for our purposes this is okay so that's all I did I created a class with a plug static void that just does our welcome application and that's it I'll create another method public static void end application where we'll say something like let's start off with just the console dot readline and that's it because that's what we have right now so here instead of this what we'll have is standard messages dot welcome message and then down everywhere we have the console dot readline will have the standard messages dot and application oops and application and by console that real I don't mean where we're capturing information just what we're saying that's the end of the application so it's the end of the application there there and there alright so now they've kind of we've started our abstraction we started our breakout because now and this is again this could be its own class and this could be its own class but my definition for one single change would be a change in the messaging the standard messaging and so in that case both of these methods would apply to that and so I feel like it's okay to put in this this sync this one class if you feel different that's fine you can break into two so I have now one class that does two different tasks welcome message and end application both around the standard messaging next we have this section right here where we are creating a user and then populating their first and last name well that seems like it should be its own thing instead of being lumped in here with static void main so let's do this let's create a new class new class we'll call this person data capture guess what it's jobs gonna be well it's gonna capture a person's data and in fact what we'll do is we'll have a public static person which is the return type of person and we'll say capture person or we just say police maybe person person data capture dot what's called a stock capture there we go and so it's job is going to be to capture a person information and then return that information so well actually cut all this out and paste it in here and then we can just say return user if we create a person user right here now normally what I do this kind of case is I actually changes to output that way we know this is what's coming back out so if you didn't capture what I did there let's let's go back to where it was I'll show you so this it was user was the variable name but I have user here I have it here I have it here and I have it here if I change it at the declaration to say output and I hit control dot it says would you like to rename user to output and it shows me the different places that will change users now B output we have changed that variable name I say yep click on and now it's changed ever it's a user - now output that's one of the shortcut things that's really helpful in refactoring if you want to change a variable no problem I has changed at the source and it intelligently changes it everywhere that means if I had a user somewhere else like here it didn't change that user because that's out of scope of this variable and so it's not the same user so it's really intelligent that way all right so now I have a class called person data capture that is one thing it captures a person okay so when I have changes to say what information I capture that's the single reason this class changes okay that's it so if I say you know what I want to ask for first name I want to ask for given name no problem I change it right there the last for last time I asked for surname same right there okay so it will change it a couple different times but all for the same purpose for changing how we capture or what we capture if we kind of capture email address now we'll just add one more set of requests here on the next line down for email address so now over here we could say person user equals person data capture dot capture write capture user now next we have these validators so we're validating hey the first name is a null or white space if it is say you did not give us a valid first name and the application well we don't want to do validation here as well so we need to also extract that out into its own class so let's do this let's create a new class and we'll call this class the person validator because again I'm gonna put a couple of different methods in here where I'm gonna validate or it's gonna validate Tuvan things I'm gonna validate the first-name and I'm gonna evaluate the last name and so the question is do I create a method for validate first-name and I won for validate last name I don't think so I think that that then the the main would have to call both and now we're tying the main to changing if we also have now an email address and so that doesn't seem like it's a good idea and so instead what I'd probably do is I'd probably create a public static I've called bool validate person an actual let's call is validate because the name of a class is person validator so the person validated person validator dot validate it will pass in that person object let's call it person okay so you have validate message that should return a boolean that boolean will be yes it worked no it didn't or yes it's valid no it's not valid and inside here we're going to do this work here let's actually go to comment as well we'll cut this out and we'll paste it in here so now it's person not user so we'll have to take care of that this is not a refactor case right here now right now we have is we have a check for first-name we have a check for last and both of them will give a standard message to end the application but they both return which in the case of our programmed SCS our static void main return actually closes the application here return doesn't do that in fact we have to return a boolean so we'll do is we'll say return false return false or at the very end return true so what this is doing is it's saying if you get through all the checks and none of them stop you then it's valid but if you hit check where it stops you it's going to return false so they'll show the standard message and application and it will return false meaning stop now I'm not sure when I keep us here you have it now twice we could do it once so let's come back over to our program not CS and say boule is valid I'd say is purse is user valid equals person validator dot validate and passing a user object and now will tell us if they're valid if is user valid equals false now I could do is not put an exclamation point in front of the bank character in front and not have to do this part you can't do both by the way maybe true but if I did this that works as well the only difference is especially if you're newer to c-sharp or if you're reading through real quick that's not quite as obvious it kind of blends in to the characters so I tend not to do that I tend to encourage you as actually explicitly say false so it's very very clear what's happening you don't miss it accidentally so is these are valid equals false so if it's false then we could do this just return that's all we have to do because we've already done the end application but I think I'd like to do instead is cut this out and I'll take it out of here as well and come back over here and I'll allow my main to make that call instead so I know it's more obvious here that's and in the application and validator then doesn't have to know anything about where we are in the application it doesn't know that we need to end because maybe we just say hey it's not valid let's loop through again ask for the information all over again versus and in the application so can I get that out of here in the validate because validation should know about where we are on the application and get it back to main whose sole job is and know where we're at in the process before you move on from this the one other thing that I'm looking at and going I don't like this really is this console.writeline you'd not give us a valid first name you as a valid last name this seems kind of like a standard message and so I'll probably do but I know we'll do go as standard messages and create a new one public static void display error validation error I'll pass in the field name so now we can do it's got a value ATAR I'm gonna copy this come back over here to these standard messages I'll paste it in and then I'll I will put the dollar sign in front and then paste it in here like so inside clear braces so now this message will say you would not give us a valid whatever name or field any pass in back over here we can say standard messages dot display validation error for first name and that field name is the user friendly field MIT not the you know first name all crunched together that reads better for programmers not so much for users so this is the last name so the last name fails call a standard message for last name okay so now again this hope has only one reason to change and that's if we change how we validate the person object and we're not quite done yet go back to program CS we still have this create the user name so let's create another let's call this class the account generator because well right now it does just one thing or we'll do one thing which is create the username I can see it doing other things as well all around account generation still single responsibility one thing is doing but it may have multiple steps in that process or multiple pieces of that process so create a public static and this is a void right so we have a there's the actual creation but then you also have this message here so the question is do we call create another standard message for this or do we have it be specific because it really is account specific and I think we create this message right inside the account generator and the reason why is because it really is account specific and it seems like the wrong place to put it to put it inside a standard message because standard messages are for things that could be use across the board welcoming and goodbye or closed messages that phrase standard and so is a validation message because it might be for a different object or different model but with this it's very specific to the the account creation and we're really simulating here we're not actually create account we're just kind of simulating the account was created so let's just say account dinner dot or a create account is the name so we'll pass in the person user I'll call it user here because we're creating a user account so that makes kind of sense and in here we're just gonna do these two lines here that's it again this is just simulating creating the user account so nothing different here and now over here we're going to do a count generator dot create account and that's it oh we hit pass in the user so user there we go there's nobody see this if we run it that's pretty standard still Tim quarry user name is T quarry it's really simple and it's welcome the application it has a cursor at the end everything looks good so that's the basics of SRP notice how now static void main it really has one job that's just a controller flow do this then do this then do this then do this now there's still a little bit of of stuff in here that I love a change now part of it is stuff that I'm ignoring because it's not part of the SRP for example we're we're newing up a user right here and that's really tightly coupled we're not doing any two interfaces yet which usually see SRP you see interfaces all over the place and we'll get to that but that's really for another one of the design principles you probably should do it here but it doesn't strictly fall under SRP in my on my opinion at least okay so what we've done is we've again we've turned main into just it does one thing and that is it controls the flow of our application we've broken out all these different parts into different classes so now if you wanna know how do we capture user information well it's probably under the person data capture section if you want to how we validate a user it's under a person validator if you wanna know what standard messages we do standard messages so it really has broken our application apart into little bitty pieces and the the benefit here the few benefits one of them is when you go to make a change you probably should know exactly where to go now if you did poor naming or if you have a thousand these classes with no folder structure yeah you're going to have some problems but if you create some kind of folder structure in here that makes sense then it should be really simple and know where to go it's also a whole lot easier to read the code because welcome message capture a user validate a user if it's not valid and the application create the account this user and the application that's pretty readable and pretty understandable so that's another benefit of this SRP the other thing is when you come in here and change something let's change a let's change a standard message each one of these methods has one line of code now sometimes you have a little bit more you'll have ten lines of code twenty lines of code but in general you'll have really small methods and really small classes and so if you do it's really not hard to review what's going on in the entire class let alone just the method you need so for example and application right now just one thing read line well you know what let's add that console dot right press enter to close that's very simple it's two lines of code I still know what's going on at the end application and when I run this it doesn't matter if I give it bad data that's not a valid first name press ENTER to close or if I give it good data using it at a quarry press ENTER to close okay I've now changed everywhere and I only had a change one class and as the class that talks about standard messaging not the one talks about validating users or the one that creates the accounts or and these other things I change in one place for one purpose and it changed everywhere so it really is it breaks your application apart net forces you think about what one thing does and the SRP really talks about classes so that's one of the things we've I've tweaked a little bit in the fact that we talk about classes but in here in standard messages I say that one responsibility or one thing that's changing is any standard message but you could go to the next level and say we could have a standard welcome messages class a standard and application messages class and a standard display validation errors class that's fine you can do that and that would be more fully implement SRP but it does add three classes each of which have one line or in this case two lines of code of actual code and so that that is the balance and so I hear you know some people say well this creates a whole bunch of classes and yes it does but I don't answer problem for example if I'm in program dot CS I don't care if I have a hundred classes if I say I need to figure out what validator does or validate does I select if I put my cursor there I hit f12 well there's the message or the method and it has looks like about eight nine lines of code total pretty easy to read pretty easy to understand and I go right to it if I'm gonna back to where I was I hit the back arrow up here I'm back to program dot C s really easy to navigate using intellisense it's really to understand what's going on and everything is just little chunks it's a whole lot easy to understand a little chunk that is the whole application so before you push back on this is you know too many classes I don't really think is a vowed argument you have to company more specific on that it doesn't cost you any disk space really and even if it does we're talking about bytes of disk space versus you know are a gigabyte hard drives so that's not really a problem it doesn't slow your application down anyway and having it's all broken apart does make it easier to read which when if it's easier to read it's easier to debug it's easier to have a new developer understand what's going on and contribute and so there's a whole lot of speed benefits from a development standpoint so I really don't see a problem with the extra classes now sure the other end of it is you can go excessive and you can have thousands of classes that each do one little thing and that causes bloat in your application absolutely so my encouragement to you is find the balance that works for you but one of the rule of thumb principles in here is if your class Scrolls on your visual studio so for example even though I have a large font size for display I don't have to scroll this now technically the using statements that might be an issue I can take those bodies and I'm never being used but for the actual class itself so this right here if this has to scroll you've done something wrong or at least you need to think about it let's put it that way so and this is the biggest one that's this is main which is a quarterback and so it probably should be a little bit longer could be a little bit longer but of any of your classes you create if they screw off a screen yeah it's probably too big so think that one through and kind of keep it back of your mind but in general if you can think through does this do two things or does do I have to change this class for two different reasons and if the answer to either those is yes yes it does two different things or yes I have to change it for two different reasons then split apart it will make your reading the code faster it'll make your understanding code better and it will also set you up for success down the road or talking about these other design principles or practices so that's the SRP single responsibility principle and nutshell there's a whole lot more definitely go until we can talk about all the the nuance and all the rest but I really want to keep it at a practical level in a way that you can easily implement in your code now if you have an existing code base it's not going to be simple to just come in and change everything all at once obviously I understand that but do a little bit of time so make one little change two little changes as you can to make it a little bit more in compliance with SRP if you create new code make it compliant with that sarpy okay I love to hear what your thoughts are about this I love to hear you know what pitfalls you see or what problems you've ran into and trying to implement SRP so leave those comments down down below and also I will distribute the source code as well so it'll be on my blog to be a link in the description down below you can go to the blog and get the source code to play around with them and kind of see and feel how I did things one thing I note is over here I probably even if this small application I probably create a folder structure for this just because even now it seems a little bit complicated so I might create a folder a folder for say person where I have person person did it capture in person validate maybe one for account information or I had just just the account generator and one for messaging or something like that so that's I might do something like that I won't do this application because it's real size scope of what we're doing but maybe sent to think through as you're creating your applications nice little folder structures to help compartmentalize and keep things together that that kind of fit together alright so that's it for SRP we will next video in this series at least go over the next principle in solid which is the open closed principle so stay tuned for that make sure you subscribe down below so you get that that notification click the little bell I kind of make sure you get notifications and also if you could just me a thumbs up I'd appreciate it that helps boost this post on YouTube and lets up you'll know this it's this here alright thank you very much until next time I am Tim quarry
Info
Channel: IAmTimCorey
Views: 179,701
Rating: 4.9656444 out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, training, tim corey, C# training, C# tutorial, design patterns c#, design patterns, solid, s.o.l.i.d, s.o.l.i.d principles, s.o.l.i.d principles c#, s.o.l.i.d. design principles, s.o.l.i.d design, srp, single responsibility principle, single responsibility principle c#, single responsibility principle example, single responsibility principle uncle bob, srp in c#, practical design patterns
Id: 5RwhyZnVRS8
Channel Id: undefined
Length: 35min 49sec (2149 seconds)
Published: Tue Mar 27 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.