Latest / North Meets South Web Podcast / LawnHub, Saloon, and Salesforce
Transcript
- 0:00-Hey. I'm Michael Dyrynda. -And I'm Jake Bennett.
- 0:03And welcome to episode 182 of the North Meet South Web podcast.
- 0:08-Chuka, chuka, chuka. -Let's j-
- 0:11-Hey. -Let's just assume you heard it. I don't
- 0:13know why you don't hear it anymore, but it definitely played.
- 0:15I have no idea. It's, yeah, it's fine. It's fine. Hey, everybody. Welcome to
- 0:19episode 182. We're going to skip the chit chat. Do you know why? Do you wanna know
- 0:23why? I'll tell you why. I'm starting the chit chat, but we're gonna skip it.
- 0:27-Do it. -I am... Um,
- 0:31I think I'm entering that stage of life
- 0:34where you're just perpetually tired, all the time.
- 0:36-Mm-hmm. -I think it's just how it is. I think
- 0:37there's... I don't think there's any coming back from it. I think it is just
- 0:40called life, and I think that's where I'm at right now. And so I'm like, "You know
- 0:44what? Let's just get into it." Like,
- 0:46no need to, uh, you know, pretend like, uh, we've got limitless energy here. Like,
- 0:52let's get down to the nuts and the bolts. But
- 0:56that'd be missing one of my favorite parts of the show-
- 0:57This has been two weeks in a row that this has-
- 0:57... which is catching up with you, Michael. How are things going, my friend?
- 1:00This is, this is two weeks in a row that you've been, like, tired, tired. Which is
- 1:04-very unusual. So- -Dude, it is. I think it... Well, I think
- 1:08-it's going back to the school thing. -It could be something, like, it could be
- 1:10-seasonal. -I think it's the changing of the weather.
- 1:11-Yeah. -Yeah. I think that may be what it is.
- 1:13-Yeah, that's what it is. -I am... We, we had like this pocket... So,
- 1:17we're heading into spring now, and, uh, Australians, we just say like the first of
- 1:21September is spring. We don't, we don't hang around for like the spring equinox or
- 1:25whatever the heck. You know, it's not the 22nd of September. We start all of our
- 1:28seasons on the 1st of the month. When they- You know, on the q- on the quarter
- 1:31that they roll around in.
- 1:33-Respect. Respect. -So we're heading into spring now, and, um,
- 1:37we... Because it's spring, it's like sun but it's also rainy. But then it's cold,
- 1:41but then it's sunny, but it's not warm. And so I had this pocket of time on the
- 1:46weekend where I was like, "I gotta mow the lawn now 'cause the weeds are getting out
- 1:49of control." And
- 1:53I'm gonna do it so that when the lawn stuff... Which I just shared a photo of
- 1:57the, the box that this came in in, in the cash money. From that-
- 2:01-Oh, okay then. -It's a local company called Lawn Hub.
- 2:04-Mm, nice. -Which sounds-
- 2:05-Good name -... similar to another thing that is also
- 2:08-a hub, and their branding- -Oh, sure. Yeah, GitHub.
- 2:10-Their branding- -Yeah, sure. Yeah.
- 2:12Yes. Yes, definitely. Um, and their branding matches color. Like, all of the
- 2:17-naming of stuff is- -Oh my
- 2:18... is very much in line with the other hub.
- 2:21-Mm, mm. -And so, lawnhub.com.au. So I've, I've got
- 2:24their stuff
- 2:26had come in today, and so I had to mow the lawn because you're not supposed to,
- 2:30like, spray... I've got this spray stuff. You're not supposed to fertilize the lawn
- 2:35or do any of that kinda stuff within 48 hours, or 24 hours, whatever it is, of
- 2:40-mowing 'cause you wanna catch the weeds- -Okay
- 2:41-... as they're in their growth cycle. -Gotcha. Sure.
- 2:43So I did this on Saturday thinking I better do it now 'cause it's gonna rain
- 2:48-on Sunday. -Yep.
- 2:49And then it didn't rain on Sunday, and it didn't rain on Monday, and it hasn't so
- 2:53far rained today but it's supposed to rain this afternoon and all night today and
- 2:56-then tomorrow and Thursday. So I've got- -Gotta put... Yep. You're playing the game.
- 3:01And, and it's like, okay, so I wanna do
- 3:04this, and you're supposed to do all of this lawn care, you know,
- 3:08in September ahead of the growth period. And it's like, I need to mow the lawn to
- 3:13get it ready so that the weeds are growing to then hit it with not the, not the weed
- 3:18-killer but this is like a growth stuff. -Okay, sure.
- 3:21That is supposed to, like... It's a wetting agent and, and a fertilizer that's
- 3:25supposed to
- 3:27spring the lawn into growth. And of course the weeds-
- 3:29-Okay -... which are also there, and then as the
- 3:31weeds are growing on day 10, you then hit it with the weed killer. Now, I don't
- 3:36-know- -Interesting
- 3:37... I don't know how you're supposed to plan this because how do I know in 10
- 3:40days, especially with the fits and starts of spring-
- 3:42-Yeah, yeah -... when the rain is gonna come? Because
- 3:45-you're not supposed to apply this stuff- -Right before rain or anything like that,
- 3:50-yeah. -Um, right before rain, you're not supposed
- 3:51-to, you know- -You want it to be dry for a couple of
- 3:51-days, yeah. -So I don't know.
- 3:53-It's tough, right? It's tough. -So I'm just hoping it works out right.
- 3:56Yeah. We've got a buddy, I've got a buddy who does like... He's really big into
- 3:59lawns and he's like, he goes out in the spring and he measures his ground soil
- 4:04temperature.
- 4:05-Right. -And so he'll like... If it's before, you
- 4:07know, if it's before the... You know, you wanna get your pre-emergent weed control
- 4:12down between 58 and 61 or something like that, and if you go, you know, I don't
- 4:17-know. So anyway- -Not to that extreme
- 4:18... I just tell him like, "Hey dude, text me when you're putting your stuff down."
- 4:20-That's what I always say. -Yeah, and I'll do it.
- 4:21"Just text me when you're putting your stuff down." And then I'll do it too.
- 4:24'Cause he lives you know, you know, five miles away, so I'm like, all right.
- 4:27-Yeah. -Chances are if it's, if his soil
- 4:29temperature is all right, it's, mine's going to be about there too.
- 4:32-It'd be about the same, for sure. -Yeah. Anyway, it's, that's a big help.
- 4:35-But, uh, anyway. -So yeah. So, so doing that at the moment,
- 4:37but like trying to fit it in with, with the weather is ridiculous.
- 4:40-Yep, yep. -And so, because I mowed the lawn even
- 4:42though it was wet it was still enough to kick up the pollen and so now hay fever
- 4:45-season is upon me. -Oh, hay fever it is. Yep. Here it is.
- 4:47So, right. So this is my thing. You know, I wake up in the morning, morning feeling
- 4:51terrible, not wanting to get out of bed because my head hurts and my nose is
- 4:54congested and, and you know, we're back in that. Fortunately, I know because I did
- 4:59mow the lawn
- 5:00and it is that time of year that I'm like it is just hay fever.
- 5:04That's what it is, yeah. It's not something else. Yeah. Yeah, yeah, yeah.
- 5:05I'm not playing the, the COVID or hay fever game. So I feel rubbish in the
- 5:08-morning but Re- -The COVID or hay fever game.
- 5:10... Re just
- 5:12had
- 5:13septoplasty because she's, like, she's always had bad sleep. Like she will sleep
- 5:19-for 12 hours, wake up and still be tired. -Mm-hmm.
- 5:22And so, you know, gets to a point where you finally want to do something about
- 5:26this. You're not gonna just accept that this is
- 5:28what it is. And so she went and saw an ENT, an ear, nose and throat specialist
- 5:33and they said, "You know, you are waking as you sleep
- 5:39but it's not enough
- 5:41that you need to start looking at a CPAP." You know, face mask while you sleep kind
- 5:46of thing.
- 5:47-Yep, yep. -This option of the septoplasty was to go
- 5:49in and to realign her turbinates because she had a deviated septum in her nose.
- 5:54-Ah, okay. -So they go in there and... Like day
- 5:56surgery, they go in there with a drill and they go, you know?
- 5:58-Oh. -Do whatever they do and sort it all out.
- 6:00Oh, nope, nope, nope, nope, nope, nope, nope.
- 6:01So it was like day surgery but she was, you know, she was under for it, of course.
- 6:05They don't do this while you're awake and she woke up with-You know, like, no
- 6:08bruising. They they do it pretty pretty good these days. Because, you know, we
- 6:12needed to start mucking around in there around the place, it's like Oh, yeah. ...
- 6:15right near the surface. So you would assume there'd be bruising and stuff, and
- 6:18I'd have questions to answer for a for a few days after. Why has your wife got
- 6:23black eyes and all that kind of stuff. But, um-
- 6:25Just stay home, honey. Just stay home. I'll go do-
- 6:26-Yeah. So- -... I'll go do other stuff that you need
- 6:28-to focus on something else. -Yeah. So she was like ... She had a week
- 6:30off work which was which was nice, you know, took care of the kids. And it was
- 6:34funny though because I said to her
- 6:36halfway through Saturday, like, she had this surgery on on Thursday, and I said to
- 6:40her halfway through Saturday, I said, "Look, I know that you had the kids for a
- 6:44whole week while I was in Denver. However, you had the kids for a whole school
- 6:50week where you get them up in the morning, you take them to school."
- 6:54-And then you say goodbye. Yes. Yes. -And you say bye bye, and then you and then
- 6:56you see them again in the afternoon.
- 6:59Which, don't get me wrong-
- 7:01-You have them for a week -... don't get me wrong, it's still ...
- 7:03Yeah. But don't get me wrong, it's still
- 7:06hard work. But there's seven hours out of the day where they're not there.
- 7:10-Agreed. Yeah. That's okay. Yeah. -I had them Saturday. Right? I took them
- 7:14grocery shopping in the morning. We we got home at lunchtime, and I'm like, crap. It
- 7:18is only lunchtime, and they're still going. Like, they wanna keep going. I'm
- 7:22like, I
- 7:23I was so tired at the end of that weekend, like, more tired than I've ever been.
- 7:27-That's fine. -But long, long winded way of saying, like,
- 7:31maybe you've got sleep problems, and this is why you're feeling tired.
- 7:33Maybe. Maybe I do. Yeah. Or or maybe it's just a seasonal thing too. I don't know.
- 7:37I'm not sure. That's a that is a fair question. Um, I do see-
- 7:42Just don't be telling me it's still a seasonal thing come December or come March
- 7:45-if you like. -Yeah. Okay. Fair enough. Let's let's keep-
- 7:47You've gotta look into it.
- 7:48Let's keep checking in. Yeah. Let's keep checking in on this. We'll see we'll see
- 7:51what's going on here, and I think that's a this is a good you know, we'll we'll make
- 7:54this a recurring section of the of the show here. So
- 7:57hey, with that out of the way, I am actually really interested to hear about
- 8:01something you've been chatting about with me recently,
- 8:05which is some of these fake HTTP stuff. So, you know, we've talked about this on
- 8:08the show a number of times, this idea of, like, this gateway pattern and how we
- 8:12structure it at Wilbur where, to give you a quick rundown, we will create a gateway
- 8:19class which is responsible for newing up a client, setting up the base URL, any
- 8:23tokens that would need to be retrieved or pulled from the config to set up that
- 8:26client. And then we will have methods that make calls to endpoints and handle any
- 8:30specifics around that endpoint, whether it's caching or whether it's rate limiting
- 8:34or whether it's, you know, massaging a response that we get back or have it
- 8:37handling an erroneous response and all those things, which is great. But then
- 8:40what we'll do is we'll, uh, bind that into in the container, um, and we'll bind that
- 8:46to, you know, an an interface. Right? And that interface will be implemented not
- 8:50only on the HTTP side of things, but also we'll have a fake that returns
- 8:54data that we have pulled probably from the API, gotten a real response, and then
- 8:58we'll sort of load that into the fake. And we'll have, um, different responses a la
- 9:03magic tokens. Right? So, you know, stripe back in the day, you'd have 4242 gives you
- 9:07a valid response and 4141 gives you an invalid CVV, whatever. So we do something
- 9:11similar to that. But I know that you guys are big Saloon users, which if you don't
- 9:16know what that is, listener, uh, you should definitely go check that out. Sam
- 9:19Carrey has an amazing package called Saloon. Very popular nowadays. And I'm
- 9:23interested to hear kind of what you've been kicking around with that. So you've
- 9:26been chatting about it a little bit, and I wanna get a clear picture of what exactly
- 9:30it is you're talking about
- 9:31and if it solves some of the same problems or or what you got. So go. It's all it's
- 9:36-all you, my friend. -Yeah. So, yeah, I
- 9:39we
- 9:40we're doing this integration at the moment where we had, like, some old, old library
- 9:45that was like, it's long since been deprecated, no longer maintained. So we
- 9:50had copied the vendor code into our application code to integrate with
- 9:54Salesforce.
- 9:56And that was, you know, to to push leads in there, to pull contacts out, things
- 9:59-like that. -So it's like a PHP Salesforce SDK sort of
- 10:02-idea? -Yeah. Basically. Yeah.
- 10:03-Is that what it was? Okay. Okay. Sure. -But it was you know, it was like PHP very,
- 10:08very PHP
- 10:095 code.
- 10:10-Okay. -But, yeah, long since unmaintained. And at
- 10:13some point in the last 18 months, I think, like, fairly recently, we moved to
- 10:17using this other library called Forest, f o r r e s t,
- 10:21and it allowed us to directly run SOQL, so Salesforce object query language, I think
- 10:27-it is. -Interesting.
- 10:27-Which is like the the version of SQL, uh- -Okay
- 10:31... that you can use to query Salesforce. And we thought
- 10:34-Customize the Salesforce. Yeah. -This'd be a great solution. You know, we
- 10:37can write the queries ourselves. We can do it. Um, but there was not really a good
- 10:41testing layer for it to the point where we were using mockery and we were creating
- 10:46mock expectations that, you know, this method would be called with these
- 10:49arguments. It would return this stuff. And
- 10:52the problem with that I mean, number 1, don't test what you don't own kind of
- 10:56-thing. -Oh, yep.
- 10:57But but number 2, mocks and I know that, um, JMack has been on an adventure trying
- 11:03to improve this in, uh, I think, Laravel specifically,
- 11:08um, and he's gone off and he's been doing other things that have come up in the
- 11:10meantime. But he's been trying to improve the messaging around when a mock
- 11:14expectation fails. Because when a mock expectation fails, it just tells you,
- 11:18like, mockery underscore some, like, hash or whatever that it's generated for this
- 11:23thing. It's saying, expected this, but it didn't happen.
- 11:26-Yeah. Yeah. And it's very -And that's it. Like-
- 11:27It's not it's not clear at all. The the error message itself is is horrible. Yeah.
- 11:30It's horrible. It tells you that the
- 11:31expectation is not correct, but you don't know why. And so then what you end up
- 11:34doing is, like, if you're a, quote unquote, rule developer, you will go and
- 11:38fire up xdebug and you would follow through and look at all these things. If
- 11:41you're a Laravel developer, you go and start digging all over the place to see,
- 11:44like, what was actually in this object. And and then you're looking, like, what is
- 11:47diff and whether you're using xdebug or you're using DD, you still have to look
- 11:51at, like, what is my expectation and what is in the thing. And some of these
- 11:55Salesforce objects are quite large. So we've got 20 or 30
- 11:59things in here, and you've got to look at, like, what's missing, what's added,
- 12:01what's different. Is it in a different order? Is it somewhere else in the
- 12:04-response? -Yeah. Right. Yeah.
- 12:06It's it's a whole thing. And so I was I was poring through the... Saloon docs
- 12:13a while back for some stuff, and I saw in there that someone had written
- 12:18a Salesforce
- 12:21SDK using Saloon. I thought, "Great. I'm pulling that in immediately. I don't even
- 12:25have to read the doc, so I don't need to know any more about it. It's written with
- 12:28-Saloon, it's gonna be good." -Yep.
- 12:29And what that has
- 12:32enabled us to do, uh, obviously is to use Saloon under the hood, which makes testing
- 12:38so much better because we can use Saloon fake. We can say, "I'm expecting these
- 12:42res- requests to go out, I'm expecting these responses to come back." We can do
- 12:45Saloon fakes, we can... Like, you know, we can record fixtures-
- 12:48-So in the testing layer, you can, yeah- -In the testing layer
- 12:50... record pictures and replay them back out.
- 12:51-Fantastic. -Mm-hmm. Yep.
- 12:52It has improved things a great deal to the point where like, "Okay, we're gonna
- 12:55replace this Forest library with the Saloon SDK." But as part of this, I've
- 13:00been doing some exploration, which is like, I guess three-fold into, how do we,
- 13:07how do we do this kind of stuff with, um, local development? Like, I don't-
- 13:13-Yeah, that's the question -... want to be handing out-
- 13:15-That is the big question. -I don't wanna be handing out keys to
- 13:17people to access Salesforce. Um, we, we spin up and spin down Salesforce
- 13:23test environments as needed. Like, we don't typically keep them around. So, you
- 13:27-might have- -Sure
- 13:27... credentials to do something now, but that, that environment might be gone at
- 13:31some point in the future when you come back to it. Um, obviously we don't wanna
- 13:34test in production 'cause you end up littering your Salesforce instance with
- 13:38all of these test accounts and things like that. And so I, I started going down the
- 13:43path of, okay, what does this look like to actually create a fake? And you and I
- 13:49have spoken about this, as you said previously, where maybe you can just call
- 13:53Saloon fake inside a service provider somewhere and record some fixtures and do
- 13:57all this kind of stuff. And so this, this then led to my second point of ex-
- 14:01exploration, which was using AI. 'Cause yeah, I'm a big AI boy now, and I like to
- 14:08I like to play with stuff. So I've been using
- 14:11Claude and I've been, you know, with open code, which is from the SST guys, um, Dax
- 14:17and, and Adam who are part of the, the Terminal Coffee, uh, empire, um, have been
- 14:23building out this open code thing. Which is kind of like, it's like Claude Code.
- 14:27It's a, a Terminal application, but it allows you to hook into different
- 14:31providers and access different models through those providers. So we use GitHub
- 14:35Copilot, um, which means we can't use Claude as, as I understand it. Claude is
- 14:40to access the Anthropic, I think, the OpenAI, whichever it is, their Claude
- 14:45-service using their Claude- -Yeah
- 14:48... CLI. And then I think Cursor's got one and, you know, all these other companies
- 14:51have got one. So what open code allows us to do is to authenticate against GitHub,
- 14:57and then we have access to whatever models we have access to inside of GitHub
- 15:01Copilot. So I can use Claude to then do this stuff. So I've been in-
- 15:04-Interesting -... planning mode. I spend like 45 minutes
- 15:06just going through, like, "I wanna do this, I wanna do this." Like, blah, blah,
- 15:09blah. You know, come up with whatever we wanna do. Switch to build mode and say,
- 15:13"Okay, now go build that." And so what I've been doing, and it's been literally
- 15:18days 'cause I'm like feeling my way through it. I'm not necessarily liking the
- 15:21output or it's, it's partially implementing things. So, you know, which I
- 15:26think anyone that's been using AI for any period of time knows that this is kind of
- 15:30the process. Treat it as a junior developer that you're pairing with, and
- 15:34that's typically how you're gonna go. So we have been building out a, a fake
- 15:39gateway,
- 15:41as you've done with Stripe, where
- 15:44in some instances, like if we wanna do a search for a contact or an account,
- 15:49there's like, here are the, here are the key phrases that you pass through. You
- 15:53know, search for Michael and you'll get like three results back that are like
- 15:56-Michael A, Michael B, Michael C. -Sure.
- 15:59If you search for Michael Dorinda, it will return a single result, Michael Dorinda.
- 16:03Um, and so we've done this. Uh, I, I reached out to Sam Curry, the author of
- 16:08Saloon, and I said, "What is the approach? Like, how do we do this?" And he said,
- 16:12"You know, there's a few people that have asked about this recently." And like a day
- 16:15after I'd asked about it, Alex Six from, um, Zillow who spoke at Arc on US,
- 16:20um, he, he had pinged Sam
- 16:23on X and was like, "Hey,
- 16:25is this possible?" And so, you know, we had this conversation about, yeah, we're
- 16:29exploring this at the moment. And what it essentially boils down to
- 16:33is hooking into Saloon's global middleware
- 16:37and, and putting our own handler in there that basically looks at, okay, is this
- 16:42enabled? Is our fake gateway enabled? So with an environment variable and a conf-
- 16:46uh, environment variable and a config switch, you know, if this is enabled-
- 16:50-Yeah, yeah -... everything should go through our
- 16:51-Salesforce mock handler. -Yeah.
- 16:53And then the, I've iterated on this a few times where I've landed with like this
- 16:58registry patent approach where we just register all of the, the response handlers
- 17:02we want. And each response class is then responsible for providing its own should
- 17:07handle method. And it will look at the pending request and say, "Okay, is this to
- 17:11an endpoint that I'm in of interest of?" And so we've got 20 or 30 of these at the
- 17:15moment, and it would just like spin through them all and go, "Okay, this is a
- 17:19post request to the contact standard object endpoint. I'm gonna intercept that
- 17:24request and I'm gonna return this response." And so we're then using Faker
- 17:30to just send back fake data. Um,
- 17:35and then where you can, you can seed Faker
- 17:39-with a, with a value, right? -Okay.
- 17:42So that you get deterministic
- 17:45fake data back. So what we do is take all of-
- 17:48-I never heard of this. -Okay. So deterministic data
- 17:50is where like you are, it's pseudo-random. Like it is random data, but it will
- 17:56always be the same random data based on that seed. So you pass it a number from
- 18:02like one to whatever the upper limit is that it supports, and then it will see the
- 18:06random number generator so that when you call Faker whatever,
- 18:11it-Internally, it will process that. You know, it'll go through its array of 50
- 18:16names, and if you've got a seed of 3, it will always return the seventh value from
- 18:21that list of 50 names for first name.
- 18:24And then the next time you call it, it will always return the same value and
- 18:27then... So then when you are developing things, if you search for Michael, you're
- 18:30going to get the same Michael back every single time on every single machine.
- 18:36-Because if you- -Interesting
- 18:37... are searching for Michael and you get a different fake value back, you know, in
- 18:40the UI context, it doesn't make sense, you know?
- 18:43-Yeah. Yeah, yeah, yeah. -But with deterministic seeding, it means,
- 18:45okay, here is, here is the value that I want to base all of my random data on, and
- 18:49it will always do that. So what we do is we look at the body of that pending
- 18:52request. We take all of the inputs,
- 18:55we join them together, and then PHP has this function called CRC32, which will
- 19:00take a string and it will compute an integer value that represents what that
- 19:05is. And then we pass that value into, um,
- 19:11into Faker's seed method
- 19:13so that we're always getting this data back. And so-
- 19:16-Interesting -... we've, we've now built out a fairly
- 19:19robust, um, implementation that will always give us, like, pseudo-random data,
- 19:26but in a consistent way. So, like, if we're searching for something, you know,
- 19:29we can, we can build our expectations on it, we can build tests on it 'cause we
- 19:33know that, like, the fake data won't change every time we run the test. We know
- 19:36that we're always gonna get the same set of data back. So we can actually write
- 19:40tests against all of these endpoints with the fake gateway enabled, knowing that
- 19:44we're gonna get back this specific data. That then extends-
- 19:47-So when you say you seed it, you're not- -Yes
- 19:49-... seeding a database. -We're not seeding a database, no.
- 19:51'Cause they're not models in your application.
- 19:53-No. -You're seeding the responses that are
- 19:55gonna come back from your mock handler for Salesforce.
- 19:58-Correct. Yeah. -Yeah, yeah, yeah.
- 19:59-Uh-huh. -So it's basically like with Faker, you're
- 20:01almost creating... I mean, it's not a database, but it's almost a database
- 20:05because it's pseudo-random. I mean, it's deterministic, right? So you're-
- 20:08-Mm-hmm. -When I'm hearing you say, like, you're
- 20:09referencing, like, an ID, it's basically like you're referencing an ID in a
- 20:12database that actually does not exist because it's just seeded-
- 20:15-Correct. Yeah. -You know, seeded fake data, essentially.
- 20:18-So- -Wow. Yeah
- 20:18... you could think of it almost as a
- 20:21sort of database, I suppose. I mean, it's not a database, but, like,
- 20:25same idea, right? Where it's deterministic, you can write tests against
- 20:28-it 'cause it's not gonna change. -Right.
- 20:30So it's almost seeded data, but you don't have models backing this stuff.
- 20:34-Correct. -So you have to use some other sort of
- 20:36-mechanism to do so. -Yeah.
- 20:37-Okay. -So you're, you're seeding the random
- 20:38number generator that PHP uses, which is using, like-
- 20:41-Yep. Yep, yep -... MT Rand or whatever under the hood.
- 20:43Yeah. MT... Like, it's a PHP function under the hood. So if you always want to
- 20:47get the... This is quoting from the Faker docs. "If you want to always get the same
- 20:52generated data, for instance, when using Faker for unit testing purposes, the
- 20:56generator offers a seed method which seeds the random number generator." And the
- 21:00crux of that is that calling the same script twice with the same seed produces
- 21:04the same results.
- 21:06-Interesting. Okay. -And this, and this-
- 21:09-Okay -... is then why it becomes helpful in, in
- 21:12the... Like, in a, in a UI context where if you are seeding based on the inputs, no
- 21:17matter what you put in there... Like, if I put Jake in there
- 21:20or I put Michael in there or I put Eric in there or I put Sam in there or whatever,
- 21:25as long as the inputs match, you will always get the same results back, which
- 21:29makes the testing a bit more predictable. If you hand that off to a QA team or, you
- 21:33know, for testing, or manual whatever, you know that you, that it's... Like, it's
- 21:38not gonna make people stop and think, "Wait, what happened there? 'Cause I got
- 21:41two different results back." It's like, no, if I search for Jake-
- 21:43-Yeah, I guess, yeah -... the same set of results come back.
- 21:46Right. So it's like you only... The only benefit that you lose of fake data is that
- 21:53the randomness of it is sometimes a bit of a fuzz test against, you know, can your
- 21:58code handle values that are not typical sort of deal?
- 22:02-Yeah. -Right?
- 22:02-Yeah. -And so that, that's part of the idea of,
- 22:05like, Faker, which is like, "Hey, it should be able to generate any value and
- 22:07it should always work." But it's like, there are other considerations to be made
- 22:11too, and so you're just making a trade-off. You're saying, "Well, we're
- 22:14okay with losing some of the benefit of that randomness for the predictability of
- 22:17having deterministic values that are getting seeded in here," and for all the
- 22:20other me- reasons you mentioned. Interesting.
- 22:22-Yeah. -I've never actually heard of this, so
- 22:23-I'll, I'll check into that. -Yeah.
- 22:24-That sounds really cool. -And so in, in the context of, like,
- 22:28actually opening up the application in the browser and, like, using it, I think it
- 22:33-makes- -Yeah, yeah
- 22:33... much more sense than having totally random data.
- 22:35-Mm-hmm. -Because if you think about it, if I'm, if
- 22:38I'm hitting Salesforce and searching for Jake, well, I expect-
- 22:41-Yeah -... Jake's data to always come back. I
- 22:42-wanna see- -Absolutely, yeah
- 22:43... the same results. And so that's where this comes in. And, like, this stuff has
- 22:47been in Faker, I don't know, since forever. And the reason that, like, I'm,
- 22:51I, I know this fancy word, deterministic, is 'cause I built this, um, avatar
- 22:56generator for Laracon AU, where I wanted it to be random, but I wanted it to always
- 23:01be the same for a given input. So if I'm gonna generate an image-
- 23:06Yeah, it's, it's almost like functional, right? I mean, it's f- it's almost like
- 23:08functional programming where it's like given the same inputs, you should expect
- 23:11-to get the same outputs every time. Yeah. -Yeah. Yeah.
- 23:14Um, and so, yeah, that, that, that has worked really well in that context and
- 23:18provides us, like, much more useful output. I'm, I'm not sure... I still need
- 23:23to do a little bit of finagling to make sure that I'm actually happy with
- 23:28-what has been built. Because- -Yeah
- 23:30... largely it has been just, like, driving the AI and letting it come up-
- 23:33-Yep, yep -... with stuff and fixing things as they
- 23:35come. But it's, it's been pretty good in terms of
- 23:38building the code,
- 23:39finding problems. Like, I've got it into this loop now where we put into our Claude
- 23:43file,
- 23:44um,
- 23:45you know, make sure that you always run PHP unit on the test. Make sure you always
- 23:49run CS Fixer. Make sure you always run Stan, so if you've introduced any
- 23:52violations, like, it'll go back and fix those things as well, which has been very
- 23:56helpful. Um, so I think the, the code is robust. I think the, the... Then the third
- 24:01exploration is, okay, we've built
- 24:04this thing. Is this something that we can... I don't know if we can package it
- 24:09up or if we produce a set of guidelines or something that go, "Okay, now for the
- 24:13other things that we want it to have..."... mock gateways for. You know,
- 24:18for a lender integration with a bank or for a provider of, like, you know, Equifax
- 24:23or something like that where we're doing these lookups. Well, we- we want the- the
- 24:26same data to always come back, but we don't wanna hit Equifax 'cause that cost
- 24:29-money every time you do that. -Again, and it will... And like you said,
- 24:31it's deterministic in a sense. You don't have to spin up an Equifax-
- 24:34-Right -... non-production environment sort of
- 24:35-deal. -Correct.
- 24:36Like, it's like you just get all those benefits that you're talking about. Now,
- 24:40there are, you know, there does end up being some drawbacks, but, I mean, you
- 24:44know, there's drawbacks with the current approach. So you just have to... It's the
- 24:47-trade-off, right? -Yeah.
- 24:48-Um, you know. -So in- in our tests, right, in our tests,
- 24:51we would still want to- to do this kind of stuff with actual fake data. And that's
- 24:57where we'd dip into the Saloon fakes, and we would use our fixtures and all of that
- 25:00kinda stuff. In terms of actually using it
- 25:05-by hand- -Yeah, yeah
- 25:06... in the browser, yeah. Then, but- so then the exploration was, okay, how do I
- 25:10build this
- 25:12infrastructure
- 25:13where I've got, like, a config file? Okay, okay, here is Salesforce, but now here is
- 25:18Equifax, here is bank A, here is bank B, here is lender A, all of these kinda
- 25:23things. And I just configure them in there, and they'll register themselves,
- 25:28and then they'll find, you know, okay, this is the thing that needs to hit this.
- 25:31And it all goes into Saloon's global middleware and whatever needs to- to deal
- 25:35with any given request. And we can build these over time. So I think I'm happy
- 25:39enough with it that I think that it will work,
- 25:42and it seems to cover all of the scenarios that exist currently
- 25:46until we start using it in practice and figuring out, okay, how do we
- 25:53create the next gateway, the next mock, the next mock, you know, and actually
- 25:57using it. That will be the determining factor about if this approach is actually
- 26:04robust enough to be that flexible across the board, so.
- 26:07-Yeah, yeah. -We'll see. We- we might revisit that in a,
- 26:10in a few episodes and see if we've made any progress on it.
- 26:14Yeah, it's like you're trying to look into the crystal ball and determine what the
- 26:17-future's gonna hold, right? It's like- -Yeah.
- 26:19It's- it's so funny, like, I... We talked to... We talked to the dev team about
- 26:24this, and they're totally on board with that- that approach where it's like
- 26:26sometimes you just gotta ship it and see. You know what I mean? Like, just- just
- 26:29push the button and, like, you're not gonna have the final answer. But, like,
- 26:33we're not building pianos here. Like, we can go in and change the code. Like, it's
- 26:37not a big deal. You know what I mean? It's like it doesn't have to be perfect the
- 26:40first time. It just has to be good enough that it's not gonna break everything. And
- 26:44if it's good enough, then it's like you can make modifications as you go, right?
- 26:48Um, but trying to make predictions about how it's going to be used everywhere, it's
- 26:51just impossible. And I feel like my IT team, they are on that train. They're
- 26:55like, "We have to have all the variables solved before we push the button." It's
- 26:58-like, you don't. -Mm-hmm.
- 26:59-You don't. -Mm-hmm.
- 27:00You just need to have enough information to make a good decision and then push it
- 27:04and see what happens and then learn and move from there. But you can make
- 27:07decisions and make changes a lot faster that way than you can hemming and hawing
- 27:11and waiting around and trying to get the perfect answer. And it's like you won't
- 27:14have the perfect answer until you actually start moving, then you're gonna figure it
- 27:17out. So, um, but the other part I was gonna say is, like, this registration
- 27:22piece that you're talking about where, like, you're registering all the different
- 27:26responses and things like that. And I'm sure you'll find a way to organize this
- 27:29well, but, like, right now, two things. Number 1, they're probably tied to actual
- 27:33-endpoints, I'm guessing. -Yeah, so the... Each response has its own
- 27:39should-handle method, and it gets past the- the pending request object. So it
- 27:44goes and looks like it... You c- 'cause then you've got access to the request
- 27:47itself, and you can figure out, do I need to intercept this or not? And
- 27:52depending on what it is, you know, sometimes it's- it's enough to just look
- 27:56at
- 27:57the endpoint. Sometimes we wanna look at the endpoint and the body and go...
- 28:03Because then we've got for authentication, for example, we've got an email, like a
- 28:08specific email address for a successful login. We've got a specific email address
- 28:12for a failed login, a specific email address for, like, a- an account that
- 28:16doesn't exist, like all of these kind of things. So some of it gets a bit grim. Um,
- 28:21some of these methods have got some
- 28:25creative regexes that Claude has written in there.
- 28:28-Yeah. -Which may or may not be the most
- 28:30-appropriate course of action. -Yeah.
- 28:31But you... I mean, in- within the context of each of those response classes, you can
- 28:36do whatever you want to determine if it should be handled.
- 28:39Yeah. And so I guess that's what I'm trying to figure out is, like, how do you
- 28:41co-locate the code that's going to be handling or that's gonna be responsible
- 28:44for figuring all that out? And I'm sure it's, like, you can have, like, some class
- 28:48double, you know, dot op generate or a class dot op register handlers or
- 28:52something like that, where you can kind of just say, like-
- 28:54-Right -... for this particular type of response,
- 28:56we're gonna have a class named this that's going to be, you know, by convention,
- 29:00it's gonna match the naming like this, but it's gonna be called, you know, blah,
- 29:03blah, blah, response register handlers class.
- 29:05-Yeah. Yeah. -And then, you know, you just call that,
- 29:07-and there you go. And, and so you can- -Yeah
- 29:09... break it up so it's not like some massive
- 29:12just config file, essentially. You know, there's actually some testability even
- 29:16around your- your registrations and things like that, if you needed it to be as, uh,
- 29:20-as sophisticated as that. But- -Yeah.
- 29:22-Maybe not. -At- at the moment, this, like, registry
- 29:25that we have, it just, like, you
- 29:29pass it a, a namespaced path, like app/gateway/sales floor-
- 29:35salesforce/fake/responses, right? And it will go and look in there, and it will
- 29:40look through... Like, it just looks through all of the files in there. And if,
- 29:45if it's a non-abstract class and it implements an interface that we've got on
- 29:48there, it will then register it
- 29:51as a, as a handler. And then it will... And then the
- 29:55Saloon is then responsible for passing all of those
- 29:58things through and figuring out, should I be intercepting this request? So it is-
- 30:02-Mm-hmm, mm-hmm -... it has been done in such a way where,
- 30:04like, the registry will go and just, like, discover all of these things
- 30:08automatically and then just slot them in there. So definitely don't run it in
- 30:12-production. -Right, right.
- 30:14Because you could be registering, like, you know...... dozens to hundreds of
- 30:18classes for all of your Saloon implementations. Um, but locally, like, it
- 30:22doesn't matter too much. Our machines are so overpowered and over-provisioned that-
- 30:26Totally
- 30:26... having this do it. No, and especially if you're just enabling them one by one.
- 30:30So there's, like, the top level
- 30:33is this thing that spins through the config and then registers all the
- 30:35handlers, and then each handler is responsible for then going and registering
- 30:39all of its responses. So if you've got them all disabled, it'll just spin through
- 30:42that top level four or five or ten or however many integrations you've got
- 30:45fairly quickly, and it'll just do nothing. Like, we just filter them out of the
- 30:48collection.
- 30:49-So- -Yes
- 30:50... I would like to share some code in time once I've-
- 30:53-Yeah, absolutely -... you know, happy that it is, it is
- 30:55actually a sensible approach. But, you know, early indications, um,
- 31:00with, like, just the Salesforce
- 31:03mock, uh, seems to be good. The proof will be in the pudding of whether or not it
- 31:09actually extends to other handlers. And I've been trying to kind of guide the AI
- 31:14to make sure that this is extensible. And anytime we start duplicating things, it's
- 31:18like, "Okay, let's pull this out, let's hoist this up to the top-level namespace,
- 31:21let's, you know, make sure this is all possible." 'Cause it is something that is,
- 31:25in my mind, that, like, we need to be able to do this. So, I think the, the main
- 31:29thing is just... Salesforce is a very
- 31:34large thing. Like, there's a big surface area of things that you can do. And so
- 31:40there's lots of overlap to the same endpoints. But when you've got discrete
- 31:43endpoints, it's much easier to have, like, a common thing that just, like, injects
- 31:47fake data based on the request kind of thing, so. I, I, I feel good about it, but
- 31:54I'm still, um, cautious about
- 31:59how well that works as we start integrating more. So we'll see how that
- 32:02-goes in time. -That's exciting, dude. Yeah, I'm excited
- 32:06to hear about that. That's, um, that sounds really cool. Uh, yeah, so we'll
- 32:10follow up on that in future shows. A couple of things I wanted to share real
- 32:13quick before we wrap this one up. Bond is a new thing by Filip
- 32:19Gagnik, Gagniks. I don't know how to say his last name. Anyway, he's a Livewire and
- 32:25Alpine dude, and he just released this library, Bond, uh, which is this
- 32:31interesting way
- 32:33to
- 32:34give you essentially, like, fully reactive, optimistic UIs on the front end
- 32:39that are also Livewire-aware. So you get the best of front-ends, like with
- 32:46modern JavaScript tooling, like being able to do includes and things like that,
- 32:50um, and bundling and
- 32:53all those, all those pieces,
- 32:55and then also all the benefits of Livewire. And so in his demo, that he put
- 33:01out a video today about this,
- 33:03um, he goes through and shows with this counter component, it's fully reactive,
- 33:08and it's like he can plus, plus, plus, plus, plus, plus, plus on this counter.
- 33:11And then in the bottom he has like, "Here's what the Livewire server rendered
- 33:14-value is." And you can see- -Hm
- 33:16... that on the front end he's able to click it as fast as he wants and the front
- 33:19end stays reactive and it doesn't make those back-end calls, and then it sort of,
- 33:22like, lazily updates that background, that background, um, amount. And then when
- 33:27it makes a round trip, it ends up updating that, that thing on the front end
- 33:31as well. Um, but your front end allows you to continue to go just as fast as the
- 33:37browser front end will allow you to, as long
- 33:39-Yeah -... as long as the, you know, user's
- 33:40machine is able to catch up or, you know, keep up with your JavaScript, uh, front
- 33:44end interactions. It will take care of sort of eventually syncing in the back end
- 33:48-which is really, really cool. -Mm-hmm.
- 33:50We've needed this in a couple projects, and, um, he's got some, uh... It's just
- 33:56very interesting. It's got TypeScript support, um,
- 34:00-super, super cool. -Interesting.
- 34:01-So Vite basically will pull out- -Do you wanna-
- 34:03-Go ahead. -You'll have to send me a link so I can put
- 34:05-it in the show notes. -Yeah.
- 34:06-It sounds interesting. -Yeah, absolutely, I will. And I'll, I'll
- 34:08send you the, uh, the video that he made here.
- 34:10-Mm-hmm. -It's really, really good. Uh, Wilbur
- 34:12Powery, uh, talked about it, um, today in our, in our dev chat. So there's the video
- 34:18and then I will send you the open source repo as well. Both look really, really
- 34:22cool. It's a nine-minute video. You should definitely check it out. Really well
- 34:26done. Uh, he seems like he, he essentially manuscripted his video that he was gonna
- 34:30do. It's, it's nine minutes and it's just pure code. Like-
- 34:34-Nice. -... doesn't stumble over one word. It's so
- 34:37well rehearsed. It's the best video on a new thing that I've seen people, you know,
- 34:41started to put out in a while. It's really, really good. So
- 34:44shout out, Philip. Good job. Secondly, uh, we've been talking about our journey, uh,
- 34:49at our company of restructuring a lot of our roles and permissions and things like
- 34:53-that. -Mm-hmm.
- 34:54And how we've sort of split the responsibilities between, uh, basically
- 34:59saying our application's only responsibility is to check permissions
- 35:02-with gate checks. -Yes.
- 35:04And then what we've done is we have bound those particular abilities to AD groups.
- 35:10And we've done that using... In AD, I mean active directory. We've done that using,
- 35:15uh, enums and enum attributes, which I swear is one of the most productive secret
- 35:21ninja combinations ever. Enums with attributes is just-
- 35:25-Mm-hmm -... awesome. It's so cool. Um, it allows
- 35:28you to have, like, type safety and also to bind additional pieces of information
- 35:33directly next to enums, which I just absolutely love. So really, really cool
- 35:37combination. I'm liking that. And I feel like we've arrived at some conclusions,
- 35:41um, about how we've found to best structure some of those things,
- 35:46specifically regarding, like, departments, job titles, and stuff like that. So, um,
- 35:50I'm interested to share some of those maybe in a couple weeks and-
- 35:53-Mm-hmm -... talk about that and some of the
- 35:55discoveries we've made, and maybe talk about this Bond thing too. We are-
- 35:58-Yeah -... right now in the process of creating a
- 36:02two-way interactive texting experience through SMS. So people who wanna get hold
- 36:07of our agents, they can do so through SMS. We're using Twilio Conversations.
- 36:12But...... we're pulling a lot of the Twilio Conversation stuff local. We're
- 36:16-saving records on our side. -Mm-hmm.
- 36:19Um, Twilio's, like, the source of truth, but we'll pull those down to our side, so
- 36:21we have database records then can- can basically enrich that data with our own
- 36:25data. Um, and we're using a LiveWire front end. We're building on a LiveWire front
- 36:28end, which is great, but this idea of, like, the optimistic UI is very
- 36:33-attractive- -Mm-hmm. Yeah
- 36:34... because sometimes it does, it can feel a little bit laggy. You know what I mean?
- 36:36If you're doing, like, high volume interactions back and forth, or you're
- 36:40trying to say, like, "Who's..." You know, "Which one of our team members is
- 36:43currently in this conversation?" How are we able to, you know, using presence
- 36:46channels or some of those things. Sometimes it can feel a little bit laggy,
- 36:48or notifications if a new thing comes in. You know, you have to kind of loop over-
- 36:51-Yeah -... a bunch of stuff in the background.
- 36:52Anyway, um, I'm interested to see if this is something we can start using and, um,
- 36:57since Wilbur Power is the lead on that project, and he's the one who discovered
- 37:00this library, I'm interested to see if this is something we might actually use in
- 37:03the next couple of weeks as well. So, looking forward to that in the next show,
- 37:08-I suppose. -Yeah. Yeah, so, um, Ash Allen, I think it
- 37:12was, tweeted something out about putting methods on enums.
- 37:17-Okay. Yeah, yeah. -Um, to, like, to- to return a label for
- 37:20something. Because, you know, your cases and your names don't always match up with
- 37:24what or how you wanna present that to the user, so he was talking about, you know,
- 37:27having a ToLabel method for things that would then return
- 37:31something that you could just put into your UI as opposed to what you're storing
- 37:34in the database. And then someone had put- mentioned in there that, yeah, you can
- 37:38create attributes here that target, um, like, the constants but, you know, enum
- 37:43members in that case, where you could put like a pound square bracket label
- 37:48whatever, and then you've got labels available through that as well. So, I
- 37:53think that's a, a, a, as you say, a really powerful combination and it gives you a
- 37:57lot of flexibility
- 37:59across enums, not just... Like, I don't have to create an, you know, a label
- 38:02method here or ToLabel and then a map and then, you know, match the value to
- 38:06whatever. You can just put it straight there on the, um,
- 38:11on the- the enum member itself, and then you can do it on a case by case basis.
- 38:15Like, you would expose the label method directly and would say, like, "Hey, is
- 38:18there an attribute here?" or return the value of the attribute. Otherwise, you
- 38:21might do, like, a string snake or a string title or whatever it is to, you know,
- 38:26have some fallback where you wanna do it that way. So, yeah, I- I-
- 38:30-Yep. Yep. Really, really powerful combo. -I do- I do think enums and attributes go
- 38:34-together like lamb and tuna fish. -Yeah. Lamb and tuna fish. I've not heard
- 38:38that. That is a new one on me, and, uh, I love it. I- I will add it to my list-
- 38:44-Pretty sure it was from Big Daddy -... of things that I tell my friends.
- 38:47-I- I will tell my friends when- -Big Daddy originals
- 38:48... when we talk about Australian colloquialisms. So this is not a, this is
- 38:51not an Australian thing? Lamb and tuna fish?
- 38:53-No. -Oh.
- 38:54Lamb and tuna fish was a, it was a character... Uh, it was Big Daddy. It was
- 38:58a character that, um,
- 39:01-uh, Rob Schneider played in that movie. -Okay, okay.
- 39:03Where he was... Yeah, he was, he played, like, you know, as Rob Schneider did back
- 39:06then, he played like a foreign, non- nondescript-
- 39:09-Sure -... foreign character. And he, yeah-
- 39:11-It's hilarious. -I'll put a link in the show notes.
- 39:13All right, I'll have to check it out. Hey, what episode are we on? 182?
- 39:17-That's right. -182, folks. Thanks so much for hanging out
- 39:20with us. You can find show notes for this episode at northmeetsouth.audio/182. Hit
- 39:24us up on
- 39:26X or on BlueSky at jacobbennett and michaeldrinda, or at North Meets... Or,
- 39:30North South Audio. And of course, if you liked the show we would really appreciate
- 39:33it if you'd rate it up in your podcatcher of choice. Five stars would be incredible.
- 39:36Thanks, folks. Until next time, we will see you. Bye-bye.
- 39:40Bye.