 Great story. Yeah, we are. Good morning, everyone. Welcome to Dev Nation Day, Modern App Dev December 12th. Greetings, developers, and welcome to a day dedicated to accelerating your business transformation and unlocking the power of cloud data technologies with your unique enterprise applications. Today, you'll have the opportunity to learn from Red Hat experts and practitioners and gain valuable insights in the best practices in application development for the hybrid cloud using Red Hat OpenShift in Kubernetes. This event promises to be packed with information you can readily apply to your own projects, dive deep into a variety of learning tracks, each led by industry experts covering a vast landscape of topics such as AIML, app modernization, integration, serverless computing, security, event-driven architecture, internal development platforms, containers, application architecture, and much, much more. I'm not sure how much more we can pack into a day. In addition to learning tracks, you'll have the ability to take advantage of some interactive virtual labs where you can gain hands-on experience with Red Hat's technologies. And also be sure to check out our keynote today from Red Hat and Intel, and then hear about the winner of the recent Hackathon event. Just a couple of logistics for today. There are three sessions going on in parallel, so feel free to join whichever track that interests you and you're welcome to hop between tracks as you go. Be sure to join our keynotes. I mentioned that will be held over on the main stage, so you'll need to pop over to the main stage at 10 a.m. Eastern for the keynote and then rejoin the tracks afterwards from that point. For any questions you may have at this point, just drop them into the comments section, and if we have time or as we have time, we'll try to field those at the end of these sessions. So with that, I'd like to hand over to Jeremy Davis who will be presenting today on avoiding microservices madness with majestic monoliths. And Jeremy, it looks like we need you to share your slides real quick here as well as we get the coffee going this morning. I'm gonna share my entire screen here. Perfect. And I'll just bounce over to my slides. So we'll get the little super haul there. All right, so here's my slides. So thanks for joining this morning or afternoon, depending upon where you are. If it's kind of early, hopefully you grab a cup of coffee and sit back for this session on avoiding microservices madness with majestic monoliths. My name is Jeremy Davis. You can find me here on my slide, Jeremy.Davis at redhat.com. You can find me on the various socials over there. I go by the Tag Arrogant Programmer. So you can find me on Twitter, Threads, and Mastodon. Mastodon at techhop.social. Feel free, if you have any questions, comments, feedback, please reach out to me and let me know. Hopefully you'll find this content interesting. So my quick background, I've been at Red Hat for 13 years, working mostly with application development technologies. The past few years really heavily with cloud related things. And microservices popped up about seven years ago. I became very enamored of the notion of microservices as I think most of the deaf world did at the time. The guys that coined the phrase, Martin Fowler, who coined the phrase microservices, cautioned people not to start projects with microservices. Of course I did that, just that. I think a lot of other people did as well and found themselves in some painful situations. And then a couple of years, and a situation like this, right? So you ended with the microservices death star, right? With like services that explode everywhere. And it becomes very difficult to version across these. Often they become coupled together. So you end up with like some of these, but end up being distributive monoliths. But there were a lot of problems in building microservices, isn't it? And having done a couple of projects with this architecture, I was reminded of Fowler's caution not to begin with microservices. And then I read this blog post, or a couple of blog posts by David Hannemeyer Hansen. If you remember him or if you're not aware of him, he's the guy that created Ruby on Rails. Recently he's created his own alternative to Kubernetes. So he's always an interesting guy to follow. It's interesting to follow his blog to get his take on things. But early on in the microservices days, he talked about what he called majestic monolith. And he's with a company called 37 Signals. They're a SaaS software company. And in his blog post here, the majestic monolith, he talked about how people were asking him, when are you going to refactor to microservices? And his answer was never. And the reason he wasn't going to do that was that they went to production every Friday. And typically speaking, the reason you want to move to microservices or a microservices architecture is so that you can get features in front of your customers quicker than you do at present. And he said for his company, going to production every Friday was fine. So a one week cycle of accepting a story to putting it into production was okay. He didn't need to go faster than that. And so he wasn't going to take on the added headache or the added overhead of distributed computing, which if you've built microservices, you know that there is significant added overhead and added headache. He followed that up a bit later with this second blog post called the majestic monolith becoming a citadel. And the notion behind this is you can extract a microservice. When we talk about taking legacy code, we often talk about a strangler pattern, right? We sort of strangle the existing monolith and pull out microservices one at a time. Well, this is a little bit of a different approach. And this approach is leave most of the application as a monolith and then pull out the pieces that you do need to scale. And this resonated with me because one of the customers, in fact, one of the first customers I worked with in refactoring an application to a microservices architecture, the reason that we did that was because of a particular part of the application had a hard time scaling, right? One of the things about monoliths is you have to scale the entire monolith. And this customer, there was a section of the application that did some really hardcore processing and they were having to scale up lots and lots of application servers to be able to meet that processing needs. And we thought, you know what? What if we just pull that out into a microservices architecture? We can kind of leave the rest or split it into maybe just one or two services and then we can scale those services individually, right? So we were able to scale up this one particular service that needed a lot of power, whereas the rest kind of just coasted along. So I thought this was a really good idea. And having built a couple of microservices applications, I decided that I would try Martin Fowler's approach of start with a monolith and then if we need to extract some of the code into a microservice. And so here's seven things that I think can help you do that or it can help you do that. And the seven things really quickly embrace code quality, commit to continuous, at least continuous-ish delivery, domain-driven design and bounded contexts which has nothing particularly to do with microservices but picked up a lot of speed once microservices popped up because a microservice and a domain or a microservice matches a bounded context. And so people began looking at that again. Still a great practice, great way to build your applications. Also putting APIs first and I don't just mean REST APIs or GraphQL APIs or Kafka and Avro. There's different ways you can look at APIs. Another thing is making data autonomous if you can from the very start. One of the bottlenecks traditionally for microservices architectures, especially if you're moving legacy code to microservices is that your data ties you together. Applications have single data sources. If you can avoid that when you start, you get a lot of flexibility. And then eventually Citadel's an outpost. Implementing the Citadel's an outpost pattern so you can pull out some functionality and turn that into an outpost from your microservice. All right, so first things first, code quality. There's a lot of different type things you can use for code quality. And I'm a fan of sticking some of these things inside of your Maven palm file when you build it. So let's jump over here. I mentioned I'm gonna do a lot of jumping around. So can you guys see that? Okay, I guess I can't really hear anybody. Let me pop this, I'll make this a little bit bigger font, a little bit bigger. Let's go to 24, see if that helps a bit. Is that better? Yeah, maybe a little bit bigger than that. 24, where are we? All right, maybe. All right, let's say Quarkus create app. And I'm gonna use Quarkus for this. There's not really any specific, there's one little bit of specific Quarkus-ness, but only one, create app, auto, arrogant, pro, grammar, colon. We're gonna use the domain, since it's winter I thought it'd be fun to have a hot chocolate pop-up truck, right? So I'll have a hot chocolate pop-up truck. And I think pop-up truck's a good argument for monoliths because pop-up truck doesn't need a full microservices architecture. We can probably just get by on a monolith and we'll say extensions equals, what do we use? We use hibernate, rm, panache. We'll use JDBC Postgres for our database and we'll use rest easy reactive with Jackson. So we got Quarkus to create the app, I've got a Quarkus CLI installed. Okay, there's my application. Let's go, let's CD, hot chocolate, pop-up. Whoops, do I already have one running? Do I already have one running? I do already have one running. All right, so this is a really basic application here. It comes with some tests. So Quarkus apps, you can see this, comes with some code already written and some tests, right? So we've got some tests. What I'm gonna do for test quality is I'm gonna add to my palm file here. And I like doing, does anybody else like doing this? I like demarcating my tests. So I'm just gonna say. And now I'm gonna cheat here. I'm gonna copy and paste this over here. So what I'm adding is Quarkus build of Jacoco and Jacoco is gonna give us code coverage. So when we run this, let's go ahead and just run this application here in the terminal. Say maven clean test. What we're gonna notice here in our, when we run our tests, our test should all pass. Let's hope they all pass. So this is a brand new generated application. Okay. Inside of our target file folder here, we have a Jacoco report. Can you guys see this? Jacoco report. And we've got an index file. Let's open this, let's say open in a browser. These Chrome here. So this is our tests, right? And this has got my package with tests. And it even goes in and shows us, if you haven't seen this before, Jacoco goes in and shows us every method that was covered. Add another method. Let's just go add another method with this greeting resource here. Let's just add a post really quickly. And we'll say, add post. We'll say, yeah, produces text plain, public, string hello, it's a post method. So we'll take a string name and then we'll say hello, plus. And then when we run our tests again, right this time I'm gonna get some red, right? So I'm not gonna cover this. All right, there's our test running. All our stuff spinning up. So when we come here now, we've got some red, right? So I'm not covering all my tests. I think this is really nice and useful. There's all kinds of stuff you can do. One of them, I have a tab of that open. So ArcUnit is another really interesting one that I like doing. This is your architects can come in and define notes. So if we look, so I thought I had this thing popped up already, documentation on this. So in this case, you can have these architecture, they're GitHub site. This allows you to do all kinds of, no, examples, here we go. So the examples are really great and you can really tie into all kinds of stuff that you want to have, right? So just look at like, test, let me look at the test here. Coding rules test, right? So you can say like, no generic exceptions, right? No Java util logging, right? If you don't want your teams using logging, you can have a rule and you can break builds based on this. So certain things I think you can break builds with. Other things I think it's just kind of nice to have. So like, this is really nice if you want to build this up for your teams. It's really good to make sure you don't get, nothing sneaks its way into your code. This stuff, I don't think that everything has to have coverage. I mean, this should have coverage, right? But getters and setters don't necessarily need coverage. So I wouldn't break a build on something like this, but on like an architecture unit thing, maybe you would want to break a build. Like if you really want to make sure people aren't using certain classes. Anyway, the idea is include this stuff, make it part of your build file, right? So second is continuous-ish delivery. Now, I don't know how many people here go to production all the time. I started off talking about David Hannah Meyer Hansen at 37 Signals and they go to production on Fridays. I have some friends who've worked at startups that go to production multiple times a day. I think that's really awesome. But I don't think most of the enterprise does that. I think most of the enterprise has kind of a process to go to production. So I think what's really key is to be able to deploy at any time. Meaning half pipelines built. You can have your pipelines built on Tecton. This is running on OpenShift here. We can do Tecton. You can do them on GitHub builds. You can put a GitHub build YAML file, right? So all you have to do for a GitHub build here is we can come over here, create a new folder, directory.github.workflows, and then we can just have a file like build.yaml. And I've got to build YAML here. I'm gonna cheat again. I can't really live code a whole bunch of YAML stuff. So let me build with the YAML. When we check this in GitHub, we can create a directory and it'll kick off that build. Actually, let's do that right now. Let's say unless we're get in it. In it. Let's hide this. Get in it. A-M-G-H-R-E-P-O. Create public source. Oh, create. We need the name of the repo. What are we gonna call this? Call this a chocolate pop-up and public source and push. All right. So that push to GitHub and we should have a build started. GitHub, Jeremy Davis, repositories, hot chocolate pop-up and we'll see our actions running. We do. So our build is running, right? So we've got a build running already. It's gonna run those tests, which actually we're not gonna be covered that well, but it's gonna run those tests. It's gonna create our application, right? So just the thing is, make sure you've got some kind of pipeline in place. So it's that easy to just get started doing pipelines. Make sure you have that stuff in place. All right. So number three, domain-driven design. Domain-driven design is an old idea. I liked it a lot. I remember reading about it way long ago, maybe 13 or 14 years ago, I think, when the book came out. It gained a lot of traction again when microservices popped up. And domain-driven design is about how to handle complex business logic. But there's also ideas inside of DDD that made it marry very well to microservices architectures. And so it sort of has had a resurgence over the past few years. Now, the first thing to know about domain-driven design, if you haven't used it before, is domains are parts of your application, right? So if we're thinking about a pop-up truck, right? We've got a window, right? Because you go up to the window to make your orders and you go up to the window to get your orders. You've got a barista who's making drinks. You've got some credit card validation, right? Because you gotta swipe your credit card, tap your credit card. And then maybe you have to do some social media or some other things like that, right? And in a microservices architecture, you would typically have a microservice that would deal with each one of these particular areas. Now, in a monolithic application, we're not gonna do that. So what we're gonna do is we're gonna make it, whoops, about our package design. So let's look over at our application here. And let's go into presentation mode. Let's go into our presentation mode and come over here. All right, so we'll get rid of all this extra stuff here that was generated for us. Delete that stuff, yeah, delete those things. Delete that stuff, so delete those things. Now, new package, so let's create a new package and we'll have a, what are we, hot chocolate popup, right? Now, we go back to those domains, right? And we're gonna make each one of these a package. So we'll have a package for truck window, right? Because windows can be a little problematic inside a Java space, right? All these things that used to have windows. So we have a truck window, we'll have another package. We will have our barista, right? So barista, we'll have another package. We had credit card, credit card, or we could say payments, whatever we wanna call it, it doesn't really matter. And then, what else do we have like social media, right? We won't build out all this stuff. But the idea here is that we're going to keep stuff separate here. And inside of domain-driven design, this also means if we do wanna pull these out into microservices, so let's say we wanna eventually pull our barista out, barista's already encapsulated inside of its own thing. So it'll make it easier to separate that out. Now, bounding contexts, so yeah, we have baristas, we have our counter, we have, we don't have a kitchen here, but we've got these various different pieces. So I also wanna talk about APIs and APIs first. We'll get back to domain-driven design in just a second too. So I attended a talk many, many years ago that was delivered by one of my, somebody else in Atlanta, I live in Atlanta, Georgia, at the Atlanta Java Users Group on user experience. And one of the things that the presenter, Guy Burkhoff-Nagel, he's one of the leaders of Ajug and he presented at Java One that year, the same presentation. And he asked about user experience and he was talking to a bunch of Java developers, right? So he said, how many of you guys make front-end code? Like a couple of people. And then he asked who made back-end code and it was everybody, right? And so he then asked, well, who, how many of you make code that is consumed by other people, right? So do you think about your user experience for other developers? And it made me think, it really changed the way that I wrote code a lot. And so we talked about some of these kind of best practices here, but one of the things that I took away from that and really like to do is to have an API package for each of these. And when we communicate through these very, or the various parts of our model here, our various parts of our application, whoops. Where is my window? Oh, we're in presentation mode, all right, there we go. All right, so when we come here, we'll have an API, right? So for our barista, we'll have an API, I'll say barista API and make an interface for that, right? And we can have, for instance, make version, right? And maybe we'll have, you know, we'll call it a ticket, right? At the moment, we won't have a domain model yet. We'll call it a ticket. So we'll have a make beverage and we'll say like, you know, take it. So we'll have these methods. And then when the rest of the application talks to the barista, we'll use this API and we'll come back to doing that. So when we go back to that, first we'll go back to domain-driven design again. And some of the domain-driven design constructs that you'll run into, aggregates, value objects, services, and repositories. So if we look at what these mean, so our package structure does match our bounded constructs. So let's talk about some of these other objects that we have here. How am I doing on time? We're doing all right on time. So what I wanna do, let's start off with our window, right? So we need a way to get into this thing and it's fun. Let's get this application running. So one sort of construction we'll say, we'll have an infra structure package and a domain package. So in our infrastructure package, let's get something going on here. Let's get a truck window resource. And for this, we're gonna say path. And we're going to, let's say, consumes media type. Oh, come on, application JSON, Autograph, there we go. And produces JSON. And let's have a post public, we will say, wristter ticket, place order. I'm gonna say a place order command. And this is gonna be a domain driven design construct, right? So we're gonna use, these are both gonna be value objects, which will be immutable objects. We're not gonna persist these things. Let's get a logger in here so we can log things. Say logger, see order for place order command. We don't have place order command yet. So let's create our place order command object. Now, one of the things we would wanna do, we'll create a record for this. As mentioned, they're immutable objects, Java records marry really, really nicely with this. And typically, we would put this in our domain package, right? This is part of our domain. Put that in our domain, add that. And our record for place order command, we need what? We need a string name, and we probably need a beverage, right? Beverage, beverage, and we don't need a quantity. And we could have like a total, probably like a double, you know, total, right? So we can get paid for this. Now, let's create our beverage here. Create an enum called beverage, put that in our domain as well. And let's see what hot chocolate. So let's have like hot chocolate. Let's have like peppermint, hot chocolate, salty caramel, hot chocolate, yeah. Jeremy, let me interrupt you real quick. Got some comments coming from the audience. It looks like the screen that you're sharing, right now you're showing your slide deck and not the IDE. Ah, all right, how about now? Can you guys see my? Yep, now we see the ID. Ah, so presentation mode is not working. All right, sorry, thank you for mentioning that. Sorry about that. I will very quickly go back over what we've got going on here. So this is a resource. So I've got an endpoint called window. That's our truck window resource. And did you guys see the other stuff I did? So darn. All right, so we've got a couple of value objects. Value objects are immutable objects. So we're gonna use a record. We're gonna put that in our domain package, not in all caps. And ticket will have our, we'll call it an ID. Just running name. All right, so we will have a rest, a post command. We'll get this place order command. And then we'll say logger info received order. And right now we'll just return new ticket. Return a new ticket like this. All right, so let's fire, let's get Quarkus running too. Terminal, completion failure on, orista API, go back to this. I'm just gonna delete that for the moment. We'll get Quarkus running here and we'll send over some hot chocolates, ID. All right, there we go. We're not sticking in a database or IDs null right now. All right, so a couple of notions, couple of things here. The idea we've got in our domain, we have value objects, right? So these objects are immutable, right? The beverage, the place order, beverage and enum, but place order command and tickets are both Java records, right? Meaning that we can't do anything with them. So we're not gonna store this in database, they just provide information. It's just a way to move information back and forth. Blides, a way to move information back and forth, right? So that's what a value object is. So an aggregate is something that we're going to stick inside of the database and our aggregate in this case will create a Java class and we'll call it an order, right? We'll call it a truck order. And that will be, you know, entity, extends, panache entity, and that'll be things like string name and beverage beverage, that's gonna be enumerated, so enumerated, enumerated. And I like enum types, so enum type string, right? Your default constructor, hibernate. Oh, and then we had a double or a double total, right? So this is gonna be in an aggregate, the idea, one of the ideas in DDD, and I mentioned this is an older idea, or an older concept, that I think the rise of ORMs, things like hibernate really kind of made it in JPA, made aggregates a little bit easier to use. But if you think the way that we used to write SQL queries a long time ago in an application, so let's say that we had an dependent object graph, maybe we also had, you know, one domain toppings, right? And we had, you know, some toppings, right? Thing here, and we were gonna save many tables. Well, when you were writing out your SQL queries, you know, hand tooling them, it was really easy to write immediately or read from those dependent tables. And so in domain design, the idea was, we're only gonna have a top level aggregate and everything you do is gonna go through this particular class, right? This is the only class you're ever gonna read or write, everything else will cascade from there. And they had a lot of methods you could add into the object to do that. Today, ORM takes care of that for us. But the idea is we still want to have, you know, one sort of top level entity. And that top level entity shouldn't get spread across the application. That's why we have value objects. And we wanna talk back and forth using these value objects. So now one thing we talk about in microservices is everybody gets, you know, their own domain model, right? Everybody gets their own objects. But when you're starting with a monolith, it makes sense to share certain things. So things like beverage, place order, command, ticket, those we should really share those because those are gonna be used by a lot of different parts of the application. So let's just go to, let's put this in a different package. We'll put it in a top level domain class, right? And so those will be, we can use those throughout the application. So like this, so the truck order, I'm gonna deal with only inside of the truck window. I'm gonna save that to the database here. Nobody else is gonna see that. I'll use a value object to pass over to the barista to actually make these kind of drinks here. All right, so that's a, that gets us aggregates and value objects. So services and repositories. So while we're talking about database, we might as well just talk about a repository. So what we would do here is we would want to instead of, actually we'll start with services first. So the idea, and this gets back to the phrase hexagonal architecture. This is an input to our application. Well, I could have multiple other inputs. I could have a mobile app. I could have messaging, something else. So what I wanna have is I want to encapsulate the functionality of persisting and handling other stuff inside what's called a service. So it goes inside of here, we'll have a service and we'll say a Java class. We'll say truck window service. Add this kind of thing. This is application scoped, logger. And we'll have, say, let's have a public ticket place order, place order command, right? So that looks good. Place order command. So I'll get my place order command and what I'm gonna do here is, I'll zoom this up a bit since that should be easier to read but also not, also visible. We're gonna wanna create a new beverage, what was our order? The order we're gonna persist. So we wanna call a truck order. Truck order, I'll say, and actually say place order command name, place order command beverage and place order command total. So let's see, I don't have this constructor yet, do I? So let's create constructor with everything, all right. And I wanna use a repository. So this is a service. So the next thing I wanna do is I wanna persist the object, right? I wanna persist truck order and then I'm gonna want to tell the barista, send it, send to the barista, right? So this is the next thing and services simply orchestrate what happens. And actually truck order, creating a new truck order, I really should encapsulate that business logic because I'm getting, I really should encapsulate this business logic inside a static method on truck order. So that way I can encapsulate any other sort of, any other sort of stuff that has to happen with it inside there, but we're kind of pressed for time so I'm gonna try to go really quick and knock this out in 10 minutes. So persist this, we wanna use a repository to persist things. And luckily, hibernate makes that, or panache makes that super easy for us to do. So we can say truck window, no, truck order repository, truck order repository and we'll create this. So all repository does is essentially, this puts, encapsulates all of the logic around persistence, right? So that way if we need to override any methods we can, all we have to do for panache is implement a panache repository truck order and we're done. And so we can say truck order repository persist. Now I wanna send this to the barista, right? So let's see, I get my barista method, my barista API here. I'll have a ticket, make, beverage, ticket, ticket, all right? And I'm gonna need to implement this class, right? So say barista, implements. Now I should also have a barista service that encapsulates this for me. Right now we're just gonna be really return ticket. And let's actually simulate the fact that it takes a little while to make this. So let's say, let's do try, yeah, thread sleep. We'll do a random delay. I'll say calculate, delay, ticket for that. We'll just calculate delay, we'll return int, we'll return, let's do new random, next int, yeah, that looks good. So that's what we're gonna do is we're just gonna calculate a delay, pretend that we're making this and then return that back, right? So if everything's working now, we should take a second here, all right? So that did take a little bit longer, right? Now it took really fast. Let's go really quick. So, so received order, try barista, make this guy application scoped. And one of those. And now we'll return the one that we get back from our barista, right? While we're making that, we're not going through there. Anyway, so that gives us also an idea of what services and what repositories are. All right, so we make our packages structure around bounding contexts. We use domain driven design. So value objects, which are immutable objects. We can use Java records for that. Those get bounced around between other, between packages, right? So we're not sending persistent objects around. Repositories encapsulate all of our database access. Hibernation makes that super easy to do. And then the infrastructure calls into a service which organizes everything. Now autonomous data. So one of the things you hear a lot about in microservices is that microservices should have their own data. In a model, if you typically don't do that, and that's one of the things that can end up leading to a lot of problems later when you go to split things out. So one thing you can do is just give each section its own schema. So if you wanna build up schemas, you can give your barista, you can give your truck window, you can give your credit card service. Each of those can have their own schema. The way that would look here, it would be to add in multiple different data sources and then simply inject the data sources into the application. So if you wanna come in here with Quarkus, you would just inject data sources this way. You guys can see this. You would just end up with multiple different data sources. You can give them names. Here's barista, we give them window. You can have as many as you want. And all I'm doing, I'm using one database, but I'm using a different schema for each of these. And the way this works is, you notice like that the order is only the persistent objects only exist within that package. It's non-persistent value objects that are passed across. And so that way if we come to pull this out, we don't have a problem yanking this out of there. I'm not gonna put that in place because that's gonna ask me for how to do that. And then all you have to do is just inject that into your class and it works great. So let's add some logging there so we can see some debugging. All right, let's go back to the slides here. All right, so avoiding bottlenecks. If we notice what we've got going on right now, and what part of this is scaling, right? I mentioned earlier, scaling is one of the early problems. So scaling before you have to scale helps, right? So there's a number of different ways you can do this, right? So being asynchronous is one of those. Quarkus comes with the mutiny programming model, small rye mutiny, which makes it pretty simple to do this stuff asynchronously or have these execute on other thread loops. What that would look like here is for instance, we have this barista API as ticket make beverage. What we could do is we could have a uni ticket loops. Ticket make beverage. And what that's gonna do is that, what do I have to really run? So what that's gonna do is that, yeah, let's give it a different name. So what that would do is this is gonna execute on the vertex event loop that's going on underneath Quarkus. We could then come back and instead of returning this immediately, we could make a void method, right? So we could have a, let's just do a, whoops, post and we'll say public and we'll say a response, right? And we'll say place order async and we'll still take a place order command, place order command, right? And we're gonna do a Jaxrs response. And what we're gonna do is we'll return response accepted, response accepted build, right? So we say play, we need to give it a different path here, right? So this way, if we do this, all we do is we can call our service, we should have this encapsulated in our service. So we can say inject truckwindowservice. Do I have a truckwindowservice? Do I have a truckwindowservice, yeah? Truckwindowservice in domain. Is this, is application scoped? We can just call our truckwindowservice place order, place order command, right? So now we can use a void method here and actually we should probably use an async here. Let's create that method. And this can be the same thing, right? So this just tells Hibernate to do this asynchronously, right? So do it in a uni. And what we would, what we can say is uni, whoops, uni create from item and we can say, you know, barista make beverage, you know, new ticket, right? Create our new ticket that way. We can also, persistence, we have to wrap that stuff inside of asynchronous code. Asynchronous code might look a little bit odd at first and there is definitely a learning curve, but it is kind of nice to get it in place and you will definitely see your application perform better. Another way we can do this is we could, one of the things that Quarkus will allow us to do is to use a Verdex event bus, right? And so we can use a Verdex event bus event bus. And then what I can do, instead of sending this directly to the barista, I can remove any knowledge of the barista for my application. I can take the barista out and I can say, still create my ticket object here, but then I can say event bus, send barista ticket and then in my barista, I can listen. So I can come here, I can have a make beverage, right by my make beverage. Whoops, sorry, I'll say avoid make beverage, let's say. Avoid make beverage. And I can say consume, consume event barista. And so what this is gonna do is Verdex under the coverage has an in-memory event bus. It's not like old fashioned event buses. What this means is it's gonna pass that object in memory. And so when I kick that object off from, it's gonna be consumed here and then it will continue making the beverage, right? So let's say that, I don't like how I go. I wanna say 5,000 milliseconds, right? It's getting mad at that method. What does it matter, do I need another one of these? So now I can listen on this event loop. So now I can completely decouple these, right? So when a message comes in, it'll simply grab, when it comes into the resource, it'll grab it, pop it on an event loop, it'll get picked up here, made, and then we need to pop it back onto a different event loop, right? So then we would need to say, event bus, event bus, publish, right? So we would publish event bus, publish. And then when it comes back up, right? When we're done, we would publish it back to the event loop and pick it back up front instead of directly calling the APIs, right? So scale up before you have to scale up. Scale up before you have to scale out. So one way we can do that is we can leverage Quarkus natural event loop so we can use the small rhyme mutiny package to do that. We can pass back unis or multis or we can go completely asynchronous using the event bus. Now, if we then eventually have to move to these Citadels and Outposts pattern number seven, what we're gonna do, oops, yeah, number seven. So we move to Citadels and Outposts, our Barista API Imple, right? So right now we are consuming an event and, okay. So right now we are consuming an event and we are simply calculating the logic here. But what we could do is we could pop this on a Kafka queue, right? So we can have an emitter, emitter, whoops. So we need to add that dependency. I didn't build this with this in place. Or we could add small, all right? So I've added a new dependency in here. Reload the project so we know what, so that we know about this. And what I would do here is once it comes in, instead of doing my logic here, I'd say emitter. So now I can pop this out to a Kafka topic, right? And because I've coded to an API, I don't have to make any changes to the rest of the application, right? This is gonna behave exactly the same way as it would. I can swap this implementation out really, really easily. All right, so to recap our topics here, what? So first thing, embrace code quality. There's lots of plugins you can throw inside of your POM. There's things you can put inside of your build. And where you determine, where you draw the line between breaking the build or simply just like, looking at things using as part of your code reviews is up to you. Certain things you wanna break the build for, certain things you probably just won't look at during your code reviews. Continuous delivery or being able to commit at any time and not just being able to commit, but being able to roll back to a previous version at any point in time is really important. It doesn't have to be any harder than just throwing a little action file into, if you're on GitHub, just throwing a little action file. You can do this on other version control systems, but have pipelines. In fact, in integration tests, the better your pipelines are, the more complete your pipelines are, the better shape you're gonna be in. Third is use domain-driven design, use bounding context, build with those kind of principles in mind, right from the get go. It will make it easy to pull those things out. So, for a lot of these following reasons as well. APIs first, make sure you're coding APIs and those can be internal APIs, like Java APIs inside of your, so each package, each of those bounding context, place an API that the rest of the application can talk to. That can then in turn become a different type of API. You know, we just looked at wiring that up with Kafka. If you wanted to do with REST, you can take that API, it can become your REST API, it can become an async API, right? But use APIs to demarcate your packages. Make your data autonomous. So, if you have to persist something, make all that persistence logic stay inside of each package. Using domain-driven design, using your bounding context makes that easy because anything the Barista needs to record, I can just record inside that Barista package, right? So let's say I wanted to record the name of the Barista that made the drink or how long it took to make it. I can record all that inside that package. And so that way if I pull that out, it doesn't impact. There's no breaking changes, you know, across the entire application. Avoid bottlenecks. Reactive programming is nice if you can use it. If you're using Quarkus, you know, I leverage the event bus inside of Quarkus, right? Use message pass, passing to completely decouple those packages from one another, right? That we didn't even have to know about that API. If I just get an order in and all I have to do is like pop it under the event bus when it's done, I'm completely decoupled. I can do event-driven applications that way. Pop it on the event bus, it'll get picked up where it needs to. It can get picked up by more than one place at a time. And then when it comes time to separate out a microservice, you just update your, you just update, you know, one class. I can have that call out to a microservice somewhere else. You can use REST for that. You can use Kafka, whatever sort of transport that you want to do. All right, do we have any questions? Finish with five minutes left. Do we have any questions here? I can't see the chat. So, oh, here we go. I don't think at the moment, we don't have anything other than there was the question of if this recording will be available later. And it will, it'll be a, I'm not sure how quickly it may be a few weeks based on last event, but it'll be posted eventually to the Red Hat developer YouTube channel. So everything from all the tracks for both days or for all of today, I should say, will be posted up to the YouTube channel there. So you'll certainly have the opportunity to go back and watch this in detail as well as all the other sessions that were a part of that. So. All right, great. Thanks, Jeremy. Yeah, great, appreciate you, Jeremy, for a great presentation. If everyone, you know, certainly hang around, we're gonna stop the stream for a moment and set up for the next one. We'll be having a presentation boost productivity of engineering team with developer portals. So we'll be right back and see you then. Thanks. Thanks.