Ember.js Berlin / September 2021

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] thank you [Music] [Music] so [Music] so [Music] [Applause] [Music] so [Music] you [Music] so [Music] [Applause] [Music] the talks that are presented by our amazing speakers andre newburgh's properly and jen webber tonight um and before we get started just a few words about our meetup uh what we actually do and then we can already get right to the uh talks that we have today and also just like as a general uh reminder and that you can reach us like at anime and twitter as well and if you for example want to share anything about the meetup we always like to see this but also if you have questions suggestions you can always reach out to us via this path and also in the very beginning a quick shout out and thank you to our supporters of our meet up who are um harvest on the one hand who have been like a very um year-long supporter of our meet up for quite a long time and also to alex farr and you can find him at uh from filmmaker on instagram who is in charge of the um recording but also the live streaming and the publishing of the videos in collaboration with posher today and also has been for quite a while so to all of these sponsors and supporters thank you so much for uh yeah making this event happen um with us and also who are we actually via yoshka and myself you can also reach us like on twitter on our handles jake kincher and jt jpeg and in with regards to our meetup we are uh kind of like every now and then meet up so currently we i think we have like this two or three months kind of like schedule where we do like talk nights so something that we do today where um people from the community uh core team members developers amber enthusiasts uh come together and actually share what they learned about the framework what they find like super interesting what they maybe built with ember like recently in a more presentation style kind of like format but we also in the past that like meet and greets um obviously with the situation right now it's like a little bit difficult to do this but uh we are thinking about that maybe also having like a more online kind of like format for this and if you have for example also ideas on how we could actually do this uh we're also like very curious to hear from you if you kind of like can imagine oh it would be really cool to have like maybe i don't know like discussion sessions or um show and tell kind of like sessions like if you have like interest in this we would love to hear from you also like important to us is that uh at our meetup we want to remind everyone that we value an inclusive and welcoming environment um the backbone for our understanding what this means uh is for example also captured in the uh community guidelines at emberjs.com guidelines but the too long didn't read is mostly that we would like everyone here at the event to be nice and kind to each other to expect like communication or like interact with others with positive intent and also uh we would really like to um yeah kind of like value that you are also like kind uh to our speakers uh who are you are sharing like a lot of like great knowledge with us and if you can share any gratitude or kindness uh to them specifically then this is also something that we really appreciate and last but not least uh probably like the most important uh point at this slide like for us as organizers is always that we want to encourage everyone to think about like things that they want to talk about at the meet up um if you have something cool that you built with ember or you learned something really cool about the framework recently feel free to reach out to us either with like a talk proposal or just like a idea that you have so far and we can also help you to kind of like shape this into proposal if you are still not really sure if this is already it what you want to talk about so yeah just like a general encouragement if you want to speak you're always very welcome to do so here and uh yeah next up where can you actually reach out to us i already mentioned that you can do so via twitter but there's also like the way of um how does this work with the slides here we go um to do so why are like the message feature at like meetup.com and we also have like an email address um where you can reach us but yeah we check it like every now and then so probably like your best bet is to reach out to us via twitter just saying and also last but not least um we are all like on the ember discord if you haven't joined this one yet i would highly encourage it not only to reach out like to us but like a general to the emma community um almost like everyone is like on here and uh also like really helpful to help you with any kind of like things even like beyond of like organizing this meetup or attending this meetup and um yeah just like also that in general like a really great resource um in the emba ecosystem to mention here and with this this would already be everything about like the meetup journal are there like any questions or so any things anyone wants to add i think there's also something in the chat okay a waving hand waving back okay then if there's nothing we are already here at our agenda for tonight uh we will have like three full-length talks and also like one five-minute break in between so everyone can um yeah maybe grab a drink or something um and have a little bit of like a breather in between like the talks and first off we were gonna start with a really really cool talk about like behavior dream development and testing and how you can actually leverage this using cucumber by andrei mikhailov and with this i give it over to him if you want to give a round of applause with uh clapping emoji hands in the chat for free to do so it's always appreciated and then there you go hey everyone give me a second to share my screen okay and i'll open the chat bag i am andrei i am a front-end developer at caliberfund.de where i specialize in amberjas i work there remotely from the snowy must of from moscow russia and i am really happy and proud being part of this amazing team this talk is uh not really specific to amber jason code samples and screenshots are in amber but the general idea applies to every front-end framework and even beyond that um so there are more than enough talks articles and even books written about bdd and cucumber so you will hear some of this today but i would also like to share the nasty bits how terrible cucumber can be and how to deal with it i will start with the brief introduction to bdd we are all on the same page by bdd behavior driven development i do not mean the assertion style i believe that you can do bdd with assert as much as you can do it with expect and should and i do not mean this famous double uh loop workflow you are supposed to write acceptance tests and unit tests prior to writing code by the way you uh this does not mean that you have to do it in a waterfall fashion so creating a full test coverage prior to writing any code is not feasible and you are supposed to work in tiny iterations you're about to write a line of code come up with a small unit test come up with a small acceptance test uh write all three then proceed in iterations but my point is even if you write not only developers but also um managers designers representatives of the client if you're a consultancy or product owner if you're a product company bdd revolves around user stories which are short text describing how a certain feature that you're about to develop is uh how it works how the user interacts with it so let's have an example for a very simple feature let's say log in and sign up from the first class you might think that you need a couple of user stories to cover it one for logging in and one for signing up but then you remember about uh incorrect passwords about malformed email addresses about password recovery so out of my head i came up with this many user stories these are just the names of the stories so each item on this list should be backed by the actual story describing how the user interacts with your app and what is the expected outcome and it includes a few very rare cases such as visiting a link from the password recovery email while being logged in or while the link has expired if you don't think about such rare cases upfront you might forget about them later and your users will stumble upon it and they will be unhappy and your client will be unhappy and typically it's the developer to blame for forgetting about these despite that uh the developer forgot about them as much as any other team member did so the idea is that all team members converge and brainstorm those user stories prior to writing any code for prior to doing any actual work and these user stories thread through the whole feature lifecycle from the conception of the idea to deployment to production after the user stories are available the designer will use them as a reference to draw mock-ups and the developer will associate an acceptance test with every user story those acceptance tests will be later executed on your ci server to deploy to production this approach has a number of important benefits as you have seen it reveals the true scope of your future and lets you estimate the time requirements more precisely certainly you will never be accurate but it prevents you from being overly optimistic and your estimations will be incorrect with a lesser uh error margin uh user story server is a specification for your future and as being a single source of truth they have a power of resolving disagreements you can create a separate issue in your issue tracker for every story or you can create an umbrella issue for the whole feature and user stories may be represented as items on a checklist or as subtests for us developers it is in kind of satisfying to check out those items as we make progress implementing the future but it's also important as an indicator for the whole team meaning that when you don't have this explicit checklist and you develop the future over a few days your team members on the daily meetings will be you will be like okay today i am working on this feature and the next day i'm working on this feature and your teammates will be like why is it taking you so long it's just login and sign up and with this explicit set of user stories it becomes obvious what the real scope is and it becomes visible how you make the progress also user stories focus over users needs naturally as opposed to developers needs there is a book called the the inmates are running the asylum by ellen cooper the name of the book is a metaphor for the fact that if you put developers in charge for designing the user interface and user interaction of your app then app development becomes a crazy hospital this is because developers are very prone to cutting corners and prioritizing geeky stuff over what is actually important for users finally user stories integrate well into automated testing and for this you need the software library i use cucumber the name the name cucumber appeared like 15 years ago or maybe more it was a working title a placeholder for the project but it stuck before the author was able to come up with something meaningful so they decided to keep it the i i have visited the github repo of this project and the first commit dates uh over 16 years back as of september year 21. and cucumber started as a simple library uh syntactic sugar basically over another librarian but later evolved into a full-fledged testing framework ported to most popular programming languages especially the ones that are used for building user interfaces javascript has the official cucumber.js and yada js which i happen to be using because when i started there was a decent emberjs add-on for it and who knows how many more exist on npm in cucumber user stories become executable test files so this file the extension is dot feature and the syntax is called gurken it uh unambiguously maps to an amberjs acceptance test the name of the feature is the name of the test module and scenario names are test case names each scenario contains steps one per line which are executed sequentially there are three types of steps given steps set initial conditions initial state of your app when steps represent user actions and then steps make assertions of course cucumber is not an artificial intelligence so you need to implement each step in your programming language so javascript in our case this is how it looks like in my code base the original syntax of yet a js is less convenient so i came up with this like high level abstraction basically each step implementation is a function and the step names in the feature file are calls to those functions when a function returns a promise cucumber would wait for the promise to resolve sorry and the test will pause until the [Music] execution of their presumes and then the next step kicks in um if you have similar steps such as i should click i should see three posts i should see 17 posts so it does not mean that you need to implement 17 similar steps this is thanks to the fact that step names uh is in implementations are actually regular expressions and for each capturing group in a regular expression you receive an argument with a matching value so in this case the number of posts this is a very powerful technique but it's not very convenient firstly because the regular expression syntax is notoriously difficult to read and on top of this you need those double backslashes because this is not a regex literal it's a string and the single backslashes are escape characters so you need to escape the escape character the second problem is that uh regular expressions return only strings so if you need a number you need to convert it by hand which is not very convenient luckily yeah the js and probably kept inverse gs2 has a syntax called they call it dictionary and converters but i find this a bit confusing i call this macros a macro is a placeholder starting with a dollar sign and under the hood it gets paired with a regular expression to match and an optional converter function so in this case it would convert a number to an integer but you can also do floats you can look up dom elements and receive the elements as arguments you can parse json convert s key tables into data structures and so on cucumber also supports tests and mattresses mattresses like plural for metrics dude perfect so in cucumber test mattresses require using placeholders as square brackets you should use them in the name of the scenario so that you do not receive duplicates and you use them naturally in both seating steps and assertions this scenario will be invoked multiple times as many as there are data rows in the table of values below cucumber has a number of important benefits first of all the most important one personally for me is the separation of concerns this means that all the pesky details petty details i think i mean are hidden away from you because uh like all those imports of libraries specific helper invocations seating patterns this is all visual noise most of the time typically when you read through a test you want to focus on its business logic and not those implementation details so they're hidden away you can work with the test on the high level and this like makes it more efficient and your at least my personally my head does not overheat as much uh cucumber tests are readable for all team members and all team members can participate in validating the tests ensuring that they make correct assertions since step implementations are reusable you can compose new tests by simply calling those steps in a different order with different arguments so ensuring decent test coverage is very quick and the test coverage itself also becomes better since those implementations are relatively short it is easy to maintain them you do not need to revisit them often they are battle tested reused in all sorts of features so you rely on them without having to maintain them being part of the bdd methodology integrates well into your team's workflow and kind of enforces the workflow also all the team benefits from the fact that tests are written in the same code style you know how tests are given the least priority when code style is concerned and reading someone else's tests can be very difficult to be honest when i read the my own tests written like months ago this is basically right only code i struggled to comprehend it because i did not put effort into structuring and organizing it with cucumber this is not an issue but this is uh too good to be true cucumber makes a lot of good promises and has an army of dedicated supporters but it also has a comparable amount of haters and many of those haters started as cucumber enthusiasts after reading articles and listening to talks like this one they managed to persuade their team to adopt cucumber spend weeks rewriting their tests and then they get bitterly and utterly disappointed basically every other claim is not fulfilled and there are two possible outcomes from this uh either the team makes a tough decision to abandon cucumber and rewrite everything back wasting weeks and months of work or as a russian joke says mice were bleeding and crying but they kept eating the cactus so the team may choose to keep using cucumber but they will stay unhappy about it and they will keep frowning upon the developer who came up with the initiative guess who has been this developer my team but i did not give up i figured that it is not cucumber as software to blame for it it's the how we use it i have an analogy for you imagine that i decided to try cooking and i failed miserably cutting my hands with a knife and i start preaching that kitchen knives are dangerous and everyone should abandon using kitchen knives when cooking this would be ridiculous right so i identified the problems that uh in cucumber brings and i came up with solutions to those problems so today i will tell you about five of the of the most important ones so these are my know-hows uh some uh are biggest and they have been known like i'm not the author of those ideas i came up with them on my own but they have been known for quite a while and not all cucumber supporters agree with them others just are tiny threats so let's start with problems the first one is that the library of step implementations keeps growing and growing every feature requires some intricate logic so you will end up both creating new steps for every feature and building on top of existing ones when you improve when your assignment is to improve an existing uh feature of your app you will upgrade those steps and this gets out of control very quickly because uh step implementations can vary across projects while step names remain essentially the same it's very difficult to look up steps step implementations for steps no ide offers a way like to quickly look up an implementation regular expressions contribute to this problem two step implementations uh can both or even more than two can match the same step so yada has a solution for this yada would always prefer a more specific step implementation over and greedy regular expression but this heuristics never works the way you expect like you look at a step implementation and you expect the step implementation to be used you don't even know that there is some other implementation that will override developers get lazy and instead of looking for step implementation that will cover their needs they end up quickly re-implementing a new one and duplicates appear they may differ in subtle details and phrasing and become a big big problem the second problem is that the step implementations are a black box the step name can say something but the implementation can do something else or nothing well we did not have such extreme cases but we many times we ran into case like this consider this example it says there are three posts in the database the title of the first post should be hello world why is it hello world and not say lorem ipsum to figure this out to make sure that this is valid you need to find and look into this implementation of the seating step and who knows what you will find there the developer who implemented it may have used the faker.js they may have hard-coded the words hello world into every post or they used fixtures so you do need to reopen step implementations every time um i used to have ah let's send the solutions okay so as you can see another promise of cucumber is not fulfilled the third problem is that steps can be tied to each other so they they may be implicit coupling this example is a bit artificial but bear with me it says the previously expanded post should contain a comment section the problem is in the previously expanded part this step implementation must know which of the posts on the page has been expanded and what if like several steps several posts are expanded in an arbitrary order yada has a solution for it all step implementations share the same this context so the clicking step can memorize the dom element on this and the assertion step can read this dom element and make the assertion this works but the problem is that it makes the feature file very tangled and the implementation is very tangled when you develop on top of it run into problems in our apps this so we use the this context very heavily and when i first ran into it i wasted the whole day untangling it and swearing and pulling my hair so though this is a powerful feature it leads to problems the fourth problem is with presentational css selectives they are a mess a non-developer will look at this and assume this step is written in a foreign language a developer understands that this is a selector but they still cannot tell if it's a new item a sidebar element or a post title and a list of posts so you could say let's solve it by using semantic selectors only but if there is a technical possibility to cut corners corners will be cut especially when you are hot fixing something on production so don't expect presentational selectors not to ruin your day the fifth problem is with debugging if you integrate cucumber into your framework in the most simple way it will offer zero debugging capabilities when a scenario fails you will only see the name of the scenario and unhelpful error message and meaningless stack phrase point into some async stuff in cucumber code base and again you need to reopen step implementations uh sprinkle them with console logs debuggers and so waste time figuring out what has happened now two solutions those solutions may seem obvious in inside but it took us a while to come up with them and they're rather opinionated so okay let's proceed the first problem was the size of the library i have realized that the user can do only this many types of actions on the page they can click something read from the page they can fill text into the form field or read the text from a form field they can select items from a drop down and such you know this list from amber test selectors and i said let's use only these highly reusable steps and never use any steps with logic specific to a certain feature this reduced our step library from several hundred steps luckily we did not reach the milestone of 1000 steps that would be a sad anniversary to celebrate but uh anyway so we are now down to a few dozen steps two dozen are very reusable from amber test selectors and a few more are relatively rare such as picking up an element from a power select using async type of head search but still these steps are not coupled to any specific feature the result is that it's easy to remember all the phrasings and the steps are so tiny and atomic that you never have to reopen them you just compose feature files and you can copy paste step names because the same step names appear in basically every feature the second problem was with a hidden logic and the solution is to extract all the truth hidden inside step implementations and expose them in feature files so in the previous example we update it by uh showing which specific ceiling pattern we're using and now it is obvious that the first uh impose has uh the title hello world and not something else previously we were using a very elaborate seating pattern based on mirage traits which were invoked in mirage trades this sitting pattern was extremely complicated and large it seeded like many hundreds of steps in every of our apps and all tests were using the same seating pattern this meant that when i needed to implement a new feature say i am adding comments to a post i would improve this seating pattern with more data and this may break existing tests like i would create a post without comments a post with a comment the post with a comment and replies and such and other tests fail i need to fix them the logic the sitting logic becomes very complicated with the if conditions and the loops by the way cucumber syntax does not allow if conditions and loops intentionally to improve the simplicity and breathability instead you're supposed to create multiple scenarios and in our new practice we use tiny sitting patterns we do not see any records which are not related to this particular test case here is another example it says that a product should be selected on the page but what does it exactly mean to be selected and with the new approach it becomes obvious we are checking for the existence of an html class which is responsible for the selected loop and we are looking for a comment section to appear inside the element the problem with tangled implementations is sold in a very obvious way we simply stop using this context and the reference steps in the feature file though obvious it took us a while to reach this and it is unbelievable how many how much friction this solution resolved with presentational css selectors we of course rely on the amber test selector's add-on which tells you that you should use a data test attribute on every element you want to interact with in your app and now the step so it is now clear that we're clicking on a post title and not a menu item but this approach still has problems it is still very hard to understand for non-developers relatively difficult to read for developers and presentational selectors can still be used technically so i came up with a custom dsl i called labels so i invented the syntax i drop square brackets from this data attribute i drop the data test prefix and i capitalize what remains in order for this label to stand out in the phrasing of a step i also reverse the order of compound selectors so instead of saying data test both and child 2 data test expand button i say the expand button of the second post this is very natural and it unambiguously maps to a css selective and i made it impossible to use the presentational selector so anything but this specific syntax will not be recognized and this made our test cases easy to read for non-developers and result another layer of friction one problem arised with the nth child pseudo selector does not works as you expected to so when i say second post i expect this post to be selected but channel does not work like that it picks the second the post from every immediate parent so it's a wrong post gets selected and more than one actually so to solve this i borrowed the idea of the eq selector from jquery i had to implement it by hand so what it does it simply selects all posts on the page in a flat list and then picks the second one from this list i use indexing starting with one for readability by developers and as for debugging i created a custom wrapper function in between cue convert test case and the queue unit test case this wrapper would report all step and locations to queue unit and when a step crashes with an assertion error or with an application error this error will be caught the error message will be enhanced and the error will be rethrown this is how the resulting output looks like so for passing steps first of all you do see a list of passing steps which is very convenient the sneaker icon represents the step name as it appears in the feature file and the gear icon represents the step implementation name that was picked for each step and you can see that whether the pairing is correct when a step fails you again see the name of the step of the implementation the meaningful assertion error and the list of arguments that this step implementation wasn't invoked with for dom elements you do not see just uh array something which is what you would see if you tried it to cast an array of dom elements to a string instead you see that this is a collection you see the label that was used in the step to make the lookup you see which selector it corresponds to and how many elements matched the strike trace is also more meaningful so most of the time you will end up either inside a step implementation or if the app crashed in the app code you will have a reference to the app code this concludes it in caliber funds we dedicate some of our work time to open source courses and i've been uh implementing the add-on i called amber bdd it is still in active development when it's finished it will be a drop-in solution for cucumber uh so far it's not yet usable but um get in there and i encourage you to visit the repo i have enabled github discussions which is a new github feature there's a more casual way to communicate in a github repo while issues are being more strict so please don't hesitate to chime in oops as a conclusion i found this amazing stock photo which i believe summarizes my talk more than any other slide would thank you so much for having me for listening to my talk and i am ready to answer questions oh this was awesome thank you so much for this awesome talk um and yeah uh let's open up the room for some questions feel free to either post into the chat if this is your favorite mode of asking questions or just like i'm muting yourself um and i maybe had like a first question already uh which would be i found it super interesting that you talked about like the csl that you developed to kind of like make the um yeah descriptions of like steps like more readable to like many different people on the team and i would be interested because i've also been thinking about like how can you actually make this more accessible like in general two teams uh what is kind of quantity tested um but your feedback has been so far and if you already have like plans on what you want to uh kind of like maybe improve or kind of like further iterate on in the dsl uh actually we've been using this dsl for at least two years we're very satisfied with it so far there are still a few minor things uh missing i'm not going to elaborate on this and implementing them properly would be would increase the complexity of the implementation a lot so far i we are happy and have no plans on elaborating on this dsl oh one thing it's mostly related not to the label syntax but rather to a set of uh step implementations uh is that there is a proposal on amber rfc to instead of using semantic selectors they use accessibility approach to selecting items on the page so select them by the text that the user actually sees and not with an attribute that the user does not see and is not aware about or yeah that makes a lot of sense here thank you and yeah also see like more uh questions like in the chat first of all like also like a one thousand ten thousand percent for this rfc uh and also like another question here that says um the after where you're explicit in seeding the data doesn't that make your other test brittle you discussed how other tests would break with more data or did i misunderstand what you said yeah so cucumber allows to have shared seeding for every scenario within a feature file but you can also see the each scenario separately so you have a tiny sitting table for each individual scenario and they do not overlap so each scenario is like uh isolated so messing with one scenario will never break other scenarios yeah gotcha thank you does this also answer the question for you with you and also one more comment here by gonzalo i had the same issue in rails with fixtures moving to factories and letting each test scenario create its own models fixed it okay we also have like a question from the um live stream and have you considered using page objects one benefit i've found with them is that they can be modular so the implementation is tied directly to eg a single component yes we started with page objects but then we realized that when we switched to reusable highly reusable and minimal atomic step implementations there is a fair amount of overlap between those atomic step implementations and page objects basically page object became redundant and the step implementations serve as page objects but they are abstracted away from individual components and are more generic so uh page of just complicated things uh a fair amount so we decided to get rid of them and we are not using them with cucumber yeah gotcha makes a lot of sense to me and i never really thought about it back this way but like page object is also fulfilling a lot of like the functions of the step implementation syntax uh yeah more comments coming in here uh first of all uh here kind of like confirmation that yeah 100 agree that each test module should have its own seating um then also one comment by ilya if you're waiting for the rc there's an add-on at tradekick or ember semantic test elbows although last i used it i think it had a minor issue with newer unit versions um he also has an open issue there then also another comment here by preston i don't like when page objects are tied to a component because they tend to reflect dom instead of user api yeah basically the same idea that we had when abandoning page objects yeah that makes sense any more questions or any more feedback or so feel free to also just like chat into the call if you like thank you everyone this was exciting yes that's great and thank you this has been an awesome talk thank you cool um and with this uh we can go over to a quick five minute break so right now it's like 51 so let's try to kind of like get back here so like 55 56 or something and then we're gonna get started with our next talk by no box properly oh no null works popular with seen a resources [Music] so [Music] [Applause] [Music] home [Music] my [Music] so [Music] so [Music] [Applause] [Music] well [Music] and then i give it over to and also don't forget your applause in the chat [Applause] all right oh right uh so yeah um i wanted to do a little tribute to control because they just had their two year anniversary recently and uh this little upside down pyramid here is the board they run the astral plane um you should check out the game if you haven't it's pretty fun um yeah i'm malvox populi um you can find me at snowvox populi pretty much everywhere i have the following side projects maybe you've seen them around they're in various states of abandonment and progressness and occasional readoption so like from left to right you have emperor clear which is end-to-end encryption in the middle uh is a rebel for markdown and ember together demonstrating my preferred way of writing docs and then on the right is kind of an experiment i was doing with uh the web animation api which is pretty cool um you should check it out you kind of don't need an animation library anymore so yeah i also want to say that i work for crowdstrike and crowdstrike's always hiring so if you're looking for a job um message me and i can send you some links or you can just go to crowdstrike.com careers and then poke at workday until it gives you what you want all right so what is a resource um first uh we got to do a brief overview of auto tracking and uh as a disclaimer um i guess a disclaimer to the disclaimer there's a scheduling scheduling issue with uh some maintenance on the roof so if you can hear hammering i'm getting my gutters replaced for some maintenance free gutters and i'm pretty excited about that um anyway uh back to the original disclaimer this is a simplified or brief version of auto tracking and not entirely an accurate representation so um let's say we start with a template this template has two references and this template has a backing component class the classic first name last name full name example um the first and last name retract and full name is a getter that returns them both as a single string so uh following the flow of execution we see that full name from the template will call the getter on the component instance and then as the full name getter is evaluating we run into a property on the component instance that we need to go look at so first name is a tracked property and tracked properties are also references but because we encounter this reference while evaluating the value of another reference we know that full name now has a dependency so we've encountered one reference for its name which is note to the original reference full name so going back to the flow of execution we run it to another property last name we see that last name is also a tracked property which is also a reference and now the template renderer is aware that the reference this dot full name is dependent on these two other references which um to peek under the hood a little bit for a little more detail we kind of think that when evaluating a reference we create a new tracking frame which is a weak set and the tracked decorator expands to add references to that current tracking frame via getters and setters um for a deeper dive into how auto tracking works um like it'll it'll give you enough detail to where you can implement this yourself uh you can check out the rex article on how auto tracking works uh url right there so what is a resource it is a helper that can be used outside of templates or a getter with persistent state and or life cycle all right so what what does this mean first we need to ask what problem do resources solve so uh they protect against side effect and getters they bridge the gap with reactive primitives provided from ember and they answer the question how do i safely deal with async data because getters can't be async maybe you've tried it before you return a promise from a getter you see your template isn't updating as you would expect it to do so what is a side effect when behavior unrelated to data derivation is triggered and the result of that behavior is accessed elsewhere and what i mean by that is this but this has an immediate problem just give give this code a read and see if see if you can find it right so the template accessed this dot query this dot query starts an async request and then request returns an object for the records which points to an empty array records was a tracked object so the asyncrequest and the query results and sets the start records to a new value since the stat record is a tracked object query depends on the reference records so you go back to the top and then that just repeats uh forever um so maybe maybe you've seen a assertion message come from this problem um i think it was added in ember 3 20. 24 somewhere around there maybe earlier i don't remember but anyway it's like you access blank on an object that was uh like accessed previously in the same rendering computation or whatever and it's like just trying to prevent infinite revalidation bugs so uh one way we can solve this is just to not access this dot records in the query getter that will avoid the infinite revalidation error but then we need to access this query getter in the template and it kind of just looks weird um because the this dot query uh doesn't provide any value to the display but maybe you've seen this other pattern uh using did insert and did update to get some records and then you add arbitrary arguments to know when to re-fetch those records so problems both the getter side effect and these did insert ended update modifiers have is that they're hard to make reusable and these types of side effects are undocumented and therefore spooky and what i mean by undocumented is that like every occurrence of them might be slightly different and your developers and co-workers might miss minor differences between each of the different implementations also the template ultimately has no business caring about the sort of data manipulation as it may have nothing to do with a particular element and with both approaches you ultimately leak state and intent everywhere so that prevents the broad understanding of what the focus of your component or whatever your abstraction is so uh i'm saying resources are gonna solve that but how do you make one so uh there are three ways so far and each of these has different trade-offs but that's a discussion for another time but in this imaginary scenario i say imaginary because neither of these libraries provide a query resource but let's say we're using a resource that abstracts the async behavior and various states you would expect from amber data's store.query so you'd expect it to have results uh error handling loading status stuff like that um and you may be asking yourself but if it does that that seems like it has a lot of overlap with ember concurrency why would i use a resource over amber concurrency and that is a great question the answer is that resources are lazy and they don't do anything until they are accessed so to just demystify how that works let's roll our own resource implementation and ignore both of these libraries so minor details aside and maybe major details depending on how you look at it this is the entirety of what an inline resource with no abstraction would look like so this is the part that is abstracted away by the two previously mentioned add-ons amber could get used to this and ember resources and this is the user land stuff closer to what you saw in the examples earlier and maybe you're thinking hmm this getter approach looks an awful lot like the getter side effect a few slides back and you'd be right you're paying attention this is a side effecting as well as imperative just like the other examples but we can do better so why use resources at all a resource will abstract the side effects and imperative nature of async data handling so that an app dev can focus on the declarative side of data derivation additionally resources have all these benefits listed here and most importantly all of these things fill the gaps left over from the old paradigm of ember classic when we all switched over to octane so in most cases you aren't going to be writing your own resource implementation from scratch so sticking with our query example let's look at what creating a resource using one of the two previous libraries looks like now when deciding on implementation regardless of what it is i like to start from the outside in what do i imagine the easiest to use public api for the function class or add-on is that i'm about to make so in the top left we can go the amber resources approach and provide a single export to use query in the bottom right we could go the ember could get used to this approach which requires two imports and personally i like the look of this butter even though it's the same number of key presses if you exclude the decorator um it's just something about the new keyword but i don't know if if you have a preference over which you like uh let me know i'm interested in that kind of thing so i'm going to be showing you how to implement a query resource using amber resources for a couple reasons i wrote and maintain amber resources so i can provide provide better support for folks that have questions and the query resource already exists in the ember data resources package so if you're interested you can reference that for a fuller implementation so over on the right we have my what might look like a resource implementation of note this is all we get for a life cycle hook oh but what about handling destruction you might be thinking well we can use at ember destroyable where we can have a setup in the body of the constructor any tracked data accessed here will entangle with the caller we have update here conditional code in the body of the constructor so any tracked data in here will also entangle with the caller and lastly uh we have destruction or tear down provided by amber destroyable and what i personally really like about register destructor is that you can co-locate set up and tear down which means you pretty much never need framework provided tear down hooks ever again which is very exciting so where were we uh this is where all life cycle happens in the constructor and this is the bulk of our resource the start method when this method runs it will set the request lifecycle unix you would expect from an async abstraction is loading error etc of note this part here exists so we can disconnect from an active tracking frame which allows us to set tracked data without running into the infinite revalidation assertion so everything above this await promise resolve is entangled with the call site and everything below won't affect the rendering or trigger that assertion so over here we have a little helper function this is optional but it is a nice way to provide only one import to the call site instead of two instead of importing both use resource and the resource itself folks can import this one query function instead this also has the added benefit of allowing you to customize how the args are passed to your resource for example in this case model name is passed directly to the query rather than part of the thunk function this ops the model name out of reactivity because only arguments accessed within the thunk function will reactively entangle with the call site but let's say you don't want to worry about that what's the bare minimum you can do while still having one import at the call site and how will that affect the api at the call site so you could use this one liner but it means you widen the api at the call site which could potentially confuse users it might be thinking what is positional what is named why do i care and that that's why i prefer abstracting them all right so if you hear if you're curious about what the real thing looks like feel free to take a look at ember data resources on github so what else could be done with resources so ember array map resource is like array.map but you can reassign array references which are records in this case and they transform you apply will only be applied to the added or updated records using object identity to track equality most of the utility comes from expensive transforms where you don't want to be re-running the transform on every array element every time the array changes so you can just reassign records willy-nilly and the transform only runs on what's changed so maybe you want to do a headless ui implementation um so here's an example here of maybe how you would manage your table and then you can hook up your own dom to it uh maybe maybe websockets um i like this approach because i often feel like using a service for websockets isn't sufficient because sometimes i want multiple connections on the same socket um on the page and since services are singletons it can get a little tricky to do that yeah id is welcome if you have an idea i'd like to hear it resources are new and still ripe for exploration thank you there are some resources for resources yeah thank you so much for this awesome talk this has been so interesting and also if like any questions come up here from the audience feel free to post in the chat or on mutual stuff like ask right away i've got a question there is a use case that computed properties and getters are challenging to implement say i am i have a computed property that creates a class a class instance for every item on the list so i have an array with amber data records and i need to represent each record with a custom class instance when this computed property recomputes i do not want to reinstantiate all the classes in order to save performance and in order to persist the state of those instances can resources help me with this yeah yeah that actually sounds like the use case for array map resource because you you get your list of ember data records and then you pass them to arraymap resource and then it it puts them in whatever class you want and then the class instantiation doesn't happen again unless you add records to that array or if a record gets swapped out for another one awesome yeah thank you any more questions i also see like a couple of comments also trickling in here matthew for example sharing can't wait to re-watch this and really live in thanks for sharing lots of applause as well yeah would also be kind of like curious um you already kind of compared like different libraries and like the syntax to each other like for example amber could get used to this with amber resources right and and beyond like the kind of like syntax differences like are there any kind of like other real differences or is it like more really very overlapping with these atoms so behavior-wise they are about the same amber could get used to this currently has unreleased code on its default branch which is like the exact same as the resource provided by ember resources but the released version of amber could get used to this requires that you make a value property or getter and that's all you can access from it um but they're functionality-wise they're very similar and they could cover all the same use cases thank you uh [Music] yeah and i also like one more comment here by my feels want to shoot over a question maybe on discord later which is like also always like great i think with most speakers on here if you have like question requests afterwards i think like all of them are also not gonna discourage if this is not uh what you were expecting then feel free to just like chime in right now kind of go like no i'm not on discord but yeah i think all of them can also reach there awesome um you have to like no more questions uh on this part then yeah thank you again so much for this awesome talk um and okay it's like another one that she pops up uh vladimir is asking what's the thing about away promise resolve again that you mentioned yeah so that's kind of a hack to while evaluating a async function above the await promise resolve um any track data you access will become a dependency of like a getter or whatever that you access that resource from but after the await promise resolve any track data you access isn't tied to the call site uh i can provide examples discord if that's not clear is this only true for resources or for all auto tracking all auto tracking so um okay so let's say you do access an async function edit any track data you access in that async function um before and await will become entangled with that getter yeah gotcha that makes sense thank you um yeah i think this is um it if there's like any more questions yeah feel free to reach out it's later on like on discord and other than that thank you so much again for the great talk and uh with this we already get to our um amazing finale of the meetup and a really really great talk by john webber who will be sharing with us um how we can actually care for code garden that is already grown in size and um this she will do in her case study about revitalizing an overgrown ember app with this i would give it over to you all right um can i get a thumbs up uh if you have a video on that you can see my slides and hear me okay great thank you so much um thank you jessica for the awesome introduction and to everyone who's listening into the meetup tonight especially those of you in berlin and then all of our friends from around the world who've tuned in so a little bit about myself my name is jen weber i'm a senior engineer at act blue which is a company that helps process donations to progressive political campaigns and non-profits i'm a member of the ember core team i work specifically on our documentation and learning resources and the public sites that you see when you visit emberjs.com i'm also the author of the ember octane cheat sheet which is a resource that helps you figure out how to change your old ember code into kind of the new and modern style i helped write the octane upgrade guides and um [Music] because i've made all of these public resources i'm going to skip over some of the nitty gritty details of like specific commands and steps and workflows that it would take to upgrade and maintain an app a lot of the things that i'm presenting today the details of the exact commands and some of the challenges you might face along the way are available as a series on my blog as well as in the official ember upgrade guide so i'm going to focus my time today on kind of the meta big picture what is the overall strategy for maintaining a very long-lived or large app even if you work on small hobby apps though some of these strategies will still help you out but that's kind of the angle i'm coming from for this talk all right so uh this is a picture of my garden um from the start of this past summer this is kind of like my little green field app everything is tidy and fresh and new i've got some little strawberry plants all neatly growing in a row i have my anti bunny fence and it's it's good it's not compromised at all there's no holes dug underneath the edges uh things are looking great and uh here's how it looks later in the season this was like a few weeks ago it looks like a wreck so there's weeds everywhere um and this is kind of like a mature app so you know i've got certain sections of my garden that have really grown in a huge way and other parts that haven't been kept up to date and there are so many places that bugs can hide and although it looks messy my garden is very productive um this is like just one one day uh about a month ago the things that i brought in from my garden this is my first season having a garden in this location um and to keep my garden productive making these fruits and veggies for me um one of the challenges i have is that my work is never complete i could spend uh unlimited numbers of hours trying to get rid of weeds pick off bugs treat problems or even just like try to make it look nicer but if i wanted to do those things if i'm dealing with my messy garden what i don't do is make new garden beds and give up on the ones that i have i'm gonna go fix them up as a developer similar to my garden my work is never complete and if i was to just start from scratch because i had you know an old app that's full of weeds um you know that's that's not really necessary um i can instead keep to working to maintain my app as it grows find ways to deal with the messy sections without starting all the way over um in my day-to-day work i work on a code base that's about 15 years old and it has hundreds of thousands of lines of code there's some get commands that you can run that will tell you just how many lines of code are in your code base and it almost seems impossible that it's that many lines but if we think about how many engineers are in an organization multiply that times the lines of new code that they write subtract the code that they remove which is probably not that much um you can get to these really huge numbers really quickly and you have to have a strategy for um managing that growth so what i'd encourage you to do as you're listening to these examples and as you're doing your own work is to think of yourself as a gardener what does it take to make your code base healthy and productive so i'm going to walk you through a case study this is a smaller app but it's the ember api docs and this will probably be a familiar site to a lot of you this is api.emberjs.com this is an app that was created in 2015 um it's used by ember developers daily all around the world and um it's one of those apps where like it just kind of quietly worked in the background and didn't get a whole lot of attention except for the times when ember's documentation structure the actual data that backs this changed shape several times and every time that documentation source it was like a json file changed shape um you know things uh documentation gets moved around all the time as files get moved around every time i change shape there's like more and more hacks and conditionals placed into this app um you know our requirements change across time this isn't because there was anything wrong with the original app we just didn't know the whole story and none of us know the whole story about the apps we're building the best we can do is build something that can adapt and grow over time and if you're using ember to build one of your apps you're already off to a good start so this app um [Music] it's not octane or anything close to octane which means that every time we have to tackle big changes uh or feature requests the cognitive overhead to get into this app and start making changes is really high i probably know this app the best and i don't know it well because i've really only stepped in when there was something that we absolutely had to do but we know that our needs in ember community are going to change across time and so it makes sense to spend some time updating this app making it more flexible making it easier to understand that lets it change from me and a couple other learning team core people changing things to us inviting the community to help out and then finding syntax that is familiar and things that are more readable so a few months ago chris thorburn also known as runspired and one of the key maintainers of ember data reached out to me and said hey i want to help improve this app i've got some things i'd like it to be able to do to help show off ember data better and chris said if you blog about it i will pair with you to help make this app better and i said okay so um we paired uh like every other week or so for some number of months and then later on i also i also pair regularly with chris manson who's a member of the learning core team he and i paired on this a little bit and i'm going to share some with you about what we discovered along the way and what the strategies are that helped us to modernize this app the first thing we did was figure out what our goal was we wanted to incrementally octanify the api docs app and make it a good example of how to use ember routing and ember data effectively so when i say octaneify i'm referring to the latest edition of ember an addition is a set of syntaxes and patterns that we think represent the best way to build an ember app so as we're refactoring we're not changing what this app does but we are changing how it is coded under the hood so the steps that we went through were we needed to write down a plan we needed to budget some time we need to see what tools were available to help us reach our goal we wanted to work incrementally meaning that each time we made a step forward in progress we wanted that to get shipped um we didn't want to have like you know a branch that doesn't get merged till next year or something like that um we want the benefits to be available as soon as possible to our users and to other people who want to work on this app um we needed to be careful not to disturb the roots of this app so um if i did a great big huge refactor but i broke things for every ember developer during their work day that would be a bad time we don't want to do that um and then the last thing is we needed to measure our progress we needed ways to quantify and communicate our success all right so um this is a screenshot of our plan the actual items in this list don't really matter they're very small you know you don't need to read them but uh the important part of this is that making the plan itself is essential so what we did was we wrote down everything we thought we could do you know all of the options all of the ways that we could spend our time all of the different things we could focus on then we made our best guess at which tasks blocked other tasks so for example we knew that we couldn't rewrite our computed to use tract until we knew until we were on a late enough version of ember that you know we knew it could work with tract and glimmer components um that's an example then there's other things that were non-blocking so for example we could refactor our ember data models um while we are also working on the computeds you know we can kind of mix those tasks around but ultimately we needed to prioritize them as well so in terms of priorities we focused on which things that we were the best suited to set the groundwork of and then we took the things that anybody could work on um and set them aside uh for later so that when it's time to invite the community to help us there are some very well well-defined small tasks that they can assist with so eventually we deleted half the items in the list that we had made because they didn't block anything and they could be done by any contributor we focused our time on the things that the two of us really really needed to do to set the groundwork so the next thing to do was to budget our time we budgeted about an hour every other week um for pairing sometimes we paired for longer if we are really on a roll um and budgeting this time if we hadn't scheduled that time and blocked it out for ourselves it probably wouldn't have happened there's so many other things to do and ultimately no one was paying us to do this work this is like a volunteer open source kind of thing um if you're looking at updating or overhauling an app for your work um what this step means is that you should try to estimate your annual maintenance effort you need to make a case to your manager to your team to your company leadership about why you need to spend time on changes that are mostly invisible to your users if you want to go from like you know ember uh let's see on number 320 and you want to be ready for number four that's coming out in like you know next month or so um it's not going to look different to your users but there's going to be maybe there's going to be a lot of changes it takes time to do that upgrade you can estimate this annual maintenance effort by thinking about how many lines of new code per engineer on your team like how many lines do they write think about how much time it takes to maintain the work of just one engineer and then multiply times the number of engineers that'll give you some sort of very very very rough estimate about the amount of time that you can expect to maintain your code base that's the absolute minimum because we're not just trying to maintain new work we have to maintain all of the work that has been done in the past as well um but sometimes if this isn't already part of your organization's process you got to start with like what you're doing this year right now sell that first and then work towards maintaining uh setting aside the time to maintain the older things as well the other thing you want to do is um as much as possible describe uh the benefits to your end users so um it like what i think about in terms of my garden is like there's some tasks where if i do the maintenance work if i remove the weeds that are blocking the sunlight it's going to result in more vegetables if you fix some of the pain points in your application it can unblock new feature development there's also a lot of maintenance where you can't draw a straight line between the work that you want to do and the benefits to the end users maybe those things can wait you can factor that into your prioritization and then of course there's the risks of not doing the work so for example we might think like oh what's the benefit of updated version updating a version of an app the users are never going to see it why don't we just wait until i don't know next year or something that's risky because if there's a problem with one of your dependencies like a security vulnerability and you're so far behind that your version doesn't have security patches for it you could actually be in a pretty bad spot um and so sometimes when you're doing your maintenance job well it looks like nothing is happening but in reality you've prevented big problems so try to write down those risks and include them in your arguments about why you should spend some time next up is find out what tools are available to you so when we were doing this upgrade the two main tools in our toolbox were code mods and linters a code mod is a program that analyzes your app and make change makes changes to it when you run a command a linter is something that looks for problems in your app things that might be errors or warnings that are about your syntax so maybe it's incorrect syntax maybe it's things that could cause memory leaks maybe it's an issue with the ra way that you've written your html that makes your app not accessible linters help you catch those things um and if you're wanting to know a little bit about what the specific um tools are what are those code mods and linsters that i'm talking about you can visit guides.emberjs.com release upgrading to check those out specifically but in general they work something like this um for many of them you start your local ember server and then in another tab you run the code mod so here i have npx ember angle brackets codemod and a flag called telemetry i'll talk about that in a minute and the path so what i'm doing here is i'm saying hey codemod my app is running on localhost 4200 that's the default for when you start your mrap and i'm saying i want you to run this code mod on all of my handlebars files what telemetry does is um it looks this is my understanding of it i hope it's correct when you actually run your app the code mod can look at the built output and use that information to determine the correct change to make so when i ran this on the ember api docs app i can see that it changed 19 files and what it did was it changed all of the curly brace uh invocations of my components into angle brackets if i did this by hand this would take so long even on this small amp but when i leverage the code mods i a single developer can make big improvements in just moments another tool in my toolbox is lint fixes so most ember apps use eslint which can help you find problems in your javascript files um there's a flag called fix that will try to make the chain the fixes so if it's small things like um you know stuff is using uh double quotation marks when it showed you single or maybe you're like me and you just forget to put semicolons all the time um it'll do those small changes that are fairly safe for you and automate those so again i don't have to make changes by hand in order to get my app looking closer to what i want this all comes with a caveat that the tools themselves are not flawless whenever you run these code mods whenever you follow these linters you still have to use your human judgment to look over the diff and say is this correct you still have to open up your app and click around or run your tests and see that things are still looking as they should so in my case you know i found there was one code mod that chris o'byrne and i ran that didn't interpret like a link to with positional params correctly or something like that it was a really strange way of doing it in the app and the code mod just wasn't um it didn't no one understood that that would even be a syntax that would come into this code mod um and so we had to go in and kind of fix that one after the fact and our test suite told us right away that something was wrong [Music] so the next thing was that in this app upgrade we wanted to work incrementally and that's because huge overhauls are risky um i alluded to this earlier but we wanted to make sure we didn't break things for everybody and so if we had one great big huge merge where all of a sudden one day something that's had like 100 commits get shipped to production like who knows what could go wrong and it would be so hard to find out what the cause of a problem was instead um we wanted to make uh smaller prs at each critical step in our to-do list this has another benefit that people who are working on the app who have bug fixes or features um they get the benefits of our refactor right away they don't have to wait until like next spring when we finish this one thing you can do to work incrementally is to refactor your components your sets of components one at a time so earlier i showed you a command that ran on all the handlebars files but you could just pick one product area of your app to run those code mods on make that be its own pr ship that and kind of step towards your goal of refactoring your components [Music] another aspect of working incrementally is that it means that your idea of done doesn't get in the way of shipping it doesn't get in the way of your success if you have this great big branch that you've done all this work on then you have to get agreement that this is done that this is enough is it done are there more things we need to add and you start having those kinds of conversations you don't get to avoid those conversations entirely but you can kind of um those conversations about whether we're done don't block making the improvements on the app itself and then the last thing is um there are tools to help you enforce these new requirements for new work so let's say you know i have my app with um 200 000 lines of code uh this one's not an ember app it's something else but let's say i have my huge huge app um you know it's really not feasible for me to update like hundreds of components at once but i can install linters and run code mods and just do those styles for new things so every time someone generates a new component it needs to pass all of these new linting rules and that way we at least don't slide backwards as we're making these improvements so there's a bunch of tools that can help you um with making these incremental updates to improve your app style one of them um is built right into ember template lint there's a feature called to do and you can run um a couple different commands that'll take all of the errors in your ember templates that are caught by the linter and turn them into do two to do items you can even say i want this to just be a warning for the next 50 days and then after that i want it to start failing so you can build it right into your app that you're pushing yourself to fix these things by a certain date you can't just say like oh i'm going to open an issue or a ticket and then maybe we'll get around to it in 60 days like no in 60 days the the um the test suite stops passing and you're gonna have to make a decision about whether to extend the time frame fix the problems it like forces you to have that decision as a company oh and another important thing here for this incremental template lending is that many of the rules baked into ember template lint help you to make your app more accessible and so if you again trying to sell the benefit to your end users this is a huge one you're allowing more people to use your app um as they should be able to the next tool here is something called lint to the future this will operate on your javascript files and what it does is something kind of similar to template lint it adds an ignore um to each of the places where your es linter is throwing errors and then it gives you this like graph that helps you track across time how many issues there still are to fix so this one's been pretty stable this is a very stable project but like you could imagine as time goes on you can actually see these graphs go down as you get rid of as you resolve more of these linting errors that's the kind of thing that you can put in your quarterly reports or your sprint wrap ups or like shout out to the rest of your company is like hey look at how and we started with all of these problems we've been gradually chipping away at them and now we're down to zero on these different things um it gives people a sense of progress and momentum if you want to enforce linting requirements for new work so every time someone makes a new component it's got to pass these rules there's tools such as husky this is a generic javascript tool this is an ember specific thing husky lets you say before each commit or before pushing um something new code up it's got to pass these linters you can kind of write basically script to do anything you want um before someone's allowed to push up the code um and if you're going to do something like this uh you know i use that i would use the sense of like enforcement slightly sometimes you just got to get stuff done you don't have enough time to learn how to do the new thing it's important to share with your co-workers how and when and why they are allowed to circumvent a tool like this um because you don't want to make people frustrated and you know hating the process and not able to do their work we want to be more unlike this happy path of gradual improvement so make sure to communicate with everybody else in your team anytime you put these new linting tools in place so they know what to do when they encounter these errors all right so um another aspect here we talked about don't disturb the roots this is just like a general rule of thumb when you go to upgrade your app um and change a whole bunch of syntax it'll be really tempting to do bigger refactors or like just put in tiny little fixes that you find along the way my recommendation is don't change the behavior of the app at the same time as your refactor and upgrade keep a laundry list of the things that could be fixed the things that you find make tickets or issues file them and do them later if you kind of follow these tangents as you find them you're going to get really off track and it's also going to change the nature of the quality assurance testing that you ask other people to do you know if i only do internal refactors i can say to my co-workers hello please click test this there should be no change in behavior once i start making other kinds of changes now i have to say please click test this also i changed out all of these modals to use this other new format can you make sure that those look okay and every time you add a new layer to that it gets harder and harder to qa people don't like to have to review huge pull requests so try to keep it small try not to change too much at once another thing is that you should give yourself permission to skip over tricky things so in this app upgrade there's a few computed properties that i looked at them and i just don't understand what they're doing or why and there's kind of like state happening in like eight different places and you know what i'm not gonna let that block me from installing these linter and fixing these other problems i'm going to ignore that file using my linting tools and come back to it later maybe i'll open an issue that's just for that component so that i can keep moving forward and also know that i'm not going to break what's already there i can give it the time and attention that it needs um and i guess i said stability is your top priority stability is my top priority at least um in my day-to-day work um there's thousands of non-profits and political campaigns that rely on me not breaking stuff um and i take that very seriously um and i try to keep it in my mind you know if i'm getting frustrated like oh i just can't clean up all of this stuff there's still all these messy things i'm feeling bad about it i maybe shouldn't feel bad about it i should maybe think i have prioritized my work in a way that makes sure that my users have a good experience maybe i don't like that it's not as neat and tidy but i can still deliver on my promise to them so i've talked a couple of times about how to ignore linting rules this is one example of how to use um an ignore with eslint so i have just as a code comment eslint disable next line and then i have the rule name um so i can add this above anything that i am not ready to fix yet it's really important though that you come back to fix this someday this is kind of going to hide that there's a problem that's going to hide that there's something that needs to be updated and like this is fine i think through you know computer properties they're part of number four who knows what number five will be will someone be mad at me years later because i ignored all of these rules and then we never had any tickets to go back and fix them like they might they'll be able to hover over this and see jen weber made this change um so try to make sure that you create a plan for fixing these ignores whenever you put them in place and then the last piece here is to measure progress so for my garden i try to take a picture every month because it's easy to forget just how far i have come as i'm working um it helps me to keep a list of all of the work that i've done because otherwise it can feel just like are we even making any progress what did i even do last month i can go back to my list and point to those as my accomplishments when it's time for me to do things like advocate for a promotion or raise for myself or from my co-workers i come back to this list and i can say hey so and so spearheaded this project to resolve like a thousand linting errors in our app and they did it with no downtime and no user bug reports like that's pretty cool and you only really get to know those things if you take the time to quantify them i'm also kind of the boss of my garden so i get to say like what is success but your company um or your teams probably have their own definitions of success if you can tie your progress into your team goals or your organization goals that's going to help you sell this work the next time you need to do this this isn't like we do this once and we get to never do this again we got to do this all the time continually every year and you almost have to think about like selling that work um because there's a thousand different things that we could all be doing how do we know that this is the right thing so some examples would be like how many components got refactored how many lint ignores have we fixed what new features of the framework or libraries that we're using got unlocked how much time did it take what new things did we learn um and if applicable what are the benefits to our users what are the things that we de-risked by doing this work now and keep talking about those things so um in this ember app that i was working on it's not done yet um we are part way through uh we've run all the code mods we've installed the linters we've updated all the library versions we're at the point now where we are refactoring things that the automated tools can't help us with um so to get to this point where now we have to do some by hand work um so far we have changed 153 files 7840 84 lines of code but it was only 30 hours of developer time um you know this is like you know two people times 15 hours has kind of gotten us to this place um and we're like well on our journey to um make this app be like fully octane style and we didn't have to do it at all by hand so again the steps that we followed for this write down a plan budget some time use the tools that you have work incrementally don't disturb the roots and measure your progress as you go if you're interested to learn more about um the labor of maintaining and scaling free and open source software projects there's this really great paper um that was just published this past year at escholarship.org uc slash item slash 3m z2d o kkk um and uh this is a great read even if you're not working on an open source project because it lists out all of the invisible tasks that go into maintaining any software project you can use this to help identify the gaps in your own organization's processes to keep your apps healthy and up to date so again a lot of the details of what i actually did what commands were what problems we ran into they're all here on my blog www.jenweber.dev you can find me on twitter um at jwweber or github jennweber and if you liked this slides theme it came from a site called slides carnival that has free themes thank you for listening i'd be happy to take any questions yeah thank you so much this has been awesome yeah go ahead hey i've got a question not a question but a couple of comments first of all it's so tempting to refactor the whole file like you start touching legacy code and you want to refactor everything in this file like in a waterfall fashion i did it so many times and every time i failed because the more legacy you touch the more risky it becomes and eventually you just give up and revert everything and do the initial tiny changes that you intended to do you log four hours of work time for a tiny change every time i tried to factor in everything i failed the second comment is about a tool called the lint staged it is paired with husky and it lets you lint only the files that you add to a commit and it will ignore other files there are two gutches with this tool one is that you when you cancel a cli command you will see that your changes disappeared and you will have a very frustrating moment thinking that you've lost hours and days of work turns out those go into a gift stash so they're not technically disappeared the second problem is that linstage does not work well with monorepos you only can lint those efficiently sequentially which will take many minutes to run so in a monorepo we ended up not using linstage and pairing husky with just a number of cli commands in a straightforward fashion or yeah thanks for those lint staged tips um that's what i use as well for some of my projects together with husky with regards to the old code the legacy code the risky code um i have found that the best i can do is pair with somebody else if i'm going to tackle one of those risky files and we have a very uh most of the pairing time is dedicated to which thing should we try to change in what order which thing should we absolutely not touch um there's a uh um sandy metz has given a whole bunch of talks about how to refactor this old legacy code um and um kind of one of the central points that sandy makes is that uh you're always gonna have lots of legacy code around there you should take like a structured strategy there's the book 99 bottles of object-oriented programming that covers some of those things um but that when you're refactoring focus your effort on high churn large files those are really really difficult to um refactor but i think you know when we if we imagine just how much time it takes to refactor those big legacy files we need to make like a careful argument for why this file needs to change versus um just like leaving it as is one of my co-workers used to tell me uh this phrase of like isolate the poop which is that you take all of your messy scary complicated code and if it doesn't need to change very often you kind of just put in a little corner by itself and let it be and focus your refactoring efforts on the things that do need to change um over time that need to evolve and grow and like that's another strategy that's helped me out so uh yeah any other questions and yeah i would have one i found it like really really cool that in your talk you showed like all the different ways like which kind of like tools and also like which features in the framework you can actually use to really do with progressive updates and when you were talking about it then i was kind of like thinking oh this is like so interesting like maybe i don't know like five years ago when you were building like javascript apps it would always be like a very kind of like abrupt kind of like change would really kind of like upgrade like in big chunks and this sounded very kind of like fluid and straightforward and i was kind of like wondering um yeah in which kind of like way do you see like the framework kind of like developing even more in this kind of like direction because like you as like a quality member you might also already have like insights into um where this kind of like developer experience experiences going yeah sure um so there's a couple things that ember has specifically done to make this possible um [Music] one is uh that whenever there's a major version of ember we don't introduce lots of new features at once um that basically all theoretically um if you are at the last minor version before a new major release and you've resolved all of your deprecation warnings you should just be able to go to the next major version um that's huge that's not how most of the javascript ecosystem worked for a long time it's still not the case for many libraries but we can see that this pattern is now being used by other projects so i believe the last major react version said um you know this is an incremental change and we're just removing deprecations and like it's meant to be this smooth upgrade path that made me really happy because i can see like maybe they took some inspiration from ember maybe they amber took some inspiration from like a shared source i don't know but like i really want to see that happen in all of the tools that we're using and i think embers played a big role um in terms of that leadership another reason that this is kind of this incremental path is this idea of additions so through lots and lots of hard work from the ember js framework team and their contributors they launched all these new amazing features and ways of building an ember app in such a way that it didn't break stuff with the old style that is incredible there's so much work that goes into making sure that the old stuff still works the same way and you still have the new stuff available so then it means you don't have to do a major version upgrade in order to start using the newest and best way to build components or something like that um so that's like pretty those two things together are pretty incredible um and then there's also the strategies of like like lint of the future and the template lint helpers that let you um change your linting rules over time without causing a huge disruption to your workflows and like you know we have uh the contributors to those projects to thank for making those as well and for kind of following this ethos of incremental updates um and like being cautious about not introducing breaking changes um so what i see happening next is like there's gonna be more editions in ember um the name of the next one has already been announced it's called polaris i don't know any more details about what's in it but uh it's another opportunity where you know as we're working towards the next evolution of what ember apps look like you'll be able to try it in the edition um and you won't have to like convert your whole app to a new style in order to start using the new style which is cool you'll totally fully agree and thank you sure are there any more questions feel free to also post in the chat if you don't want to chat directly and if there are none then yeah thank you so much again like for this amazing talk thank you so much for having me yes sure um and with this we already came to the um end of the amberjs billing meetup september edition thank you so much for um or thank you to all the speakers that gave like amazing talks like tonight also thank you for everyone joining and chiming in if you have like any questions feel free to reach out to us like on twitter or like also i can discord and other than that i hope you have a great morning day evening night whichever time zone you're in you
Info
Channel: Pusher
Views: 436
Rating: undefined out of 5
Keywords: developer language, language code, libraries, help, tips, forum, meet-up, meet up, learn code, coding education, coding hints and tips, lecture, coding lecture, learn about code, learn a developer language, amazon alexa skills, developer conference, node.js, javascript, backend
Id: caBrL8weMps
Channel Id: undefined
Length: 137min 1sec (8221 seconds)
Published: Tue Sep 07 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.