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