 So it's pretty common and popular to go to a job interview and be asked to program FISBuzz. And I think now that microservices are such a popular kind of movement, I think it's time to, that we equip ourselves for distributed FISBuzz, the microservices interview test. So before we begin, I want to review the rules of FISBuzz. In a normal interview where you're asked to build, to write a FISBuzz program, you count from one to a hundred. Each time one of those numbers is divisible by three, you output FIS. Each time a number is divisible by five, you output buzz. If they're divisible by both of those numbers, like 15, you output FISBuzz. For all the other numbers, we output the number itself. Now one of the things that happens when you really need to extend a presentation duration and need some filler is to review the origins and history of the thing that you're talking about. So I'm going to talk about the origin of FISBuzz. Twenty years ago it became popularized as a children's game, but before that it was actually a drinking game. So you and your pals would get together in the tavern and you would take turns and each player says the next number or FISBuzz or whatever. And of course you lose if you end up getting it wrong. And the lesson that I take from this is any game that's suitable for adults when they're drinking is also suitable for children when they're sober. So with that in mind, I'm going to kind of give you an example of two people playing FISBuzz together, player one and player two. And they're at the tavern together and they order around a beer and then player one decides to throw the gauntlet down and challenge the other to a duel of FISBuzz. He says one. Now player two, she responds with two because she's always willing to take up a challenge. So the game is afoot. And player one responds, it's player one's cue, FIS. And then they realize this is a really, really boring game. It's not very fun. So they're going to make some, unfortunately they're going to make some really bad decisions here and we'll see what happens next. So player two finally resumes the challenge and musters up her best four that she can muster. And now player one is forced to get the next one, correct. But unfortunately, four rounds in, player one fails miserably. So that's the model for FISBuzz microservice. It's instead of having one program count from one to 100, we're going to simulate having different players or different clients. So the rules here are the clients of the microservice, whether that's another microservice or a web front end or something like that. The clients will submit the next answer and the service will keep track of the game counter and whenever a client submits a correct answer, the service is going to advance its counter internally and it's going to publish an event message. When a client submits an incorrect answer, the service is going to reject that turn. And so these messages that we're sending, the command message and the event messages that we're publishing, that's the API or the interface of this service. That's how you interact with it. And whenever we're talking about sending messages, there's a reality that comes into play, which is messages are sent over computer networks. And that means that the fallacies of distributed systems come into play. And we need to remember whenever we're making any network calls, actually in any context, we should never assume that the network is reliable. We should never assume that the latency is zero or it doesn't matter. We should never presume to have infinite bandwidth, et cetera. And those first two fallacies, the network is reliable and latency is zero. I'm going to focus on those next. So because the network is not reliable, we can count on messages never arriving sometimes. And other times, we can count on messages arriving more than once. And we can also count on those messages arriving in a different order than they were sent. This is reality. There's no getting around the laws of physics here. And because that latency is not zero, services can only really operate or work with their own local data. So they can't query other services because in the time it takes to get a response back, that information might be out of date. And so you can make a wrong decision based on inconsistent data. So we don't do that. And we also have to be prepared for our microservice to cope with failures in way, failure modes that did not exist in fully synchronous systems. So that's kind of the first big kicker here, is when we had FizzBuzz the program, it was very short. It was about 17 lines of code. But once we have the network and messaging in play, we now have to deal with failures and recover from them. Otherwise, our service is going to crash and burn very, very quickly. And the other conclusion that we have to draw is that synchronous request responses like HTTP get calls, those are out. Because for the aforementioned reason that the data could be out of date by the time we use it. So all of that is to set up this contraption here. We have clients that are sending command messages over a command queue to the FizzBuzz service, which is going to publish events. Now I'm going to get into the details and I'm going to show you some code. First of all, we have our message objects, our command message and event message. They're actually not really, they are objects in Ruby. But the more important thing is that they're schemas and they're contracts that our services agree on with other services to exchange information. And so we often have this pairing of command messages and event messages. The command is to take a turn, and the event is turned taken. And there's other events that I'll go over in a minute. One thing to note is very, very commonly when we have command messages that publish event messages, we copy the common attributes. In this case, game ID, answer and time are copied from the command message straight to the event message when they're written. And we also have two time stamps on our event message. And the reason for that is, well, you have two notions of time. You have when the client requested the turn to be taken, and you have when the service actually got around to processing that command. And it's very important to keep those two straight. So let's look at the command messages and the event messages. Here's our schemas. We have take turn, it's a command message. You can start a new fizzbuzz game by taking the first turn, for instance. And if your turn is accepted by the game, in other words, it's correct. The service will publish turn taken for all the world to see. If you get it wrong, though, if your answer's wrong, the service will record and publish turn rejected. And finally, there's exit criteria for the game. Either the counter reaches 100 successfully, or somebody gets it wrong. And the game ends abruptly. Okay, so the next element I want to talk about is the entity. And I'm actually going to show you some real code for this. And I'll do a brief walkthrough as we go through it. Okay, so this is our entity. It's a data structure. And you can think of it as being somewhat similar to a model in Rails, but there's no persistence attached to it whatsoever. And if you really want to crush an interview, separating your persistence layer from your entity layer is a great way to impress the interviewer, I promise, impresses me. So we have a command method take turn, and we have a predicate method correct that tells you whether a proposed answer is correct or not. So you can see the core logic of fizzbuzz is here in the correct predicate method. And so this entity keeps track of the state of the game. And it can answer questions about whether somebody got an answer correct or not. And I think that's enough for the entity. So the next one I want to show is the command handler. And remember that clients are sending command messages over a command queue directed at the fizzbuzz service, take a turn. And there's got to be a handler class that handles that message type. So I'll show you that next. Now the first thing we'll see here in the command handlers, there's a lot of boilerplate. Boilerplate is a great way to really show that you are capable of making a class really long and full of stuff that really shows that you know microservices really well. Below that boilerplate, we have some business logic. It's really hard to point up there at this angle. So when we take the turn, we fetch the game, that game entity. We fetch it from a store, a repository. And based on the correctness of the answer that's submitted, we either publish turn taken or turn rejected. And then we write whatever event is the one that we write. We write it to the event stream. We'll go over that later. Don't worry, if it seems complicated, the more complexity, the more likelihood you have at really impressing your audience. There's also something akin to optimistic locking going on. So when we fetch the entity from the store, we get a version back and then we're putting it back in on our right. And when you're in an interview, you really got to highlight how much you know about mechanical details like optimistic concurrency and things like that. So one thing I showed you is I showed you an entity that doesn't have any persistence attached to it. And I showed you a store that can fetch the entity. So how do we get a game entity from the store? How does that happen? And what are we doing with those events that we publish? It turns out that the answer to both of those questions is the same because we're using event sourcing to track the state of our entities. And we have something called a projection. This thing is really gonna impress them, trust me. So we can imagine that this projection is being actuated with a game entity that is newly formed. And we're reading all of the events that have been published about the game in the past and we're applying each one to the entity. So on line nine, we set the game ID. You know, on line 1112, we're getting the timestamp from the message. It's packaged as an ISO 86 of one string. Again, when you have the letters ISO or RFC followed by a number, you are killing that interview. I promise. So we take the turn, which on line 14, which is gonna advance our game state. And of course, when the game is ended, we're gonna set the ended time timestamp, ended at, ended time. So there's one other element that I just wanna give you a brief walkthrough of, and that's the event handlers. And they're gonna look a lot like command handlers, actually, and that's because command messages and event messages are made of this. They're both messages. They can both be handled the same way. So here we have more boilerplate. Again, boilerplate, very sharp. And we handle turn taken by courying the game entity and determining if the game has met its victory conditions, i.e. have we reached 100, or has the game already been ended? And if so, we're gonna write a game ended event. So we handle every single turn taken event, but only when the exit criteria of the game is met do we publish game ended. Turn rejected on the other hand, it's gonna end the game abruptly, according to the rules, that are completely arbitrary. And so it's gonna always write game ended unless the game has already been ended before. So I'm gonna give you a live coding demo because that's a real great way to embarrass yourself. And I'm a big fan of embarrassing myself publicly. Here we go. So up on the top pane, I've got the service, the fizzbuzz service running. And on the bottom, I've got an interactive IRB console where I can submit, I have handy utility helper methods that will issue command messages for me. So obviously the game hasn't started yet, so I'm going to give it the first value. There we go. Does anybody wanna wager what the next correct answer is? Is it buzz? It is not buzz, it's fizz. There we go. So that's our demo. Thank you. But wait, there's more. So I remember I talked about the distributed systems fallacies. We know that messages can arrive out of order more than once. And none of the code I showed you really had all that, those affordances necessary to handle and recover from those situations. And what I'm really suggesting is, I haven't built item potents into the turn taking system. So when we issue a take turn command, it can be processed more than, the same message can be processed more than once and that is definitely a huge problem. So now's where you're really going to, we're at the point now where you've already aced the interview. This is about leverage for the negotiations that are gonna follow. You're gonna bring up three really awesome patterns. The first, I mean patterns. The item potents key pattern. I'm, by the way, I'm very passionate about patterns. The second pattern we're gonna use to make the turn taking system item potent is the reservation pattern. And then I'm gonna show you the sequence number pattern. So we're just gonna fold that code into the code we've already seen. It'll be really simple and wonderful. Nathan. Where's that coming from? Oh. Nathan. I totally didn't know this was gonna happen. I find this highly questionable. Borderline objectionable. Are you really standing here in front of all these fine people who are just trying to. Come on up. You want help? I don't want your help. Fair enough. I've been taking some notes while you've been talking. You're talking about events and item potents and item potents, keys and flubble grommets and all kinds of things. And I gotta tell you, I've been doing microservices my whole life all the way back to last December. And on my team, we're using go. And you're talking about Ruby. So we all know that microservices have to be done in another language. Are you telling us all that that's not true? I think if you're gonna adopt a new architectural style like microservices, that's probably the worst time to switch programming languages. All right, I got another point. Another point. I've been doing microservices my whole life. And every blog post I've read from other people on my team say that microservices are about HTTP APIs and GRPC. Well, how do you respond to that? You've not talked about, you talk about messages and events and item potents, flubble grommets. I mean, are we all supposed to just believe you that what we've been writing about microservices from our web development background is somewhat not correct? Come on. Yeah, I have to say the most important principle of service architectures is autonomy. And while it's certainly the case that a service can have a web API, it's very, very dangerous to not understand the need for the machinery underneath for item potents and other such necessities. That's a fair point. So if you have an API, you can't have service autonomy. Yeah. Because of the thing you said earlier about when you, okay. Yeah, remember what I was. No, no, no, I'm not finished. Every single person on my team is talking about Docker and Kubernetes when we're talking about microservices. And we're really, really, really excited. We're all going to Docker and Kubernetes training. It's gonna be weak and we get to go away. So are you telling me, are you literally, could you not mention containers at all? And everybody knows containers. Containers and microservices are basically the same thing. Well, a container is just a package with an operating system inside of it. That's how you wanna deploy. That's fine, but it's not necessary or even part of the same universe as microservices. It's an architectural style that doesn't specify how you're supposed to package that. Well, how would I test all my microservices on my laptop? Huh? You don't. Huh? Yeah, if your service is autonomous, it's a computer program that stands on its own. Ergo, my development context, should never need to involve or should very rarely need to involve more than one service. I'm still going to the Docker training. Well, you know, power to you. All right, all right. Answer then this one, smarty trousers. Thank you. Why not? Instead of doing all this idempotence keys and reservation patterns and all this stuff, why didn't you just use a message broker that guarantees exactly one's delivery? Huh? Huh? Huh? Huh? How does it guarantee exactly one's delivery? Take a message off the queue, right? You're with me, you understand this, messages? Yeah, yeah. Apparently, right? And then you send an act when you're done. Okay, and how do you send the act? Like over the network. Well, can't that fail? Yeah, so what happens if it fails? Then you handle the message again. Oh yeah, okay, so that doesn't work either, huh? All right, I got you. I'm afraid not. I got you. A very important and wise man once said, the first law of distributed systems is not distributing your systems. How do you respond to that, oh wise one? I believe the original. Let me take this one. Okay, okay. The real first law of distributed systems is to not distribute your objects. There's no law of distributed systems that says don't distribute your systems. It says if you're gonna build distributed systems, you're gonna need to know the difference between a distributed object and a distributed system. And we had these things in the old days called distributed object brokers. Corba was one of them, Decom was another one, not so that Rails is left out. It also developed Active Resource, made it a default gem, and then two years later, removed it as a default gem, as one might expect. And you get distributed objects, by the way, when you build microservices based on APIs, and not based on loosely coupled events. So, the fun of all this, and the real head fake here is, there are a ton of myths of microservices. They're mostly reinforced by us as developers in our own developer communities, because we're really sort of hearing about what microservices are from our peers. And our peers, not always, but frequently enough, aren't really coming from a background of distributed systems, and therefore, we really gotta do what we can do with the tools we have, and we sort of apply our predispositions of web development and web tooling upon it. But that is really leading to a lot of the circumstances where you're seeing failures in these projects, and it usually results in creating what we call a distributed monolith, which is effectively a monolith with network hops between your active record objects, and that is always failure prone, and that's ultimately why Active Resource was pulled out of the default Rails installation. We're gonna do this workshop next week, and this slide should have updated, and I don't understand Linux. And there's a discount code here. Your touchpad doesn't work like a touchpad. Somebody give me a back. This is the kind of torture that I just, I love. This was my super seven. Well, I was to proceed to the last slide. So we have a discount. There's a, there you go. We have a discount code, KeepRuby. It's a 20% off discount for the workshop we're doing. It's three days, it's online and remote, unless you wanna do it in person in Austin, and then we can talk about changing that discount code if you want access to it. However, and we're also gonna give away one free ticket to the workshop. If you wanna win that prize, great. You gotta make it, it's a three day workshop, so make yourself available. That's gonna cover all of the distributed systems theory and all of the stuff we can do in Ruby right now with Ruby, with distributed services, with the kind of stuff we're doing, building scalable and autonomous systems based on event sourcing and event stores. And with that, let's hit the next slide. Thank you all. Yeah, thank you everyone.