9 "rules" for cleaner code | Object Calisthenics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody i'm nick and this i'm going to show you nine rules that can help you write cleaner code this rule set is called object calisthenics and it was defined by jeff bay back in the day in his the thoughtworks anthology book and it talks of nine rules which i prefer to define more as guidelines because defining them as rules sounds harsh and absolute so i'm gonna say guidelines to help you write cleaner code and it's building upon principles like yagni solid kiss dry these types of acronyms that we all use to write cleaner code now clean code is a very subjective thing and what is clean for me might not be clean for you but we're gonna try to explain why they're considered like this and whether we should even use them because yeah they're nine but i don't actually use all nine of them and i've actually adapted some of them because i don't agree with the original definition so i'm gonna talk you through the ones i use the ones i don't use and the ones i have adapted to my own liking now the reason why i'm making this video is because i made a refactoring test video before this and many people ask how am i going about refactoring code and how i identify those patterns so object calisthenics is one of those things i have in mind and i just naturally do nowadays if you like this type of videos and you want to see more make sure you subscribe during the summer notification bell so you don't miss any new episodes so let's go straight into the code and what i have here is nine projects one project per object calisthenics guideline the first one is called only one level of indentation per method so what we have here is some sort of cache that we call the build cache method and then it's building some caching around that through the um through some objects let's see what the method looks like internally so what we have here is a nested for each loop we're posting a data table so we're going rows first column second and then we are checking if there's an error if there is nowhere then we continue and we process the columns and we're matching the columns and rows and we're adding items now the rule says that this where my cursor is right now is intendation level zero and you can go as deep as here when it comes to nesting you cannot go deeper so this is kind of violating that rule because you're nesting in two levels deep code that is deeply nested is actually hard to read in this example it's a very microscopic example you might not actually see it you might be like i can see all the code but i'm sure that you have code that has deep nesting that is very hard to read and work with the solution to that is using method extracting so you can simply use the extract method functionality of your id and in this scenario what are we doing we're pausing the the columns of the data table so i can just say past columns the reason why i'm using generic names as past columns and not something more specific is because the example is generic you might initially be uh let's say iterating over clothes like hoodies and then you might want to have a color iteration as well so you're iterating for every color of every item in a deep nesting pattern but for now i'm just going to extract it using a very generic name and the other thing i want to extract is the outer for each loop which can also be extracted to a pause rows or even pause items depending on how you gonna name this depending on your context and now this continue statement kind of violates that rule still but we are not going to remove it because continue doesn't really have much logic in it it's easy to read and it's better to leave it like this and also i intentionally have the curly brace here i don't have them removed because i like to have the curly braces defined code that defines the context is less prone to errors and now the main code which is this is way easier to read i just need to know that i'm pausing the rows and then if i under check them i just go to the method and i see what's happening in that method and then if i need to go deeper i go down you might say that now the code is less readable because i have to scroll and find every method that this original method is using i disagree because you don't read a class usually you read a method especially when you're working on it so it makes more sense to separate them with meaningful names not only it makes it more manageable to work with but you might get other side effects benefits like but the stack traces um when you're debugging your code or when something is happening that is wrong or you might be able to read these smaller methods easier and this is one of the things i am personally using so if you go to the refactoring test code that i did in the previous video there is no more than um one level of intendation in terms of nesting per method so this i have seen it working i know it works and i have personally used it and i do recommend you using it let's go to the next one and the next one is called don't use the else keyword now i already have a video talking about this very thing and i actually go on and on with more examples so for that reason i'm just going to tell you to click on the top right corner of the screen right now if you want to check that and then continue this video because i cannot do it justice in a 20 minute video it did actually require a bigger video which i already have out so i'm going to skip over that but the general statement is don't use an else keyword it might sound very absolute but please check that video because i do explain why it makes sense to do it now the next one is called wrap all primitives and strings and the differentiation there is because in some languages strings are not primitives this is another video this is another topic that i actually do have a video out and it's the video i have for primitive obsession which is another thing you can click on the top right on your screen right now to check so for that reason i won't really stand on it in this video because i do it justice in a different video i highly recommend you go check that out instead and luckily uh rule 8 actually builds on top of that idea of the rule 3 so we're going to talk more about it in this video as well but just to keep this video more to the point and focused you can check that rule in that separate video so let's go to the fourth one which is first class collections what i have here is a client service and this client service has a bunch of things has a logger um it creates and it gets a client by id and obviously it's all fake totally memory and it also has a dictionary and this dictionary has a good as the key and a client as the object now first class collections says that if you have a class that has more fields than than just this single collection of items whether that's a list or a dictionary then that thing that collection that dictionary in our case has some domain logic behind it and it should be encapsulated should be in its own class and the reason for that is in my case it represents my clients so should the client service directly be able to mutate and get anything it wants from that dictionary well maybe not maybe we should replace that with its own collection called client dictionary in our case and now if i go to the client dictionary i am composing my own client dictionary using an internal dictionary and i'm exposing to the user only the things that i want to allow to this collection to happen so i won't create i want update i want i get by id and i want delete by id i want these very specific things could the service do it them itself yes sure it could but by wrapping the collection in its own class i'm giving it a more well-defined structural reason in my domain you know it's my client dictionary it's a very specific thing so now my code would change and instead of just doing add on the dictionary i would do clients dot create and what does create need well actually i forgot what create needs the client so how the good will be used internally to create the client i don't care i just give it a client and create it for me same goes here with the get by id should i handle any default logic here absolutely not let's do that in the collection that is responsible for is so the collection now became a first-class citizen in my class by having its own thing to represent its own class this is one of the things that to me are more situational so i don't use it all the time but when i'm working with domain specific things i am actually using it um it's something that you could actually just keep over but i do see a big benefit in using it when you need it the next one is called one dot per line so let's take a look at this main class here as you can see i have i'm using the configuration of a dot net project and i'm trying to get a specific item from the configuration structure so i'm going dynamodb region details and region name and this will be nested objects in the in memory of the um configuration now the rules as one dot per line as you can see i have two dots here this is one of the two things that this one.per line rule means so instead of doing this this this code is very hard to debug kind of hard to read but not terribly hard to read but very hard to debug because if i just want to see what the value of this is i have to open the debugger window and try to compute it on the spot during runtime so it's very hard to see what went wrong especially if something goes wrong in this line as well like what went wrong you don't know so something like this would actually be written dynamodb section and then you would extract the dynamodb section here then region section and you would have dynamodb section dot get section here and in the end you would have the actual region name which i can actually do this region section now my code is easier to read and also easier to work with this might make more sense in a more domain entity areas so let's say that i have a pet so let's say new pet here and i want to update the postcode of the pet because the pet is registered in a specific house so i'm going to go pet dot set postcode e1 for ly i don't know something random and this might look fine to you but let's take a look at what's going on in the set postcode method the setpostcode method is using it's going to the owner which is an object in the pet class it's going to the home address and then it's going to the postcode now should the pet class know about the home address of the owner not really the person because the address the postcode is driven by the person not by the pet so this would look more like said postcode here and yes the person knows about their home address so they're able to mutate that and then if you want to do it in the pet level i mean just use the owner dot said postcode and set the postcode here and now we again eliminate this one dot per line thing however this rule does not apply when you have um a fluent api or query builder so if we had something like this i know that there's a config builder actually let's say a new configuration builder yeah so in that type of scenario you have the you know chained things like add and you can have as many as you want in that scenario it's fine to use it what i like to do personally is i knew line on dots because it makes it easier to follow in terms of what you're doing you just need to know that this one.line doesn't really apply when you have a fluent api or link in a net scenario you don't need really to um to think about it if you do that basically it is to satisfy the law of demeter which says that you should only talk to your immediate friends you should not talk to strangers and this is the reason why that specific rule exists this is another thing that i tend to use a lot but sometimes when i'm doing you know link and more complicated things um i might skip over but i am actually trying to use this as well next rule is called don't abbreviate and this one is one of my personal favorites because i see it all the time it makes sense to abbreviate for some other languages i know in go or you know c plus plus but in languages like java code links is a python javascript whatever you don't need to abbreviate don't abbreviate and what does abbreviation mean right let's let's go to this youtube channel object here here you have two things you have a decimal called cpm now what does cpm mean to you right well it doesn't actually mean anything or it might but probably doesn't now cpm actually defines something called cost per mill which is how much revenue you make per thousand views through ads so don't type cpm cost per mill it makes it easier for you to read what it is potentially google it as well and also communicate it to business to say okay can you explain to me what cost per mill is give long descriptive names to your properties fields methods however this value which does have a long descriptive name is also wrong because i know the context right i am in a youtube channel class but this still has a youtube channel id in the name i don't need that just remove it if you name something id in a class called youtube channel i know that you're talking about the youtube channel id you don't need to tell me you can see this in this user service even more where you have a user service and then the methods are called add user added user delete user i don't need to have the user here why do you have it right if i just tell you add edit delete what do you think i'm editing a crocodile no it's the user don't have it here so long descriptive names but when you're context aware do not bloat your naming with things that can be interpreted by just looking at the class name this is one of my favorite rules i use it all the time it just makes so much sense especially in cshop to have long descriptive names because it makes it so waste to work with and on board people that might not know the domain so well so yes absolutely use that the seventh rule is called keep all entities small now this rule is a bit yeah okay i'm going to tell you what the original rule says so the original rule defines that you should not have a class with more than 15 lines of code and no package by package in this context we mean a folder or namespace in javascript package with over 10 files i mean i get that your justification writing this would be that more than 50 lines violate single responsibility principle but come on 50 lines do you know how much is 50 lines this file is 30 lines um it's not something i follow um other people might tell you the following so keep classes under 100 250 lines of code keep methods under 10 lines of code and then classes under five properties and classes under five methods this is more something i can get behind but again it's not something i can just look in the eye until you do this you know even as a guideline what i'll tell you is just do whatever the hell you want as long as you don't violate same responsibility principle because it's more important to not violate srp than to follow an arbitrary rule around a number of lines which can be inflated in so many ways you know especially with method extracting which is a good thing but if you extract methods then you might violate this rule which is not really a violation really right what i think in my mind when i'm working with code is that when my class reaches or goes close to 250 lines then it probably does way too much and i need to refactor it but i don't think that setting such a rule makes too much sense so in my opinion yes i know what jeff wrote this but i cannot really get behind this so it's up to you if you want to use it for me i choose to say that if i'm reaching 200 250 lines then i'm like okay hold up a minute i might be going too far uh but that's as much we're gonna say for this specific rule it's up to you to do whatever you want now the eighth one is called no classes with more than two instance variables what does that mean well let's look at the player service this player service has four four instance variables the logger the metrics collector account service game client we just violated by two by by doing that but in my opinion we need all of them this is another one that i don't really agree i get it and it makes more sense if you go to models and you go to the player character right where in the player character imagine this is a game you have the name actually let me show you how this is being initialized you have a name if you play something like call of duty you might know that your name is your username and then a tag so this is what we're building here and then you have a character and the character has two properties here the player name and player id and the player id has the value the player name has the username and the tag this is actually satisfying that rule i find it easier to do such things in a more ddd scenario where you have value objects and you try to break things down to way smaller manageable pieces this is another one that i feel like i get it but realistically i probably won't be able to apply it easier to apply micro services but i cannot like if you're building something like a blazer app um and you have a bigger component you might not be able to use that or a bigger application altogether so i get it but i don't really think about it when i'm using it i do however in my mind say okay we're exiting five is this class doing too much i'm injecting way too many things here but things like the logger and the metrics collector i don't count in that five number because those are things you want to improve your resiliency and your you know debugging experience so yeah maybe if you're injecting five things from five different services then that class is doing way too much and you should reconsider it but you know it's it's yes but under some conditions but that's another thing that i don't really get behind unless it is very obvious that this class is violating responsibility principle which is what this is all about the last one is called no getters setters or properties that's another one that is vaguely absolute and let's see what that means let's say we have two football teams actually the majority of my audience is american let's say you have two soccer teams um arsenal and manchester and you want these teams you know to play a game so you have a home team and an away team and manchester us calls a goal how do you count that right you would go to game and then you would go to the away team score and then you would say value and plus plus to increase it this would be a violation of this rule and rightfully so i totally agree with the rule in that context in the you know the main entity context because it's not the responsibility of whatever class i am in here to know how to score a goal how to increase it you know this value shouldn't have a setter or the setter should be private and it shouldn't be exposed and instead if you want to score goal just have a score goal method so score goal and we're doing this because we want to satisfy the rule tell don't ask i don't want to lick my you know encapsulation outside to some service i'd rather be the one who's responsible for this class deciding how this class will be mutated and exposed and in that context it does make sense to have the score goal methodical here because now the score object itself knows how to increment itself it knows how to add a goal it knows how to subtract one if you actually you know get a goal removed because of some reason so really this rule does make sense but it makes more sense in the context of objects and entities in the main level than something like a dto or a contract from an api that's another rule i do actually use but very specifically to the domain level so these nine guidelines do make this thing called object calisthenics and like i said throughout this video i'm using some i'm not using some i've adapted some because i don't think that they all make sense in the way i'm writing code tell me which ones you're using or not using because i'm very curious and let me know what you think that's all i have for you for today thank you very much for watching special thanks to my patrons for making these videos possible if you want to support me as well you can find a link in the description down below leave a like if you liked video subscribe for more understanding the bell as well and i'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 36,816
Rating: 4.8934083 out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, clean code, clean c# code, .net clean code, clean coder, object calisthenics, 9 rules for cleaner code, SOLID, KISS, DRY, YAGNI, dotnet, .net
Id: gyrSiY4SHxI
Channel Id: undefined
Length: 23min 26sec (1406 seconds)
Published: Thu Feb 25 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.