SOLID Design Principles in #Angular (Advanced, 2021)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

SOLID principles will not take you to the promised land. Zealotry in following them will only lead to despair. There is no one true path to Heaven. --Lone voice in the wilderness

👍︎︎ 16 👤︎︎ u/dethswatch 📅︎︎ Jun 08 2021 🗫︎ replies

This seems really great, when I was working on React project I tried to follow SOLID principes and I found in the long run it looked cleaaner and easier to maintain, even though it's mostly OOP thing it still helps in some degree to have an understanding on those principles as a FE developer.

Will definitely watch this fully when I get home

👍︎︎ 2 👤︎︎ u/Morsmetus 📅︎︎ Jun 09 2021 🗫︎ replies
Captions
hi everyone dmitryanskis here and today we're going to talk about solid design principles in context of angular this video was inspired by this comment and i found this topic really interesting because i remember myself many years ago i remember i knew all those five principles but when it came to real life called the real implementation i could not recognize them in the source code i could not apply them and i decided that maybe not only i had such an issue so i decided to make this video for you and explain it a little bit and show you real life cases so this video will be split into five sections time codes will be in the video description check this out and we are getting started but before we start diving into those five design principles let's talk a little bit what is design principle itself and design principle this is recommendations how to design your code such a way in order to keep it maintainable flexible and so on and so forth and telling that it's recommendation it means that it is very abstract it doesn't have any concrete implementations you can implement some design principle many different ways and already on top of this design principle we have design patterns which solve some already concrete use case and implement one two or more design principles and we are not restricted by only those five design principles we have many more like dry don't repeat yourself principle or keys keep it simple and there are many of them but those five are most popular ones and we will have a look at them right now and the first one i'm going to start with is the single responsibility principle which sounds like there should never be more than one reason for a class to change which means that some component or class or model should do only one thing but do it well so let's have a look at the application i prepared for you this is just a simple widget weather widget which just exports some json data and now let's have a look at the implementation of this by the way i have uh in this project five branches uh every branch for uh reserved for some certain design principles so you can clone this project to your local machine and switch between branches and the implementation of every design principle okay but yeah let's get back to our implementation you can see that my app component which is only one component for now we have the material toolbar we have the main tag which should contain the whole content for my web page and also i have the widget template and besides this i also have on export json function which does export of whether widget data in json format and i have some styles yeah but i collapsed it for now okay this piece of code violates pretty much everything not only single responsibility principle however we focus on the single responsibility principle here and yeah let's figure out how we split responsibility between components actually it is sounds easier than it is because very often it is hard to decide where you know where ends responsibility for class a and starts their responsibility for uh component or class b however i have one rule which i use in order to determine this to determine if my class does too much or not this is end word rule and it means that you describe the responsibility of some certain component and once you encounter the word end it might be the signal that your component does already too much let's uh like apply this rule to this example and how i would describe the responsibility of app root component i would say that responsibility of this component is to render the skeleton for my page so it's a top level components like toolbar and content and we have already toolbar we have this main content and we render also the widget layout and we do export json file json data for this component as well within one single component so it only gives us a hint that this component does too much and what would be the solution for this case i would suggest that widget should be definitely the separate component and the logic here might be might belong to the component itself so the solution would be is to generate additional component i will call it like a widget then i say that it has scss it should have inline styles in line template and we skip tests and we also do it flat so well i don't want to have the separate folder for this component and i click run and we have to get the new widget component here we go good and now i can refactor it like this so i can copy this everything including this section and we can paste it to the to the template of widget component here we go also i move on this on export json handler here we go and also i have to to copy styles so i will copy this part this part header widget icon basically everything except the content so it will move to styles here and go back and instead of widget oops i forgot it here and instead of widget we just say that it should be app widget here we go so if we go back check it here everything looks good and hopefully our application should work as well what's wrong here ah okay now i have to place it host here because we apply uh these styles to our host element good uh now it should be compiled successfully and you can see nothing has been changed but our app component became more lean and it is responsible exactly for rendering the content and rendering the toolbar but still if we have a look at the widget component we can say that all right widget component it generates the layout for the view of our component and it exports the data as a json and most probably the export of the json is not this logic i mean is not responsibility of the component itself yeah it can handle this on export json click event however the logic is not the responsibility of this component so i would suggest you to create the separate service and this service we could call json exporter all right so let's run it and yeah we see that we created json exporter service so we can move this logic from here and create some methods like export yeah here we go so yeah and here i would inject our json exporter like this and now i can call the export method against this json exporters exporter sorry and i can save it i should save it here as well and we can go back and click export as a json and it doesn't do its job what is wrong ah sorry actually it does it for whatever reason jumps right i have to fix it all right now it's better just if you're curious it's a command option minus on or plus on mac os and you zoom zoom in or zoom out this view all right never mind but still you can see that our widget is working but we have splitted responsibility between three entities app component widget component and also service but one recommendation so keep it find your balance in splitting all these responsibilities because you may split it to such a small pieces that yeah you will be flexible like a hell but it might be too hard to support this so find your balance usually you find it within your team during the code reviews and yeah it's my variety from team to team uh what the what responsibility of what because there is no some super strict rule which can determine that here responsibility of this component ends and starts the responsibility of another one and this is everything about single responsibility let's move forward and the next one is open closed principle so open close principle very important one and it sounds like software entities should be open for extension but closed for modification and what does it mean on the in the real life it means that you should design your classes models and libraries even libraries such a way that you should extend it functionality without touching this component it is a very good example libraries you cannot modify components which are coming from some certain library yeah because they closed they are published into the npm you have no access to the source code to change but still you have to be able somehow extend this functionality and here i prepared another example it is very similar to what we see for single responsibility but now we have two widgets but different content inside so the first one is weather but when the second one is uh oops it's by mistake also whether but it is the velocity which shows the last velocity of your last sprint and this is how i implemented this it has small differences comparing to the first implementation but this is like pretty much similar we have the ev separately apple uh apple app widget and it has the property weather or velocity and if we have a look at the component implementation itself we will see that it has such a thing like ng if if it is if if it widget is weather then we render the view for weather otherwise we render the velocity view you can of course use ng switch here it doesn't really matter for this particular case but you understand the idea so the problem with this that it is closed definitely especially if we distribute this while library it is closed you cannot modify it but it is not open you cannot add the new content to it as example i want to have third widget which renders i don't know some just a paragraph or some another view and i cannot do this because i restricted by only these two types either weather or velocity and this is the violation of open close principle how we can solve this issue well we can create separate view or separate component for every of this widget and then we would use the just a content projection like ng content so i would suggest you to generate two components first one i will name weather content and then it will be scss it will be flat in line by the way you can configure this everything inside the angularjson file but i'm too lazy to do it i think it is enough so we can run it here we go and then we create the same bot for velocity oops here we go i can close it i can close i believe this part and now let's move this class or this html from weather to weather content right here here we go and then we will do similar to for our velocity velocity and this part and copy it here then we have to adjust this part we have to remove this everything and instead we will use mg content right so here instead of ng content will be rendered anything we put between uh app widget tag you'll see this in action and there are another way how to implement it you can use this with the component outlet and ng container but it doesn't really matter for this case uh you are free to implement as as you want yeah and i save it and i have to i have to probably add some styles yeah because the definitely value and widget icon should be part of styles for these guys so i will create a new file i will say widget content scss so here will be common uh styles for for this everything and and weather widget weather widget it is um ah here we go this is this container let's rename it to the widget content here we go and for weather we also rename it and now we have to copy this part as well and we and we copy it here and as we renamed it widget content it should be good and yeah i forgot that style overalls should be here and let's import the widget content scss here we go and the same will do for this part as well so i save it and inside app component already i don't need these inputs anymore and i can define between those um widget tags i can define which content i want to have here and in my case this is the web app weather content and in the second case i want to have app velocity content and now see the uh benefit of this everything if i want to introduce the new widget and with some specific content there inside i can easily do this i can just place the paragraph there and say that content is coming i don't know whatever and you can see that without modifying the app widget itself i could extend it with another content and now if you have a look at our widgets you can see that i reused completely the widget itself but content is uh customizable and i can easily customize this and change the view so this is the open close uh design principle in action all right and the next one in the turn is uh lisk of barbara lisco's substitution principle and it sounds like functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it yeah it sounds a little bit complicated however everything boils down to next thing imagine you have two classes parent class child class which extends the apparent one and lisco substitution principle means that objects of this super class or parent class should be replaceable with its subclasses or child class without breaking the application let's have a look at the example so here is pretty much similar where we stopped except i fixed the issue with titles for our widgets yeah and and this is pretty much it there you can see the content for for our widgets widget content css and yeah things like that however let's imagine that we want to have slightly different wrappers yeah we we want to have this one and maybe we we are planning to have some another modifications of this widget container and we know that all those containers will have some functionality like export to json and all of them should support the input title and we can we don't want to duplicate this everything here we want to extract this to the i don't know some base class so let's create this have a class and i will name it like widget base i will call it and let's generate one so inside this widget-based class i will move the whole logic from here so i will copy it and paste it right there then i have to import the input okay class is using yeah this is it means that we have to decorate this with directive as example because since iv you have to do it if you going to use inputs as example and extend your another component with this new one what we exactly uh going to do right now so i do not export but extend this is what happens when i uh typing and talking at the same time so we successfully extended this and how we can violate the list of substitution principle we can violate this by overriding this method on export json and as example instead of exporting the export json we throw some error like i do not support it all right and this is the only violation because it changes the behavior of this on export json comparing to its parent there's completely different logic and if you replace the implementation of this widget base with widget content you will break your application which is actually the violation of a list of substitution principle so the solution to not violate this principle is to just remove it and remove it completely if you don't do a do some any additional logic for widget component or if you do you should not break the contract of this it should not return some completely different type which is not compatible so if here return type is void let's say then also type of this handler should be also void and you can of course call super and then you have to you can i don't know do something like console lock additional whatever so this is how you can uh extend it without violating this design principle all right we're getting closer to the end and the next one is interface segregation principle and it sounds like many client-specific interfaces are better than one general purpose interface and what does it mean as example uh we have velocity and weather content and we would like to define some interface for them some contract yeah and we usually do it via interfaces so let's generate the interface i will call it widget content and run it here so here we go and let's open this widget content and as an interface let's say i want to have the id which should be some string maybe just for testing purpose whatever and let's assume that this content should support let's save live reloading so means that we're pulling some data from the server if some new data arrives we render the view and we can say that we need the property loading yeah to show some maybe spinner during the request to the back end which is boolean and we need some maybe function let's say reload and it should return void all right so we save it and we implement this interface for every uh content so it implements widget content here we go it already complains that we have to implement all necessary fields so let's implement this interface here's the string we can define some i know empty string as a default and here we can say that it falls and reload throws some error but let's say that con so log do polling right so this is what will happen for this widget content and we have to do the same for another one so let's save it right here and for weather we're going to do absolutely the same so i import so i import widget content and we also need to implement this thing here empty of false and do polling whatever so and i see that i didn't save my app model okay and now we are done but here is the problem imagine that someone i know product owner comes to us and says that uh you know what uh that life reloading for weather makes sense because weather changes uh really fast and we need to reflect the latest data but velocity we update this data only i don't know every end of the sprint usually two weeks and we don't need to do polling for this data it should not be supported yeah it doesn't make sense for this kind of data so it should not support the live reloading but the thing is that we have to okay we don't support we can uh leave it empty but in this case uh we have still have to keep this loading property and reload just in order to follow the widget content interface so this is where interface segregation can help us so instead of having this let's say big interface we have to split it on two interfaces let's say we can create interface reloadable right and we can move these two guys inside the reloadable interface and then we would say that okay weather should support it so we will implement also reloadable interface here we go but here we do not support live reload so we can safely uh remove this code which is not being used and which is obsolete for our velocity content like this and this is the interface segregation principle in action so you just split one big interface to many other smaller interfaces all right finally the last but not least design principle is dependency inversion principle and it says that we should depend upon obstruction no concretions how does it look in the real life angular application you encounter this design principle every time when you use dependency injection let me show you some small example say we have the service polling service and you inject this service inside your constructor and we have to call super because we extend widget base all right so once you inject this you might think that you depend on concrete class on the concrete service which is polling service but it just looks like this in fact angular under the hood performs some magic uh and and it creates such a thing called injector which acts exactly like this abstraction layer if you don't completely understand what i mean by that i would recommend you check out my video about angular dependency injection and this video will make everything clear but just to finish this example what i mean that we don't depend on the polling service is that you know that we can use dependency providers like use class as example and we can i don't know provide some another polling like this and i have to create a some specific class and and having this setup we are not pointing to the polling service anymore but rather to uh pointing to this another polling class so so despite we see the reference to some concrete implementation here it doesn't mean that this concrete implementation will be used but i'm going to remove it and i will show you slightly another example for this everything so actually we can create a lot of obstructions we can create obstructions over abstractions and so on and so forth sometimes it is over engineering sometimes it might be helpful and let's imagine that in widget component inside our wrapper we want to get reference to the component which supports the live reloading and trigger this reload method so how i could do it i would i would call content child and i would say that i want to get reference to the weather component because it supports live reload right so i will say that this is content and that type will be a weather component like this and it might be optional of course and somewhere let's say in ng after view indeed or sorry content in it and let's say if content exists i want to call the reload method for this component and i will remove these things and the problem is that we depend on the concrete content weather content when in fact we might have a lot of and other different uh contents which are reloadable which are supporting the um polling mechanism and life reloading right so this is a violation of dependency inversion principle because we depend on um concrete implementation rather than obstruction so let's create this obstruction and this abstraction will be represented in my case by injection token so i can create the widget content token and here i will export constructable content and it's going to be new injection token which has value reload will content right and the interface will be reloadable so basically we say that the value for this injection token should support should implement this reloadable interface so so it should have the reload method and its loading property right and now we have to provide some uh assign some class to this token and as we know weather content it is something which is implement this reloadable interface so we will use dependency injection in order to provide the this component instance as a value for our injection token so we say that provide reloadable content and use existing weather content components so once we try to get reference to their reloadable content there will be it will be resolved as an instance of this class right if you have some problems with understanding this i have video which will pop up right there at the top and there i explain in details this mechanism good and now having this abstraction layer which is represented as a token we can replace our concrete implementation with this token and we can say here that the interface will be not the weather component content but it will be something reloadable right so now we don't depend on the concrete widget content we don't care what will be inside we just care that this component or even directive should support this method and these properties that's it and if we save it and reload our page we see that reload is happening called once for weather component because velocity doesn't support this feature and this anything widget also doesn't support reloadable so in our case we have this widget component which is which is high level model and it doesn't depends on the concrete implementation it depends on the abstraction and our concrete implementation also depends on the on the abstraction implementing this reloadable interface and this is how dependency inversion looks in action all right guys thank you for attention it was everything i wanted to tell you about solid principles in angular don't forget that i have couple of courses about angular material theming and graphql engine called hasura in the video description you will find links to these courses and discounts which are currently active also don't forget to subscribe to this channel leave your feedback in the comments as you can see i listen to your feedback and of course share this video if you find this useful i wish you productive week ahead and thank you for attention see you in the future you
Info
Channel: Decoded Frontend
Views: 21,811
Rating: undefined out of 5
Keywords: angular solid design principles, solid principles js, solid principles javascript, Solid design principles, solid design explained, solid design example, solid design tutorial, single responsibility principle, open closed principle, liskov substitution principle, interface segregation principle, dependency inversion principle, angular 12, Web development 2021
Id: Y-MRJ9QYCvI
Channel Id: undefined
Length: 41min 49sec (2509 seconds)
Published: Tue Jun 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.