NG-BE 2019 - Kwinten Pisman - RxJS Recipes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello hello hello all right our next speakers name is Quintin Pittman teaching awesome angular is this guy's mission if you're rxjs has you needing therapy Quentin is here with the perfect recipe this does his work can you hear me surprised I am back even even though I'm not on the list again this year but if someone cancels then I always go like put me in coach I want to go so when I heard that someone was not able to come Jurgen and Sam asked me to step in and obviously I was very happy to do so even though I it's quite unfortunate that someone again couldn't come but I hope at least I can give you a good talk as well so what I want to talk about today is one of the problems but that I have faced and also a lot of other people have faced is that if you actually start using ArcGIS it is very difficult it has a very high learning curve and you could always say it's as difficult as climbing I'll cop dumb but I actually think that arcs just is even more difficult although I haven't climbed El Capitan but I mean it just doesn't seem that difficult right but once I started writing a lot of rxjs code I started noticing these patterns that I was using over and over again and that's some of the things I want to talk about today so I want to show you some of the patterns that I came up with but I also want to give you a little tool kit that can help you to determine how you can actually translate things you want to do into rxjs code so I want to help you get that reactive mindset but first of all I want to thank Dominic who's right there because normally this is do a talk at this one I prep together with him so if you think the slides the slight X not that good it's 50% his fault right just just remember that a little bit about myself my name is Quinton I'm a Google developer expert for angular I also do trainings with strong brew and I recently started working for stagnates which is an online editor the top picture is how are actually looking at nowadays the bottom pictures how you'll find me on social media I just haven't figured out how to let go of losing my hair so I'm keeping that picture for a little bit more I want to talk about two projects that I've built together with Dominic actually one is angular checklist which is a list of curated best practices that you can apply to every angular application so definitely check that out and the second one is angular profile or dev tools which is a Chrome extension that can actually visualize your component tree and it can also visualize change detection inside of your application that way you can know where you actually need to to optimize your change detection by the way this only works in ivy and it actually is broken in angular 9 so I need to fix that but I'm at the conference right now so that will be for next week so topic of today we want to talk about patterns but what is a pattern so first let's let's go to a common definition and and let's look at this one and software engineering a software design pattern is a general reusable solution to a commonly occurring problem within a given context and software design so what does that mean if you have some problems and those problems always have kind of the same characteristics and you solve them using the same tools and the same pieces of code you've basically discovered a pattern and and that's what I want to tackle about but in the context of this presentation we're gonna talk about three types of patterns different levels the first pattern is going to be an operator in rxjs we have these things called operators and operators are so common use case things that we want to do with an observable that they're actually baked into the rxj source code so we could have an observable and that observable is something we want to map over so if we map over it we get a new observable and that's like a super common thing to do so it's directly baked into the source code and there's a lot of operators on top of that we have to think that I want to talk about today and that's a pattern and a pattern is something that you would see in your own code base and you would use it over and over again but it might not be that common enough to actually put it into the source code you don't know maybe it is and you can always suggest a new operator but it's it's kind of something you use a lot and if you combine a couple of these patterns together you could get something we call a recipe and the last thing I show if we have time enough will actually be one of those recipes okay talking about code is cool but seeing code work is even more fun so we are going to do some patterns by example and we are going to build a world of jokes application because I have a really specific sense of humor I really love Chuck Norris jokes and especially Chuck Norris jokes in the in the context of programming so we're gonna build this application where we'll see jokes such as Chuck Norris can finish infinite loops in four seconds I hope that's at least a little funny because otherwise this is gonna be a quite boring talk I guess but we get this from a designer but what do we actually do with this what does it actually need to do so what we can do is we can go to our product manager and then we are in luck our product manager is Michael Scott from the office I really love the office it's a great show so when we go there and we ask him like what do we do with this design and he tells us well we need a list of jokes that is cached and it should be updated every 10 seconds and if it feels we want to retry and we call every five seconds and bla bla bla bla bla and it just keeps on blurting out stuff and when I leave the room I'm kind of mad and I want to punch a hole in the wall because I mean what do I actually do with all of this information this is super difficult so one approach that we want to teach you is that we want to show you how you can actually use such a thing which is kind of difficult and kind of split it up and to do that we can use a divide and conquer and we're gonna apply this but you can basically apply this to a lot of things and in divide and conquer you basically take a problem which seems unsolvable and then you just split it up into multiple subproblems and you keep doing this until these subproblems actually seem manageable and once you have manageable problems you fix you fix those you get sub solutions and then we're gonna we're gonna reassemble those sub solutions back together into a final solution and that's also the approach that we're gonna take with regards to our requirements but first we have this guy and this guy name is Dwight K Schrute and he's this really weird guy from the office but he's gonna give us some good tips today so the first dip that he gives us is if you have a difficult problem use divide and conquer split it up solve the subproblems and recombine to a final solution okay with that in mind if I take a look at this diagram I can figure out some of these sub requirements so I could for instance say okay I need a list of jokes that is cached and it cached updated every 10 seconds and so on and so forth okay now that we have that let's look at this first requirements the list of jokes should be updated every 5 seconds now hmm how do I actually translate this into ArcGIS code this is still something you would have you would have gotten like years ago when when people were not already using rx yes so to do that we're gonna use something called pattern detection and pattern detection is going to help you reason about your codes so we are always going to look for three things we're gonna look for the what the one and how make sense probably not okay let's go a little bit deeper so the what is basically what is our end result what do we want to achieve when we implement this requirement and we are going to think in a reactive mindset so what's gonna be really important is that our what is always gonna be a stream we are going to work towards a stream when that's actually an easy one usually a requirement starts with if this happens then I want you to do this if this happens that's going to be our trigger that's gonna be the trigger that sets off or observable chain and again trigger should always be an observable we have a reactive mindset if you do not have an observable we are actually gonna create one and then we have the how and how is actually the pattern how do we go from our trigger to the end result that we want what are the operators that we need to apply to achieve that so sure it's step number two triggers and result should always be streams because we want to have observables in our code base so the first requirement the list of jokes should be updated every five seconds so let's take a look at what is our what here what do we want to achieve well we know what should be an observable and I want to have Joe on my screen so I think I need a joke stream that wasn't that difficult right when do I want to have jokes well it literally says every five seconds so I guess that's gonna be my trigger that's what I want to do and how am I going to get there well if I think about angular every time I want to get jokes from the back end I basically perform a back-end call and get my data so I guess I want to perform a call every five seconds and then show it on the screen that's not that difficult right okay we're gonna apply this into an application and our application has a really simple architecture we have a jokes list components and a settings dialog component and a joke service where we're gonna cache all of our jokes and a setting service so the first thing we're gonna implement into our joke service and I haven't told you this but we're actually gonna do some pair programming I'm always quite nervous to do live coding but someone wants told me you should just tell the audience that you're gonna do pair programming and it's like everybody's responsible for my mistyping so let's let's try and do that so if I make a mistake you have to help me okay so we're gonna go to our jokes service and inside of my joke service I have this HTTP call and then I'm assigning that HTTP call to an observable but what is there an error where is it okay so we have our jokes and we're fetching them only once so what do I want to do again remember my trigger was every five seconds and our trigger should be an observable but I do not have an observable so what do I do I create one so I'm gonna create an observable and I'm gonna use a timer operator to do that and the timer operator is basically going to fire an event every five seconds which is exactly what I want and then in this kid in this case it actually makes sense to use this flattening operator here which is called exhaust map and exhaust map is basically going to I'm gonna return a function and an observable here and this is basically going to subscribe to the observable for us so a flattening operator helps us to avoid having having nested subscribes I'm quickly going to reassign this should look good so we basically trigger every five seconds and then after five seconds we use exhaust map we return an observable here what does exhaust map do subscribe to the observable what do we know when we subscribe to an observable we execute it so we do a back-end call and then I'm using share replay here because I basically want that result to be shared so now if we go to the application we should hopefully be able to see some really cool jokes and I'm gonna read one Chuck Norris finished world of oh that was quite unfortunate did you see it refreshed before I could actually read it so we have polling enable which is cool this works but we can actually improve on this so this is the first pattern that we have oops and let's first describe this pattern and we've gave these some silly names so this is called a repeater pattern and it basically says if you have work that needs to be executed and times where n is bigger than 1 what you can do is we can use this trigger and then we can use a flattening operator because we do not want to have nested subscribe so we flatten this and then we map it to the work that we want to do so the work is the thing we actually want to repeat a couple of times this is called a repeater pattern which is something I use on an almost daily basis so shoot step number three translate the written requirements into the what when and how because this is going to help you translate that requirement into into our HS code so the second requirement we only want to show the new data when the user actually requests it so even though we have new data we do not want to override it because people should be able to read the jokes right so what do we want to have quite easy we want to have jokes stream on our screen but only update it when we actually request it so when do we want it when you use a request set so what are we going to do how are we going to do that well when do user requests it I'm just going to get the latest value from my cache right that doesn't sound that difficult ok so let's implement this and this is something we're going to implement inside of our jokes list component so inside of our jokes list component we have our most recent jokes here which already set up so what I'm going to do is I'm going to say that well hmm now I kind of have a problem right because I need to know when a user clicks a button how does that work here so I have this button here and this button has a click handler but it's currently not possible to create streams from click events in angular templates until you watch Dominic's talk this afternoon just a small spoiler but we're using this update next year and what does this do well update is basically a subject and a subject is a special kind of observable in the sense that we can produce values for a subject so what I'm going to do is I'm going to say this dot update and this is basically a stream that is firing every time the user clicks that button so if I do this dot update a pipe and then and this is what I really like about rx yes it's super declarative what do I basically want to do whenever this virus I want to get the latest value from my cache let me rephrase that just a little bit I want to add data to this with the latest value from my cache did you see what I did there no okay what I did is with latest from C that's cool right and then I add my cast so I can say what the latest value from Mysore jokes and then I obviously need to map this because the waist with latest from works is going to give me an array where I have my trigger and my jokes and in this case I'm only interested in my jokes so now I have this joke stream here which is bound to my view which has my initial jokes and now also my most recent jokes we need this initial jokes because otherwise we shouldn't we shouldn't see any jokes on screen on the first render so if I go to the application now and when we refresh this let's refresh this so now I can read this joke Chuck Norris knows the last digit of pi kaha super funny yeah and actually there was a back-end call but I can see still see this and now if I click this update it's actually updated which is pretty cool right so we already have this but when I was prepping this talk with Dominic and Dominic is kind of a pixel perfect guy he hated the fact that this the button was here while there might not be updates because I can click this even though there's no update so that's something we fixed as well so let's see how we can do that but first let's go to the pattern that we have and this pattern is something we call to the enricher and the richer is basically going to rich and rich data whenever a trigger fires so whenever our trigger fires we are going to combine it with the latest value from some other stream and then we're going to enrich it so in this case we're just mapping to data but we could also add we can match or merge the trigger and the data inside of this map operator so that's how we enrich it but next requirement is if an update is available the users should see a notification to update the list of jokes but only if an update is available so what do I want to have I basically want to have a stream that is going to show me that's going to tell me whether or not I need to show this notification bar so I'm going to work to a show notification stream and then one do I want to show it well I want to show it whenever the cache fires data that makes sense because there is new data but when do I want to hide this and this is where it becomes a little bit more complex because you want to hide it whenever well basically if I think about it if the user just clicked on the button I'm pretty sure that there's no new data anymore so I want to show it when the cache fires but I also want to remove it when actually the user clicks on that button so that's what we're gonna do and how are we going to that we're basically going to have two triggers and we're gonna merge them so what does that mean go back to our code and inside of our jokes list components I am going to create two streams I'm gonna have a show stream which is gonna equal something and I'm gonna have a hide stream which is gonna equal something show my show stream is basically a stream that I want to admit true from because well I want to show my notifications bar so I'm gonna say if my source jokes fires I'm gonna take that trigger and I'm gonna map it to a static true value and if my hide stream when do I want to do that well basically whenever you user clicks that button and I know it's this Update button I want to map this to a false value so if I have a trigger that tells me when something is going to be false and I have a trigger that tells me when something is going to be true I can just say that my show notification stream is going to eco merging those two streams together so I have one that says show and I have one that says hi and now the only thing I need to do because I can not type CSS code that fast is I'm actually gonna comment this in and I'm gonna comment this out you did not see that right I did this super quickly so if we go to our application I can see that I have my jokes it refreshes I can now click this button it goes away yeah that's a good thing let's wait till we have a new call and I can again see that button but we actually made a mistake because if i refresh this I can already see this update even though there is no data I think we made a mistake in our trigger because I said whenever oops here we go whenever my source jokes fires I want to show it but I probably do not want to do that for the first time because the first time is when my first call is gonna arrive and then I'm just showing the data but it's the first data render an update mmm probably not so what we're gonna do is we're actually going to change our trigger and we're gonna say that we're going to skip this first value so we're only going to show our notification bar for the second time so now you should see if a call arise which it does that we have this bar wow that's awesome no yeah mm-hmm sorry I get so excited about oryx yes okay so that's requirement number three let's take a look at our pattern and this is called the group aggregator I know these names are kind of silly but whatever so when we have a result and that result should be an observable of boolean what we can just do is we can combine all of the values that are going to set it to true put that into stream combine all of the values that gonna put it to false combine that to a stream and then we just merge it together to get a result stream okay next and now it's words actually be kind of gonna become even more interesting and you I'd actually be able to sprinkle some of the things you saw in a previous talk and in this thing but we're gonna keep it pretty simple so we wanna our user to be able to manage settings and these settings well settings this kind of states so I'm gonna create this object but what's really important is that we always put all of the state that we have inside of a stream one of the biggest sources for box is when you would have a variable which is in a state you did not expect it to be if we put our state inside of a stream it can only be changed because of some trigger and that trigger is that's only one trigger basically so it becomes very deterministic when something is gonna change and that's gonna actually help you with a lot of your bugs so I want to have a setting stream and that setting streams should encapsulate all of my settings data when do I want to update it well whenever the user changes one of the settings so he has this dialog where he can change it and that's where he can he can change this and how am I going to do this I'm going to keep the state inside of a stream and then I'm gonna update the state whenever this trigger fires so let's take a look at how we're gonna do that and this is something we're gonna do in this setting service so inside of my settings service I have this settings stream here and in this case I'm using a special kind of subject I'm using a behavior subject so we had a subject before to create a stream from our click events but now we're going to use this to create a stream for States and the specific thing about a behavior subject compared to a subject is that a behavior subject also has our initial state so we can see that we have that initial state here so what I'm going to do is I'm going to say that my settings whenever my behavior subject fires oops let's do this other settings equals there's the underscore settings so whenever this one fires I know I need to change my states and changing a state is something you can do with the scan operator which you also saw in a previous talk and scan is basically going to allow us to whenever this fires and let me quickly type this because I I'm really bad at typing and talking at the same time so updates oops that seems pretty okay I guess nobody says it's wrong so I'm gonna assume it is so scan is basically gonna allow us to calculate this state over time so every time there's a new update we're gonna have an instance to the previous state and then we can actually add our updates to it so this is a very naive implementation of a state management tool but it could be interesting for a beginning situation so I'm going to subscribe to this to just be able to log it out and now if we go to our application I'm gonna open my console so you can see that we already have this initial state and whenever I change something here you can see that that stream also gets updated and this is where it becomes really interesting because before I set that triggers and result should be streamed now I have a stream here and this stream is actually going to be the trigger for my next requirement so if your trigger and your result is a stream you can easily compose these patterns back together and that's where the real power in our X J's lies composing patterns together so this is what's requirement number four shrewd step number four states should always be managed within a stream otherwise you will not be able to use it as trigger for other parents so this is the state manager and it's basically a very very lightweight solution on how to do state management I would not use this for full-blown applications but for this demo application or something really small it actually makes sense I cannot just ask the people from the audio to move on the screen so I can see the timer thank you okay so so Schrute step number five if we want to use the statement in repair and we can use it as a very minimalistic alternative to some full-blown solutions such as redux or ng rx so last requirement I'm going to code because I'm kind of running out of time it should be possible to toggle the notifications and appalling so what do I want to do well I want to enable or disable my jokes and my show notifications when do I want to do this whenever my settings changed so remember we had a setting stream that we created in the previous pattern so whenever these settings change I basically I'm gonna react to that and how am I going to do that well I'm gonna do that by conditionally stopping and starting the notifications of polling and this is going to be our next pattern so I'm gonna go to my jokes list component jokes list components and inside of mic jokes list component I now have this show notification but I do not want to execute this all the time because the user should be able to just delete a notification or hide the notifications all the time so what I'm going to do is I'm going to say this dot show notifications oh not show notification setting service settings remember this was the result from our previous stream and now I'm gonna say I'm gonna bump it up just a little bit more and now I'm gonna say well whenever these settings fire I basically want to decide if the show notifications is true I want to show the notifications if there is an update at least otherwise I want to hide them so first thing I'm gonna do is I'm gonna map and I'm gonna take my settings and I'm not gonna get the show notifications out so I have these show notifications and then what I could do is I could say that I'm going to switch map over this and I'll explain in a bit what this actually does so show notifications and now I'm gonna say if show notifications is true what do I want to do if show notifications is true I basically want to show the notifications if there are any so I'm just gonna take this oh that was fast I'm gonna copy this and I'm gonna say if my show notifications is true I'm gonna return this stream else if it's false I'm going to return what well I basically want to hide them all together so I can basically say I'm going to return off false I want to hide them and then I'm gonna take this put it in front of here and now I have a stream and that stream is going to every time the settings fires it's going to get out the show notifications and then it's going to switch map over that weis which map because Mapp cancels the previous execution and starts a new one which is what we want in this use case and then we're checking if show notifications is true then we return the previous pattern that we had to remember now we're already combining a couple of patterns together and if it's not enabled then we just want to say false so that the notifications is basically never shown so if I save this and we go to the application we should see if a network call fires and that is now that we have this update but then if I go here and I basically toggle the notifications you can see that this was nice no basically everything kind of came together wow that's that's that's magic no to me to me it's still kind of magic so and and this is really the power of rx yes because I changed something the settings changed and all of that thing all of those events that we defined like this is what needs to happen it happens it's basically like a chain reaction you don't define stuff anymore by oh I'm gonna look up that value and then I'm gonna hide or show them you basically say like we're doing in our code here we're saying oh I know that showing my notifications depends on this stream so I'm going to define it as a trigger for that stream you're going to define stuff in terms of its dependencies hiding or showing the notification depends on the settings so we define it based on that that's that's really cool so this pattern is what we call the work decider so if you have work that needs to be restocked stopped or started or if you have based on a certain decision you want to do work a or B you can use this pattern so based on a trigger we can use a flattening operator if it's actually restoring you probably want to use switch map here as a flattening operator and then you can check if its condition if the condition is true we do this otherwise we do that that's cool so shoot step number six use observables as the boundaries between services and components because that is going to make our code composable because we expose that setting stream from our observable it actually becomes composable and then the last requirement which i'm not going to type out but I'll I might be able to show you so if the fetching fails we want to retry fetching it and if we are offline we want to only retry it for back online otherwise we want to retry once every five seconds and that's again pretty difficult now so let's use the same divide and conquer approach remember shoots that number one we're gonna split this up so we want to have if the lists fetching fails we want to retry it and actually retrying a such a common scenario that there is an operator for that in oryx yes and we're gonna use retry one for this we can basically we don't need to think about the pattern here and the next thing we want to do is if we're offline we only want to try if we're back online and so let's just focus on that for now so I want to retry this cash jokes and when do I want to retry it when an error occurs call to the backend fails and then we have a decision to make remember the previous pattern where we had we were making a decision based on a notification value now we have a decision to make based on whether or not we're online so we're already reusing this pattern so how are we going to do that well if we're online we're gonna retry and if we're online we're gonna if we're offline we're only gonna retry when we're back online so I'm quickly gonna cheat now and check out the next branch so if I go to my jokes service yes joke service you can see and I'm not gonna go into this too much but we have a retry one here and inside of my retry when I have this error stream that fires whenever there's an error and you can already the only thing I want you to see here is that we're using this error decider again we're using a decision based on a property so if we're online we're just gonna retry immediately and if we're offline then we're only gonna retry when we're back online so we're basically based on a condition deciding which work we need to execute a pattern that we're reusing which is pretty cool so now if I go to the application and if I go offline I'm gonna click this quit this so we have one call that fails which makes sense now we have no calls anymore I need to talk for five seconds otherwise you're not gonna believe me and then if I go back online you see that we immediately have a call which is pretty cool I would say oops wrong shortcuts okay let's wrap this up this is the pattern kind of already explained it so I'm gonna skip it one thing you could also do is you can go from a pattern to an operator if you have a pattern that you're reusing over and over again you can transform that pattern into an operator for your code base for instance if you have like a debounce time in there with a specific time interval putting that into an and a separate operator that you would use in your own application will make sure that it's always gonna be the same for your entire application okay Schrute step number seven if we have an OP pattern that keeps emerging put it into an operator okay key takeaways I want you to remember divide and conquer that's really really important nothing is on fixable just think about it and subproblems patterns you can use some of the patterns that I've shown you but the most important key takeaway is pattern detection always try about always think about what is actually going to trigger this action that needs to be hat needs to happen make that an observable where do I want to go towards to make that an observable and then try to go from one to the other that's the most important key takeaway because that's going to give you that reactive mindset and also think about custom operators so think react it reactive everything should be a stream and that's it thank you very much [Applause]
Info
Channel: NG - BE
Views: 1,055
Rating: 5 out of 5
Keywords: ngbe, 2019, angular, conference
Id: cjjjaOsc6JI
Channel Id: undefined
Length: 32min 36sec (1956 seconds)
Published: Mon Dec 09 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.