React Chicago July 2020 Virtual Meetup Sponsored by TEKsystems
The Balance of Monoliths and Shared Packages: Lerna, Yarn Workspaces, and Microservices and Libraries
Alex Jewell is a UI Software Engineer at Rally Health, having come from Fiverr, Raise, Designation, and Lightbank before that. With a masters in Human-Computer Interaction but a passion for code, Alex thrives on the frontend where there are React snacks and JavaScript cups of Joe for everyone’s pleasure. In his free time, Alex manages a foodporn account on Instagram (@bestfoodalex), doesn’t shut up about blockchain while his wife is trying to sleep, wrestles with his two good boys (Waffles, a goldendoodle, and Chicken, an Australian labradoodle), and gets a bit too political on the internet.
So we are going to talk about Monori post today, and I even noticed that one of the questions that gets very asked is using Monori bows, you know, and in production environments or for for production environments and sort of an enterprise company where there's a lot more considerations and things that we have to think about. But they can end up being either sort of a nightmare or they can end up being useful. So try to answer that question a little bit as I go through this. Hopefully the presentation itself sort of gives you a window into how we use it at rally and how it is used in the past as well. So I'm Alex Joule, I'm a software engineer at rally we're hiring. So if you guys are looking, definitely let me know. Previously worked at five or I was at Re's Dotcom back in the day before is raises coupon trade. There's like 15 of us then. I worked at a bank before that for a while. So I have some other interests here in the block chain market economics trading. I have an Instagram account, Bestfoods. So if you're curious of where to eat in Chicago, really into politics, social justice and change. And then I have two dogs, chicken and waffles, the brunch group. All right, so we're going to talk about. Circle of life, how how do we end up here? We talk about the tech stack, obviously we're going to go through Lernout pretty extensively because that's mostly what I work with. We're going to look at Yarden workspaces and how that improves dependency. They're going to look at the future and finally got to have those closing thoughts. So the circle of life, Monori, both monoliths now, they can also be called multi reposts, a lot of a lot of different ways and say the same thing. We began back in the day with analysts. We had these early web apps that were often MBM. You had Ruby on Rails. Maybe you maybe had some huge job like object style JavaScript files milage. So you had a bunch of Jacquier in there with your views. And it was sort of a mess. It was really easy to break something else somewhere else. And you had a lot of a lot of risk and release. So what ended up happening, the natural trend was the move to micro services in this became really possible with a lot of JavaScript libraries that allowed us to really run apps differently on the front end and more powerfully. And so the trend in technology allowed us to also fix some of the problems we were having with monoliths. And so you had wrapped in angular giving us the freedom to separate out services. And this broke up our work also and sort of organized it so that especially on larger teams, you could have people working on different apps, different services and also managing versions of things. So you could properly test and make sure that a new version wouldn't break something before that new version ended up in production. However, this sort of ended up being released help if you're having to open papers to upgrade versions along the line of six or seven services, micro services, that's going to take forever. And this is something that we ran into a lot of fiber where, you know, we would we would have like a handful of services. You're opening hours, you're having to build release, watch it build again, wait for it to finish, wait for the new version to be available, get the new version in your next package and on the line. And this ended up being, like I said, really help. And so where we are now is. Some somewhere in between my services, my monitor reports, I think that a lot of different places still have a lot of micro services are trying to manage, you know, what should be its own service and what should be sort of something that's monolithic, because we obviously can make every little thing. We can't make an individual button an app somewhere that you're upgrading versions every time somebody changes a little thing. So what we've ended up doing at rally in terms of front end and in a lot of the projects that I've worked on, at least I'm monitoring, possibly become extremely useful. And so it allows us to separate out our services and organize our code and a lot of the ways that micro services did, but still work quickly and efficiently because all of those separate packages are inside the same rebell. So we're going to talk about how that sort of works. So what's the tech stack here, and I hope you guys enjoy this lovely Venn diagram again, it kind of looks like war between yarn and I'm just like letting off their animals at each other with react like in the middle. So learn is what what we use a lot. It's it's the preferred tool for officially managing rebels. And so what it does is it kind of bootstraps, the complex map of dependencies together for all of those shared packages within the rebels. And we're going to go through a pretty good example with this, what Yoran Workspaces adds to the table. And a lot of people are probably looking at us like you've got NPRM and Yard together. How does that work? What yarns new solution for moderate those workspaces does is allows you to install dependencies across the table rather than for individual packages. Right now, with each individual, package still has its own node modules directory. This is obviously not super efficient. It's it works really well. But if we can make it better or something like Yaroun Workspaces, that's that's not always a bad idea. This cuts down on dependency redundancy. Say that a hundred times fast improves performance. And then obviously, this is a reaction made up, so we'll be looking at how this works specifically and react projects, but just want to make sure that you guys know, learn anything or not, obviously react specific. All right, so this is our oh, I was there's a couple more notes actually I was going to make here, so. There before there is some ways that you could kind of make these things work, AMPM Link was one of them and under the hood, NPRM Link is still being used for something like Lahner. It wasn't a viable solution outside of your local environment and even then is pretty cumbersome. I'm also going to note to yard work workspaces, and this is one of the reasons why I'm not using it super frequently yet, is because it doesn't actually play super nicely when you're using AMPM learn and create react app together. Now, I've seen some people online posting like ways that they've kind of hacked it together using like the create react app required. But I haven't necessarily needed your workspaces so desperately that I've that I've gone to the effort to do that for some projects. OK, so let's talk about Linda. Note, we're using Ampex here as the package runner because it's a little bit more efficient. We're not waiting for things to we're not waiting for everything to install. We're not having to install things globally. So it's pretty nice. Like otherwise, you have to install Lerner globally and that starts to get a little messy. OK, so I'm calling this project where I work on Triniti, you'll see why so we make a directory, learn a trinity, and then we go into it and then inside of that package and learn it in it. And that's really simple. You can see it over here at initializes kind of what learning needs, which is essentially going to be learning that Jason here will go into details on what that that does. You create your packages, so like in this packages directory will go into detail on that is each package that manages the dependencies for booby traps, everything together. So a root directory may eventually look something like this, where you've got your storybook, you have storybook, got your packages, your actual apps, libraries, live scripts. This is, you know, deployment stuff, web pack for all of your apps. And then, of course, you learn that adjacent to your package, Jason, and whatever other DOT files, you know, if you've got Linta or anything like that, get ignored. So. And. So let's look at the example. And so this is what I was talking about in reference to package's. So let's say for let's pretend for a moment that we've got a new new project coming down the pipeline, and this is actually kind of based on a real project that I've worked on. So let's say that you have a new marketing initiative coming through and let's say you need three apps that are going to be extremely similar. For slightly different purposes, that kind of mean that they're going to be accessible in different ways to different audiences and have enough differences where you're obviously not just making it one one at. So this is sort of the perfect example of when to use Ladha. Say we have a partner site that's maybe for like brand partners for that camp campaign. Let's say we have a marketing app that's like the landing page for it to, like, funnel people to convert them. And then let's say we have a member site, and that's a version of the of the app. That's what they're they're trying to we're trying to sell them. Right. And so when you're a member, you have a whole different experience. And then we also maybe have some libraries now, like these are just naming conventions that I've decided these are not specific and it's just sort of for us to know, like, OK, these are our three apps and these are three components. So that I just wanted to note that. But say you have like some shared components, let's say maybe your future stuff is in here and then maybe you have like a bunch of utilities and stuff that you don't want clouting the uses of the other things maybe that are shared between them. Right. So maybe like you have colors in here or something. OK, so this is a really good way to show how I'm honored by my work with Llorona in the real world. And so out of your library components, you have components that are that are exported and then you're able to import them into your apps. So each package has its own package. Jason, it's it's it's literally it's own radical app. It's a standalone react package. But there's a few key differences. The other packages that shares components with should be dev dependencies and the external import dependencies are going to be pure dependencies. And this is how Learn decides how to bootstrap everything together in the right order. And so we kind of know that, like, these apps are going to have a similar design, maybe some of the same components, maybe even some of the same end points. Right. And that's why we have a library, Futcher, utilities, et cetera. All right. So common commands, and this is sort of like your day to day use of learning, like how some of this stuff works, you're going to be doing learn to clean and learn to bootstrap constantly. Sometimes when something's not working, it's going to just clean it as that is the case for most things in life. So there's different ways to manage versioning. This is one of the biggest questions that comes up for when people are learning about learning. There's a way to do independent versioning, and this is that that flag that you see here with it, it allows you to manage or even publish your manage and publish then because you're doing it this way, your packages with independent versions rather than the one single version for the whole rebo, which is what happens by default. LERN allows you to add packages by name either to the overall scope to a specific package. So you can add a certain dependency for everything or for the certain just one of the apps. And so, like I said, too, sometimes it's good to just clean something up when things are going awry. Notes about publishing this isn't something that affects us too often, and this is like a good point. To bring up in reference to a more enterprise solution, obviously, and when you're working with something like Jenkins' and you have a Jenkins' file creating Docker images, et cetera, maybe publishing to like your internalised private repositories where it's scope's using like a factory or something, you're jenkins' files kind of handling that process. Right. But say you're just doing something on your own. You don't really need all that learn. I can handle the publishing registry. So like I said, we use our factory and have some pretty lengthy Jenkins files to the final stages. But you can handle that process just from learn. A few things are simpler and so learning gives you from GIT, which publishes packages tagged in the current commit or from package, which publishes packages out of date in the registry. And these are things that I don't have a lot of experience with personally, but there's a lot of resources on line of how to use those, and they're pretty good for personal use. So importing your components and this is where, like, you know, really how simple this is, like once you kind of set it up a certain way and you know how to, like, npm run bootstrap to kind of get things going on your app. So when we import things the same way that you would from any other skill package, that's a package just happens to be in the same local repo you're working with. And so you can easily see how this cuts out all of the the release process that sort of drains people's lives when you're working with micro services. So if you bundled your library package correctly with Lepik entries from where your components are being exported and you've included the scoped. Package indef dependencies in your actual app package, and you'll be able to import them normally from a couple of important notes, you want to set up ways in the root app to run and watch. Obviously, the current application while you're developing as well as run watch relevant library packages and other taps. So I looked at a script for each app in my root package, Jason, like the following. And so what this allows me to do is say, like, you know, npm run partner, this executes on RPM start a scope to the certain packaged. Using, using underneath. OK, so let's talk about your workspaces a bit and how this can improve your use case just to make things a little bit more efficient. The major benefit of using your own workspaces, we've learned, is that, like I mentioned before, is you only have one node modules directory to support all of your packages. Learning does a great job of managing how to bootstrap your dependencies and packages together. But still, ultimately, it has way too many modules, directories for each package or one for each package and ends up being sort of inefficient. So. What you can do is you can run bootstrap with these workspaces as long as you set it up properly and we'll talk about that and you can create a script in your package, Jason, as well. Simply call it bootstraps. This allows you to to run your bootstrap from now on and line up with Chappuis workspaces. So how do we change to using workspaces? Learn, Dodgson, you change your client a yarn and use workspaces is true, and then you also add where your packages are for workspaces. And then you just renyard or usual, so you can see that both of these things are extremely simple to set up, and they give you a pretty powerful way of like having the best of both worlds in terms of being able to manage micro services, but also avoid the release, how that we talked about in terms of like services. One thing I'll mention about yarn to a lot, there's there's yarn versus AMPM is like one of those things. It's always been a huge discussion. Yarn itself is borne out of the need to have a more and more performant package manager. So what's interesting is that right away, when yarn was released, it had a ton of performance issues, but ultimately it figure them out. And for for a brief moment, it was actually more performant than NPM. NPR's pretty much caught up now. And so there is really a you know, it's really preference at this point. And. So, yep. Let's talk about the future. I think this is this is where things get interesting, because this is how technology always works, right, is that you end up through cycles and you end up in some sometimes convoluted way of solving an issue or solving a problem in this case, ending up with some options for these three separate libraries that kind of change a little bit about how you work and the way technology kind of moves forward is it is it starts offering you new solutions to those things that that somebody somewhere thought was better. Right? That was one of those things. And so a lot of work going into component collaboration tools like that when used in conjunction with Monori, because it can be really powerful ways to share components more efficiently between packages. Really, what I want to talk about in terms of the future is something called model federation, and this is really awesome. I haven't gotten to really, like, implement it anywhere at work yet, but I think it's something that could really benefit benefit us in any any role or position. Like if you're using it for something personal, using it at work, something like Module Federation is going to be huge. It's already an Watpac five. So obviously, minority groups present problems of scalability and can you get resource hungry in the wild for sure? And what Module Federation does is it allows microfinance to work more efficiently together and share their what module federation calls parts cross team. And this is also important, right, because. Even if you're having some sort of minor repo where like several teams are working on, you have like a ton of pictures and things are so easy ways to step on each other's toes. And so what Model Federation does is it allows you to start working with microfinance, going back to micro services a bit, but really efficiently, sharing parts between them, their separate builds. So these parts are compiled as containers, which can be seamlessly consumed by other applications or containers because it's separate, builds its good performance. And it may be a good solution for some people working on particularly large applications across multiple teams with a minor rebo with learning may not be as scalable for that context. And so this is something to keep an eye on for the future, because it's also, like I said, it's already in Watpac, five cents on anything you're having to install separately or deal with separately. Something exciting. OK. So kind of included a quote here, because I want to also discuss, like the importance of being really careful, as you know, you should be with any solution, like not overusing it or using it incorrectly or just building things that you haven't designed well on top of other things that you have designed well. And so one of the first learning projects that I worked with was set up where there are two apps, the root angular Jessep was parallel with a second app in packages as I was angular six and then in the packages directory was a bunch of components that both of them share that were in react angular six J.S. And there wasn't a lot of like planning notes. You you you can't really avoid those things all the time because maybe you started with one small app and you know that those things build on each other over time. So what I really want to caution with this is like don't misuse your power. Don't build on top of poor design, push for the ability to design and go back to the drawing board and decide what's the best solution here and push back. It's not always realistic, but I think that sometimes it's easier for us to say, like, I'm like, I don't need to push back on this. I'll just build on top of something else. And more often than not, if you if you really present it well and you explain the importance of it to your manager or to a team, then people will sort of understand the importance of it. And I don't mean that that's always the case, obviously. Like if you have a serious deadline for some other client or something, that's, you know, I can't really afford that all the time. But as much as possible, push for designing things the right way and not just building a monorail on top of itself. So be contextually smart about how you architect your packages. So that's just a word of warning, if you will. So closing thoughts, I think, you know, it's interesting to see the trajectory of the history of how we've gotten here and where we're going with things like monetary powers and being able to share components easily between my microfinance. And I hope that, you know, if you're if you're in a situation at work where you're or personally where you need to figure out how to share things and you don't want to do a monolith that's out of control and outdated and you don't want to do a bunch of micro services that are unnecessarily cumbersome in terms of release. You know, hopefully this is able to help a little bit. So here's my contact information. If I'm on LinkedIn to and definitely let me know if you're looking for a job, too. Not that tech systems is awesome. Also, let me know if you get. All right. All right.