SOLID Design Principles in #Angular (Advanced, 2021)

SOLID Design Principles in #Angular (Advanced, 2021)


SOLID Design Principles in #Angular (Advanced, 2021)

🔥 Learn how to build really complex Angular forms \u0026 form controls with my new advanced course https://bit.ly/advanced-angular-forms 🔥
Use coupon: YOUTUBE_DISCOUNT to get -a 10%-off discount!

I am quite sure that every one of you has heard about S.O.L.I.D design principles which help to design our code maintainable and flexible. In this video, I wanted to show you how these principles could be applied to your Angular applications. I hope you will find something useful and enjoy watching it!

⭐ Successful Interview “Angular Interview Hacking” course
https://courses.decodedfrontend.io/co

⭐ Become a Pro in Angular Material Theming
https://bit.ly/angular-material-themi

⭐ Blazing fast GraphQL Backend just in 1 Day with Hasura Engine
https://bit.ly/complete-hasura-course

00:00:00 - Intro;
00:01:05 - What is Design Principle;
00:02:23 - Single Responsibility Principle;
00:13:21 - Open/Closed Principle;
00:21:40 - Liskov Substitution Principle;
00:27:15 - Interface Segregation Principle;
00:32:52 - Dependency Inversion Principle;
00:41:02 - Outro;

🔗 Link to the source code on GitHub:
https://github.com/DMezhenskyi/solid-

#webdevelopment #angulartip #frontend


Content

4.4 -> Hi Everyone! Dmytro Mezhenskyi is here and today we're  going to talk about solid design principles  
11.84 -> in context of angular this video was inspired  by this comment and i found this topic really  
20.88 -> interesting because i remember myself many years  ago i remember i knew all those five principles  
29.04 -> but when it came to real life called the real  implementation i could not recognize them in the  
38.88 -> source code i could not apply them and i decided  that maybe not only i had such an issue so i  
48.4 -> decided to make this video for you and explain  it a little bit and show you real life cases so  
56.24 -> this video will be split into five sections  time codes will be in the video description  
63.2 -> check this out and we are getting started but  before we start diving into those five design  
70.64 -> principles let's talk a little bit what is design  principle itself and design principle this is  
80.32 -> recommendations how to design your code such a  way in order to keep it maintainable flexible  
88.56 -> and so on and so forth and telling that it's  recommendation it means that it is very abstract  
97.04 -> it doesn't have any concrete implementations  you can implement some design principle many  
103.76 -> different ways and already on top of this design  principle we have design patterns which solve some  
113.68 -> already concrete use case and implement one two or  more design principles and we are not restricted  
122.88 -> by only those five design principles we have many  more like dry don't repeat yourself principle or  
132.48 -> keys keep it simple and there are many of them but  those five are most popular ones and we will have  
141.6 -> a look at them right now and the first one i'm  going to start with is the single responsibility  
148.96 -> principle which sounds like there should never  be more than one reason for a class to change  
156.88 -> which means that some component or class or  model should do only one thing but do it well so  
166.96 -> let's have a look at the application i prepared  for you this is just a simple widget weather  
174.96 -> widget which just exports some json data and now  let's have a look at the implementation of this  
184.88 -> by the way i have uh in this project five branches  uh every branch for uh reserved for some certain  
194 -> design principles so you can clone this project  to your local machine and switch between branches  
201.92 -> and the implementation of every design principle  okay but yeah let's get back to our implementation  
209.36 -> you can see that my app component which is only  one component for now we have the material toolbar  
219.28 -> we have the main tag which should contain the  whole content for my web page and also i have the  
228.72 -> widget template and besides this i also have  on export json function which does export of  
239.6 -> whether widget data in json format and i have some  styles yeah but i collapsed it for now okay this  
250.08 -> piece of code violates pretty much everything not  only single responsibility principle however we  
258.4 -> focus on the single responsibility principle  here and yeah let's figure out how we split  
269.04 -> responsibility between components actually it  is sounds easier than it is because very often  
278.64 -> it is hard to decide where you know where ends  responsibility for class a and starts their  
286.48 -> responsibility for uh component or class b however  i have one rule which i use in order to determine
298.24 -> this is to determine if my class does too much or  not this is the "AND-word" rule and it means that  
308 -> you describe the responsibility of some certain  component and once you encounter the word "AND" it  
320.96 -> might be the signal that your component  does already too much. let's apply this  
329.68 -> rule to this example and how I would describe the  responsibility of the app root component I would  
339.92 -> say that the responsibility of this component  is to render the skeleton for my page so it's a  
349.12 -> top-level components like toolbar and content and  we have already toolbar we have this main content  
360.8 -> and we render also the widget layout and  we do export JSON file JSON data for this  
375.04 -> component as well within one single  component so it only gives us a hint that  
384.72 -> this component does too much and what would be the  solution for this case I would suggest that widget  
396.16 -> should be definitely the separate component  and the logic here might be might belong to  
405.6 -> the component itself so the solution would  be is to generate additional component
418.88 -> I will call it like a widget then I say that  it has scss it should have inline styles inline  
429.6 -> template and we skip tests and we also do it  flat so well I don't want to have the separate  
441.2 -> folder for this component and I click run and we  have to get the new widget component here we go  
451.28 -> good and now I can refactor it like this so  I can copy this everything including this  
463.28 -> section and we can paste it to the template  of widget component here we go also I move on  
475.28 -> this on export JSON handler here we go and  also I have to copy styles so I will copy  
493.6 -> this part header widget icon basically everything  except the content so it will move to styles here
510.08 -> and go back and instead of widget  
513.76 -> oops I forgot it here and instead of widget  we just say that it should be app widget
525.2 -> here we go so if we go back to  check it here everything looks good  
533.36 -> and hopefully our application should  work as well what's wrong here
545.52 -> ah okay now i have to place it host here because  we apply uh these styles to our host element  
558.08 -> good uh now it should be compiled successfully  and you can see nothing has been changed but  
564.8 -> our app component became more lean and it  is responsible exactly for rendering the  
575.44 -> content and rendering the toolbar but still if  we have a look at the widget component we can say  
584.24 -> that all right widget component it generates  the layout for the view of our component and  
594.64 -> it exports the data as a json and most probably  the export of the json is not this logic i  
606.56 -> mean is not responsibility of the component  itself yeah it can handle this on export json  
614.4 -> click event however the logic is not  the responsibility of this component so  
621.6 -> i would suggest you to create the separate service  and this service we could call json exporter
637.04 -> all right so let's run it and yeah we  see that we created json exporter service  
647.6 -> so we can move this logic from here and create  some methods like export yeah here we go  
665.28 -> so yeah and here i would inject our json  exporter like this and now i can call  
678.72 -> the export method against this json exporters  exporter sorry and i can save it i should save it  
687.2 -> here as well and we can go back and click export  as a json and it doesn't do its job what is wrong
704.08 -> ah sorry actually it does it for whatever reason
709.76 -> jumps right i have to fix it all right now it's  better just if you're curious it's a command  
718.24 -> option minus on or plus on mac os and you zoom  zoom in or zoom out this view all right never mind  
728.56 -> but still you can see that our widget is working  but we have splitted responsibility between three  
740.16 -> entities app component widget component and  also service but one recommendation so keep it  
749.76 -> find your balance in splitting all these  responsibilities because you may split it to such  
756.8 -> a small pieces that yeah you will be flexible like  a hell but it might be too hard to support this  
766.08 -> so find your balance usually you find it within  your team during the code reviews and yeah it's  
774.24 -> my variety from team to team uh what the what  responsibility of what because there is no  
782.4 -> some super strict rule which can determine  that here responsibility of this component  
789.28 -> ends and starts the responsibility of another one  and this is everything about single responsibility  
796.96 -> let's move forward and the next one is open closed  principle so open close principle very important  
804.96 -> one and it sounds like software entities should  be open for extension but closed for modification  
815.84 -> and what does it mean on the in the real life it  means that you should design your classes models  
822.48 -> and libraries even libraries such a way that you  should extend it functionality without touching  
832.88 -> this component it is a very good example libraries  you cannot modify components which are coming from  
842.72 -> some certain library yeah because they closed  they are published into the npm you have no  
848.16 -> access to the source code to change but still you  have to be able somehow extend this functionality  
858.72 -> and here i prepared another example it is very  similar to what we see for single responsibility  
866.08 -> but now we have two widgets but different content  inside so the first one is weather but when  
875.6 -> the second one is uh oops it's by mistake also  whether but it is the velocity which shows the  
884.56 -> last velocity of your last sprint  and this is how i implemented this it  
891.6 -> has small differences comparing to the first  implementation but this is like pretty much  
899.36 -> similar we have the ev separately apple uh  apple app widget and it has the property  
907.6 -> weather or velocity and if we have a look at the  component implementation itself we will see that  
917.6 -> it has such a thing like ng if if it is if if  it widget is weather then we render the view  
926.4 -> for weather otherwise we render the velocity  view you can of course use ng switch here it  
934.08 -> doesn't really matter for this particular case  but you understand the idea so the problem with  
940.8 -> this that it is closed definitely especially if  we distribute this while library it is closed you  
947.84 -> cannot modify it but it is not open you cannot  add the new content to it as example i want to  
956.08 -> have third widget which renders i don't know  some just a paragraph or some another view  
965.28 -> and i cannot do this because i restricted by  only these two types either weather or velocity  
974.8 -> and this is the violation of open close principle  how we can solve this issue well we can create  
986.32 -> separate view or separate component for every  of this widget and then we would use the just  
996.72 -> a content projection like ng content so i  would suggest you to generate two components
1009.44 -> first one i will name weather content and then  it will be scss it will be flat in line by the  
1020.64 -> way you can configure this everything inside  the angularjson file but i'm too lazy to do it  
1030.56 -> i think it is enough so we can run it here we go  and then we create the same bot for velocity oops  
1042.64 -> here we go i can close it i can close i  believe this part and now let's move this class  
1052.8 -> or this html from weather to weather content right  here here we go and then we will do similar to for  
1070.56 -> our velocity velocity and this part and copy it  here then we have to adjust this part we have to  
1083.68 -> remove this everything and instead we will use  mg content right so here instead of ng content  
1096.16 -> will be rendered anything we put between uh app  widget tag you'll see this in action and there are  
1104.8 -> another way how to implement it you can use  this with the component outlet and ng container  
1111.84 -> but it doesn't really matter for this case  uh you are free to implement as as you want  
1120.8 -> yeah and i save it and i have to i have to  probably add some styles yeah because the  
1131.12 -> definitely value and widget icon should be part of  styles for these guys so i will create a new file  
1142.24 -> i will say widget content scss so here will be  common uh styles for for this everything and and  
1157.68 -> weather widget weather widget it is um ah here we  go this is this container let's rename it to the  
1167.6 -> widget content here we go and for weather  we also rename it and now we have to copy  
1179.28 -> this part as well and we and we copy it here  and as we renamed it widget content it should be  
1193.52 -> good and yeah i forgot that style overalls should  be here and let's import the widget content scss  
1206.88 -> here we go and the same will do for this part as  well so i save it and inside app component already  
1216.8 -> i don't need these inputs anymore and i can  define between those um widget tags i can  
1228.56 -> define which content i want to have here and  in my case this is the web app weather content
1240.56 -> and in the second case i want to have app velocity  content and now see the uh benefit of this  
1252.08 -> everything if i want to introduce the new widget  and with some specific content there inside  
1261.2 -> i can easily do this i can just place the  paragraph there and say that content is  
1271.68 -> coming i don't know whatever and you can see  that without modifying the app widget itself i  
1281.76 -> could extend it with another content and now if  you have a look at our widgets you can see that  
1290.64 -> i reused completely the widget itself but  content is uh customizable and i can easily  
1299.92 -> customize this and change the view so this is  the open close uh design principle in action  
1308.64 -> all right and the next one in the turn is uh  lisk of barbara lisco's substitution principle  
1316.32 -> and it sounds like functions that use  pointers or references to base classes  
1324.16 -> must be able to use objects of derived classes  without knowing it yeah it sounds a little bit  
1332.48 -> complicated however everything boils down to next  thing imagine you have two classes parent class  
1341.92 -> child class which extends the apparent  one and lisco substitution principle  
1348.72 -> means that objects of this super class or  parent class should be replaceable with its  
1359.36 -> subclasses or child class without breaking the  application let's have a look at the example  
1366.32 -> so here is pretty much similar where we stopped  except i fixed the issue with titles for our  
1376.32 -> widgets yeah and and this is pretty much it  there you can see the content for for our widgets  
1386.96 -> widget content css and yeah things like  that however let's imagine that we want to  
1394.96 -> have slightly different wrappers yeah we we want  to have this one and maybe we we are planning to  
1405.44 -> have some another modifications of this widget  container and we know that all those containers  
1417.68 -> will have some functionality like export to json  and all of them should support the input title and  
1429.44 -> we can we don't want to duplicate this everything  here we want to extract this to the i don't know  
1438.08 -> some base class so let's create this have a class  and i will name it like widget base i will call it
1453.36 -> and let's generate one
1461.28 -> so inside this widget-based class i  will move the whole logic from here  
1468.56 -> so i will copy it and paste it right  there then i have to import the input
1479.6 -> okay class is using yeah this is it means that we  have to decorate this with directive as example
1491.2 -> because since iv you have to do it if you  going to use inputs as example and extend your  
1501.12 -> another component with this new one what  we exactly uh going to do right now so i do  
1508.64 -> not export but extend this is what happens when  i uh typing and talking at the same time so we  
1519.28 -> successfully extended this and how we can  violate the list of substitution principle  
1527.36 -> we can violate this by overriding  this method on export json and  
1534.24 -> as example instead of exporting the export json  we throw some error like i do not support it all  
1546.56 -> right and this is the only violation because  it changes the behavior of this on export json
1558.88 -> comparing to its parent there's completely  different logic and if you replace the  
1566.64 -> implementation of this widget base with  widget content you will break your application  
1574.88 -> which is actually the violation of a list  of substitution principle so the solution  
1582.8 -> to not violate this principle is to just  remove it and remove it completely if you  
1589.44 -> don't do a do some any additional logic for  widget component or if you do you should not  
1599.44 -> break the contract of this it should  not return some completely different  
1605.44 -> type which is not compatible so if here  return type is void let's say then also  
1615.04 -> type of this handler should be also  void and you can of course call super  
1622.16 -> and then you have to you can i don't know  do something like console lock additional  
1628.24 -> whatever so this is how you can uh extend  it without violating this design principle  
1634.8 -> all right we're getting closer to the end and  the next one is interface segregation principle  
1642.56 -> and it sounds like many client-specific interfaces  are better than one general purpose interface and  
1653.6 -> what does it mean as example uh we have velocity  and weather content and we would like to define  
1664.24 -> some interface for them some contract yeah and  we usually do it via interfaces so let's generate  
1674.72 -> the interface i will call it widget content and  run it here so here we go and let's open this  
1686.16 -> widget content and as an interface let's say i  want to have the id which should be some string  
1694.96 -> maybe just for testing purpose whatever and  let's assume that this content should support  
1705.44 -> let's save live reloading so means that  we're pulling some data from the server if  
1712.8 -> some new data arrives we render the view and we  can say that we need the property loading yeah to  
1723.28 -> show some maybe spinner during the  request to the back end which is boolean  
1730.88 -> and we need some maybe function let's say reload  and it should return void all right so we save  
1741.92 -> it and we implement this interface for every uh  content so it implements widget content here we go  
1754.96 -> it already complains that we have to implement all  necessary fields so let's implement this interface  
1762.08 -> here's the string we can define some i know  empty string as a default and here we can  
1770.08 -> say that it falls and reload throws some error  but let's say that con so log do polling right  
1783.92 -> so this is what will happen for this widget  content and we have to do the same for another one  
1793.92 -> so let's save it right here and for weather we're  going to do absolutely the same so i import so i  
1805.2 -> import widget content and we also need to  implement this thing here empty of false and
1819.36 -> do polling whatever so and i see that i didn't  save my app model okay and now we are done  
1833.76 -> but here is the problem imagine that  
1838 -> someone i know product owner comes to us and says  that uh you know what uh that life reloading for  
1846.88 -> weather makes sense because weather changes uh  really fast and we need to reflect the latest  
1853.44 -> data but velocity we update this data only i don't  know every end of the sprint usually two weeks  
1863.28 -> and we don't need to do polling for this  data it should not be supported yeah it  
1869.36 -> doesn't make sense for this kind of data so it  should not support the live reloading but the  
1879.52 -> thing is that we have to okay we don't support  we can uh leave it empty but in this case uh we  
1890.8 -> have still have to keep this loading property  and reload just in order to follow the widget  
1899.6 -> content interface so this is where interface  segregation can help us so instead of having this  
1911.2 -> let's say big interface we have to split it on  two interfaces let's say we can create interface  
1924.08 -> reloadable right and we can move these two guys  inside the reloadable interface and then we would  
1935.76 -> say that okay weather should support it so  we will implement also reloadable interface
1945.28 -> here we go but here we do not support live  reload so we can safely uh remove this code  
1953.84 -> which is not being used and which is obsolete for  our velocity content like this and this is the  
1962.88 -> interface segregation principle in action so you  just split one big interface to many other smaller  
1971.12 -> interfaces all right finally the  last but not least design principle  
1977.52 -> is dependency inversion principle and it says that  we should depend upon obstruction no concretions  
1988.48 -> how does it look in the real life angular  application you encounter this design  
1996.48 -> principle every time when you use dependency  injection let me show you some small example  
2004.96 -> say we have the service polling service and  you inject this service inside your constructor  
2014.96 -> and we have to call super because we extend  widget base all right so once you inject this  
2022.32 -> you might think that you depend on concrete class  on the concrete service which is polling service  
2029.76 -> but it just looks like this in fact angular under  the hood performs some magic uh and and it creates  
2041.6 -> such a thing called injector which acts  exactly like this abstraction layer  
2048.88 -> if you don't completely understand what i mean  by that i would recommend you check out my video  
2054.48 -> about angular dependency injection and this video  will make everything clear but just to finish  
2064.08 -> this example what i mean that we don't depend  on the polling service is that you know that  
2071.28 -> we can use dependency providers like use class  as example and we can i don't know provide some  
2081.6 -> another polling like this and i have  to create a some specific class and  
2091.28 -> and having this setup we are not pointing  to the polling service anymore but rather to  
2098.64 -> uh pointing to this another polling class  so so despite we see the reference to some  
2106 -> concrete implementation here it doesn't mean  that this concrete implementation will be used  
2113.84 -> but i'm going to remove it and i will show you  slightly another example for this everything  
2123.68 -> so actually we can create a lot of obstructions  we can create obstructions over abstractions  
2131.12 -> and so on and so forth sometimes it is over  engineering sometimes it might be helpful and  
2138.64 -> let's imagine that in widget  component inside our wrapper  
2146.24 -> we want to get reference to the component which  supports the live reloading and trigger this  
2154.56 -> reload method so how i could do it i would  i would call content child and i would say  
2164 -> that i want to get reference to the weather  component because it supports live reload  
2170.64 -> right so i will say that this is content and  that type will be a weather component like this  
2179.84 -> and it might be optional of course and somewhere  let's say in ng after view indeed or sorry content  
2190.32 -> in it and let's say if content exists i  want to call the reload method for this  
2201.76 -> component and i will remove these things and  the problem is that we depend on the concrete
2214.24 -> content weather content when in fact we might have  a lot of and other different uh contents which  
2224 -> are reloadable which are supporting the um  polling mechanism and life reloading right  
2231.68 -> so this is a violation of dependency  inversion principle because we depend  
2238.8 -> on um concrete implementation rather than  obstruction so let's create this obstruction  
2246.32 -> and this abstraction will be represented in  my case by injection token so i can create the  
2255.44 -> widget content token and here i will export  constructable content and it's going to be  
2266.48 -> new injection token which has value reload  will content right and the interface will be  
2279.28 -> reloadable so basically we say that  the value for this injection token  
2286.16 -> should support should implement this reloadable  interface so so it should have the reload method  
2293.36 -> and its loading property right and now we have to  provide some uh assign some class to this token  
2303.52 -> and as we know weather content it is something  which is implement this reloadable interface so  
2311.6 -> we will use dependency injection in order  to provide the this component instance as  
2320.88 -> a value for our injection token so we  say that provide reloadable content and  
2329.84 -> use existing weather content components so once we  try to get reference to their reloadable content  
2341.12 -> there will be it will be resolved as an instance  of this class right if you have some problems with  
2348.56 -> understanding this i have video which will pop  up right there at the top and there i explain  
2356.56 -> in details this mechanism good and now having this  abstraction layer which is represented as a token  
2367.52 -> we can replace our concrete implementation  with this token and we can say here that  
2376.4 -> the interface will be not the weather component  content but it will be something reloadable
2387.84 -> right so now we don't depend  on the concrete widget content  
2394.08 -> we don't care what will be inside we just  care that this component or even directive  
2402.4 -> should support this method and these properties  that's it and if we save it and reload our  
2416.08 -> page we see that reload is happening called  once for weather component because velocity  
2425.2 -> doesn't support this feature and this  anything widget also doesn't support  
2433.44 -> reloadable so in our case we have this widget  component which is which is high level model  
2441.44 -> and it doesn't depends on the concrete  implementation it depends on the abstraction and  
2448.32 -> our concrete implementation also depends on the  on the abstraction implementing this reloadable  
2455.44 -> interface and this is how dependency inversion  looks in action all right guys thank you for  
2464.4 -> attention it was everything i wanted to tell you  about solid principles in angular don't forget  
2472 -> that i have couple of courses about angular  material theming and graphql engine called  
2477.76 -> hasura in the video description you will find  links to these courses and discounts which are  
2484.8 -> currently active also don't forget to subscribe to  this channel leave your feedback in the comments  
2490.8 -> as you can see i listen to your feedback and of  course share this video if you find this useful  
2497.68 -> i wish you productive week ahead and  thank you for attention see you in the
2502.16 -> future you

Source: https://www.youtube.com/watch?v=Y-MRJ9QYCvI