Mastering SOLID Principles | The Ultimate Guide to Clean, Maintainable Software Design! 🚀

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone welcome back to the channel in this video we will talk about the solute principles it was first introduced by Robert C Martin also known as uncle pop in the early 2000s these principles are like a set of guidelines which provides developers a road map to write robust scalable and easy to maintain softwares it is primarily Advocate about how to write classes but it is equally effective for function programming languages like kolang so with that note let's start the first principle is called single responsibility principle and by definition it goes as there should never be more than one reason for a class to change or in other words you can say every class should have only one responsibility for example if you have a users's class then it should only handle user specific functionalities like the C operation like the creating user updating user deleting or reading the user it should not have anything like authenticating the user authoriz authorization of the user and all for such cases what you can can do you can simply have another class of authentication uh and another class for authorization if you have any class which is kind of doing two kind of stuffs or handling multiples things so that time you can consider like okay it is kind of violating the single responsibility principle let's understand using a example as we all know in golang there are no classes so we have to use struct and interfaces to implement this solid principles so for the single responsibility principle uh let's assume we have a report struct okay and this particular report struct what it do is like it create uh it generate the report and we have a schema report schema so it can have like a ID field one field two this particular function uh it is generating the report schema and then we are just printing it as like report generated so so far it is not violating any single responsibility principle because it is only handling the report related functionalities now let's suppose after generating the report we also want to export Port it into some other format okay what we can do is like we have our Json Marshall so it is converting the report schema to bytes and then we are exporting this particular report in the txt file so now this particular generate report is doing two task one is generating the report and another is the exporting the report so this is the clear sign of single responsibility principal violation to resolve this violation what we can do is like uh we can create another type called export and this particular functionality we can move it to there so we can have similar to this like a type export and another function like suppose export to txt and it will accept a bite and it will just write it and at this particular position what we can simply do is like we can simply call uh like suppose export okay and then e do export. txt okay in this way okay so this is one way but it's still right now it is not not completely satisfying the single responsibility principle because uh even we have moved this export functionality to another class or another type it is still calling it so the best way to do it like we can simply first uh return the uh this report schema okay so return the report schema and we can move this thing like uh return RS okay and in our main function what we can do uh we can first call the report report then do generate report so now we got a report schema and now we can do this thing like we got the report generation uh schema and it we convert it into bytes and now we are calling to uh calling the export so in this way now we have more control of export and and if anything is changing in the generate report it will not affect the export txt so in this way we can handle all these things the next principle is called open close principle so all the software entities should be open for extension but close for modification so what it mean is like if you have any core functionality so it should not modify for each and every use case okay it should stick to its core functionality but at the same time if there is any extension needs to be provided like if any new functionality needs to be added it should be open to add those thing without affecting the core functionality okay so let's understand it using an example let's reuse our existing example this particular example also viting the open close principle let's understand how it is violating so before that let's make few changes like instead of receiving the bite okay we can have it inside the export struct and we can have like a simple bite okay and here we can simply say e do okay by seeing it we can say it is open for extension like if we want to add another um extension like suppose export to CSV so we can simply do it using export. CSV and we can simply say output CSV okay so suppose in this way so what is the problem here actually the problem here is like suppose in this export function or the sorry the export struct if we add certain few more Fields like the length of the btes okay suppose in this way so now by Design open close it should be closed for any kind of modification but the moment we are doing any modification here it kind of affect everything in all the extended functions so to resolve it what we can do is like uh we can use the interfaces so suppose we have export provider okay and instead of this we can have a interface and we can have a function called export simple okay in this way so this thing we can kind of remove and suppose now we want to export or support the txt format so we can create a new type called export txt and it can have a struct and its Fields can be simply bite okay in this way and now we can simply rename it to export and it can be export txt okay so now it is kind of satisfying this interface it is open for extension okay but at the same time suppose now we have one more type called CSV export CSV and instead of bite it takes suppose io. reader in this way okay and we can simply say export CSV and here suppose whatever the file is in this way so now even if we are changing here even if we are modifying it here it is not modifying or like it's not affecting the export provider so it is closed for any modification but at the same time it is open for extension so this is how we kind of satisfy the open close principle so now if you want to change here what you can do is like simply uh whatever type you want so suppose we want txt so you can simply have simple bite format and buy export in this way and it will work properly and it is satisfying the open close principle one small tip to identify the open close principal violation is like suppose you have uh many F conditions switch statements where you are kind of checking the interfaces and all those things so these are the places where you can uh you can look after and and you can identify the open close principal violation so suppose you have a function called area and it is taking the interfaces and there you are checking if if its type is rectangle or not or Circle or not in such places what you can do you can create another interface suppose called shape and then this rectangle struct or Circle struct can implement this area so in that way you can satisfy or like the you can and follow the open close principle the third principle is called discop substitution principle and by its definition it says objects of a super class shall be replaceable with objects of its sub classes without breaking the application so quite complicated among the five principles of solid uh this is little bit complex or I will say it is easy to confuse with let's understand this using a simple example so in shapes we know like all squares are rectangle but not all rectangles are square so in such kind of situation this Lisk of substitution principle kind of violate or we have to take care of it for example if a function is expecting a rectangle and you are sending a square so that application logic or the application Behavior might change because it is dependent on both different length and breadth or it can just uh it can change it and it will not behave in a certain way uh another example is for birds like uh suppose we have a bird and we have two birds like eagle and penguin so we can say like okay uh the the functionality is expecting like all birds can fly but the penguin can't fly so in this particular uh scenario also if you can see uh it is kind of a violating the Lop substitution so to tackle these kind of situation what you have to do is like uh you have to Define different classes or like the different categories you can say like the flying birds and non-flying birds and when you will have certain kind of Separation that time this Lop substitution passes now suppose we have a bird interface and it is implementing the fly function so we have eagle struct and penguin struct and Eagle implemented the fly and it is like bird is flying and then the penguin also implemented the fly but it can't fly so it is panicking okay and we have a function what it do is like uh it sends letter and it is expecting bird interface okay or bird type so we have eagle and penguin and with all these birds we are trying to send these letters so if you'll run it it will Panic if you can see here it is panicking okay so this is uh where like the Lop principle is kind of violating because we have implemented the bird the penguin has implemented the bird but when we are trying to replace it it is not satisfying its core functionality like the fly okay so to do it properly what we can do is like bird uh we can just simply say it like flying bird okay and we can have another type called non-flying bird in this way and now the penguin can uh implement the nfly and we can simply remove the Panic so so in this way uh we kind of satisfy the Lop principle okay the fourth principle is called interface segregation client should not be forced to depend upon interfaces that they do not use for example we have a interface and it has three function in it and we have a type A which satisfy this interface by implementing those three functions then we have another type called type B and to satisfy this particular interface it also has to implement those three functions but that particular typee B only required the one function of it so in this scenario we are kind of violating the interface segregation to resolve such kind of conflicts what we have to do is like we have to create two interfaces and one with only one function and one with the three function so in that way we kind of prevent such kind of interface segregation violation now let's understand this with our example let's reuse our existing example of reporting so we we have one interface called export provider so we can add one more function to it suppose like export to Cloud okay in this way so now the thing is like uh we can have one more type suppose um like simply export to command line okay like CMD so right now this export to command line we only require in our low local system or in our uh command line but we don't want this particular output to go in the cloud now to satisfy this export provider we have to implement both the functions like export and Export to Cloud so we have implemented it like the export and we are saying export to CMD okay and now but this CMD thing we don't require in the cloud but still we have to uh implement it with the empty result like the return to satisfy this export provider interface so this is kind of violation of interface segregation principle to address this violation what we can do is like we can create two export interfaces like one interface uh we can have like export provider offline okay and it can have only the export and we can one have like export provider online or like a cloud okay and this can have the both the things so in this way we can satisfy the the inter uh interface segregation principle The Fifth and the last principle is called dependency inversion principle high level modules should not depend on lowlevel modules uh both should depend on abstraction for example we have one service layer where we have the business logic and we have another layer called database layer where we have all the database operation and if this service layer directly interacts using with the database layer so it's very tightly coupled okay and suppose in future if we want to change this database uh like from MySQL to postgis or mongodb or any kind of thing so that time this service layer is tightly coupled with this database layer so you have to make all those changes in the service layer so it's kind of violating this dependency inversion principle okay because the two layers high level modules and lowlevel modules are kind of uh interdependent on each other okay so to prevent the scenario what we can do is like we can create abstraction layer in between and using this abstraction layer only both the modules or like the both the service layer and the database layer can talk to each other so using abstraction it gives you the freedom like in future if you want to just change the my SQL to post gra the only thing you have to do is like you have to just change the reference uh of it in the service layer and it will work flawlessly let's understand using the example so far in our report example we kind of generated the uh report and then we exported it into uh multiple formats like the text format PDF format and and command line now we can add one one more layer like once the report is generated now we want to send it using email or like we want to notify the user like your report is generated so for that what we can do is like uh suppose we can simply have another type okay like uh one email notification one SMS notification and both will have a function called send which will tell like okay sending report via email and sending report via SMS for example we want to send a email notification first okay so what we can do is like uh in the report only uh we can add a email notification thing okay in this way and we can have a email notification service okay and when we are initiating it and uh so that time we can have one ens email ification service and yeah and here we can send it using email okay and after the report is generated so we can say like okay R do email notification. send Okay so this will send the email notification here we can see like this is our business logic uh which is our use case or service layer and this you can consider as another layer or like a repository layer okay this thing so now both are very tightly coupled if I'll change anything here like suppose if I'm changing the email uh email service like suppose from email provider one to email provider 2 it will directly affect this particular generator Port function okay so it is very tightly coupled and suppose if I'm changing anything here uh in a way it will affect that also okay so and one more thing is like now I have only email notification do send now suppose I want to send using the SMS also okay so that time what I have to do I have to add one more email notification service like uh sorry uh one more notification service called SMS and then again I have to do the same thing okay and then there might be possibility like you want to just send the email notification or the uh uh SMS notification depending on certain condition to prevent such tightly coupled situation what we can do is like we can create another uh interface called suppose notification service okay and it's a interface and it can have one function called send okay and now instead of accepting the email notification what it can simply have a a notification service and it can have like a notification service in this way now whatever you want you can send like if you don't want to send the email notification okay uh okay we just have to add the pointer this way okay so uh as we can see now if you want to send the SMS notification so that time we just have to change it to SMS okay and it will work this is how you implement dependency inversion principle and prevent such kind of a tight coupling I hope you like this lecture and please subscribe I'll see you in the next lecture thank you
Info
Channel: practicego
Views: 821
Rating: undefined out of 5
Keywords: golang, golang tutorial, learn golang, golang for beginners, golang api, gorilla mux, mongodb, web development, backend development, rest api, api development, golang web app, golang crud operations, gorilla mux tutorial, deploy golang app, coding, programming, software development, tech, tutorial, beginner, fullstack, freecodecamp, goroutine, interview, interviewquestion, 2024, docker, containerise, optimise, SOLID, Clean code
Id: 5RwxrELDHhE
Channel Id: undefined
Length: 19min 2sec (1142 seconds)
Published: Fri Mar 08 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.