 Yeah, I want to talk about microprocess architecture. So this is a technical slash coding talk. So unlike a lot of the presentations at most actual conferences, which are about process and people and a lot of important things, I talk a lot, it's going to be talking about code. So I think it's why I'm the very last, speaking on the very last day because that's not our focus here. So what is a microprocess architecture versus this microservice stuff you hear about? What I mean is basically taking fruit salad that most of our systems look like and really trying to make sure you don't build it that way. Make sure you sort of keep it nice, clean boundaries among the various components because of all the things we want to do. By the way, All My Artwork is generated by Dolly too. So this is what they generate when it's a mixing fruit. You're mixing oranges and apples. This is what you get. And brilliant picture, just a brilliant picture. So we're trying to do that. So basically you're looking at coupling. So we're talking about coupling. So things that are basically how you relate to each other, we want to couple. There's cohesion there. We want to make sure they're there. They've got the nice pretty skin of the orange or skin of the apple around them. On the other hand, we want to make sure we separate the apples from the oranges and keep the boundaries really clear. And we want to push that to a high degree. So you try to do this some, but you say, well, a little leakage is fine. But once it starts leaking, then you've got fruit salad again. It comes there. Now that she's shown fruit salad at some degrees, okay, more fruit salad is okay as well. And it keeps progressing and progressing like that. And you wind up with some really ugly systems which give me new opportunities for business. Thank you. So I got three different architectures with different purposes for each one of these that I've used. Mostly in the last five years, I've used each one of several times with clients. So I want to talk about these. They sort of fit very nicely in the Kenevan model. Dave Snowden's model that you've heard about in the conference and seen quite a bit. And in these segments, this is what I typically would call the traditional applications because these things have answers. There is an answer to what your bank balance is. There is a way to settle sickness benefits in Norway. It may be very complicated. It may be embedded in Norwegian law, but it is nevertheless a way to do that. Versus this side of the world, which I typically call fuzzy because basically it doesn't have an answer. There's going to be always some uncertainty here. There's always maybe the best guess is going to be what you're going to do. So when I talk about some of these frameworks, I work in both different segments. I work in traditional and fuzzy problems. In fact, the first thing I do with my clients is I look at their problem and find out where it fits. And then I think about what architecture makes sense for their problem. Then we worry about putting a team together, putting the process in place around that. But it always starts with understanding the problem. And this is my model of which I typically use doing that. So I get two different frameworks that I'm going to be talking about today that are in the sort of traditional world. One's called the command framework. The other's a step framework. And I'm going to talk about how microservices also fit into that. Because that's been where I've been playing for well over a decade and talk about quite a bit. But it is only good for that segment in my world. So why do you want to bother doing this? So I was thinking about writing these apps and I've been working for some banks of late. So here's the green bank and you're worried about this guy writing a bad check. So we're going to write some code associated with that. So this is going to be Kotlin in most cases sort of thing. But if the account balance is less than some amount, then reject it. So make sure you get the money before you pay the check. Now if it's above some certain limit that I want to go get that approval. And unless I have that approval, I'm not going to approve it. If I don't get that approval, we're going to reject it. Because it's just too much money, it's a little suspicious. And otherwise you approve it. Now this is the essence of the problem. I mean you can't get much simpler than this than handling this. So this is sort of the essential essence of doing this sort of application. Okay, along comes another bank. We want to support it because we want to get their business as well. So we get the red bank. So what do we do to our code? Okay, let's go into the code and fix it. Well again, most people care about bank balances. You haven't got the money, we don't pay the check. Well if you're the green bank, you care about this green limit, which they've specified. But if you're the red bank, we have a super limit that says if it's really high, we want to make sure the VP sign's off on it. If it's one lower tier down to that, let's just pay that, but that's the red limit. Otherwise we approve it. All right, the essence of the problem is gone. We now get the fruit solid here. And now along comes the purple bank. And so what's our reaction to that? Well we throw that away and this is how you feel as a programmer. It's like, oh my God, what are you gonna do? Now I got clients that have 13 banks. You can imagine what they're wrestling with. So some of the solutions they have is let's go back and do something else. And by the way, the poor green bank which had a perfectly running system keeps updating the software and all of a sudden it starts breaking because it's kind of ugly. It's got some optional errors. It's fruit solid. It's not their fault. They were like, you're a perfectly good vendor for me. What happened to you? And then I stopped upgrading. Which means now I got 16 versions out there running around. And when somebody has a bug, what do I say to them? Upgrade. And they say, well, that's gonna break things. And they're right. It breaks things. So how do you attack this? Well we put feature flags in place and parameters and configurations. We'll put some of these parameters in place. So then our code looks like this. So we're gonna say if you're greater than some of this parameter, then you're not gonna reject it. If you have this feature and this parameter, we'll do this. And if you have this feature and these parameters, you're gonna do that with these parameters. Otherwise you're gonna do these feature flags. Otherwise you do this. It's not better. If anything, you just add another level to the fruit salad. Now we got grapes in there somewhere. And literally, I have a client who has four pages of flags they have to set up for each of their clients. Four pages. Do you think they get it right? Ever? This is not the way to go. And so I've been working with these clients and sort of saying, you know, your fundamental concept that says let's put this code in one place, let's satisfy all banks with one piece of code. And remember, it's just one more bank. You can add this into the code. It's not a big deal. And once you've added the purple bank, you really have trouble distinguishing when the yellow bank comes along saying, I can't do it for yellow. Well, you did it for green and you did it for red, you did it for purple. Why is it different about yellow? It's just another bank. And they push that chain through and it gets uglier and uglier. So that's why you care about this to some degree, is this whole problem you can create it. So there are a couple of different domains that sort of have this trait. And I've been working with clients that have this. And that is when you're sort of in a software service industry. I'm providing software for banks. And I want multiple banks to be supported. I work with clients in Norway that do that, clients in Jordan that do that as well. Or there's some sort of a retail has the same sort of phenomenon. There are a lot of places where we write software as a service or software as a product. And we want to customize it for these various environments. And you get into this fruit salad very quickly. All right, so how do you separate this one? Well, I like to put sort of what I call the command framework together, which is really good for any process you follow. Like taking a check and working it through the process. You have various stages. Or perhaps the process is getting a new customer online. You have to get this, this, this, and this get done. So a sequential process. So we use what I call the command frameworks for this. It's basically based on design patterns. A book from the 90s, no less. I use a lot of the command patterns, composite patterns, state patterns, visitor patterns. And I also use a collecting parameter, which is not in the book. I think Ward Cunningham was originally the guy I first saw using collecting parameters back in the dark ages. But it's a common pattern I like to use as well. So it's all set around the concept of a command. And the command conceptualization says, here's something I want to do. I just don't want to do it right now. I want to do this at some point in the future. So it kind of understands some behavior, but the behavior is going to run in the future. And what you do basically is you tell the command to, to basically exist and you tell it to execute itself. And then it goes and does what it needs to do. But not until you tell it to execute. So you set it up and you wait for the product to pull the trigger, so to speak. The result is it either succeeds or fails. And it turns out another case is really important. That is, we can't finish. We're stuck. We got to wait for some asynchronous answer to come back in. Some check to be run. Some more period to come in. So you could have a third possibility for this command. It could succeed, fail, or we don't know yet. We want to suspend. But since I know what I'm trying to execute, if it doesn't work, I should know how to undo it. Because again, I understand something that needs to be done. And therefore, it's also my responsibility to make sure I can undo it. And so I want to be able to take the undo command that says, oh, by the way, something downstream failed. And so I want to come back and undo it. Now you put these together and you get to sort of have a process. You can put these together, it's called a composite pattern. You have one command calling another command calling another command. You sort of wrap a pretty ribbon around that and then call that another command. Because all intents and purposes, it has the same interface as the primitive commands. Composite pattern. Anytime you have a tree structure, this is the structure you want to be using. So when you tell this guy to execute, then he just goes and tells this guy to execute and sort of walks his way down and if everybody's happy, then I'm happy. Very straightforward process. It could fail. One of the steps could fail, in which case I'm going to undo the others, tell the other guys to undo themselves because whatever they did, I can't use it anymore, roll the transaction back, give the money back, open up the account again, whatever it takes to do. So basically this is the case where we failed. But you also have the case when we suspend it, like we're waiting for something else. And so basically you just have to stop, just let it freeze, go put it in, you snap shot it to the disk, wait for that, whatever that event happens to go happen and then you try it again. So basically when we try it again, we want to skip the first two because they've already run successfully. They've already been done. And you just want to execute the last one. Here's where we just used a simple state pattern. So the comparison of events been executed successfully, it's been rolled back, it's failed. These are various states of there. Very straightforward kind of idea behind there. And so basically what happens when you resume to submit a command? Well, he can succeed, he can fail, or he can suspend again. And we're back to the same sort of situations. So again, very straightforward sort of concept behind that. But I want to do some more decoupling here. Because what I've described is the capability of setting up a flow. But the behavior associated with the various elements, I can tease them out. And I like doing that into pulling them out. So I want to separate the behavior from the flow. I want to separate the apples from the oranges here. So we have a command, but the behavior is going to be put into a task. And the task can be something I can turn around and execute. And he's going to even have it succeeded. But the flow is associated with the command. It turns out I also have a reversal task. In other words, the behavior that takes to undo it usually is not the same code as it takes to do it. Sometimes it is, in which case just put another green guy there, but usually it's different. It's doing some different behaviors. So when you tell it to execute this guy, this guy goes to that one. And if the guy gives no positive answer, you just keep going to the next command. If he fails, then you start unwinding the stack. If somebody passed you to the size he's going to fail, it comes back to us and say, you know, I knew you were very successful. Thank you for succeeding, but somebody downstream for you can't finish. And we have to abort the whole process. So it comes back to the undo. We call it reversal. He does his undo action and we keep undoing as we go. So that's all it takes to do this. So I have an open source code up there. It's my GitHub account. It's done under an MIT licenses. So I have to have a way with it. So here's a situation. I got a couple of banks. So what do you do? Well, you want to build the behaviors. So you build a little catalog of behaviors because some of these behaviors are going to be used by lots of banks. Some can be parameterized and some may be unique. So you start building your little catalog of these tasks. So like checking to see if your balance is valid, doing an approval process. These are probably some standard steps that you're going to put into your inventory of the task. But Red's going to have some unique stuff associated with him. You're not going to dirty up the rest of the world with that. You're going to put it in there separately. So the red guy says, well, if you're not a citizen of Norway, I don't want to do something with you. I only handle citizens of Norway. Meanwhile, the purple bank says, if you don't have a lot of money, I don't care about you. I don't want to be your bank unless you have lots of money. I remember there's a Citibank branch in the aisle of Jersey which basically says, unless you have at least $150,000 you're going to foot with us, we don't want your business. And I'm like, OK, I guess I have to find another bank. So notice that these are all independent tasks. These are very easy tasks to write. They're very self-contained. They're not subject to a lot of change by stress of the organization. So now when you start building a sequence for this particular bank before doing your implementation for this particular bank, look at what process they want. You pull your steps from the various buckets you have. You have a sequence. Here's one of your processes. Here's another process. Just put it together. And when the purple bank comes along, you sort of lay these out again. Again, using the various components and put them together. Whole separate different commands. You're not trying to have a universal command sequence for all the banks. Separate out their commands. They're easy. They're standard components. So this is all it takes to sort of keep it sane, even though you have numerous banks. Yes, we'll have a different set of implementations for the red bank. And guess what? If we start changing the red guide, purple bank is not at risk. There's nothing about the software that's going to break for him, because we haven't touched it. Unlike the other approach of using feature flags. So you're going to have some information for following this process. So we use a collecting parameter to pass the information among these various elements. Because basically one task will probably do something that's going to provide input to another task. So we put ourselves a little common structure here with a bunch of fields in here. And by the way, this is a bit of a anti-pattern, having common structures. So we'll talk about that a little bit. But basically this task will suck some information out, add some information back, and et cetera, suck some information, put it in and out. But to sort of make this a little more sane, what we want to do is we want each task to declare exactly what he needs in order to behave. What information do you need? And what information are you changing? So we will specify those explicitly. And what that will allow us to do is run some static analysis on this to see who's sucking information out, who's putting information in, what information needs to come from outside sources. And you can sort of see when people start cheating a little bit, like pulling too many fields in. You can have sort of almost a linting tool that sort of looks through this and says, you've passed a threshold. Let's look at your situation. So again, we're trying to get a little more control over this. But it's quite easy to snapshot this structure. What does the code actually look like? Well, the task is actually pretty straightforward. This is simply an interface. This is the Kotlin version. And it says I have ability to execute passing in the context. And I'll return one of those task results. I also have a set of fields I'm interested in that I like to have input on. And I have some fields I will change. This is actually how I set up a catalog. Catalogs are just enums. They have labels for the various tasks that we associated with it. You can have multiple catalogs. You can have the red catalog, the blue catalog, common catalog. And basically, each one has a method here that basically says when I call this label and tell you to give me the task associated, it will instantiate a new task for me. So I can plug it into my command. Again, pretty straightforward to put this together. So notice it is a generation process. And what's the command actually? Well, we have a couple of different types of commands. This is the more primitive one. But there's a sequence command. So this is how we define sequences of operations. This is Kotlin. Kotlin allows you to put some nice DSLs. So here's a three-step process that says, first of all, perform that task. You have to unwind, do that recovery. Perform next to the other task and there is no reversal necessary. Whatever it is, doesn't have side effects. And there's a third task that says, do that one. Define the sequence. It's that easy. And by the way, I can take something like this with these nice labels in short to a business guy that says, this is what you mean? Is this the task process you're talking about? You can even have sequences of sequences because it's composite pattern. So in this case, we have, you'll do this step, do this step and then do this other sequence and maybe a common sequence is elsewhere. Now notice in this case, this is one of my test cases. I put a task in here that's gonna fail. So I can exercise and see what happens in this case. So in fact, we will run this test. We're gonna see that the first task is gonna run, second task is gonna run. We go to the internal one, run that one. Then we hit the failed guy. So we're gonna run this one, this one, this one and then we're gonna have the failure. Now the failure is gonna drive us to unwind the ones that we have already executed. So that one and then those get started running back in backwards order. So that's kind of how the flow works. Again, a pretty straightforward flow to implement. And actually when you run the test case against this, this is the actual test case, the overall result of executing this is we got it, we were reversed. We attempted to do this but we got reversed because of some failure. We can even run some test analysis. Test analysis is actually just a visitor pattern that sweeps across the command and collects the data about it. What do you see there? Well, they found that one task failed, yes. There are three tasks that were reversed. In other words, they were executed and got reversed successfully. And two we never even tried. So it's easy to get a snapshot of what the state of the process is. Now understand what part of the process failed. It's sort of screaming at you. So debugging these systems and trying to put them together quite easy with this separation of the apples and oranges. So that's what I use when I have a procedural-oriented process. And again, a lot of those exist especially in various applications I've worked with. There's another one that comes up a lot that sort of says things I want to do but the order doesn't matter. For example, I was doing an application to allow somebody to, somebody leasing a flat to sort of get somebody moving out of the flat from the landlord and get everything done and get somebody else in the flat. So from the landlord's perspective, you want to minimize the amount of things done. But there's no sequence that's necessary. It's not like I have to do this step before I can do the next step, before I do the next step. So there's some concept of parallel activities here. So you want sort of this checklist metaphor. And so we built a framework associated with that for those types of applications. And again, I've done it several times now. It comes out very useful. So the order is not important. So what do we sort of have in this model? We have the concept of a need. I need something done. And so the idea of the need is something that's going to have three possible values and see they've been unsatisfied because I haven't got an answer to it. I do have an answer and it's a good answer. It's now satisfied. Or it's unsatisfied because it's a problem. The value is incorrect. It would be something like, well, have you got the keys back? The answer is no. Oh, okay, that's a bad answer. We may need to do some more stuff like go get a locksmith and some other stuff. So some more steps would have to be created. So they're very straightforward sort of ideas. I've already implemented some of these. There's numeric ranges, there's multiple choices. There's string values. Again, they're quite easy to implement. And you want to implement lots of these because each one steps quite easy to build. The other thing is almost every one of these needs in a given application is associated with some party associated with doing this activity. For example, if I'm trying to change the flat from one resident to another resident, there's certain things the current resident needs to do. There's certain things the landlord needs to do. There's certain things the new tenant needs to do. And so the nice thing about a step is each needs going to be associated with some role that's responsible for resolving it. If it's not resolved successfully, you know who to go ask for a resolution. So status is basically a summation of all of the needs. So take all the needs together and that's the status of the process. And some of these needs can be satisfied. So all of these needs are satisfied, the process has been successful. You could do whatever the next thing is. You can move into the flat. If something in here is not satisfied, in fact, something in particular has failed, then we have a problem. We cannot move into the flat, not until we resolve the problem. And otherwise, we're sort of in the middle of process of something still pending. And the nice thing about this, this forms a very natural checklist of things you need to go chase down. Why can't I move into the flat? It's because, look at the list, these things haven't happened yet. I haven't got your deposit check. Your credit check isn't good. I mean, whatever it is, I can tell you exactly why. The nice thing about these systems that I'm building is the status of the system is very transparent. It's easy to explain it back to the users exactly what's going on. Versus their current systems, which are basically, I'm sorry, I haven't got you a check yet. I'm sick, I need a check. I can't tell you why it's not working yet, but it hasn't happened yet. So again, the nice thing about this, if you have problems or unsatisfying needs, you know exactly who to go ask and who's the only responsible for that. But every other party knows who's on the hook. So you get all that behavior for free. So let's look at what the basic concepts are. What is a step? A step is something that manipulates needs. In other words, it's gonna say, well, here's a couple of needs. If you need, if I see these needs, I can actually take an action and create an answer. Maybe positive, maybe negative. So that means there's certain preconditions. I don't want to run this step unless some of these needs exist. Or perhaps some of the needs have certain values. Or maybe I don't want to run if the need does exist. Like I don't need to pull a locksmith in if the locks were fine. If I got the keys back, I don't need to have a locksmith. So I should never run that step. And because of this presence, it's actually pretty easy to create a little sequence if you need a sequence. Because not every step is completely independent. Some steps depend upon others. It's pretty easy to chain them together just by chaining together requirements around their needs. So you can build these little mini chains that you need them. What's a process? Well, a process is basically defined as a set of steps, needs, and some steps to associate with resolving those needs. So one of the things I want to do here is I want to make sure I don't have to worry about the order of the needs. What order should you run these steps in? Well, that's kind of the hardest to bear prone. So one of the things about this, we don't care about the order. The order is independent. How do we work that out? Well, the first thing we do when we execute here is we make a copy of the status. We snapshot it. And then we run through the steps in any order, as long as we're consistent or into the same order. We run through these steps in the order. In this case, it changed a few things. Well, if the status has changed, then we basically want to re-run it again. Because some of the other steps may not want to run, but they couldn't run before. So we're going to continue processing here. So we're making new snapshot, marking the ones that have been changed. We re-run it again. This time nothing happened, which means at this point, we're in a steady state. So as we hit a steady state, we need to wait for somebody to change their mind about something. We need some more information. We need the keys back, or something else has to trigger the system. So we're sort of an appending state for the overall process. All right, so somebody actually puts some more data here. So externally, we say, yes, we got the keys back. We update the status of that, and of course we start running the steps again. Make a copy, snapshot it, run the steps. In this case, one of the steps says, yeah, I don't like the answer there. We have a problem. So what's the status of the process? We have problems. We have to resolve it before we continue the process. Again, pretty straightforward model, but again, a nice separation in between oranges and apples. So the nice thing is you can customize this by creating new steps. That's how you build your system. If you have new steps, you just build them in there. If there's one client wants a different set of steps or some more steps than you have, write them and keep them away from the old steps. For each client, you're configuring the steps for their process. If a different client has a different rules associated with that, and that's true in the rental industry, they have different clients want different things, just put their seven steps together over there. It's easy to build new needs. You have standard formats for them. If you don't like some of the ones that exist, make your own, they're quite easy to write. And order is not important, which means that configuration issue that we have often about getting them in the right order for this client. That doesn't work for this client. Let's rearrange them and try to get that order perfect. We don't need to worry about that. It's an order independent system. In fact, let's see how that works in particular. So let's say I have these three steps and they have a dependency on each other. The first step, it needs A in order to run, but it's gonna push B into the stack. The second one needs B, pushes C. The other one has C needs D. So we start this out, we prime it with A, then we go through this order and it adds B, adds C, adds D, and then we run it again, and no changes happen, therefore we're finished. What happens when you rearrange these? All right, we prime it with A, we go through, we can't run this one, can't run that one, we can run that one. But the status has changed, so we run it again. Status has changed, we run it again. Status has changed, we run it again, oh no, we're happy. Order independent. So checklist sort of code, that works out quite well. This is actually literally the output logs from running this particular test, it's in the test suite. This is the status log as we're putting this out, and you can see exactly what went on and how each one worked. So again, one of the things we put into these frameworks is visibility to what's going on. The processes, you wanna debug the process, we make sure programmers can easily debug the process. It's not a black box. All right, again, the code is up there in a different repository in GitHub, pretty easy to find again. Let's look at what the code looks like. So what is a need? Well, a need, first of all, has a state. The state's associated with either satisfied, unsatisfied, satisfied, or it's a problem. Again, that's the state of each particular need. So in the interface, as long as you implement that interface, you're fine. You need to be able to copy this particular need because we wanna make that clone of the status for the snapshot, so we need that code. And of course, we need to be able to sort of check its value to see if it's a positive value or a value we're looking for, like are the keys returned. So let's look at an example of this. This is one of the more complex steps. Again, this still fits in one page of code. This is a multiple choice need. So it has two parameters, which is a label for itself, so we can identify it, and a list of valid values. Here's the choices. We have a variable that we keep in track of the current value. We do initialize it to null. Nulls are, in this language, nulls are assigned that it's unsatisfied. We haven't got an answer. So now we can write the state thing that says, look at the value. If the value is null, we're unsatisfied. If it's one of the valid values, it's satisfied. Otherwise, we have a problem. By the way, this is Kotlin code. It compiles its lovely piece of code. We also have the ability to set it. We have ability to get the current value out, which is actually pretty easy. Here it is, just send it back to whoever asked about it. We have the ability to clone ourselves, which is to make a copy of the object, change the status value to be the same. That's how we clone ourselves. And of course, since we're doing comparison, we need an equals method. Again, a very straightforward method to implement. That's the complete implementation of a multi choice need. You can imagine if you write your own needs quite easily. This is how easy they are to write. It was a step. Well, a step's an interface, of course, because we have different types of steps. So basically, you have the criteria by which I want to run this step. So some steps say I want this label or I won't run. Some steps will say I want the label to exist and be valid. In other words, the state is actually, it's a satisfied need. I may have a particular value I care about, give it a map, and map those two. And these are the labels that exist I do not want to run. So it's a forbidden list. And basically, again, you have a capability of executing yourself passing in the status. So what does the process look like? Well, it turns out the process code just fits on one page as well. It's not that complicated. So basically every process is a set of steps. And when we execute that, we pass in the status and he's gonna make the step, we're gonna execute the steps and do that. First thing we do is take a snapshot. We call the status, we ask you to give a snapshot and give us a back into the status object. We'll hold on to that. And we're gonna keep looping through all the steps as long as there's a difference. As long as the status has changed in some way, we're gonna keep looping through the set. For each step, we're basically gonna see if you're ready to execute, we're gonna execute you. So we're gonna check the filtering criteria. Filtering criteria is pretty easy. We say, have you got the labels we need? And are the forbidden labels there, in which case we don't wanna run? Are all the labels valid? Or are all the ones I care about values have the value I expect? This is the code for the process. It's no more complicated than that. But a nice separation of steps, which can be done in any order, versus needs, and everybody may have a different set of needs for their particular implementation, for their particular client. There are set of steps. You can mix and reuse them quite easily. No feature flags required. Okay, so those are the two sort of traditional application frameworks I've used. I've used probably two or three times in just the last three years, with various clients. Again, first thing you look at is what problem you're trying to solve, where we have this application process in the bank. We have a process by which we need a process with transactions. And it has to be done in a certain fashion. Sounds like a process sequence. Put the framework together for that. By the way, you can mix and match these. One step, one part of the sequential process, one of the tasks could be in fact, a step process. Or within a step process, one of the steps itself could be a command sequence. You can mix and match these as well. But microservices is a different beast. We're trying to solve fuzzy problems. So here, as explained many times in this conference and in other places, you need to explore. You need to experiment in order to find out what's gonna work. So it's a whole different beast. So requirements in fuzzy domains are pretty much useless because that says somebody knows what the answer is. Like, I know how to beat the market. I don't have to put the perfect Google ad that everybody will have to click on. They can't resist. Those things don't exist. I know exactly should I loan you money or not because I know precisely you will always pay it back. These are fuzzy questions. You don't have precise answers. And therefore the requirements process are typical don't exist. What you can't put in place though is you can put success criteria. What does it mean to be successful? Is it more money? Is it more new users? Is it logins? Is it retention of particular users? Whatever those are, those metrics do make sense. And they're the ones you're gonna measure our experiments against. And by the way, it's oftentimes you do something in a fuzzy domain that is a positive thing. You're getting a better KPI. You work the next month and it's a better KPI. In the third month, the KPI goes down. Turn it off. That's the nature of a fuzzy domain. Sometimes it works and sometimes it stops working. So experimentation is how you get competitive advantage in this space. I worked at a startup in London where we were doing experimentation in Google advertising. We made 50 million pounds with 50 employees. We were able to react to our system to changes in results of Google work and changes in Google rules within a day or two. Our competitors would put a schedule in place to do this in the next release three months from now. Three months from now, of course, Google will change the rules again. And they never caught up. So we were recording the market in this sort of advertising because of how fast we could experiment. Time to market is key. So we were doing small continuous deployments. In fact, we were deploying code to production every two and a half minutes, three and a half minutes. The new thing would go out. Every three and a half minutes. That's how fast we were experimenting. Now the principles of these microservices in this domain, microservices can be applied to other domains, but for fuzzy problems, this is what sort of the pioneers of microservices sort of summarize microservices to be. First of all, they're really, really small. I mean, a really large microservice, you saw in Netflix was a thousand lines of Java code. In my environment, it's hard to get more than 25 lines of code in a service because it's doing one little thing, one little experiment. We typically are very loosely coupled because that allows you to experiment. And it's also very nice to be able to deploy two versions of it out there without taking down the old one so that you can try something out aggressively. And so that's the design criteria you want for your system, you should do that. Self-monitoring, if a service wakes up and can't do its job because it's missing something, it needs to make a big noise about that so that other people hear about it. If you do something interesting, publish it so other people can use that as a trigger for their experiments. The nice thing when Google did this, this is a Google trick, is that you do something interesting, you publish it. Don't worry about who needs it. So if I want to try an experiment, I don't have to go negotiate new APIs to all the services. They've already published their conclusions on some event bus. Therefore I can try my experiment without having meetings with all those guys to get it. This made Google very, very fast. And of course, applications when you have lots of these small services, it's kind of hard to draw a boundary around this beast that you're building. The analogy we like to use is Rapids, Rivers and Ponds. This was, I drew this with my finger on a new iPad flying across the US so I don't apologize for the artwork. But the key thing is in this upper right corner. And that is we're gonna use an event bus. So rather than have an operational data store which sort of takes the data coming in and sort of massages it and put it into a permanent form, we're keeping all the data. So if this event comes in, we want to hold on to it. It's interesting. Because it turns out if this is an email change and this is another email change, just recording your email may not be enough. In fact, a change may be interesting. And how often it changed? By holding on to the events we have access to that information. But we want to make it easy for everybody so we can put every event on the same bus. No topics, no themes, no nothing. Every event on the same bus. So that the experimentation is going to be easier to happen. Then that makes it rapid. That means it's turbulent, it's got lots of different things in there. If you're logging something, put it on the bus because that must be interesting. That's why you're logging it. Put it on the bus. User journeys, put it on the bus. Services putting the output, put it on the bus. Now you pull these things off the bus with the microservice into a theme. So certain traits of message you're looking for, tease them out. And that becomes a river because this is a consistent thing. It's a nice, smooth, flowing body of water. And you still need entities. We still need to keep track for this entity what his email address is. I call those ponds because they're stagnant. They've lost that time nature of the events. But they are still very important. And the way you do this is you put a microservice up here, looking for email changes, and you update your database. Just another microservice. So you need a high performance event bus. When I started doing this in 2007 originally, this was kind of a new idea. But of course now it's out there and there are lots of other buses. The nice thing about these buses is first of all, they're really dumb. Which means they're not trying to do all these other things for you. They're dumb buses, which makes them fast. So even back then Kafka could handle a quarter of a million messages a second. The problems I work with, you can't drown that bus. Not with every possible event you can think of. You cannot drown a bus with that capacity. It also is a persistent bus, which means it will save the data to a persistent store before it triggers any events. So if something goes down in the middle of process, those events are still there, it can be replayed. Again, you have to replay from where you left off and you're responsible for figuring out where you left off, not the bus. Again, dumb bus, but fast. So what is a river? Well basically, the way they count capacity on these buses is a little bit cheating. So if a bus writes a message one time is read 10 times, that counts for 11 messages. So if you have 100 guys attached to the bus, it's not a quarter of a million messages anymore. It's only 2,500. I'm getting a little nervous. So you try to minimize the attachments to the bus by basically setting up these rivers. Zero MQ is one of my favorite tools for doing that. And you attach these this way. And I never really needed much more than five or 10 attachments to a bus and the applications I've played with so far. But it's still a new virgin area. So this becomes your sort of event bus structure. You attach your services to the rivers, but you always publish to the rapids. You don't just publish to your river saying, oh, nobody else needs to know this except me. You're not that smart. You're killing the experimentation. Somebody coming along and saying, I'm interested in your event. Well, you don't want guys to go across four separate event buses trying to figure out, put a time sequence together, put their experiment together because it makes the experiment hard. It can't be done fast. So we always publish to the rapids. So new architectural patterns emerge out of this process. So basically to become asynchronous algorithms. So this is called the need pattern. So basically a service is sitting here asking a question on the event bus. And he doesn't know anybody's gonna be listening. But I loan you money. All right, so the two services here that gonna answer that request. The first service here is gonna basically look at your bank account. Let's say you're making regular deposits. It doesn't go negative. Sounds like it feels like you have a job. I'm okay with this. Yeah, let's let's loan you some money. Maybe the other thing goes to a service bureau and ask the questions of the service bureau. What do you think about the credit risk? And they express opinions back on the bus. They do not know about each other. They don't wait for each other's answer. It's asynchronous. And this guy will collect all the answers to make a decision based upon what he's hearing. Maybe one of the guys vetoed it. Over my dead body, you give this money. Otherwise, it's up to this guy to make the decision. Like it's a fuzzy problem. We're not sure what the right answer is. I'm not sure I should loan you money or not. But I'm making a guess. Well, look what happens here. Maybe I got a better idea for purple. I can deliver a new purple service, put it on the same bus, see what happens. I don't even have to tell them, is this the purple? You don't have to tell the green about it. You don't have to tell the yellow about it. I just bring it up. Experimentation. Imagine the yellow service goes down. Well, the system doesn't stop. I'm still getting answers. I may not get as good a answer as I used to get, but it's a fuzzy problem. I don't know you're gonna pay it back anyway. So it turns out this architecture has, it's easy to put variations in there and try things out aggressively and it's easy to degrade the system. If the system degrades, you don't stop. Yes, alarm bells are going off that we need to bring the yellow service back, but the system doesn't stop. Imagine you wired this together with RESTful APIs and when this goes down, you're stuck, you're dead. You're getting no answers. So this allows us to create incremental applications where we're deploying something very, very soon in the development cycle. This maximizes the return on investment of investments and data in your budgets. So when somebody says, write some code, we can write some code and get it out there. So for example, this is the one we're gonna be doing in the class tomorrow. We're gonna have a rental car agency. We wanna put some advertising on the page to try to get to the cell. It's called an offer engine. And so we're gonna get ourselves an event bus in place. We're gonna put a little hook into the legacy system to tell us about that something's happening here and I got two guys that are providing offers. At their locations, they're just gonna say, well, I have a lot of SUVs, so here's a good deal on SUVs. The brand guy says we have this, at the corporate level, we have this concept of double days or double points today because we're trying to incent you to become customers of us. I can bring this system up and have it running very quickly. It's not that hard. Now I'm making money. But now I can enhance the system. I can do segmentation. I can look at who the user is and look at their pattern of purchases. In the rental car industry, if you rent between Monday and Thursday, chances are it's a business rental. You don't care about discounts, it's your company's money. But double points or car upgrade, you love that. On the other hand, if you're a weekend rental, price is very important. So just by understanding a little bit about your usage pattern, I can give a hint back to the system about what a better use may be. So now I got a better system. Now I'll make more money. I can look at membership programs, frequent rental programs. Turns out it's very important if you have somebody who's buying from you to keep them as a customer. Winning a customer back costs you about $500 in the US. Just winning a customer back. It's a very expensive get-it-back. So give them a better deal, hold on to them. Again, make more money. We built this system when I was in California, we built a system like this for a hotel chain, for a big hotel chain. Recharge them $6 million to develop this. It was a little more sophisticated than this, but not much. They made 40 million additional revenue in the first six months. So fuzzy problems, incremental applications, huge return on investment. I'm not waiting six months or 12 months to deploy something. It's being deployed almost from the first instance. So again, this code is in the microservice workshop. It's up there. There are versions of this, the frameworks that handle these sort of problems. Then you have reference and rivers and ponds concepts. There's one in Colin and therefore also Java. There's one in TypeScript that also handles JavaScript. There's one in Python and there's one in C Sharp. So whatever your language is, there's some frameworks to doing this. This is a framework, by the way, we use in the Norwegian Welfare Association for working every color of code together. Even if it was a service, using only a bit bus, we use these analogies. It worked out quite well for us. And the code is up there and will be used tomorrow in the workshop. So generally there's a workshop, we run it one or two days. One day you sort of get the concept, second day you get to practice the concepts. It is an event-based architecture. We use RabbitMQ because it's easy to bring that up. You'd ideally use Kafka, it's a little more expensive to bring that up, a little bit more difficult. We'll write a dozen little applications in the first day. It's not that hard to write them. They're very, very tiny. You'll get a chance to experiment. Again, lots of languages in there. So that's the microservices comments. So again, three different frameworks, two of them for traditional problems. One's a process sequence, one is kind of a checklist sort of world. And there's one over here for the fuzzy world. These are the frameworks I've typically used with clients. Any questions? Thank you. Welcome, thank you. Please stay back, we have a closing ceremony and also anyone like to register tomorrow there is a workshop. These are for micro-services. So anyone interested, please reach out the receptions. We can help them out to register. Yeah, thank you. Thank you. So my question is, I can see how this works great in largely process-based sort of business flows, right? Like loan approvals, insurance policy, et cetera, how would something like this come into like a, somewhere where you need user inputs like say an order fulfillment where somebody's going through a screen by screen kind of a, where they're giving you information in sections like personal information, age. Like let's just say insurance, I give you my age and I answer a bunch of medical questions. Yeah, but basically, there's certain steps in the process. You need this information, then you need this entry. So the step could suspend itself. That command could suspend itself because it's waiting for an answer from the user. That would trigger the suspension of that. We trigger an event that says go ask the user this question. And whenever we got an answer back that we'd fill that back into the status and restart the command process. And when that status comes through the command the task will have it, then we can make a decision and move to the next step of the process. That's why it's very important to have a suspension. It could be for asynchronous services, but it could be we have a dialogue we have to have with the customer. Either one of those situations would make sense. But also since we have a sequence it's very easy for him to say, what about backing up? It's a well-defined sequence to back up and unroll something and try something else. Like, oh, I really don't need that much money since I've lost the approval, but how about this much money? Got it, got it. So you can sort of roll yourself back since it's well-defined and back up a couple of steps and keep going. So back button basically undo, undo, undo, undo and then you sort of roll forward again. Absolutely. Got it, got it. It's not that hard by the way just to sort of say throw away some of the information you already have rerun the process from scratch. Because you, oh, I got this, I got this, I got this. Oh, I'm still missing this, but now I have a new answer for this. And I'm guessing since your needs are on that large even if somebody is waiting on a UI for it to come back with the next set of needs. Remember, if we're talking about a sequential we're talking about commands and tasks. So one of the tasks could be I need, I need some more information about your savings accounts. Sure. And what's about your mortgage on your house? How much do you own your mortgage on your house? So I don't have the information readily available in my status. So one of the things I'll do is I'll say stop, suspend the process until I have that information. And I know why I suspended, I make some signals about that. I can even post something off to Event Bus saying this is the next question for the user. Okay. Thank you. You're welcome.