In the season finale, Kevin and Andrew fly close to the sun to understand which snake strategies work best, by A/B testing live with DevCycle. Do they keep their wings?
Speaker 0: Hello, everybody.
Speaker 1: Hello. I'm sorry, Kevin. Ready yet.
Speaker 0: You are ready. Alright. Let's try this again. Alright. 3, 2, 1.
Hello, everybody, and welcome to ready no. I
Speaker 1: didn't know where to do that. We're gonna
Speaker 0: do it. Ready. Ready. Set. Set.
Battlesnake. I don't think we're gonna get it, Kevin. I don't think
Speaker 1: we're gonna say the final episode of
Speaker 0: Alright. We're gonna try this again. I feel like this is I feel like this is good for the final episode. Let's do this. For the final episode.
Let's get this right. Welcome to the final episode of Ready set, set, battle mistake. Mistake. We're close enough. We got there.
Speaker 1: Close enough.
Speaker 0: We got there. I'm gonna count it. Alright. So welcome, everyone. Episode 4 of Ready, Set, Battlesnape.
I'm Andrew. This person either down below or to my right or left. I don't know where he's he is right
Speaker 1: now. Direction.
Speaker 0: Is Kevin, and we are your your snake charmers, your code, your code coaches, your, your fun fans. I don't even know. But we are here today.
Speaker 1: You are fully overestimating our entertainment value.
Speaker 0: I I don't know what you're talking about. I feel like our entertainment value can never be underestimated. We are we are more entertaining than we even think. Thank you so much for coming back and checking this out, Kevin. Thank you so much for for coming back again after I kinda threw you, a little bit of a, a little bit of a challenge at the end of our our last episode together.
Speaker 1: It was tough.
Speaker 0: But we got there. I'm sure you'll return the favor to me today. Yeah. So if you haven't caught episodes 1, 2, and 3, you should probably go back and check those out. We, kind of we're gonna talk a little bit more about exactly what we've been doing, But, in episode 1, we built a Battlesnake, and we'll talk a little bit about Battlesnake kind of as we go through.
Obviously, in episode 2, we implemented, that same logic from our 1st JavaScript starter snake in, Directus. In episode 3, we added a whole bunch more logic to our snake but mostly just to visualize the games that were coming through the platform. And today Kevin, do you know what we're doing today?
Speaker 1: I I do, but I will let you I will let you share. I think it's your turn.
Speaker 0: I think it is. I feel like you've been leading the show for the entire time. So it's probably my turn. Also, I feel like should I be let me see. I'm, like, wanting to be more centered.
Oh, where are we? There we go. Now I'm feeling good.
Speaker 1: Okay. Good.
Speaker 0: Alright. I thought that, like, make make the choice to change where your camera is as you're as you're on on camera. Yeah. Screw it.
Speaker 1: Why not?
Speaker 0: Good vibes. Good vibes. So, on today's episode, we are going to be, implementing a new technology that we haven't really looked at, called Devcycle. And so, you now know from the last few episodes about what Battlesnake is. You know what Directus is because you're here on Directus TV.
And so now is the time to introduce you to the technology that I work with on a daily basis as a developer advocate at Devcycle, which is a feature flag management platform. So our plan today is to try and add some logic to our, Directus snake to get this, working is maybe a relative term. Getting the the dev cycle platform yourself
Speaker 1: a lot of scope there. A lot of scope. Working is a relative term.
Speaker 0: But we're gonna use the dev cycle platform to, add a little bit of, add a little bit of flavor to our snake and give it a little bit of, give it a little bit of control. And that will make a lot more sense in a minute. But Kevin, you look like you have something to say.
Speaker 1: I I mean, I'm gonna ask the question which I think you're probably gonna work towards, which is like, can we just talk for a moment about what feature flags are and then maybe what you had in mind, and then we launch straight in.
Speaker 0: I love it. So, a feature flag, if you've never heard of them before, condition conditional statement in your code, that allows for you to, turn features on and off depending on a bunch of targeting criteria. So let's say you are working on a new feature on your platform, or a new feature maybe for your Battlesnake, and you're not quite ready to to roll that out in all of the games, you could add a feature flag. Just wrap it around the code and then through a feature management platform like DevCycle, you can say, for these kind of games, I want you to use kind of this logic. And for these kind of games, I want you to use these this logic.
It's a really big part of things like trunk based development. So if you're moving from, like, branch based development where you're sort of, like, having features in branches that are long lived, and then we all had to deal with sort of, like, long lived branches and merging and dealing with merge conflicts. Mhmm. Feature flags are kind of a way to avoid those things just by constantly having your new features in code, and you can kind of decouple the code release from the feature release process.
Speaker 1: Interesting. Okay. And just to embellish this with my understanding, and you can tell me if I'm wrong, they basically work. So you put these conditional statements in your code, and what triggers those is this feature management platform. And typically, you would do that with some form of either like AB testing where people get allotted into these random buckets or you can be a bit more pragmatic and say 5% of users are gonna have this conditional turned on and therefore get a new feature.
And then we will also, like, we'll analyze their behavior as a result and decide whether it works, if people get it, and so on, rather than going it's an all or nothing kind of deal. Right?
Speaker 0: You got it. You got it.
Speaker 1: Got it.
Speaker 0: That's it. Alright. Money. So Great. That is a very ambitious plan that I just laid out, by the way.
I I feel as though may we get to a stage where we're able to, like, just determine, what kind of gameplay we're gonna have? That's possible. Maybe not in a 2 hour stream, but, we are gonna get Directus and Devcycle working together. How do I know they work together? Because I've already written a blog post on this separately from Battlesnake, so I got to explore.
And so now is the time to use my knowledge for for good and for evil.
Speaker 1: We'll link the blog post, by the way. We'll link the blog post. There are 2. There's 1 on our blog, that Esther wrote, which uses dev cycle, and 1 on the dev cycle blog, which you wrote, which is direct us. And I'll put a link to both of them in the resources section that accompany this video.
Speaker 0: Yes. I love it. So, y'all are seeing my screen right now. And so up here, you'll notice that this looks very similar, to, 1, mister Kevin Lewis's screen, although not in the Arc browser. I'm not apparently a strong enough, software developer to use Arc.
Not there yet. Once it comes to Windows, I'll start using it. It's it's it's happening. I know it's coming. I'm in a month of this.
Speaker 1: And then people will full on get this, but we're clearly recording this a day after the last one because they these are the games from the last episode they created about 23 3 hours ago, which is completely legit. We did something a little cheeky before this stream. We in a completely low rim fashion, you're running a director's to project. And I literally was like, here's a sequel database file and here's the extensions. Go run them and here's the creds I used to go log in.
We may have to reconcile with that at some point when things break. So there is a chance things won't behave and we'll have to fix that on the fly, but should be okay.
Speaker 0: I love it. So we have our snake our direct to snake here. It's alive. It works. Not yet.
We haven't determined if it works yet, which we probably will have to do. I also have our snake that was running on Replit. So the original, ready set battle snake that we created from the JavaScript starter snake. So Mhmm. I have that snake, but Replit was getting real mad at me today because I was using too much RAM and and compute.
So I pulled that down, and put it into this wonderful, repo here. Yes, sir.
Speaker 1: And you're gonna be bumping your font size up about 5 times.
Speaker 0: No. We're gonna expect everyone to to zoom in. Exactly. Exactly. That's the look of the look at
Speaker 1: my spectacles.
Speaker 0: Everyone has. And so, yeah, let's let's zoom in here a little bit. Alright. So this is the the kind of the original snake that our code is based off. So you will notice here that not all the logic that we implemented over the past couple of episodes are in here.
That's fine. This is more just to, like, show us how it's gonna work once we get there, and then we're gonna implement this indirect disk. We're gonna try and implement it in direct disk. But I think maybe the first thing we should do, Kevin, is actually get our Directus snake working. What do you think?
I feel like that's a logical first step.
Speaker 1: And what we're gonna do to make that happen is we're gonna set up ngrok. And so do you pay for ngrok?
Speaker 0: I don't, but I have ngrok. So, like, I can I can set it up right now, but it'll be ephemeral?
Speaker 1: Incredibly heavily, like, rate limit to you. Let's pause here. Let's get NGROC set up and using temporarily my auth token, and then we will come back. Great. So this bit, we won't we won't publish.
But, yeah, it was actually the one thing we forgot before we started. So let me just figure that out.
Speaker 0: Yeah. Throw me the key and then I can,
Speaker 1: Indeed.
Speaker 0: Alright. And let me just go to engrok now because I was actually logged in earlier. It was working for me in the games that I was playing, but,
Speaker 1: it but then it gets mad. That's the whole problem here. So what we want here is your auth token. So, here is the engrok command you are going to want to run here in the chat. Yep.
Speaker 0: Sorry. I'm just
Speaker 1: then because I'm on, like, old, the command looks slightly different, and that's there.
Speaker 0: Where are you hiding? Hold on. My windows have all disappeared. Where are you, Kevin? There you are, in chat here.
Alright. Wonderful. There's a chat. Here's a command. We're gonna add this auth token.
Beautiful. And we're gonna head back over here to our terminal and oh, nice. There we go. Paste. Beautiful.
Auth token saved, and let's run
Speaker 1: Nice. This.
Speaker 0: It's good. I set up ng croc earlier.
Speaker 1: I knew Yeah. Yeah. Absolutely.
Speaker 0: Beautiful. Alright.
Speaker 1: Good. So I think we can actually snap back now, and Yep. It's up to you what you want on the screen. We could be here if you want.
Speaker 0: Yeah. I mean, I mean, if you've never used ngrok before, I mean, we talked about this in episode, I guess, 2. We were looking at this. I have the free version. Kevin's got one that's less rate limited, so we're using that one.
But it's super easy to install. Like, just homebrew it, and then you add your auth token to ensure things are happening. But, anyways, we've got it running right now. And then my direct to snake over here is should technically be working. Now, Kevin, I'm really curious.
You should technically be able to go and run a game on yours, and see if it works. And I'm interested I think
Speaker 1: Are you running directors?
Speaker 0: Apparently, I am not. I think I might have closed it. Nope. I'm running it. Yep.
We're all good. Where is it running though? That's the real oh, you know it's running in another one.
Speaker 1: Do you have another
Speaker 0: I do.
Speaker 1: Versus code do. Window. There it is. Awesome. So we're gonna watch
Speaker 0: these logs here. We're gonna bump Shall
Speaker 1: we whack the font size up there as well? So I'll add ready set battlesnake and hungry bot once again to an 11 by 11 board. I'll hit start game.
Speaker 0: Yeah. And there we go. It's coming through. Awesome. We're working.
And you're like, but Andrew and Kevin, we can't see the games, and therefore, this isn't fun and enjoyable for us. Us. Fear not. Because I think actually an easy way to do this so we can keep ready, set, battlesnake in your repo. Can you make ready, set, battles cake public so that I can add him to my Yeah.
Speaker 1: I can. Yeah. My battlesnakes. Ready set battles cake. We named it that.
So it had a k instead of an n because it was the Kevin version of the snake as an FYI, and it is now public.
Speaker 0: Awesome. And so if you're ever in the Battlesnake platform, really easy. All you gotta do is just search for snake. Ready, set. Should find him skate.
There we go. That's what we want it to look like. And so now we've got them in there. And now we're gonna see this game going on, and it should be all of our logic and direct us. Something's not happening.
Something's unhappy here. Let's see what it is.
Speaker 1: Womp womp.
Speaker 0: I love that we tried and then we failed.
Speaker 1: Could you remove the what the old one password, pop up?
Speaker 0: I certainly can. Okay. There we go. Oh, no. Nope.
Same thing happened again, actually. Create Rematch.
Speaker 1: So let's think it through. What is going wrong here? It could be that our flow isn't running correctly, but it should be. Yeah. Like, it's going off.
It's triggering the flows. It's getting a 200, which means it's getting a response, and it's returning. So what is going what is going on?
Speaker 0: What is going on? We haven't gotten Because
Speaker 1: it was randomly breaking last time too. At the end of session 2, at the end of the second episode, our snake was, like, overpowered. Like, it was so good, and then it started to crumble. It started to grumble, last time.
Speaker 0: Let's take a look at our logs. We have got some logs in here. Holy moly.
Speaker 1: We do.
Speaker 0: Let's look here. So is there anything going on in here? We've got move now. Original. Yeah.
So I think we've got something going on there. Some so what do we have here? Yes. Feeding a lot of things there. False, false, false, false.
Oh, no safe moves. Avoid head to head. I think it might be in there. False, false, false, true, true. Yeah.
I think the issue is in
Speaker 1: Which we've already determined that we think is the case. So you know what we'll do to keep ourselves moving? If you close the pane, why don't we just avoid that entire operation and just take avoid body straight to determine move? Avoid head to head is a, you have to just hit the little edit in the top right of the Oh,
Speaker 0: of course, we do see.
Speaker 1: Yeah. And hopefully yeah. If we just do that and hit save, yeah, just yeah.
Speaker 0: Oh, we're back. We are back. We're back. It's alright. We're there.
I have a belief that if you just hit the save button enough times, we're gonna be able to resolve.
Speaker 1: I'm pretty sure that's the definition of insanity. I
Speaker 0: think it is too. We're gonna switch things up for just a minute. Yeah.
Speaker 1: And save
Speaker 0: this, and that didn't work. And then we're going to go back over here. And then we're going to go back here. And we're going to see if that worked. Oh, disk.
It was a bug.
Speaker 1: It was a bug, by the way. And it had an issue has been opened on this bug. So there you go. Maybe just discard the changes and just we can have
Speaker 0: Alright.
Speaker 1: Let's see
Speaker 0: if we can create another game, see if this will do it. I mean Okay. The oh, nope. Still doing the same thing. Still so moving out of bounds, logic is there.
It's definitely happening in 2 minutes ago. Let's get You
Speaker 1: have to refresh. Sorry.
Speaker 0: Alright. So let's go here, and let's see again. So determine move is still where things are, yeah, getting hung up.
Speaker 1: Oh, and you're saying avoid head to head is where everything went to force when they're logically, it should not been happening.
Speaker 0: I think so. Maybe that's what it is. Let's go avoid head to head options. There we go. False, false, false, false.
Payload. Avoid bodies.
Speaker 1: Okay. So so you know what we're gonna do? We're gonna jump into avoid head to head, and we're just gonna return the inbound date. Like, we're not gonna do anything.
Speaker 0: Alright. Let's go in there and do that. So here we go.
Speaker 1: Right. Because that's clearly where it were. Yeah. We're gonna literally delete everything apart from line 2 and 30. So everything in the middle there, ditch it off.
Doesn't matter.
Speaker 0: Can we not just oh, we can't comment. Really?
Speaker 1: I think no. So just but it's fine. We don't need it. This is this is the last episode. There we go.
I also have a copy of it, so it's fine.
Speaker 0: Ah, success. Alright. So let's save this and see if it works. There we go. And now let's go and try and recreate a game again.
Speaker 1: Because if that's the step that was causing grief.
Speaker 0: It was. Yep. Do
Speaker 1: you remember when I wrote all that really elegant code and it worked fantastically? Turns out not so much.
Speaker 0: Well, it's alright. It worked fantastically until it didn't. And that is the key to all the programming. It's all good until, you crash production.
Speaker 1: Okay. That makes me feel better that we've identified the issue and removed it for now.
Speaker 0: Okay. So ready, set, battlescape is working, and this is really the key here. It's still doing the job that it needs to do. So we're gonna make, we're gonna do something a little bit different now. We are going to actually be, having we're gonna bring ready set battlesnake back from the dead, in a new world.
So let's, let's kinda go over here. So this is good. Directus is working, and now we're gonna we're gonna ignore that Directus even exists for the next little while. And we're actually gonna head back over to
Speaker 1: Who needs to pay rent?
Speaker 0: Who needs to pay rent? Not me today. And I wanna look at, wanna look at our code here. And so is this okay for you, Kevin, or is it still too small?
Speaker 1: Yeah. Maybe take up another yeah. Maybe that maybe that's good, I think, for people watching.
Speaker 0: Awesome. So in here, not a lot has changed from when we were dealing in replit. So we still have our server dotjs, which is just an express server. We've got the 4 endpoints, the sort of root endpoint, start, move, end, and then we've got a bunch of stuff in here that's kind of, yeah, talking about what it's returning. We've got a read me here, which explains just how this works, which we don't really care about right now.
And then we've got our package. Json. I haven't added anything new to here except for this new dependency, which is the dev cycle, SDK. And so this is necessary for us to implement dev cycle. If we want to do it this way, technically, we could do all of this via our management and bucketing APIs, but I think it's cleaner through the through the SDK.
And then, there's some small changes. There's another file that's here, and we'll maybe call this in just a second. And I'll explain how I got to this file, which was not fun this morning when I was prepping for the show. So, originally, in here, we had our run server. We had our info endpoint.
We had our start and end endpoints. And then we had this move endpoint, which actually had some really good logic inside, that if we go and ignore all of this stuff, here was our original logic. And I'm gonna uncomment all of this stuff. Oh, I'm gonna try and uncomment all of this stuff if I actually uncomment the right section. There we go.
So this was our original logic. And I'm actually think just to make sure that this is working because, yeah, I've changed this so it wasn't async now, which was part of my issue earlier. I'm gonna save this. So this was sort of our dumb snake that we first started with. So Not dumb.
Yeah. But, like, dumber. And so you can see here all of our steps have kind of been implemented here. The base steps here, same thing that's going on over in Directus. Disk.
So let's see if this is working. I'm gonna run this express server. I think it's node index dotjs. So this is gonna run
Speaker 1: How are you gonna expose this as a Battlesnake if we're already running ngrok for directors?
Speaker 0: Oh my good guy. Also, updated cache direction to down. It is constantly running that caching. Interesting. That's fun.
Speaker 1: So the caching wasn't originally there, Andrew. So Wasn't. And please tell us about the cursed file.
Speaker 0: So we're gonna ignore the cursed file for a minute, and then we'll get to the cursed file. But let's see if we run this right now. Technically, I should be able to run 2, right, through engronk?
Speaker 1: I'm not convinced, but we'll we'll find out.
Speaker 0: Okay. What port does Directus run on?
Speaker 1: Not that one.
Speaker 0: K. Well, let's see if this works. No. It works. It's there.
Speaker 1: No. No. No.
Speaker 0: No. No. No. No. No.
No. No. No.
Speaker 1: Locally, but you still have to expose it.
Speaker 0: Yes. So can you see if one shows up in your, is it list it'll show up on your ngrok dashboard on your end if it's running.
Speaker 1: I didn't even know there was an ngrok dash I didn't even know there was an ngrok dashboard.
Speaker 0: We'll see. But yeah.
Speaker 1: Let's take a look.
Speaker 0: So behind the scenes, I'll actually pull this up just so people can see what this looks like. So when you go to the ngrok dashboard and you're logged in, if I am logged in, so you have, like, this authentication and set up stuff. And then you also have this tunnel section. And in the tunnels, I think it's tunnels where it actually shows you, yeah, what are currently online in your account. Account.
And so you should see you should see
Speaker 1: I've got one.
Speaker 0: You've got one? K. So this is not doing what we wanted to do. Wait.
Speaker 1: Wait. Wait. Wait. No. No.
Yeah. And the one is you. Oh, it is? Yeah. Started 10 minutes ago.
I'm not running anything locally.
Speaker 0: That's that's Directus, though. That's why.
Speaker 1: That's directives.
Speaker 0: Okay. So here's what we're gonna do. And now we need
Speaker 1: to try and run it a second time, but I'm not convinced.
Speaker 0: We can shut down directives for right now because we don't need it as we're just kinda demonstrating how this works in the index dot JS. So we're gonna shut down Directus for a second, and then we're gonna run it over on our other one. Alright. So we've shut down Directus, and let's go back over to index dot j s. Let's cancel this out and awesome.
Restarted that. What is the address that I'm wanting to go to, Kevin? Can you paste it somewhere for me?
Speaker 1: I don't understand what you're asking.
Speaker 0: Never mind.
Speaker 1: I But, also
Speaker 0: yeah. I've But you're not running ngrok yet. Right? Oh, that's right. I have to rerun.
No. I am running it.
Speaker 1: You need to rerun it.
Speaker 0: Exactly. Rerun ngrok. Yeah. Oh, there we go.
Speaker 1: Got it.
Speaker 0: Bad things happening. Okay. Let's go
Speaker 1: But this time, not 8,055. Yeah. Yeah.
Speaker 0: 8000. Alright. Here we go. Beautiful. Alright.
Alright. So let's go over here and see if this is working. Beautiful. Alright. So this is running now.
So if I go back over here to account settings oh, not account settings. My battle snakes. I'm gonna go ready set battlesnake, and we're gonna leave a JavaScript, and we're gonna have this on nothing, no platform today, and then we're gonna change our server URL. Yes. Like that.
And now if I go in and add ready set set, Battlesnake to a game, create game. And ready to set Battlesnake.
Speaker 1: Remove the Octa thing in the top right? It's very annoying.
Speaker 0: My goodness. All of the prompts. And then we are going to see if this runs. Okay. Good.
Basic logic, not running into himself, not running into walls. Good. So he's working. Alright. But I haven't implemented the logic for dev cycle yet.
So let's go look at what's going on. So we've got the moves that are feeding through there. That's awesome. That's what we want. I'm gonna actually turn this off for a second, and then turn it back on.
No. I'm not gonna turn it back on because it's gonna constantly need to be caching. Okay. So, that's our basic code. Right?
We're good. We're there. We're not here for basic code today. We are here for confusing broken code that will cause many problems and will make our heads hurt.
Speaker 1: You're really teeing this up, and I'm horrified before we've started.
Speaker 0: Don't worry. You and me both. So let's look at the new logic that I have in here, which is not great logic, but, I'll explain it. So, what we're doing is every time the move endpoint is called, this move function is called. Yes?
Everybody should track that so far. So what I'm doing here is I am calling a, this get cache direction function, which is basically every second or millisecond. I'm not sure. I think it might be millisecond. It's calling the dev cycle, platform and asking what move should I be getting for whatever user is on the platform right now.
This will all make sense when you kinda see the logic, but, basically, it's it's pulling the dev cycle platform to ask it what move you should be making as a snake. Does that make sense? Yeah. I think your face
Speaker 1: Unfortunately, this isn't even remotely the direction I thought we could go in.
Speaker 0: No. Don't worry. We're not gonna we're not gonna manually we're not gonna manually do this. We're I just wanna demonstrate the, like, how it actually functions. And so this is good.
Speaker 1: Mhmm.
Speaker 0: And I actually you can do it mid game too as long as your your click game is is on point. Oh, man. Which we can do today because there's 2 of us here. So Oh my god. We're gonna go and actually look in this cache dotjs file.
So here's our cache.js file. Couple things happening here. First thing, we're importing the server SDK that this dev cycle from there. Then we're initializing our dev cycle, client in here, despite it being a server application, we're calling it a dev cycle client. This stuff is That's fine.
That makes sense. Yeah. This stuff isn't super important, the cloud bucketing and enable EdgeDB. It is and isn't, but really the important thing here is that we're initializing the dev cycle client. We're creating this cached direction, which is setting the default move for our snake to go down.
So, basically, if, the first time, if there's been no caching, if this has never run before, it's gonna go down. And then, yeah, within this function, we're feeding in the user variable. So you have to feed this in every single time that you, that you do anything with the external platform. You have to feed to the user. You can feed in custom properties, which we may try and do today, where you can, like, base it on different information that you may have.
But this is the idea here. And then once we've got this dev cycle, client established, we're then going to look for a specific variable that exists in the Dev cycle platform. Think of a variable as, like, the feature flag that you're looking to pull. So whether you're wanting to see on or off, we're actually pulling a string. So we're pulling for the direction for this user.
What should this user be seeing if we're looking for the direction variable that's in there? And then we've got if we do end up having a preferred direction. Yeah. Because where's my preferred direction defined? I think it was defined over here.
Right? Yes. There we go. So, preferred direction. So, basically, it's saying that if there is the DevSecLE client being established and it finds that that direction variable exists, then we're gonna look for that preferred direction variable that we had defined over an index.js.
And if it returns anything but none, it's going to put a new cache direction value in there, and then it's gonna log that it's updated the cache direction. Otherwise, it's gonna give you an error. And then if we go down here, yeah. We're basically updating this every 10 it's not ten seconds. This is, like, every 10 milliseconds.
Speaker 1: That's very, very often. Very often. So a1000 is one second.
Speaker 0: Yep. And then I gotcha. Yeah. So this is our code that we're doing here. Basically, we're just constantly pulling the dev cycle platform to, like, get the latest updated stage.
So there's a little bit of a delay here, but it works pretty well.
Speaker 1: I will believe it when I see it. Gonna be honest, mate. Okay.
Speaker 0: Alright. You're like, this is garbage spaghetti code. What are you doing, Andrew? It's not like it's not the code.
Speaker 1: It's just this isn't how I would have. Can I give you maybe an idea of how else
Speaker 0: we could have implemented this sort of code? Yeah. Let's yeah. Let's go.
Speaker 1: We literally just have, like, branching logic in the flow. And based on, like, there's the snake gets an ID for every game. So you can enroll them and then, like, 10% of the time or whatever, they get thrown into, like, strategy 2. And strategy 2 could be it become it just goes left all the time. Like, it doesn't matter.
Yeah. But you could implement branching logic. Right?
Speaker 0: So we are and that is what we are gonna do. So you're not wrong with that. I just wanna show how this works.
Speaker 1: That's fine. Okay.
Speaker 0: Then we can get into the logic. So Okay. That's our logic here. So, basically, we're calling this every 10 seconds, and then it's gonna if it's updating, it's gonna show us this using cache direction, and then it's gonna do that.
Speaker 1: And just to clarify, the whole reason you've created this notion of a cache direction is so we're not gonna go to dev cycle every single move. We will go a 100 times a second instead.
Speaker 0: So what's what's interesting is because we're basically running an async method here, there's a delay and devs battle sync doesn't like there being any sort of a delay. So I had to I completely got it. So you
Speaker 1: have to have some I got it.
Speaker 0: Yeah. You've gotta do the polling yourself. I think you probably if I was a better programmer, I could probably figure it out, but this was like No.
Speaker 1: No. I I I get it now because you could call dev cycle every time, but you're not gonna be able to respond within 500 milliseconds confidently. Yes. So for that reason, instead, we will catch the last direction it gave you. Exactly.
I got it. I got it. That makes sense. Fine. You're I'm with you.
And
Speaker 0: it's interesting. The reason I figured out that this was working is so if you notice here, in the logs, so we actually it returns move 117 right. What I was seeing in my logs was it would be like move 01746328. And so it was taking time to actually do the the the calculation. So anyways
Speaker 1: Which is no good for the snake. It just won't work. Yeah. And so
Speaker 0: I'm gonna leave this I'm gonna leave this at, at 10 milliseconds for right now, now only because I'm running on my own device, and I think your end grunt won't get upset at me. And because I know that it will demonstrate how this works. The downside here is I actually, Kevin, will need you to be the one that is starting no. Because nobody's gonna be able to see it. Okay.
We're gonna see how fast Andrew can click things is what we're actually gonna see. So we're gonna start this again. So if everything's working properly over here, I've uncom oh, I've gotta uncomment this. Let me cancel that again. Let's uncomment that import statement.
I think all the rest of this logic has already been commented. Awesome. So now if we run this yeah. So we're basically checking this, like, every 10 milliseconds. It's kind of crazy.
I don't fully know why I don't think it's running every time it shouldn't be.
Speaker 1: I'm unsure logging every time it's making your terminal choke.
Speaker 0: Here's my question though, is we're not calling move all the time. So I'm confused why
Speaker 1: That's a good point.
Speaker 0: Get cache direction is being called every single time because it shouldn't be. It should just, like, literally only be called when moved unless I've got a game running somewhere. Do I have a game running somewhere?
Speaker 1: You shouldn't be. No. I don't even know how you would check that.
Speaker 0: Yeah. I don't know either. But, like, if I look at this okay. Request made.
Speaker 1: Oh, are you the squiggly brackets? Yes. The destructuring.
Speaker 0: I shouldn't have done that. Alright. So, yeah, it should not be running. It should be running every time. What is going on here?
It must be something in this actual cache file. Let's see what's going on here. Import dev cycle, initialize dev cycle, let cash direction go down, update cash direction, import dev cycle.
Speaker 1: Yeah. Because you're set into it here on line 33. So that's happening regardless. That's happening the moment it's imported. That's not linked to that function running.
I don't think it's that much of an issue.
Speaker 0: I'm gonna change this to, like, a 100 because what's that?
Speaker 1: That would've that was gonna be my only suggestion is maybe just knock it knock it down a bit. Okay.
Speaker 0: Yeah. Anyways, we're gonna do this. We're not gonna do a lot of this, because it's gonna be less important. But, we're gonna set this running, and then we're gonna go and actually take a look at the game. So here we go.
So we're basically changing this direction, and I'll actually actually, let me cancel that for a second. And I'll go to the dev cycle platform so I can show you. I already set this up.
Speaker 1: Yeah. Yeah. Yeah. That'd be good.
Speaker 0: Here are the dev cycle form. Once I log in once it logs in come on, dev cycle. What are you doing? Oh, there we go. Logged into the wrong one.
So we actually just launched a, a bunch of new example apps, and so I've been playing around with those. But there's no way to log out without, getting rid of the the demo mode. So, that's how we're gonna log out.
Speaker 1: I feel like it's like a user retention is great if the user can ever log out, get a life hack.
Speaker 0: All right. Let's close these again, see if I close this. And let's try app.devcycle.com again. And I think this is gonna load. Yeah.
There we go. Awesome. Log in with my work count. It's gonna bring us over to the dev cycle platform, all of our production stuff. We're not gonna mess with our production stuff today.
Speaker 1: Do it. Do it. Let your intrusive thoughts win.
Speaker 0: So I did it at, at KubeCon. I actually we made a bunch of live changes while we were doing demos, and our entire engineering team got very unhappy with us. And so I think we're ready to set Battlesnake. And I've got this features area here. So I've got a feature that I've set up called my choose move feature.
And this is Could you,
Speaker 1: zoom in, sorry, 1 or 2 times? No. That's okay. The small text is quite small. We're good.
Nice. Thank
Speaker 0: you. Perfect. Yeah. So we've got our choose move feature. This isn't super important for us right now because I've only got one feature.
And then I've got this direction variable that I have there, and I've defined 4 different variations, left, right, up, and down. These are string variables that are in there. And then in my targeting logic, I'm basically saying who to serve what or what to serve to what users that are feeding into that SDK. So here, I'm basically saying serve all of the users down, but that's also my default. So I actually want to be serving to see if this is working and actually talking right.
I'm going to change this to serve everything right. And if this is working now, when I turn on that Battlesake server, I should be seeing everything in this updated cache direction except for the first one showing as right. So let's see if that works. There we go. And even the first one did.
So we've got the changes happening here. And now if I go back over to the platform, change this to up and save and then take a look at my logs. And so it's like real time changes that are happening in there that you're able to kind of differentiate what's going on. So the interesting thing here is that, technically, platform to control your snake in real time. It's a terrible idea.
Speaker 1: That is literally the like, like, we've seen people play Battlesnake live using, like, games controllers. And even that, you're like, well, there are some questionable choices here. This is like drop down and then save.
Speaker 0: So but I'll show you something inter I'll see if I can get this to work, and I'll just do a I started using, there we go. So I started using, rectangle, and
Speaker 1: Sure.
Speaker 0: I can't believe that I've never used it, anything like that. Oh, yeah.
Speaker 1: I use Raycast for it, and I have keyboard shortcuts. Oh, look at you. Which is really, really nice.
Speaker 0: So let's grab ready set battle sneak in here. And we're gonna go start gaming. Just ready set battle in here. And so you'll see it's not gonna work right now because it's not running. So he's going up.
So we know it's not down. There's no conversations that are happening right there. So since we know that we've set our game mode to, let's change it to left so we know that something's working here, and then I'm gonna start my server. And now if I create a rematch, should go left. Awesome.
So we know that it's working. Sure. Alright. So now I'm gonna do the thing that is, like, the test of Andrew's ability to click things really fast. I'm gonna create a rematch.
And then in, like, real time, I'm gonna click save. And there should be a switch if the board is big enough. But, actually, I need a bigger board because that will give me more time for things to go wrong. Let's go 19 by 19. Add, ready, set, Battlesnake.
Start game. Oh, I shouldn't have done that. Anyways, it's fine.
Speaker 1: You've done that. You you moved moved.
Speaker 0: Do do do do do. No. It's too late. The game already runs as soon as you click create rematch, so I gotta be a super fast. Alright.
Here we go. So right now, he's set to go left. I wanna change it so he goes
Speaker 1: Don't worry about hitting play. Just hit create rematch, hit save, and we can see it in the playback that it's happened.
Speaker 0: Alright. Here we go. There we go. Oh, and he's going left first. So literally, the worst example
Speaker 1: that ain't gonna work. Before you create rematch before, you wanna yeah. Prime. Prime. Oh, yeah.
Change it.
Speaker 0: So right now, we're going down. So we're gonna get it. So we're gonna go first, we'll be going down, and then we should go right as long as we know where it, as we long as we know where it spawns. Okay. This should work, actually.
This should be good. So here we go. Should go down first, and then at a certain point, go right. Oh, not fast enough. We're gonna try this again.
I tell you, it did it does work. You just gotta have the the right movement.
Speaker 1: Andrew, I full on believe you. You you don't have you're not proving anything. Don't worry.
Speaker 0: Come on. Really?
Speaker 1: Your your taste.
Speaker 0: Oh, did we see that? We did it. We did it. So here's the thing. Right?
So we changed it from right to up. So we're going right. We're going right. We're going right. And then suddenly, we start going up.
And that's there's no logic in here that says, dearest, dearest ready set battlesnake, avoid that wall. This is all just, Andrew changing that logic in real time. And you can see if we go to the logs there, which are gonna be, like, super overrun now, not that logs, these logs. But you can see here in our terminal there we go. Yeah.
So we're updating our cached app, updated cache direction app. And so you can see that there's, like, the change that happens in here. Yeah. Oh, and this is the interesting thing too here. Right?
Is you actually see so most of the time, it's updating cash Kevin, are you impressed? Are you blown away by my amazing implementation of this?
Speaker 1: I am so blown away. Thank you so much. I feel like my life has been genuinely enriched in the last 39 minutes of recording. Thank you, Andrew. I don't
Speaker 0: know what I would do without you as
Speaker 1: a friend, a mentor, a colleague.
Speaker 0: Thank you. Thank you. Good. Yeah. And that's it.
Episode over. We're done. Episode wrapped. Thanks. So, that was just like this is I feel like in every good episode, in every good coding experience, you should do something that's totally useless and makes absolutely no sense so you have the knowledge and skills to do something that actually makes sense.
Speaker 1: But there are some things already set up. Right? So we've got the dev cycle, like, prod forgive my terminology if I use the wrong terminology. But we've got the project set up, we've got the variable, we've got the options, we've got the ability to change it and hit save. We have a client, you know, we have like an ID for this specific feature.
So, you know, we have all the parts, and we can just apply it in
Speaker 0: Exactly. Different ways. So what we're gonna need to do here is I'm going to so we're gonna forget that all of this ever happened. We're gonna go shut off ngrok, for a second, and then we are going to go back to our direct us instance, and we're gonna start direct us up again so we can start to have some fun. And we've got all of our code here.
Why
Speaker 1: We do. Are you It's it's it's the other it's the other Visual Studio code that's in the back. Yeah. Are you
Speaker 0: talking about? What? Hold on. Alright. We'll doc, and then we'll go back over here to engrok, and let's get this running.
Oh, I'm running the wrong one. There we go. Nice. Wonderful. And let's go over to here, which I should actually have open in my window.
Oh, and we don't need this for right now. So let's open that and make that bigger. And we should be able to go to here. Wonderful. I am gonna need to log in again, I think.
Speaker 1: No. No. No. I think it'll be fine.
Speaker 0: No. I need to log in again.
Speaker 1: Oh, you're gonna need to log in again. Battlesnake@lws.iohunter2. Glasses us what I set this up with. There you go.
Speaker 0: Okay. So here is our logic. We removed a bunch of stuff from in there. Great. Our snake is working again.
Should be working again. Logs are all there. I feel less bad about all the logging that I was doing of every time that we were calling Dev cycle now that I see these Exactly.
Speaker 1: Thousands of We actually you know, this was I mean, all the dates, like, visible elsewhere. Just today, we actually recorded, or we we did a live request review, which is our show where we or it's our live event, which then becomes a show on director's TV a week later, where we go through feature requests to talk about them, and today's was all about flows improvements. And one of the big things is the ability to change the retention of those logs. I like that. Because, yes, they get they get chunky.
Speaker 0: They do. So, what I think we are going to do, and I liked the idea that you were talking about before, Kevin. I think let's do 2 pieces of logic, and we're gonna we're not gonna delete all of this stuff. We're just gonna kinda remove it for right now, and then we'll reconnect it. And I think we'll have just right now 2 different blocks.
1 of them that returns right, one of them that returns left for moves, and we'll have some branching logic in there. How does that sound to you?
Speaker 1: Let's create a new flow for this, and then we could just hook it up to the extension, rebuild it. Like, I think that might be a good a good shout.
Speaker 0: Let's do that. So let's call this snake, cycle. Alright. And Great. We're just gonna leave that.
Speaker 1: All of that's good. Just next.
Speaker 0: And webhook or webhook. Yeah. Okay. And then get, I think.
Speaker 1: Host.
Speaker 0: Not the get. Not I had a 5050 shot there, and I got it wrong. There we go. No async
Speaker 1: calls either. Because because we'll get because we'll get a post request from the Battlesnake platform. Yeah, data of last operation safe. And then what we wanna do here is grab that URL. Yeah.
I think yeah. Perfect. Go go to the code editor. Go to the extension called snake. Yeah.
Speaker 0: I think so. And then in our source index dot JS, and we just wanna update this. Right?
Speaker 1: For move for move. The move one. And just to not have to do the round trip, we'll change the for local host 8055. But hit paste. That'll give us the ID
Speaker 0: of the trigger and everything.
Speaker 1: Yep. And then, yeah, we'll just change that for HTTP, not HTTPS, localhost
Speaker 0: secure my how to secure my URLs. Kevin, who who are won't work. Phone's bloody work, man. Actually, it does. No.
No. It does. I'm pretty sure. I'm pretty sure ngrok automatically anyways, I don't I don't need to
Speaker 1: Not not on not on this one. Yeah. Yeah. But yeah. Yeah.
Yeah. But not on the local not on local host. If you were doing it via ngrok, but then we're gonna have to do another round trip to ngrok for what? It runs locally.
Speaker 0: Smart. Okay. So we've got our trigger there. This is our move. So now this is all feeding through to the place that
Speaker 1: we want. Now we've got to rebuild the extension and restart directives.
Speaker 0: Npm run build?
Speaker 1: Yeah. From the from that extensions directory. So let's create a new terminal in here.
Speaker 0: Yeah. CD extensions.
Speaker 1: Yeah. You got it.
Speaker 0: And CD directives Extension.
Speaker 1: Extension snake. Jake and m You got it. Build. You got it.
Speaker 0: And then restart And then we just Oh, because cannot.
Speaker 1: Okay. This is fine. This is like macOS going overboard. Open up your open up your settings on your Mac. Security, I think it is.
Speaker 0: Yeah. We may not be able to do that just because of the security settings. Security
Speaker 1: No. It was there. It said privacy and security.
Speaker 0: Security settings.
Speaker 1: No. Just yeah. There you go. Allow anyway. It's right there.
It's right there. Fsevents.net. Yeah. Yeah. Cool.
Yeah.
Speaker 0: Great. Alright. Let's try this again.
Speaker 1: You got it.
Speaker 0: Beautiful. Okay.
Speaker 1: Lovely. And then restart and then restart the Docker container. Fixed in directory version 10.9, which we have not upgraded to right now. There you go. Hooray.
And now you're good.
Speaker 0: Okay. So let's head back over to Directus, which is Yeah. Somewhere. It exists. It is in the world on this device.
Too many windows. Directus. There we go. Okay. So here we go.
So this should be talking here. I'm actually gonna go start a game just to make sure this is working. So let's go, play.battlesync.com. Let's go create game. And I think yeah.
Does it still save recently used? It doesn't. That's so sad. Used to do recently saved escape. There we go.
And if this is working, we should see a log showing up here. Don't look. Happen. Just no. That's fine.
We don't it's probably not gonna work work, but it should show a log here. We have 10 logs. I love it.
Speaker 1: Awesome.
Speaker 0: Yeah. Okay. Method post. Yes. So that's 10 moves that it took to pass away.
Perfect. Logic is coming through there. Accountability. Awesome. Okay.
It's working. So now we're gonna do some branching logic in here. So we're gonna go and condition. And we're gonna worry about the condition afterwards, but let's call this dev cycle response.
Speaker 1: Oh, it's
Speaker 0: not here.
Speaker 1: Well, hang on. Not in not in a condition. 1st, we need to go get data and then we run conditions on the results. So I'm assuming we can just make I'm assuming with DevCycle, just an API, we can make an API request, right, just a raw API request. So you want the webhook request URL, one there.
Perfect. And first, we need to go get the data, then we'll do the conditional logic. So this might be a moment to look at the dev cycle docs.
Speaker 0: Yeah, that would make sense. We should probably Yeah.
Speaker 1: And there will be a moment here where we'll we'll redact it for for the recording, but you're gonna have to authenticate yourself. So you're probably gonna need to put in, like, an API key or token. Can you create multiple inside of your dev cycle?
Speaker 0: That's a good question. We're gonna experience this together. Yeah. I haven't played around with the yeah. So we're gonna do a little bit of this together, and then we're gonna not do a little bit of this together.
So let's head over there. So jumping into the dev cycle docs, APIs, management API. This is to create features and variables. I don't think it returns anything. We actually want the bucketing API.
So this is used to fetch on HTTP. Yes. Yes. Yes. Unique identify the user.
Definitely, this bucketing API. Get all the variables. Get all the features. Post events. Get variable by key.
Okay. This is what we're looking for. So let's head over to bucketing API, and we are going to have to get our key Wait. What what my key?
Speaker 1: Yeah. Sorry. What's the endpoint we wanna hit?
Speaker 0: So we are going to do get variable by key for user data, I think. Let me look here. Private platform SDK type. Missing SDK. Get all variables.
What is that gonna return? Is that gonna return the status?
Speaker 1: What's our what's our end goal here? Our end goal is to
Speaker 0: We wanna just get the value for the variable. So it's very similar to what we're dealing with in our SDKs.
Speaker 1: To the user ID to start.
Speaker 0: Yeah. But everything is hidden behind our bearer token. So I'm just gonna find where all of this is hidden. So key type variation, variation in variation key, response examples, get all features by key post events. No.
Fetch
Speaker 1: No. I think get all fee I think I think you were right. Get all features by key for user or get all variables by key for user data. And this will no. Because this will
Speaker 0: return Here it is. Yeah. Here it is. The value. Fantastic.
That's what we're that's what we're after is the value. So, we're gonna go offline for one second as I go and get all of my authentication stuff sorted out, and, then we will be back with our API stuff.
Speaker 1: Sounds good. Okay. So For what for what it for that's worth, we could totally have kept it going, and we could just redact it, adjust that slither slither
Speaker 0: and time. Keep it going. Yeah. Let's do that. Alright.
We're back. Yeah. We haven't gone anywhere. We thought we were gonna go somewhere. This is interesting too because we if an so, technically, our management and bucketing API are actually using the same stuff.
I need to update our docs because we should actually have this curl command in, both, and they're not both there. I guess most people are just assuming we're gonna be using that. So, I'm gonna go and, in a different window, actually, open up, my OAuth token using the client ID. Okay. So I need to go over and what do I need here?
Client ID and client secret in my dashboard. Alright. So let's go over here and yeah. I don't think
Speaker 1: Yeah.
Speaker 0: Showed anything.
Speaker 1: I'm a I'm a little bit fuzzy on how you authenticate.
Speaker 0: Let me show you. Okay. So what we do here is alright. You're seeing my screen now. Hey?
Speaker 1: Yeah.
Speaker 0: So and, again, I will fully admit that I have only messed around with our API in a very limited way. So, basically, we are doing a curl request with our client ID and client secret. We can actually obviously do this same post request in Directus, and we're just using our client ID and client c. We can't do it directly and directly.
Speaker 1: I've just spotted it. The type the encoding type for this, for this request is a URL encoded form, but that request URL, you know, operation that's built in only sends JSON. And they're just you don't work around this. Like, you can't do it. However, I'm not too too sad because you can, of course, do it using a custom endpoint.
It's not quite what we wanna do, but could we do or building a little custom operation. So maybe that's what we do in order to to do that round trip. It's not the ideal, like you know, it means we're gonna have to spend some time doing a little bit of extension development. Like, just spotted that. Is that is that the only way to do it?
Speaker 0: Yep. Yeah. We have no real public API stuff, which is interesting, but also so what's interesting so we are having so we're working right now on some webhook stuff. So you can technically get when, certain changes have been made, like an audit log. You can read that through a webhook, but you can't actually read what people's values are.
Speaker 1: Because that would that would be so good because on a webhook, you could trigger a separate flow, store indirect just like your cache Yeah. And then do stuff based on that. But that's completely fine. So we could do this or if we're building a a little custom, operation, we could just straight up use the SDK.
Speaker 0: Yeah. So let's do that. And then we've already got the code there. So, yeah. Okay.
Let's, are we gonna do this here inside of our code, or are we gonna do this over on the platform to get started? Where are we gonna
Speaker 1: I don't under let let's let's build an operation for flows as an extension. And the goal of that operation is to, right now, just get a fixed, you know, a fixed response from from the API. So, no, we don't do it like this. We actually use the extensions SDK CLI, which will boil the plate a whole extension for us.
Speaker 0: Alright. We're gonna delete that bad boy. Alright. Let's open
Speaker 1: a new terminal here. Open up a new terminal. You got it. And we'll go into the extensions folder.
Speaker 0: Alright. Oh, into the extensions folder. Extensions folder. Yeah. Yeah.
Speaker 1: Yeah. Sorry. Yeah. Yeah. Exactly.
Exactly.
Speaker 0: And then how do I pull up the docs? Or are you just gonna Yeah. Docs. I mean,
Speaker 1: I could tell I could tell you this one, but let let's let's do the docs. Let's let's have the authentic experience with someone who doesn't live in this every day.
Speaker 0: There we go. Alright. Let's head over. And we're gonna see this is gonna be my challenge. How long does it take Andrew to find out what I'm looking for?
Alright. So when direct to stocks, we're in extensions. We're in device extensions.
Speaker 1: Zoom in.
Speaker 0: We're going to zoom in. We're going to go extensions. We're going to go, developing extensions and we're gonna go extension services and introduction. No. That doesn't look like what I'm looking for.
Speaker 1: Maybe Very good. Very very good little piece of feedback there. Go into the fundamental section, the one you haven't opened out of the 3, the last one, and creating extensions.
Speaker 0: Perfect. We're just gonna use this. Alright. Let's go back over here and run this.
Speaker 1: But I I do see that. I do see that path you took. I'm glad to know that. Discussed it with one of our colleagues just yesterday. So yeah.
Speaker 0: Like, when things work oh, oh, I need to change my note version. It's upset with me. Wait. What? Oh, it's just warnings.
Really? Oh, yeah. Whatever. Sure.
Speaker 1: Me. That looks
Speaker 0: what do
Speaker 1: you wanna create? Operation, please.
Speaker 0: Oh, there it is. Hidden down in that list. Choose a name.
Speaker 1: And they so they must start so they must start as of this release. I think it might be gone in 10.9 or it'll be gone in a soon release in a upcoming release. Directus dash extension dash whatever you want. Dev cycle is fine.
Speaker 0: JavaScript because I don't play with TypeScript.
Speaker 1: I respect that.
Speaker 0: Dependencies. Yes. Scaffolding it. I love this. This is so smooth.
I like a I like a good CLI.
Speaker 1: Good. Great. So now we have if you go into the extensions drop down, you have a new extension called dev cycle inside of source. We have API dot JS. We have App JS.
App JS is for all of the configuration. So it's all the UI part. It's all of the options when you create a new one, you have that little pane that pops out. It's the information that will show on the on the card in the overview where you connect to all the nodes. That's the overview there.
And then the API dot JS is the node code that will actually be executed in the background. Right?
Speaker 0: So we're gonna go and I think right now what we wanna do is actually grab, just so we're not having to worry about this later. We're gonna grab our code from here. So not going back and forth, because this is basically all the stuff that I need.
Speaker 1: Yeah. Great.
Speaker 0: And we're just gonna put you down there and comment you out so that things don't get upset with us.
Speaker 1: Sounds good.
Speaker 0: Alright. Perfect. So let's save that, and let's do an install. So I do have to have to go into this folder to install, slash extensions. Directus extension CD.
Extension. CD. Cycle. Not we're not we're gonna put it at the end and see what happens. No.
Start. Start. Start. Start.
Speaker 1: For a moment, I was like, am I about to learn something?
Speaker 0: No. There's there's very little learning that will be
Speaker 1: There's very little learning. I got it. I got it.
Speaker 0: And then we gotta go over to because we're gonna install the, the SDK. We're gonna go over to the dev cycle docs. So we'll move back over to docs, and let's head back over to the dev cycle docs, docs.devcycle.com. And we're gonna head over to our SDK section, our node JS SDK
Speaker 1: You got it.
Speaker 0: Installation. And let's grab this because who uses yarn, NPM or bust? I've become so opinionated in my coding Alright. So that means that our import statement should work now. Actually, is this import or is this require?
I This is import. Yeah. I thought so. Alright. Let's move you to the top.
Alright. Perfect. So step 1 complete. We're done. Time to go home, everybody.
End of episode.
Speaker 1: So a couple of things that are just important before we continue. There is an ID here called custom. Let's rename that, and then we have to reflect that ID in the App JS and the corresponding App JS. I think dev cycle is a perfect ID. So we just want those 2 to match, first of all.
Very good. And let's, while we're here, give this a name. Dev cycle, this is the nice friendly name that shows up when you pick your operation type. Sure. Yeah.
Then are we gonna ask the user for any configuration up front? And I'm gonna say that maybe we do. Maybe we wanna collect the snake eye like, the the the ID. Right? Are we gonna do it?
Are we gonna have time to do that? I mean, can we give it just an arbitrary ID, or does do you have to register users inside of the dev cycle system first? Like, how does that work?
Speaker 0: So you would need to feed a specific user's information. Yeah. Let's call a snake name. Yes. I think that's a great idea.
Yeah.
Speaker 1: I was a snake ID. Snake ID. So let's do that. And at first, we'll just hard code it, but later, you can put dynamic values in here in flows. So instead of text, let's just change text to snake.
So there's a friendly name. Yeah. Yeah. Perfect. There's a friendly name.
Speaker 0: Yes. Is that correct? Is it? I changed this from tests from is this yeah?
Speaker 1: Yes. That's all good. The options need to change too. That's the part. So that that's the overview that will show on the card.
Cool. Whatever. It's the options we care about. That's the pain that comes out and you select all the options. So in here, the field, the field will be called snake.
And that's what corresponds with the snake in the overview. That's the friendly name. It will still be a string. It'll be full of input. Great.
Save. Now we'll go over to API dot JS, and there's text here. We'll change text for snake. So that says taking in the snake value and now we're going to execute some code. But before we do this, I think that's everything on the UI side done.
We want to initialize this client and we'll want to initialize this client between lines 13. So everything in your yeah.
Speaker 0: Great. So, we're going to ignore this because we're not actually going to I'm actually I'm interested to see how this works. Once we have done this, we're going to change some things up eventually. But we're not gonna worry about that right now. So let's grab
Speaker 1: Oh, which was straight upon commenting everything. That's that's crazy.
Speaker 0: I mean, nothing could go wrong because nothing's really running yet. So this is good. This server is gonna change. I'm gonna leave these. I don't actually know if we need these, but I'm not gonna question it.
Speaker 1: If it works before, our goal is to take what worked and apply it here. So we're not gonna make any changes to the logic here.
Speaker 0: Yeah. Exactly. So we are initialized there now, and now we need to pull all of this stuff up above. And I think we're not gonna need that get cached direction elsewhere.
Speaker 1: I don't think we wanna necessarily play with that right now. And at the very least, we wanna make sure that we can get data from dev cycle in a flow Exactly. And then pass it on. But if you were having an issue where it's taking a little while to do that round trip, there's a pretty good chance that we're gonna hit that here too.
Speaker 0: Okay. So let's go here. Awesome. Alright. So here we go, dev cycle clients.
So we're established here. We've got this cash direction. Again, I don't actually think we need this anymore because we're gonna be calling it sort of once to determine what's gonna change. We're not gonna be calling this again and again and again. Right?
We're not gonna be calling this every move. Is that our that's our focus. Right?
Speaker 1: I mean, we were. Yeah.
Speaker 0: Do we we were gonna call it every move? Oh,
Speaker 1: this is all in the wrong endpoint. This actually wants to go in the start game, doesn't it? Once you're in the start game and then for the game, we determine the strategy and then we execute on it. This is okay. Let's keep rolling now.
And then before we've done it with yeah, exactly. Precisely. So let's really let's let's keep this light. In fact, I think doing everything in a separate function may not even be what we Exactly. Want too much here.
Speaker 0: So I'm gonna pull all of this out of this update cache directory.
Speaker 1: Hang on. Hang on. I think the only bit we care about is this dev cycle client variable.
Speaker 0: I think
Speaker 1: that's the only bit we want.
Speaker 0: We also care about this user thing. So that's
Speaker 1: where that's going to snake. Yeah. But that's going to that's already that's coming in from the snake value above. So we're gonna get to feed that in.
Speaker 0: Yes. Yes. Yep. I guess it has to feed a very specific way. It has to be a very specific object that's feeding in, but maybe you're right.
Let's let's see. Let's see. I think I think
Speaker 1: it'll be okay. So so if we if we go down to where the actual flow handler is, which I think is down. So inside of the handler, instead of the console log, snake is a string. So what we want to do here is we want to make on line 41, we want to make this an async function. Right?
Yep. No. As in as in we wanna change just before the the snake. Oh, I see. We wanna make it async, then we'll just use a sync yeah.
One more to the left. One more to the left.
Speaker 0: Goodness gracious. And we're gonna get rid of you. You don't need to be there.
Speaker 1: And then and then inside, what we wanna do is is run that run that SDK method, but we can do it with a wait instead of then just to clean it up in this context. So if you scroll just very slightly up oh, yeah. We'll ditch something small. Yeah.
Speaker 0: We're just gonna do this. We're not gonna need to do this call. Perfect. Let's just work the day.
Speaker 1: Grabbing this. Yeah. But only 17 18 to start.
Speaker 0: Oh, yeah. You're right. Yep.
Speaker 1: Because we're doing a sync await.
Speaker 0: Yep. Yep. Absolutely.
Speaker 1: So we want that. That goes straight in there, within within a wait at the beginning of line 33 and a store this in a variable. Right?
Speaker 0: Yeah. Let's call this strategy.
Speaker 1: Beautiful. Love that. And then user is now gonna be I mean, if you wanna grab lines 13 to 15 just to get the structure, but really it's just an object with the user ID and snake. Yeah. Yeah.
Exactly.
Speaker 0: Let's see what happens. And then yeah. So we're gonna Other way. We're gonna define this above. Yep.
We can assign this above. Awesome. And we're actually gonna feed this in. User ID here is gonna be snake. So we're gonna feed in snake here.
Speaker 1: Snake? Yeah.
Speaker 0: I think that should work.
Speaker 1: I think that should work. But we don't know what comes back in strategy yet, so we're gonna log it. Perfect. And then we're going to return strategy.
Speaker 0: Beautiful. And that's actually add some comments there so we know it's being logged. Strategy.
Speaker 1: Oh, can I show you can I show you a quick tip for this, which I think you'll
Speaker 0: really like? Love a quick tip.
Speaker 1: So remove that remove that string in the comma from the console log. So it's just the word strategy again. Yep. And then highlight all of the word strategy, just the word strategy, and then surround them with squiggly brackets. And now that is an object where the key is strategy and the value is strategy.
So when it logs, you get strategy, colon. Yeah. It will be an object. So that is just a real shorthand if you if you just want to quickly tell what something is and you have just a variable key.
Speaker 0: You know, sometimes I enjoy JavaScript, but only when people that enjoy JavaScript are doing JavaScript with me. Okay. So technically, this should this should do all of the things that we want it to do, I think.
Speaker 1: Yeah. And
Speaker 0: so this is wanna change this to hold on. Oh, sorry. Go ahead, Kevin.
Speaker 1: No. No. No. Go ahead.
Speaker 0: So I'm just saying here so here, we're actually gonna go and create an so this is a direction variable. We're gonna create a strategy variable and kind of put 2 strategies. We're gonna do, like, hungry and tailchase or something like that.
Speaker 1: I mean, we we're not gonna implement those. So why don't we do left or
Speaker 0: right? That is a very smart decision, Kevin. So let's head back over to dev cycle here, and we're gonna get out of there, go into our features again. Into our choose move, it doesn't really matter again what this feature is called. We're gonna create a new variable.
We're gonna call this strategy. We're gonna set this as a strict technically, we could just do Boolean, but we'll do strategy. And because of the way that we have this set up with, like, these 4 different options of left, right, up, down, we're gonna actually go ahead and kind of move this around. So we're gonna call it, this one's gonna be left, and this one's gonna be right. Actually, we'll just leave it all exactly the same.
Down, up.
Speaker 1: But it's just called strategy this time.
Speaker 0: It's called strategy now. Yeah. Sure. Alright. Amazing.
Look at that. We changed literally nothing. I love that I did a thing that was completely unnecessary. We could
Speaker 1: have just kept the stream.
Speaker 0: Just kept the same.
Speaker 1: That's fine. That's fine. We we okay. So we're logging this and we I think I think this works, but what we want to do here is is
Speaker 0: what do we
Speaker 1: wanna do here? We now wanna hook this up to a start.
Speaker 0: Yes. So we need to do we need to do a new end.
Speaker 1: And we need to change the data model to, have this extra, like, strategy string, which I think is amazing because then even in our insights dashboard, we can be like, when using this strategy, this is the win rate. Like, it's actually really lovely.
Speaker 0: Now we're done in code for right now, though. Right? So I think that we can No. We're not?
Speaker 1: Build this one. Build this extension. I think we're gonna need to change which flow is being hit on start. I think we need to create a new flow. We need to create a hang on.
Speaker 0: Oh, metadata.
Speaker 1: Hang on. Hang on. Is this are these errors or are these suggestions? I think this is all about and has been rewritten. I have a sneaking suspicion this is inside of the SDK.
There
Speaker 0: might be no module in
Speaker 1: But it said done.
Speaker 0: Yeah. This may
Speaker 1: And it says and has been rewritten. All of these have resolutions. I've not seen the error before. I have a sneaking suspicion it's in the dev cycle and the way we're rolling up and bundling code, not a problem. If it works, it works.
Not sure if it works. We'll figure that out. So what we actually wanna do is create now another
Speaker 0: Flow. Flow. Do we need to create another item? No.
Speaker 1: No. We don't. We can alter our existing start endpoint. Yeah. So yeah.
But you've built this. You need to restart Directus.
Speaker 0: Yeah. Okay. There we go. We're gonna restart Directus. Oh, I need
Speaker 1: there we
Speaker 0: go. Let's restart here. Oh, wrong one. Just ignore the fact that we're rebuilding it again. Ignore all of those errors, everybody, and go to the right ones.
Speaker 1: To me to me, they read as warnings. That's the spirit.
Speaker 0: Alright. And that should be running again, and we're gonna close that down. We're gonna get the right thing open now. And I think we were here. Let's mark
Speaker 1: this out. Absolute chaos. I literally can't get behind your window management.
Speaker 0: There is no there is no window management that is occurring. There is nothing. So,
Speaker 1: there is one other thing we want to do just before we hook all this up, which is we want to go into the data model. And for a gain, we want to, just add a string strategy.
Speaker 0: Right?
Speaker 1: Yep. Yeah. Lovely. And then just because it makes can you make it half width, please? Sure.
You use you you could do it with the little 3 dot things on the side come out of this pane, the little 3 dot thing, and then half Got it.
Speaker 0: Got it. We got there. Alright. So that's in there now. Awesome.
Let's head back into flows. Oh, that's not the right spot. Back into flows, and we're gonna change this one. I wanna change the name here before I forget. Can I change that?
Yeah. I can.
Speaker 1: Yeah. Yeah. Back here. Yeah. Yeah.
Yeah.
Speaker 0: Sneak strategy. Awesome. Nice. Perfect. And
Speaker 1: then, yes, start. And now we want to see if this new thing can so we extract the snake count, and then we create data. And we basically want to create one there in the middle, which hopefully won't pose too many issues for us.
Speaker 0: Let's build
Speaker 1: So no. No.
Speaker 0: Not on
Speaker 1: the on the success path.
Speaker 0: Great. And what do we do in our custom operation? Right?
Speaker 1: Yes. There is at the bottom.
Speaker 0: Look at that. It even says dev cycle. I think that's a good name to keep for it. I like that. I also like that it converts camel case into, what's what's this?
What's the
Speaker 1: that is called I wanna say hang on. I will I will tell you this because I actually have it inside of my raycast case. That is called that is called, coming up, camel case.
Speaker 0: That's camel case? This is camel case.
Speaker 1: Oh, no. Sorry. Sorry. That is I'm I'm I've picked a ridiculous string to test against. So it had, like, it had, like, hang on.
That is called, scrolling through, Pascal. Is it snake or is it Pascal case? Snake case. It's called snake case.
Speaker 0: What is snake? Enough. That's a case. There we go. That is
Speaker 1: appropriate.
Speaker 0: It's almost like I knew this, and I wanted to bring it up. Okay. And for a sneak ID, we can actually put in anything. We're just
Speaker 1: Oh, encoded.
Speaker 0: Yeah. We're just gonna put, like, a really basic actually, no. Let's call this ready, set, Battlesnake because there's some cool stuff you can do with your targeting rules, including include. So let's just set that.
Speaker 1: I mean, remember, that can be a dynamic value from the first step.
Speaker 0: It can. But for now, we'll But
Speaker 1: we can we can yeah. Absolutely agree. So inside of the dev cycle step now sorry. Can we just go in? That was the only option.
And so dev cycle is gonna return some data. Yeah. All of that happens in the background. So we don't know whether it works yet. So now we wanna redo the nodules.
Speaker 0: Yeah. Oh, yeah. We just wanna move this to here. Right?
Speaker 1: Yeah. And this is where we seem to keep having a bad time.
Speaker 0: Awesome. Thank you, Directus, for doing exactly what we were expecting you to do.
Speaker 1: On behalf of the core team, you are very welcome.
Speaker 0: So what is our issue in here? What is our issue?
Speaker 1: But remember, we had this all the way from the first episode, and we just kind of wrote like, there was a specific set of moves we did, and it worked.
Speaker 0: Okay. That works. I think it
Speaker 1: might have been this. I hit edit again.
Speaker 0: Yeah. And then bring it back and then bring it back. No. What if I just disconnect that altogether? K.
That works.
Speaker 1: We're getting there. And then and then do it again now? Edit and just do that last one?
Speaker 0: Come on. There we go. There we go. We got it. 2, we're gonna
Speaker 1: set of actions. There you go.
Speaker 0: It's 1 at a time. Yeah.
Speaker 1: Okay. So that Now we want to start a game and just see if it works. And there's a we're also going to want to look at our directors logs too because we did console log just data. But let's we need to start the game.
Speaker 0: Let's start Then we can first. And let's grab create new gate. Oh, not create new battle sync, create game, and let's grab escape. Oops. Escape.
Escape.
Speaker 1: Which I now regret.
Speaker 0: K. Add game. Is it in there? There we go. Beautiful.
Okay. Let's see. Game is running. Something's happening. Not what we want to happen.
Sure. That's okay. Let's head back over to Directus and see what our logs are saying.
Speaker 1: Scroll up because, obviously, all the turns happen. Right. Strategy. Boom. We
Speaker 0: just need to do dot value.
Speaker 1: That's why. Okay.
Speaker 0: It's it's returning this. It's the yeah. Request to get variable strategy failed with the response variable not found for key strategy. Hold on. Did I not save?
I feel like I might not have saved something over on the cycle, which is a necessary step here is to actually save it. Okay.
Speaker 1: That does sound necessary.
Speaker 0: Oh, hold on. Maybe this is not that window. Ah, see this? Save. It doesn't actually know that it's there.
It's my own darn fault. I got too many windows open. Darn you, Andrew. Honestly, I'm pretty sure
Speaker 1: it's the curse of academics. Every academic I've ever seen or a covering academic. I think you are though current. Correct. Yeah.
It's it is that. So while we're here, maybe we just straight because this is a DVC variable. Let inside of the extension itself return strategy return dot value. Yeah. And then rebuild, restart.
Speaker 0: Yep. So we're gonna return
Speaker 1: This is good.
Speaker 0: Yep. Dot value. Awesome. There we go. So that should work.
That should do what we want it to do. Let's rebuild here.
Speaker 1: You got it.
Speaker 0: Yeah. We're in the right oh, that's snake. We wanna be dev cycle and not CD. Let's go npm run build. And now we're going to need to restart again.
Speaker 1: Yeah. Once again, not the case now, but I'm too I'm too nervous just just in case. The upgrade is right in this moment.
Speaker 0: Okay. And I need to oh, why did I do
Speaker 1: that? Why did you do that? I
Speaker 0: don't know. Questions questions have been asked. Okay. So let's see if we can create a rematch. Should work this time.
Nope. Not working.
Speaker 1: Well, it's not so much that. That's just the bit we care about because it's our new snake. What we care about is if we go back to the logs
Speaker 0: Are these the new
Speaker 1: No. No. No. No. The the log the logs won't tell us anything.
Go see if the strategy has been saved against the latest game.
Speaker 0: Oh, that's true. Yes.
Speaker 1: That's what we're actually testing here. Oh, no. No. No. We're not doing that.
Sorry. We check the flow logs, the flow logs for start. This is what we're doing. And we check the latest log. We check the dev cycle payload.
Speaker 0: Ready, set, battle, snake is the snake we're feeding in. Payload up. That's good. I should be feeding everybody up right now. Up, up, up, up, up, up, up.
Yes. Hey. We did it. That's awesome.
Speaker 1: Now so now we wanna store the strategy. And then in the move logic, we want to grab this next this game strategy. We want to act on it.
Speaker 0: I love this. Okay. So we have this here. Now we need to store it in here, right? We're actually Yeah.
Speaker 1: We just wanna edit the create data.
Speaker 0: Edit the create data. Oh, in here. Gotcha. Yeah. Because we're already creating it.
Speaker 1: We just need to add
Speaker 0: strategy.
Speaker 1: You're missing a comma on line 3.
Speaker 0: But I laugh at commas.
Speaker 1: Okay. Do you
Speaker 0: wanna hear do you wanna hear a fun do you wanna hear a fun, little story while we're doing this? I'm ready. So I, am teaching at at the university this this term. And, I was talking to my students who are all future teachers about using proper grammar in the posts that they're doing on the WordPress blogs they create. And I misspelled grammar.
Beautiful.
Speaker 1: Well, you can't have it all. You could have good grammar or good spelling. So so remember, the value was no not trigger. The returned value from the dev cycle step. And remember, the key was dev underscore cycle or lowercase, so not the dollar sign, was the string.
So it is just dev underscore cycle, and the value of that will be the string.
Speaker 0: All right. Let's see if this works.
Speaker 1: Because that's what was returned out of that step to save. And so let's start one more game. Let's make sure that's being being stored.
Speaker 0: Oh, cut out there, Kevin.
Speaker 1: Oh, I actually just stopped talking.
Speaker 0: I'm not sure. Oh. You you definitely froze.
Speaker 1: Oh, okay. Fair fair enough. Yeah?
Speaker 0: Okay. Good. Okay. Perfect. So we ran a game.
Yeah. That's fine. And then let's head back over to our logs here. And the I mean,
Speaker 1: the proof is gonna be in the pudding here.
Speaker 0: No. So But then no
Speaker 1: no no the options. Strategy up. So if we now go look
Speaker 0: at the latest Oh, there we go. Yeah. We're there.
Speaker 1: Yeah. Yeah. So if so if we go just check the content module in the sidebar here in the, module bar far left, let's go look at the latest game and make sure our strategy was saved. That's the top one. Top one.
Speaker 0: What is Games.
Speaker 1: What what an easy quick way to do this is if you just hit the plus in the top. Like, if you add a if you add a field, perfect strategy, boom. Nice. Amazing. So now we're gonna go into our move, our new move, which does nothing, which is why our snake is doing nothing, and we wanna respond to that strategy.
Alright. So So not this one. We we we we we we we Oh, that's right.
Speaker 0: Yeah. Yeah. We did a strategy one. That's right. Okay.
Awesome.
Speaker 1: Snake strategy.
Speaker 0: And let's do this as a we're just gonna return. Right? So we just need to do
Speaker 1: No. Because there's a few steps here. So this takes in a move, right? And that move has a game ID. So the first thing we want to do is we want to look up the game to find out the strategy, right?
So we want to read data first and my confidence has just gone through the floss. So let's close out this for a moment. Can we just look at the logs here and just understand the shape of the data again?
Speaker 0: All right.
Speaker 1: So So the payload, body, game, ID. And that should match the ID of the game in our collection that has been created by the start step.
Speaker 0: So let's see. 4ff ending in 70. Let's see if that is in fact the case.
Speaker 1: Sure. I I think it should be. Yep. There we go. Perfect.
So what we want to get out is that strategy. So, so we'll create a new step here, and we can call this get game or something.
Speaker 0: Yeah. Get game strategy. Let's call it.
Speaker 1: I'll just get this is gonna get the whole game. So let's just get game. And then permissions full access because I can't be bothered to deal with permissions, collection, games, IDs. Now this is important. We want in squiggly brackets, double squiggly brackets here, trick, dollar sign trigger dot body
Speaker 0: Body. Yeah. Dot game
Speaker 1: ID. Game. Yeah. You got it. Dot ID.
Yeah. And hit enter. And hitting enter just slightly, you know, you have to enter. And just like you're hitting save over there in dev cycle, that's one that gets me.
Speaker 0: There we go.
Speaker 1: And this should get the game. So hit save. Let's see. And let's just do this very sequentially. So, yes, let's let's test this again.
Once again, the value should absolutely be up.
Speaker 0: Perfect. Options.
Speaker 1: Permission to pull
Speaker 0: the games ID. Wonderful. Wonderful. And we get our strategy.
Speaker 1: Lovely. And the strategy now is what we're gonna check. So now we're gonna do some branching logic. So what we want is, I think, a conditional.
Speaker 0: Yep. Right? Yep. And we're going to call this strategy.
Speaker 1: Strategy. Well, let's be more specific because we're gonna check if it is one strategy or the other. So Oh, that's true. Is, you know, strategy, yeah, is up. Although, was was up the value yeah.
Yeah. Off was the value.
Speaker 0: Yeah. It's up the value.
Speaker 1: It's up. Yeah. Perfect. So let's fill in the so I don't think we do wanna fill in the default. Yeah.
So squiggly like, this is JSON now. So squiggly brackets on the outside.
Speaker 0: There we go. I love this, by the way. This is such a smart little
Speaker 1: Except we are gonna have to go edit it. So I know. It's all it's. So trigger change for last because we wanna grab stuff from the last step. Oh, sorry.
A dollar sign. Yeah. Last. Perfect. Yeah.
Correct. And we're gonna be checking the strategy. So not category, strategy. Yeah. And when you see whether it is equal to up and it's case sensitive.
So yeah. Perfect. Wonderful. And hit save.
Speaker 0: Now, honestly, this is where this is where
Speaker 1: I mean, nothing would oh, yeah. Suppose we can check. We can check that.
Speaker 0: Kevin, let's follow, strategy every time we do this, but, no, we won't follow the strategy. Let's see.
Speaker 1: Oh, wait. Wait. Wait. Nothing it didn't get saved.
Speaker 0: What?
Speaker 1: Didn't save the flow. You just refreshed.
Speaker 0: Oh, did I really?
Speaker 1: No. Womp. Womp. It's okay. Come on, Andrew.
Speaker 0: Come on. I mean, to be fair to
Speaker 1: be fair, there is a little bit of allowing you to do that without prompts. Anyway, anyway, is up Yep. Was the name of the condition, and it's gonna be lost. Last. Yeah.
Speaker 0: And you call them strategy.
Speaker 1: You call it.
Speaker 0: And oh, strategy, and up, and save and save. Up. It's the double save.
Speaker 1: I get it. I get it.
Speaker 0: Let's set out. Let's finish this game. And so I figured out the thing that it is here. You actually have to finish the game before it'll let you do a rematch. You have to play the whole game.
That was the issue we were facing.
Speaker 1: Good tonight.
Speaker 0: So we should have it showing up now. Yes. He's up. Payload. Yep.
Awesome. Is
Speaker 1: up. Now, this basically will fail if it isn't up. It will it will, like, it will have a validation error, and the whole flow will fail. And this is correct.
Speaker 0: Yeah. Let's see. Look at you go. All right. Here we go.
And amazing. Alright. And let's go back over to directors refresh. Look at our logs. Shut up a bunch more.
Let's go. Oh, oh, something's happening. Oh, I need to actually press the button. Alright. Here we go.
Oh, option payload validation error.
Speaker 1: Validation error. Wonderful. And so this is where, we have to be creative with flows and work within some of the limitations, to be frank. So because all all conditions, there is no, like, case statement where you can be like a, b, or c. It is true or it is false.
It is resolved or it is reject. Right now, our flow simply halts because it goes out that reject path and fails. Right? But what we're gonna do now is we're just going to put, you know, we're going to just put one thing on the reject path, but it isn't failed. It's just the else.
Right? So it's just an interesting terminology thing there. So we don't, we don't we don't even need this now.
Speaker 0: Oh, I guess Unless you wanna do can be Well, why don't you wanna do it? Yeah. Let's just do all 4. There's only 4 to do. So
Speaker 1: So hang on. Hang on a moment. Have you put you've put this on the reject path. Right? Yes.
Perfect.
Speaker 0: Yep. Okay. Last strategy down, and we're gonna call this is down. Perfect. Yes.
And then we're gonna create another.
Speaker 1: Off the reject path. Off the reject path. So it gets a little bit unwieldly here. So it's not up. It's not down.
Speaker 0: Strategy. Let's call this last.
Speaker 1: Copy it out this time before you hit save.
Speaker 0: Look at you, left. Perfect. Copy. And then one more.
Speaker 1: So you so you see here how these kind of more convoluted case statements can get a little bit messy in here?
Speaker 0: Yep. I definitely do. But, is right. Okay. So let's go there.
Save this. And go to the game. And let's finish this game. Shouldn't take too long.
Speaker 1: And this one should do the same thing. It should have a validation error after the first one.
Speaker 0: Yeah. Alright. Oh, yeah. That's true. Oh, no.
Speaker 1: See if
Speaker 0: it does. No. No. No. No.
Speaker 1: That's a lie. Sorry. It will it will go until it fails. Just ignore me. That was incorrect.
Sorry.
Speaker 0: Is up. So that was our first one. Is up failed. Must be up, and then it dot stopped.
Speaker 1: That's not correct.
Speaker 0: Did I do is up twice? Is left, is up, is down.
Speaker 1: Oh, no. No. It's connected to read data. It needs to be connected to the reject path of is up.
Speaker 0: Oh, there we go.
Speaker 1: Not that one. There we go.
Speaker 0: Yeah. Yeah. Yeah. There we go. Oh, did too much stuff.
Disconnect, save, edit, reconnect.
Speaker 1: Oops. I'm glad. I'm no. No. No.
Reject. Reject. Yeah. I'm glad we finally got back to that point of just finding that little that little set of actions. I can't believe it got us so, so much.
But, yeah, I've submitted
Speaker 0: that as a bug report. Awesome. Alright. Let's refresh this. And we should be now we should be seeing the process that you were hoping for.
Speaker 1: Yeah.
Speaker 0: Lots more moves there. So we should be seeing is oh, yeah. Here we go. Awesome. Yeah.
It's up. Validation error. Validation error, validation error, validation error.
Speaker 1: Why is there a validation error on all 4? It has to be one of them.
Speaker 0: Oh, last must be of type object? I wonder if that is not Oh,
Speaker 1: of course. Last is the last step. We've foot gummed by using last, which I actually spoke about in a previous episode. What we wanna check is, can you click into read data? The read data Yeah.
Key is called get game. Right? So let's maybe rename this game. So if you go up to the key in the top right of this whole pane, scroll up. Yeah.
Yeah. And the last will always be the one that came before it. But in this case, we're chaining a bunch. So, like, changes. So we actually wanna change.
So if we change this to just game, let's keep it nice and short.
Speaker 0: Perfect.
Speaker 1: And and, yeah, save. And now we could do it in is up. The is up last is correct, right? But in all the others, it isn't lost anymore.
Speaker 0: And then we're just removing this, and it's actually just gonna be game. Right? No Correct.
Speaker 1: Yeah. Correct.
Speaker 0: Okay. So let's go No,
Speaker 1: dollar sign.
Speaker 0: Yeah. Or no dollar sign. Yeah. There we go. And let's call this one game.
Oh, game. And copy that this time. And I'm quite impressed with where we've gotten here. I feel like episode 4 finally figured things out.
Speaker 1: Yeah. Alright. Here we go. So Yeah. So now so so let's test that once more.
And while we're doing that, let's talk about what's next. Because all we're gonna do is execute the most basic strategy, which is to just return, move up, down, left, right. And we're not gonna do anything more fancy here. Right?
Speaker 0: You would implement
Speaker 1: is up, not correct. Is down though, is correct, which Awesome. Great. So now out of each of these success paths, now we need to run the strategy, which of course could be a lot more convoluted. Another thing that's worth noting is there is a flow operation, which is to run another flow.
So you could you could kind of modularize your strategies into separate flows, go off and call those those come back with the response. And then so, you know, there are ways of organizing your flows. It's not just one big mega flow. But it's I think for what we're doing, it's beyond the scope, but that that would kind of be how you organize game logic, I think.
Speaker 0: Great. Okay. So what are we gonna do here? What are we we're sending this
Speaker 1: to We are literally gonna return. So run script. So sorry. I run script was near the top. And the reason we're doing run
Speaker 0: script just to move and then up and down and left. You got it.
Speaker 1: That's awesome. You got it. Because in the trigger, we said respond with the last operation. Yeah. I love that.
Speaker 0: All right. So let's just grab that, save, and let's do oh, yeah.
Speaker 1: Then that's correct. Yep. That's correct. So that's the is up success path. The names and the keys no longer matter, because If
Speaker 0: we unless we forget which one where it is down, so this one's gonna be down. Save that, and then we're gonna go here. This is left.
Speaker 1: I'm glad you you've come with me on the up, down, left, right rather than the clockwise.
Speaker 0: We got there. We got there eventually. We got there. Alright. And then our final one is gonna be right here.
And then this one's gonna be run script and
Speaker 1: return You got it.
Speaker 0: Move right. And let's see if this works. So if this works, our move right now is down. So snake should go down if everything is done the way it's supposed to be. So we've been going up because it's been failing.
Now we should go down. Alright. This doesn't necessarily mean it's working yet because let's see if we go right. Save. Did we just actually implement this in, like, an effective way?
This is wild. I'm, like, kind of
Speaker 1: Hang on. Hang on. Hit play first.
Speaker 0: We don't know yet. Yeah. What is up?
Speaker 1: Snake went right straight off the board and died.
Speaker 0: This is fantastic. I have never been so happy to see a snake die. I mean, last episode, I was really happy because we really wanted our snake to die. But, like, I'm
Speaker 1: Oh, yeah.
Speaker 0: I'm far more happy. That's pretty freaking cool.
Speaker 1: That is cool. But there was one final part, and then I think we're we we can we can call it on ReadySet Battlesnake, at least season 1 of ReadySet Battlesnake, who knows, which is right now we are saying all users that there is no segmentation. There are no different audiences. It's just everyone gets one response. But in the flow creation, in this start game, you know, flow, we can put in a dynamic value there.
Now, I do not know how this works in dev cycle. Is this something that's viable?
Speaker 0: Yep. Yeah. Yeah. So hold on. Let's go back over and actually look at this.
Because you said words and I heard the words, but then I stopped hearing the words. And so let's, let's go and shift this in that flow. And so we could do it in our in our dashboard. Right? We could actually
Speaker 1: We we we wanna do it in both. So here in the start, right, in the dev cycle operation that we created, if you go in and edit it, you see we put in our as fixed snake. So the question here is right now we're getting I think there's a step missing here, which is we want to register users.
Speaker 0: No. No. You don't actually so you don't technically need to register them there. Oh, I've gone all blurry. Hold on.
Hold the phone. Why have I gone all blurry? What's happening? There we go.
Speaker 1: Alright. I'm back.
Speaker 0: I'm back. Okay. So what we can do here is this is all just stuff used for targeting rules. So let's say, okay. So you know how if it doesn't see anything, it goes up.
Right? Correct? Not right. I shouldn't say right. If if it Yeah.
If it's not seeing anything, it's gonna do that. So let's leave this as ready, set, Battlesnake and go over to the platform here Yes. And say Yes. Go, let's say go left, but only if the user ID contains ready.
Speaker 1: But but what I'm wondering is, can we get this to a spot? And, like, we can assume the outcome here, like, we'll we'll we'll do this. But what I'm wondering specifically is can we, in 10% of games, maybe this is about the game ID and not the snake ID. So maybe the the name of the property isn't quite right. But can we say in 10% of games or 10% of users, I suppose, can we change it?
So in that case, when we first feed it the snake ID, which will make the game ID, is that can we do that?
Speaker 0: Yeah. It's just this. You literally set it to random distribution, and we say that we wanna serve 25% each of these distributions, and it will automatically do this for all users.
Speaker 1: So we don't need to do anything with this passing a random name or anything? No. I mean, you could do it within that. You could say only the snakes that have ready in it. Yeah.
Exactly. Do this, you know, so you can further branch that logic down and get a real small selection of your audience. Should we remove that, the first set, the first conditional where you put ready? Yeah. Should we remove that,
Speaker 0: I guess? Because it's kind of just do all users. Yeah. And now we're just saying that all users random distribution. A random distribution.
Speaker 1: So if
Speaker 0: I save this, we should see if we run, say, 10 games, we should see something similar to that. So let's make sure this works. That's good.
Speaker 1: Oh, that was remarkably easy.
Speaker 0: It is very smooth.
Speaker 1: But but there is that other thing still where, like, if we if we register, can we say, no, ignore me. That makes part of that same mistake.
Speaker 0: All of these things are possible. If you can feed information into the platform, then you can you can do lots of stuff with it.
Speaker 1: And we've only discussed all of these ways of feeding data in, so we don't necessarily need to go too granular. But, yeah, let's create a ton of games.
Speaker 0: Okay. So here we go. So let's go first game. So we went left first game.
Speaker 1: Sure.
Speaker 0: Let's go create rematch. So we're going left. So that's 2 for left. Let's create a rematch. We should start going a different direction, and we're not.
Maybe I didn't save. Hold on.
Speaker 1: Yeah. I was gonna say, did you hit that save button?
Speaker 0: All users, random distribution, schedule, none. No random distribution. We should be seeing that. That. All users feeding that in.
25%. K. Let me change this. I just wanna see if something happens. A 100%,
Speaker 1: 0. Oh, you you you have to make it worth what happens if it exceeds a 100 there?
Speaker 0: I don't I don't know. I'm curious. Yeah. Yeah. So we should see this.
Like, all users should ever run a 100% should be there. Random distribution might require something else, but let's see.
Speaker 1: Yeah. Maybe.
Speaker 0: No. No. That's right. Yeah. I guess
Speaker 1: if I may.
Speaker 0: It must just be the logic that's being used in there. So let's do 5050, and that might be a little bit easier. 50 right, 50 down, and see if that Sure. Does it. That's there.
It also does say a couple minutes to update. So let's see.
Speaker 1: Yeah. Maybe that's it. Maybe there's a little cache. Which is fine.
Speaker 0: Right.
Speaker 1: As I say, our snakes aren't spawning in particularly in particularly good spots to live. They're not? This isn't feeling unless it is really that thing because you you don't need feature flags to be literally like sub second. Know, there can be a little bit of a of a moment there.
Speaker 0: Yeah. So this is over, like, a longer period of time. So that might be part of it, but we should see a down eventually,
Speaker 1: because
Speaker 0: the logic that's there is technically correct. Oh, you know what it is? No. I'm wrong. Here's the thing.
I I totally forgot about this. So because it feeds in user ID and we're feeding in the same user ID every time. So if we wanted to change this, it's actually not that bad. So that So this is
Speaker 1: actually what I wanted. Yeah. Yeah. So users and that makes sense because in the real world, you have a feature flag. You don't want that user getting a random thing every time they reload.
Speaker 0: Yeah. So ready, set, battle, snake was getting right after Oh, no.
Speaker 1: No. No. No. Hang on. Hang on.
Go back. There's a there's a better value to put in here. Let's put in the game ID. Let's put in the because that's random. That's in every new game is a new is a new That's true.
User in this context. So actually
Speaker 0: grab game.
Speaker 1: Okay. Double double, double brackets first, and it will be trigger dot body dot Game
Speaker 0: dot ID.
Speaker 1: Game dot ID because that's a random value each time. Yeah. It is. That's good. Yeah.
Yeah. Yeah.
Speaker 0: That might that might do it. So we should now see 5050 if it works, which it may not.
Speaker 1: Mhmm. Mhmm.
Speaker 0: K? Good. So right on the first one, right on the second one. It's not looking good so far.
Speaker 1: It's not looking good so far, is it?
Speaker 0: Oh, there we go. Hey. Hey. There we go. So So
Speaker 1: that logic that I think that's Andrew, I I I'm I'm both really happy that we got this to work, But I'm also kind of sad because I think I think that might bring us. What do you think?
Speaker 0: I think I think we have we have eaten into to your evenings for many, many dates.
Speaker 1: Not for that reason. Not for that reason, but just I think that's I think anything more now is us just in hot like, doing things we've already done, but in this slightly altered context, but that's awesome. So you can really, like,
Speaker 0: yeah. So smooth. Yeah. I gotta say, like, I when we set out to do this, I knew that we might be able I knew Directus would work. Like, that made sense.
But when we decided that I was gonna take the lead for the final show and we were gonna do the dev cycle, I was like, I don't know if this is gonna actually work because I tried to implement dev cycle with Directus a lot of ways. So I'm over the moon that this works. And, like, what a cool piece. And it's so fast too. Right?
You're not having to worry about direct us doing anything. It's all managed externally. Like
Speaker 1: Yeah. And and part of this is an approach that we chose. And this is a very battle snake kind of thing. It is an approach we chose to make sure that we are we're not combating that 500 millisecond return require return requirement. And that is because we determined a strategy at the beginning of a game, not every move.
So there is a couple more round trips within directors. We're having every move to go and figure out the game strategy, but this is all internal. These are just little database operations. That's awesome. And then, of course, going back to the last episode, we could now enrich our insights dashboards and saying when this was the strategy, this was the outcome.
We could use the little global variable drop down to to pick. We could even go off to dev cycle, populate directors with all viable strategies, That was awesome. That was fun. Happy?
Speaker 0: This was a fun day. I'm I'm so Kevin, I was so it's been a couple episodes since I've been, like, on the keyboard. And, like, you were walking away so pumped after every and I was happy. I was definitely feeling it. But, like, I'm having a good this was a good It's good.
This was a good day. We got we got things working, and our snake does the things, and other people can now go and use this to meld the world's all the d's, Directus, Devcycle.
Speaker 1: Yeah. What what do you say, as for as for Directus as a Battlesnake engine?
Speaker 0: I love it. I think it's super, super smooth. And I love the fact that there's actually, some code that exists out there for building a dev cycle management setup within the Directus platform. So, like, like, use Directus and then implement dev cycle and then play Battlesnake. That's the real that's the real goal here.
Do Everybody wins. Everybody wins.
Speaker 1: Everybody wins. Everybody wins. Everyone, thank you so much for joining us. Andrew, thank you for getting on board with this idea to to, you know, have a Battlesnake video, you know, series after after a little while. Thank you audience for joining us for this limited series of Ready Set Battlesnake.
If you want to learn more about Battlesnake as with all of these episodes down in the resources, you'll find a link to the docs for Battlesnake. It is such a satisfying and fun hobby project for developers at all stages of their career, whether you're just getting started or you are really pushing, you know, your very, very advanced knowledge and it becomes an optimization game. There's something in it for everyone. I'm glad they all worked. Honestly, there were so many points in this where we might have discovered this doesn't work irreparably and the whole thing's ruined.
And every barrier we came against, there was a solution primarily actually through the ability to build extensions. Yeah. So that is wonderful. Oh, lovely. And a melding of my world as a big time and long time battlesnake lover and running dev rel, at, director.
So Andrew, once again, thank you so much.
Speaker 0: You're welcome. And should we do it our one last try? This is our last opportunity? So
Speaker 1: here we go.
Speaker 0: What do you mean? What do you mean? You have little faith? This is it. You have a So here we go.
What do
Speaker 1: you mean? What do you mean? You have little faith. This is it. You ready?
Speaker 0: Alright. Here we go. Alright. Do you want to count it down? Should we count it down first?
No. Hang on.
Speaker 1: Hang on. Hang on. Hang on. I've got it. Uh-uh.
Alright. This has been
Speaker 0: ready. Ready. Set. Set. Battlesnake.
Battlesnake. Bye for now. Bye.