The Chirpolith: Successfully Migrating A Mess App to Ember
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 27 | |
Author | ||
License | CC Attribution - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/35700 (DOI) | |
Publisher | ||
Release Date | ||
Language | ||
Producer | ||
Production Year | 2018 |
Content Metadata
Subject Area | |
Genre |
EmberConf 201814 / 27
3
4
6
8
12
13
15
16
18
21
22
23
25
26
00:00
VideoconferencingMobile appLinker (computing)Cartesian coordinate systemXMLComputer animationLecture/Conference
00:28
ArchitectureQuicksortDifferent (Kate Ryan album)Physical systemLibrary (computing)Cartesian coordinate systemRight angleMultiplication signLevel (video gaming)Scheduling (computing)State of matterView (database)Decision theoryInterface (computing)CuboidSoftware frameworkProcess (computing)Number
03:05
Product (business)MathematicsPoint (geometry)Cartesian coordinate systemWeb page
03:38
Complex (psychology)MomentumArchitectureView (database)Right angleProcess (computing)Multiplication signNumberCodeMathematicsCartesian coordinate systemPattern matchingView (database)Reduction of orderFigurate numberProjective planeFunctional (mathematics)Pattern languageUniform resource locatorMobile appMomentumComputer animationLecture/Conference
06:01
RoutingEndliche ModelltheorieAuthorizationWave packetConnectivity (graph theory)Bit rateCartesian coordinate systemMultiplication signDebuggerMessage passingMobile appLecture/Conference
06:52
Scripting languageCodeBitMultiplication signVideo gameMobile appLecture/Conference
07:27
CodeFunction (mathematics)Router (computing)Level (video gaming)Default (computer science)Data modelVolumenvisualisierungEuclidean vectorView (database)Mechanism designWeb pageElement (mathematics)Endliche ModelltheorieSystem callRight angleRouter (computing)View (database)Library (computing)BitNumberOffice suiteComputer scienceConnectivity (graph theory)MereologyRoutingQuicksortHookingTable (information)Web browserCache (computing)WritingStructural loadPattern languageEvent horizonComputer animationLecture/Conference
10:15
Computer fileFunction (mathematics)Router (computing)Instance (computer science)Default (computer science)Hash functionMereologyUniform resource locatorBitRoutingAsynchronous Transfer ModeMultiplication signInstance (computer science)Mobile appCodeLink (knot theory)Home pageStructural loadCartesian coordinate systemTable (information)MathematicsCuboidWeb pageNumberLengthConnectivity (graph theory)Hash functionPhysical systemRouter (computing)QuicksortComputer animation
12:47
Euclidean vectorRoutingCodeSingle-precision floating-point formatView (database)Connectivity (graph theory)NumberLogicMultiplication signLecture/Conference
13:18
Euclidean vectorView (database)Uniform resource locatorRootElement (mathematics)Error messageUniform resource locatorFocus (optics)Element (mathematics)Attribute grammarRootConsistencyCodeError messageGoodness of fitData modelMultiplication signView (database)Coordinate systemConnectivity (graph theory)Series (mathematics)Electronic mailing listEndliche ModelltheorieLogicProcess (computing)MathematicsRight angleNumberRoutingComputer animationLecture/Conference
15:38
Mobile appConnectivity (graph theory)Multiplication signPhysical systemMathematicsBitCartesian coordinate systemMeeting/InterviewComputer animationLecture/Conference
16:01
Broadcast programmingComponent-based software engineeringService (economics)CodeEndliche ModelltheorieSpacetimeEmpennageIdentical particlesComplex (psychology)Router (computing)Revision controlScheduling (computing)GodTerm (mathematics)Suite (music)Software testingConnectivity (graph theory)Endliche ModelltheorieQuicksortMobile appBitCartesian coordinate systemWeb pageMultiplication signCASE <Informatik>Link (knot theory)CodeLine (geometry)Branch (computer science)Electronic mailing listGoodness of fitNumberNamespaceRight angleHadamard matrixShape (magazine)Complex (psychology)Computer animation
19:51
Hash functionExecution unitInclusion mapCuboidAmsterdam Ordnance DatumConnectivity (graph theory)Cartesian coordinate systemMobile appWeb page
20:24
Projective planeDifferent (Kate Ryan album)Multiplication signTerm (mathematics)Scripting languageCore dumpNumberTrailMathematicsMobile appQuicksortCodeLecture/Conference
22:07
Multiplication signMathematicsRight angleProduct (business)
22:41
MereologyQuicksortElectronic mailing listCore dumpCodeFrame problemCircleComputer animation
23:09
Endliche ModelltheorieComponent-based software engineeringCodeEuclidean vectorMobile appFrame problemCartesian coordinate systemDebuggerEntire functionMereologyMomentumConnectivity (graph theory)Computer architectureEndliche ModelltheorieMultiplication signWordOnline helpCodeRoutingMobile appComputer animation
24:32
Linker (computing)AverageDaylight saving timeSquare numberLecture/ConferenceComputer animation
24:51
Coma BerenicesBlock (periodic table)Data typeComputer animationXML
Transcript: English(auto-generated)
00:17
Yeah, so my name's Alex Rossenburg and I'm going to be talking about the Chirpilas and
00:22
how we spent the last year migrating our messy application to Ember. So I work at a company called Iora Health and we're founded by doctors and our mission is to restore humanity to healthcare. So we do that by running primary care practices around the country where we serve
00:43
about 15,000 patients right now and you know if you've been to your doctor recently you've probably noticed them in the corner typing on a computer and if you've looked over their shoulder you may have seen sort of an ugly application with lots of gray boxes and complicated interface it's hard to understand.
01:00
And that's because those applications are typically been built for billing systems for insurance reasons not for patient care. So you know our CEO had used a lot of those systems in the past and one of the first decisions we made as a company was we were going to build our own because he hated pretty much everything he had used in the past. So we call our system Chirp and you know it's really designed to do everything that we
01:27
need to do to help the practices run. So everything from scheduling to documenting a visit to ordering labs to you know refilling prescriptions and you know from day one it's been a JavaScript heavy application
01:42
because we wanted it to be friendly and easy to use and really get out of the way between the doctor and the patient. But you know day one was a long time ago. So we started building it back in 2011 and at the time the state of the art for JavaScript was backbone. So we started as a backbone application and backbone was great but it's much lower level
02:02
than a tool like Ember is today right it's a much lower level library. And before long we realized we weren't only building our own application we were building a custom ad hoc framework on top of backbone. So you know we looked around the community and there was something called backbone marionette that was emerging.
02:21
So we start to take pieces of our application extract them into separate application built using backbone marionette and that worked well but we know we kept looking around and we saw ember and you know we got excited about ember so we did the same thing we took other pieces of our application extracted it out and you know you can imagine right
02:41
we're beginning to get a pretty messy system right lots of different technologies lots of different applications but you know we weren't even done yet because we also looked around and we saw react and you know we thought you know this time we wouldn't make the same mistake we'd do something different so reactive view layer we thought can we just use it as a view layer inside our backbone application and we did that
03:04
and that worked pretty well but you know we had really sort of painted ourselves into a corner you know at this point we had a pretty complicated you know bunch of technology and bunch of application that we as engineers didn't really want to work on and to the product team it was frustrating to them because everything was expensive
03:24
and hard to make changes to so you know it took us about five years to create this mess and what I'm going to talk about is how we spent you know basically the last year plus digging ourselves out of this mess so you know what we decided was we weren't
03:41
going to make the same mistakes we made in the past we're probably going to make our own special new mistakes but you know we're going to try and learn from the past so we thought about the things we had done wrong before you know and you know the first thing is you know each time we tried to dig ourselves out we didn't really know where we were headed so we knew the small little thing but if it was wildly successful
04:03
we didn't know what wild success would look like so this time we decided on a wild success would look like a nice clean member app you know something similar to what you would create if we'd start in a greenfield world instead of the brownfield world we were in you know the second thing we did is each time we extracted a chunk of functionality
04:21
we did is a big bang release right so users saw nothing nothing nothing and then we dropped this big change on them so we weren't going to do that again we were going to work in really small incremental changes you know the last thing we did is each change just made our world more and more complex so we weren't going to do that right we were going to reduce the number of technologies we had reduce the number of applications and the last thing is we
04:44
can never you know maintain our momentum every time we started off it started like gangbusters but then we you know we lost you know we lost interest we lost motivation and you know this so we came up with some techniques to keep motivation throughout this process
05:01
so because we had worked with all these technologies in the past you know we realized that you know if you squinted hard enough so you ignored all the details about the application they'll pretty much do the same thing right so they take a url in they do some pattern matching on the url to figure out what to do with it they call some api so load your
05:21
data and then they build an interactive dom you know with that data in it and you know that was true of all of them and we also realized that from when we had done the experiment with you know using react as our view layer inside the backbone app you can mix these technologies together so we thought what if we did the same thing as that experiment but we flipped it around
05:42
what if we put ember in charge let it take over the routing layer but made use of all of our existing backbone code and then slowly over time we could replace that backbone code with ember code until we'd end up with a nice clean ember app so that's you know the project i'm going to talk about and what we did so let's get started so the first thing
06:05
we needed to do if we were aiming towards having a nice clean ember app at the end of the day was we needed to admit we didn't know how to do that so we brought in mike north from front end masters to do some training and and it was really great you know he came in for a couple
06:23
days and really gave us a great foundation of how ember worked the philosophy behind ember how to think of routes components models right all of it but something else he gave us was also just a voice of authority so later when the time came to start building our application
06:40
and we would begin to get into the religious debates that all teams get into we could back off and say let's just do it the way we learned in training and cut those debates off at the pass so we want to build a nice clean ember app you know we did it the way all of you guys would do it right ember knew we'd start our ember app
07:02
but you know we weren't really building a greenfield app this was a brownfield world so we had to do a little bit of work to integrate it with our existing build scripts our existing deployment scripts and you know basically we treated all of our legacy backbone code as a third-party vendor code so we could just call into it by
07:20
loading it that way so now we had a nice ember app that did absolutely nothing the time came to make it start doing something so you know we started the top layer with the router and you know one of the things that our doctors do a lot in the office is they're documenting the visit right so they're writing notes and reading the old notes to remind them
07:42
what happened in previous visits and you know we looked at our old backbone routing tables and you know when we started creating the ember routes you know they they did the same things but the fact that ember pushed us into having these nice nested routes
08:00
all of a sudden got us really excited right so when we started having a note view route a note show route it could really focus on just the note right it didn't have to load the patient and everything else for the other parts of the page right we had an ancestor route that could take care of all that and the note show route could really just focus on the note
08:21
so we went in and started building that route out and you know when you typically think of building a route and the model hook right you you're probably used to thinking of calling into ember data to load your model but there's nothing that says it has to be ember data so we were able to call into our old backbone model and load the data that way which was great and
08:45
if you look really carefully here you might notice right this is not just loading the note it's get or fetch because in our old backbone world we didn't have something like ember data that would do some intelligent caching of what's in the browser what's already been loaded or not so we built our own caching mechanism and you know it's kind of a joke in computer
09:06
science that caching is one of the hard problems but it really is one of the hard problems and we really didn't want to be in the business of maintaining our own caching library so again we were excited for the day where this would go away and we could just live in ember data land where this would take care we would take care of this for us so we had our route
09:26
we went in to build the component so we did pretty much a similar pattern where we would call into our old backbone view that would load the view for us passing in you know the model which remember is the backbone model so it all worked fine and the only trick here
09:46
was we had to get that backbone view to render itself in the part of the page that ember had set aside for the component so it turned out that wasn't that hard you know in the component we could ask the component for the DOM element that ember set
10:01
aside for us and just pass that into the backbone view and it would render itself so the last thing we did is just a little bit of cleanup when ember tears down the component we just tell the backbone view to clean up after itself unbind events whatever else it might need to do so will this work and you know the answer is for the most part yes you know inside the
10:22
red box we have that component we just built right so it is loading data from the API and displaying it on the page so that that was great but if you look up at the top you can see a link to notes so that's taking us back to the index page of all notes and if you sort of look carefully at the link here right starting with a hash and again that's because back when we
10:45
started this application you know hash URLs was how you did front-end navigation now of course that's not going to work in a modern ember app where we use real URLs so you know at first you know we all started getting depressed this was you know we were going to have to go into
11:01
all of our old code find all the links and start rewriting them and that seemed like a huge pain and exactly what we want to avoid which is you know going into that old backbone code but you know then we realized ember was actually gave us the tools where we didn't have to do that so we wrote now a little bit of code stuck in an instance initializer and what it
11:23
does is it uses ember's hash location API to ask it to notify us anytime the hash URL changes and whenever it does we just strip off that leading hash and send the rest of the URL into the ember router where you know if it's a URL that we've already rewritten and we have a route
11:41
for everything's going to work great you know the ember router will route it to the appropriate route and if it doesn't we just stuck you know a new wildcard route at the bottom of our routing table that would navigate us out of our new ember app back to the old legacy app and you know once we did that it actually worked you know we could
12:01
not only display the data but we could link back you know across you know URLs and links worked as well you know but there was a problem now navigating between two apps was really slow you know every time you leave an app you know you left the ember app loaded the backbone app you click to link load the ember app right loading a new app takes time so you know
12:24
luckily we had a good feature toggling system so we were able to keep you know migrating these routes and releasing them without turning them on for users so without inflicting that slow pain on our users and took about six weeks for us to get all you know 32 of our routes migrated
12:42
over and then we were able to turn it on for all our users and that made us really happy because then we were able to start deleting some backbone code right all the old backbone routes were unused so we started deleting and we felt like we were on our way so once we had these
13:01
you know 32 routes in place each one wrapping a single backbone or yeah each one with its own component and each component wrapping a single backbone view it's time to start rewriting you know those backbone views and putting the logic into ember but before too long we started seeing pull requests that looked like this you know they were enormous they were too big to
13:24
deal with you know too big to review too big to you know make the changes incrementally and quickly so what was going on so we thought we were living in a world like this where you had one component wrapping one view but once we dug into the backbone a little more you know each
13:41
view is really coordinating with many child views and there's you know just a lot of logic in there so we did what you do when you have a problem that's too big to handle and we broke it down to a series of smaller problems so we realized if we could wrap each of those child views and then replace you know that coordination from backbone in ember now we had you know smaller
14:04
problems and we could just rewrite each component one at a time until we were left with a clean ember you know pure ember ember only solution so that's how we rewrote the view later but what about the data right we didn't want to deal with backbone models we wanted ember data models
14:20
so we had to also rewrite the model layer and you know we thought we had done a really good job designing our apis that we were really consistent but once we moved into an ember data land which really pushes towards the consistency and anything that's not you know conventional it you got to fight ember data on we realized we weren't so you know we usually had root
14:45
elements but not always we sometimes had two different URLs serving the same resource often with slightly different attributes coming down and you know some of our URLs were non-restful and you know we'd built our own homegrown errors and pagination
15:01
solution so we were able to work through all these problems but there was pain and you know we started asking ourselves should we just rewrite our apis you know in something like JSON API or GraphQL you know something conventional and you know the answer was maybe we should but not right now that we wanted to you know keep our focus on deleting backbone
15:22
code and rewriting the apis was a good idea but wasn't going to help us delete backbone code so you know basically we had a list of technical debt that we'd get to later and we put it on the list and we moved on with the existing apis and now we were in a place where we had a system and we could work through these components one at a time
15:43
and tackle them and make the changes so so that was all good now I want to you know switch gears a little bit and talk about some of the other problems we had made you know when we had extracted all those different applications so one of the applications we had
16:02
was our scheduling application where you know you'd schedule patient visits see who's coming in for the day and you know a really common use case was to go from the schedule into a patient's face sheet back to the schedule you'd go back and forth a lot and that's the same problem we had before where you're leaving an ember app loading a new ember app leaving that ember app
16:23
loading a new ember out right so it's the same problem of it being slow in the past when everything was sort of slow you know users noticed but didn't notice a huge amount as we migrate more and more into ember and the ember apps are getting faster users didn't always notice
16:40
the app getting faster they noticed the things that remained feeling slower so we knew we had to tackle this problem and this is where we decided to take the chirp face sheet and the chirp scheduling app and combine them together into one chirp list and so you know the problem we had when you know combining two apps is similar to the problems you have when you're merging two
17:05
git branches right you know as long as you have no conflicts it goes super smoothly but anytime there are conflicts you know you're in a world of pain so where you know where did we see the conflicts you know the first place we saw conflicts was just in our own code so that could
17:21
be you know any you know any of the code we wrote you know routers models components and pretty much if you had the same thing that was named the same way but was not exactly identical that's a potential conflict so for example you know both of these two apps had a patient details page and in the face sheet right the patient details displayed pretty much everything
17:45
about the patient whereas in the scheduling app it displayed just a little bit about the patient and a link over to the face sheet page so we realized what we could do before merging them was just to namespace each of them differently so instead of calling them both patient details
18:01
we'd call them you know rename it so it's the face sheet patient details and the scheduling patient details that way when the merge happens there's no conflict you wind up with two separate components and again you know somewhere down the line we can decide how to merge you know how to actually combine them if they really are doing the same thing so the other place we saw conflicts was in our package json and you know immediately we
18:25
realized things like ember js had to be on the same version in both applications but what surprised us was there were other packages that were only in the face sheet or only in the scheduling app that we didn't think would cause any problems but once we combined them both into the same
18:42
package json there were you know surprising conflicts that we didn't expect so the way we solved that was to just you know basically add all the missing packages from one application to the other and vice versa until we wound up with two package jasons that were identical in the original apps and then the merge could go through smoothly in this case you know having
19:05
a really good test suite helped you know saved our bacon in terms of knowing you know when things failed and working through them in small pieces rather than you know a huge thing where everything's broken god knows why so you know so we were able to do the merge successfully
19:22
and it went really well but you know it again it sort of distracted us from deleting the backbone code in the scheduling case it was really important right our users were feeling real pain and it was the right thing to do but you know we had a bunch of other apps and we didn't want to pay that price of doing the merge and you know spending all that time
19:45
on it instead of deleting backbone code so we wondered you know was there a different solution and we came up with you know an old favorite or an old you know not a favorite the iframe you know we realized if we built a component that had an iframe in it and we changed you know those
20:02
other apps to be skinned so they would fit nicely in this red box with no nav bar or anything like that you know this component could just load a brand new other application inside of it so this is the approach we went to you know to merge or to fake merge all of our other applications now the last thing i want to talk about is
20:29
how we stayed motivated over time so you know we worked on this project for a little over a year and you know a year is a long time so we you know came up with a bunch of different
20:41
techniques that helped us stay motivated and the first one was drawing a pretty picture so what we did is we wrote some scripts that would just count up you know the number of bytes of backbone code in our app and the number of bytes of ember code in our app and you know every monday morning we ran that script and updated this chart so that we could see over time you know
21:02
the red bar is going down we were deleting backbone code and again right it made us feel good to know that we were on the right track here in fact you know this chart you know i made this chart my home page that i'd come in and i'd see it you know first thing because it was really exciting and if you look closely sort of over in the bottom right corner
21:21
we're this close away to getting you know the last of that backbone out but didn't quite make it in time for today so the second thing we did is we defined what we were doing in business terms so we said you know a core goal of our team was to speed up our ability to deliver changes to the chart and the reason for this is you know technical initiatives often get
21:44
deprioritized and forgotten about compared to user facing initiatives so and that did happen to us but having this written down in black and white and sort of agreed as a core goal of our team helped us you know whenever that started to happen was to you know reprioritize it and bring
22:02
it back into discussion instead of being forgotten about forever and you know on the flip side you know it can be exhausting you know as an engineer to work on technical cleanup for a year so over this time you know we kept shipping features we you know we didn't only work on this we also did stuff to help our users and to make
22:24
chirp better and you know in fact somewhere midway through the year our users and our product team started getting excited when they saw that changes were becoming easier right it became faster to make these changes and we started getting payoff in doing these you know and the last
22:42
thing we did and this you know I sort of mentioned when we were talking about our API redesign or the iframes is things that were not part of our core goal of deleting backbone code we you know shamelessly put them on a technical debt list of things to get to later and you know so far it's worked out well for us in that you know it hasn't been a black hole
23:03
of things that just get forgotten about you know we have circled back to them and taken care of them and gotten them done so where are we today and basically over the last year we have you know swapped out our entire front-end application from underneath our users
23:20
you know for the most part without them noticing so that's been really good and today you know we have about 95 routes 75 models you know over 200 components which you know I don't know if that feels like a big app to you it feels pretty big to us and you know how we did this was just by remembering that you know at the end of the
23:44
day we were aiming towards having a nice clean Ember app by really focusing on the small incremental releases by reusing as much of our backbone code as we could in the beginning by rewriting one component at a time and by you know deferring everything that was off the critical
24:01
path of deleting backbone code and we also you know focused on simplifying our architecture so we wanted you know to have one application one technology so it's so much easier now that we you know when we have to work on this code base we can go in and think Ember rather than go in and think was this the backbone piece or the marionette piece or maybe
24:22
the piece with a little react so so much easier to do that and then all those tricks I just talked about right to help us stay motivated and keep the momentum as we went of course I'm standing up here today but it's you know thanks to the whole team who worked on this that we got it done so thank you guys very much