All Episodes

September 26, 2024 • 51 mins

In this episode, Jake and Michael are joined by Jason Beggs from the Laravel team to discuss the approaches they're taking to fake interaction with third-party services during development of their upcoming product, Laravel Cloud.

Show links

Mark as Played
Transcript

Episode Transcript

Available transcripts are automatically generated. Complete accuracy is not guaranteed.
Michael (00:00):
Hey. I'm Michael Dyrynda.

Jake (00:02):
And I'm Jake Bennett.

Michael (00:04):
And welcome to episode 163 of the North Meets South web
podcast.

Jake (00:10):
Hey, everybody. Welcome. Welcome. First question that I
want to ask everybody who'slistening. Have you ever watched
one of our videos on YouTube?
If you have, and you can reachout to me on Twitter, I want to
know if you clicked on the linkbecause I had such an incredibly
awesome background. Now here'sthe here's the, you know, the

(00:33):
gist of this. Michael and ourguests today, mister Jason
Beggs, so I'm gonna introducehimself in a minute, were giving
me crap about the fact that Ihave a white shiplap background
and a missing light switch coveron my wall and have for, like,
last forever for both of ourpodcasts. I mean, how long have
I been podcasting in front ofthis wall? Usually, I have a
happy birthday banner up heretoo Yeah.

(00:54):
Michael. It's been years.

Michael (00:55):
Look, at least it's not your bedroom anymore. So that's
that's

Jason (00:58):
It's true.

Michael (00:58):
Step up.

Jake (00:59):
That's true. That's true. So speaking of cool backgrounds,
yes, Michael's background islooking very nice. And then our
guest today, mister Jason Beggs,he's got some, guitars back
there. So everybody welcomeJason Beggs to the show.
Jason is a member, nowofficially, of the Laravel team.
If you go check him out ontwitter at jasonlbeggs,
x.com/jasonlbeggs, you'll see onhis cover image, he has a

(01:23):
picture of the entire Laravelteam and then an arrow pointing
that says me. And there's Jason.And I think Jason just, like, in
the middle of Laracon, accepted,a position on team Laravel. So,
Jason, congratulations.
Way to go. Nice job. For anybodywho might not know you, you've
been in the community for quitea long time. But tell us a

(01:44):
little bit about yourself, kindof what's your background in
Laravel? When did you getstarted?
And, what what brought broughtyou on to team Laravel? What are
you doing over there? All thosethings.

Jason (01:55):
Alright. That's a lot.

Jake (01:57):
Let let me start let me start easy. How long ago did you
start in Laravel?

Jason (02:01):
Yeah. So I think probably 7 years ago. 7 to 8 years.

Jake (02:07):
Yeah.

Jason (02:08):
Yeah. So I've been working with Laravel in various
JavaScript frameworks and thenTailwind for as long as it's
been available. Yeah. Yeah. Idon't even know how I got
involved in all the projectsI've I've helped with, but at
some point, I started.

(02:30):
I converted the Laravel Newssite to Tailwind, way back, I
don't know, 4 years ago,probably. And then after that,
Taylor hired me to convert tolaravel dotcom site to Tailwind,
then I ended up building aredesign. And then I built the
Laravel News redesign, and I Idon't know. I just ended up

(02:54):
building a ton of different,designs in the community for
Laravel and other people overthe years, and they asked me to
help with the the latest projectthey're working on, Laravel
Cloud, and, did help with it upuntil Laracon probably 2 months

(03:17):
before Laracon I started. Andthen, right before Laracon, they
decided to, invite me to jointhe team officially.
Finally talked me into it. SoNice. We announced it. Yep.

Jake (03:32):
That's awesome. I know that, like, your, your MO, what
you're well known for is, like,pixel perfect, compliance with
design files. Right? So, like,somebody hands a design file
off, and I've heard other peoplesay this, like, everything is
spot on, like, to the pixel.Like, margins, exactly perfect.
Padding, exactly perfect. And soyou've made a bit of a name for

(03:55):
yourself just being the guy whocan deliver on getting
everything to look exactly as itlooks as a designer hands it
off. Give it to Jason. Jasonwill knock it out quickly.
That's the other thing.
I've heard you just, like, knockit out. Like, you just, like, go
after it, get it done quickly,and it's done perfectly. So,
yeah, I think, your work haslent itself to, giving you lots
of great opportunities, which iswhich is pretty cool. And I've

(04:19):
even tried to hire you a coupletimes. I think at one point, I
maybe did have you do somethingfor us.
I think maybe I actually youmight have you might have done a
tailwind site for me one time. Ithink I had it designed, and I
think you did it. Maybe. I thinkthat happened once.

Jason (04:35):
Maybe. I don't know. I think so. Said many. I don't
remember.

Jake (04:39):
Yeah. Yeah. I think that happened one time. But, anyway,
stoked to have you on the showtoday. And, actually, we're not
on the show today with you totalk about, like, the design
aspect of things.
We actually are on here to talkabout something else that you've
been working on, at Laravel. So,like, the Laravel cloud
platform. So we could talk aboutLaravel cloud because it's kind

(05:00):
of unveiled and, you know, it'sout there in the public. I know,
however, there are some thingsthat we might have to dance
around a little bit as far as,like, how we talk about what
we're gonna be dealing withtoday. But just to get down to
the nuts and bolts of it,essentially, and I'll put this
preface out there.
It is 11:30 PM Jason's time. So,thank you for coming on the
show, first of all. But we'regonna try and get to the point

(05:22):
of this so we can kinda getthrough some things before,
before it's midnight. But youhad put out a tweet the other
day, that said, you know, inTaylor's talk at Laracon,
everything in his talk washitting real infrastructure.
Like, it was actually spinningup real servers.
It was actually provisioning newdatabases. It was actually
spinning up queue workers.Right? All of those things were

(05:43):
happening from the stage forreal on the Internet. Yep.
However, like, some of thedifficulty, with that is when
you're handing things off tosomeone who's not necessarily
going to be interacting with ormaybe you don't want them to
have to interact with the realversion of those things, like a

(06:04):
designer, like yourself, orsomebody who's dealing with
interactions and things likethat. The question is, how do
they get the application tofunction as it would if it was
hitting the real thing butwithout having to give your own
credentials for, like, you haveto set up your own, you know,
AWS, credentials and do all thatnonsense. Right? So that's
that's really, like, thechallenge. As a as a designer,

(06:26):
how do I see that model thatpops up after a database is
provisioned without actuallyprovisioning the database?
Do I have to do some janky weirdsort of, you know, voodoo magic
to get it to pop up and now Ican design it? And so what you
had said is you have since goneback and added fake providers
for different things inside ofLaravel Cloud so that you can

(06:49):
basically interact with theapplication locally without
having to ever hit anythingoutside of your local machine.
Does that sound like a prettygood summarization of of what
you were saying in that tweet?

Jason (07:00):
Yep. So, basically, the whole 2 months before Lyricon,
when I was building a lot of thefront end, I didn't have access
to any of that stuff. Didn'thave any of it set up locally,
so I was kinda flying blind onsome of it. I would have to hard
code, like, show the databasepop up or whatever Mhmm. Mhmm.

(07:23):
Just temporarily just to be ableto see it. And then Nuno, he
would, like, test it in the devenvironment and stuff where
there was actual everything wasactually set up, or, like, for
Git installations, like, I'dhave to, like, manually go in
the Git provider's table and addan entry just so it would, like,

(07:47):
recognize that there's a repo inthere. So, yeah, it's a little
bit difficult when you'redealing with a lot of different,
APIs and different, I guess,third party providers that you
don't necessarily even if you dohave access to them, like, you

(08:09):
don't necessarily wanna spin upan AWS server every time you hit
deploy locally. Like, if you'rejust if you're only wanting to
test, like, front endinteractions, you don't wanna
have to actually spin up aserver and then figure out how
to spin it down later, and,like, you're just gonna waste a
lot of resources and money doingthat kind of thing. So, yeah,

(08:33):
Nuno kind of spearheaded thateffort.
He got the Git providers set up,and then, he made the Git fake
kind of provider. So, like, whenyou basically, how it works is
when you first set up anapplication, if it's the first
application that you've set upin cloud, it'll pop up and show

(08:56):
you, like, connect to GitHub orconnect to GitHub account,
connect to your GitLab account,connect to your Bitbucket
account. And then if you'relocally locally now, we have a
4th option that's called gitfake. So if you click that
button, it kinda just loads ahard coded list of repos you can

(09:17):
choose from, and each of thoserepos has hard coded branches so
you can just kinda select thoseand go through it, and
everything just kinda workslocally. You can even fake the
deployment.
It'll recognize that it's a fakerepo, basically. It'll fake a
deployment, like, go through allthe build steps. It looks like a

(09:40):
a actual deployment andeverything. It's pretty cool how
it works, but

Jake (09:45):
yeah. But what it's actually doing on the back end
is is so, like, let's talkthrough that, like, git fake
one. Right? So Yep. You wouldI'm guessing you have some sort
of, like, driver or or somethinglike that where you say, like,
it's it's GitLab, it'sBitbucket, it's GitHub.
Right? Is it is that kinda howit works? It's like you have

(10:05):
some driver implementation thatsays, like, we are going to talk
to this particular type of APIendpoint, And then do you have
some sort of, like, interface orcontract that says, like, it
should interact with theseparticular methods, but you're
swapping out the drivers? Isthat kinda how you're doing
that?

Jason (10:20):
Yeah. So, basically, there's a source provider
interface that the GitLab,GitHub, and Bitbucket, classes
all implement. Then there's alsothe Git fake one, which
basically, like, each of thosehas, like, I don't know, Git

(10:41):
account details methods, Gitrepos methods, Git, branches
methods, that kind of thing. Andthe git fake one, basically,
instead of hitting an API thatgoes out to GitHub, it just
returns an array of repos. So,like, we have, like, Laravel

(11:02):
slash beep, Laravel slash cloud,Laravel slash forge, all in
there.
And that's basically the optionswe get to see. Select one of
those and when it creates therepo in our table or
repositories table, it'll setthat type on the repo's table. I

(11:30):
think it's on that table. Itcould be, I don't know,
Somewhere it sets a type that'sgit fake. So then every time
that repo is loaded, it knows touse that driver, basically.

Jake (11:41):
Yep. Yep. So to interact with anything on that
particular, you know, record,that that repo record, it's
going to use the Git fake driverto do that. No. I I absolutely
love that idea.
And the one thing I was gonnasay, and, Michael, I'd love to
hear if you guys have had to doanything similar to this, is it
also makes it much, much easierto test the non happy path.

(12:06):
Right? Because if you're dealingwith a real provider, trying to
figure out how you get it toactually give you an error,
like, if the username isincorrect or if there is some
sort of rate limit that you hitor if you don't have permissions
to get access to that particularrepo or if there's only write
access and not or, you know,there's only read access but not
write access or things likethat. Right? Like, what are all

(12:26):
the different non happy pathsthat could exist?
And they might be differentbased on which provider it is.
Those are very difficult thingsto do or to, imitate so that you
can see the UI when you'redealing with real world
implementations. And so one ofthe things that a fake provider
does is it allows you to be ableto, in the way that we've done

(12:48):
it in the past, and and thatStripe and some of these other
things do, is they'll have,like, magic tokens essentially.
Right? We're all familiar with,like, when you're dealing with a
Stripe sandbox, you put in4242-4242, that's a thumbs up
successful.
Put in 414141, it's like, that'sa CVV error. You put in, you
know, 43, that's like ainsufficient funds. Now that's

(13:08):
not really what it is, but thoseare the ideas. Right? And so
with these fake providers, youcan even, have this idea of if I
select this particular repothat's getting returned, I
should get this type of errorwhen I try to do some particular
thing.
You know? So that's one of thereally nice things I like about
those fake, those fakes is youcan test the non happy path much

(13:31):
easier. Michael, have you everimplemented this sort of pattern
in your own code base?

Michael (13:36):
No. We've I mean, we we use a lot of, the saloon library
that for HTTP requests. And sowe we fake things, but not not
like and that's faking them inthe context of our test, not to
the extent

Jake (13:52):
we're being

Michael (13:52):
able to kind of swap these things out with fake
responses in the execution of,you know, opening the
application in the browser. AndI think that's a really good
idea, especially when you've gotother people that need to look
at it, you know, whether it'sproduct people or it's, you
know, UX people or QA people,whatever, in your business,
where they wanna be able to goand just, like, click through

(14:13):
and do some exploratory testingand and test different
scenarios. There's there's noreal way of doing that. As you
say, Jake, there's no way tokind of fake what a failed
response is or something'sinaccessible. So I like I was
really, interested with thisthis approach that you've got in
terms of, you know, effectivelybeing able to fake out the

(14:35):
entire real application in in adev or, you know, QA environment
to kind of be able to do thatand hand that off and and see
what it actually feels like toexperience it.
Because it's one thing to writea test with a fake that's like,
yeah, when this happens, we hitthis endpoint, we get back a a
failure. Like, this is what weexpect to see back in the
response. But in terms of seeingthe actual application in the

(15:00):
context of, like, this errorcomes back or you get this toast
not or this modal notificationor whatever based on the inputs,
I think that that was whatreally interested me the most.
And in a large application whereyou would have to, like,
retrofit this stuff and figureout, like, you we certainly
haven't. People probably don'timplement in with this kind of

(15:21):
behaviour in mind, where you canfake out interactions with
external parties quite sosimply.
So, yeah, that's that's why Ikind of said, you know, I'd be
interested to to hear more aboutthis and and how it might be
implemented because I thinkthere's there's certainly a
place for in you know, a lot ofthese real applications that are
they're hitting up externalservices.

Jason (15:43):
Yeah. I think, it's easier in cases where you you
have multiple providers anywaysbecause typically, you're gonna
have some kind of interface thatthey all adhere to. So it's a
lot easier to to write a fakeprovider for Mhmm. Those cases.

(16:04):
But, there are a couple caseslike the deployments and stuff,
where we're just usingdependency injection to swap
them out always locally nomatter whether it's a real repo
or not, which I might we mightchange that to where there's a
EMV variable or something thatyou can use to toggle it.

(16:25):
So you could test realdeployments locally if you
wanted to. But,

Jake (16:31):
I love that you're talking about this because if we have
dealt with the same thing, weso, go ahead and finish your
thought if you if you have moreto say on that because but I I
wanna loop back to that in justa minute as far as, like, how
you're swapping them out withthe ENV as

Jason (16:44):
well. Go

Jake (16:46):
ahead. Yeah. So, so what you're what you're saying there
is that, you know, with thedeployment, for instance,
typically, you're deploying thesame way every time. Right?
Like, you're saying, like, we'realways deploying to this
particular location.
Our deployments always act thesame way or interact the same
way. But maybe you've nowextracted that sort of to a

(17:09):
contract so that you can have afake deployment driver as well.
Mhmm. And so this is what we docurrently with anything that
interacts with a third partyAPI. What we do is we always we
always do this regardless of ifwe actually can interact with it
for real or not.

(17:29):
We will create a contract first.So I will create let's just say
we have a Laravel cloud. Let'ssay I'm talking to the Laravel
cloud API from my localapplication. So I would create a
Laravel Cloud contract, but Ijust call it Laravel Cloud.
That's that's the contract, butthat's the that's the class I'm
gonna call it.
Actually, sorry. Let me let melet me re resay that. I'm

(17:51):
thinking through how our how ourconvention is. We call we call
it Laravel cloud, contract. Thenwe would have a Laravel cloud
HTTP gateway, and we'd also havea Laravel cloud fake gateway.
Then what we do is in ourservice provider, we bind to

(18:11):
that contract either the HTTPversion or the fake version,
depending on whether we're indev or act actually, not
depending if whether we're indev, if we're in production. For
in production, we bind to theHTTP. If we're in dev or
testing, we bind to the fake.And then we also have a facade
that references that, and wewould just call that Laravel
Cloud. So that facade would sayLaravel Cloud.

(18:32):
So that does the servicelocation to go grab out of the
container whatever was bound inthe service provider. And so in
that way, it's really nice. Inour tests and in our local dev,
we just hit we just locally hitit. No big deal. But in the case
that we want to test it withproduction, we do exactly what
you're talking about, which iswe have a ENV that says, should
fake, trying to remember how weuse it.

(18:54):
But, basically, should we useproduction in local? And then in
our service provider, we justsay, like, if not in production,
so or or if in production orshould use production in local,
then we load the HTTP one. Andso, it is nice sometimes to be
able to hit from local the realthing, but not super often. Most

(19:16):
of the time, we're wanting tohit the fake. But that's how we
do it on almost everything is wealways swap them out at the
service level, or the, you know,at the service provider level,
typically, because we don't havea lot of things that have 4 or
or 5 or 6 drivers or 2 or 3even.
It's usually we just have theHTTP and the fake one. But,

(19:37):
yeah, I could I could see thatbeing, you know, especially
where you we only have, like,the one sort of deploy method.
You have to extract that to acontract in order to be able to
use a fake so you can see thatthe other way. So that's
interesting. I I'm it validatesfor me so much of what we've
been doing for the last coupleyears.
I talked I remember talking toSam Curay who built Saloon and

(20:01):
asking him these same questions.And he was like, no. We don't do
that. We don't we don't providefakes like that. That's not
something that Saloon does.
And I was like, really? Becausewe really need that. And so it
makes me feel so glad to knowthat team Laravel is doing the
same thing, that pattern. Itmakes me feel so happy inside.

Jason (20:17):
I think A couple of people have mentioned, like,
maybe extracting it to apackage, but I'm like, I don't
know the the differentimplementations depending on
what services you're interactingwith are so different. Like, I
don't know how you could evenstart to extract that and

(20:37):
provide, like, good APIs, but Idon't know. Maybe somebody
smarter than me can figure itout.

Michael (20:46):
Yeah. I think I think in the in the context of Saloon,
you'd you'd have to introduce alayer on top of it. Like,
everything would have to create,like, some service class that
accepts the connector, that thatswaps those things out. And so
you you're always gonna bebuilding an extra layer on top
of it, in order to facilitatethat kind of thing where you can

(21:09):
kind of switch out. Like, thisconnector goes here, and it
returns, like, fake responsesfor everything and things like
that.
So it's definitely it's morework, but I think what it what
it provides you at the end ofthe day is is really good. Like,
we have a lot of issues withwith Salesforce, because we use
Salesforce for, the CRMcomponent of our main

(21:31):
application at work. And there'snot really a good testing story
for it in terms of a UATenvironment that you can hit to
do things with. Like, we have tospin it up. And that that
environment is run by our,product people.
It's run by our Salesforcedevelopers. So it can, like,
change state and things likethat all the time. Whereas if we

(21:51):
could swap out how we'reconnecting to it and just return
fake things based on the inputsand things like that, that would
be a lot easier. I suppose it'snever really occurred to me to,
like, these these things that wedo in testing to swap out the
underlying connection to returnsome fake data to then figure
out, okay, well, how do weactually translate this into

(22:14):
running the code, you know, inthe browser? Good for thought,
though.

Jason (22:20):
Mhmm.

Jake (22:21):
Yeah. To me, I think people typically think, well, I
have, like so here's the reasonwhy I don't think it occurs to
many people to do this and whyit occurred to me so early. I'll
start with why it occurred to meso early. And I'm not saying
because, like, I'm not I'm notpatting myself on the back. The
reason I'm saying this isbecause we had an application

(22:41):
that depended solely on having aconnection to an API.
This API connection was crucial.Like, we could not do anything
without this API providing thedata that we were going to
display on the screen. You couldthink of it almost like an SPA
with a API layer back end, butit lived, like, over there. So
our Laravel application wasfetching stuff from this API and

(23:03):
then displaying it on the frontend. Well, the there was no way.
This the system that we wereinteracting with with this API
is this crusty, old, old, old,old, old legacy legacy database.
And so it just became painful soquickly to try and get in there
and modify those values in orderto get what I needed on the
front end. I was like, there'sgotta be a better way to do

(23:26):
this. And so, actually, I waswatching Adam Wavin's course
testing Laravel, and he talkedabout this with Stripe way back
then. So, like, hey, instead ofit, like, interacting directly
with Stripe, create a gatewaythat's going to interact with
Stripe.
And then you can create your ownimplementation locally so you
don't have to constantly hitStripe. I was like, that's
genius. So that's what we did.And, I don't think many people

(23:50):
have that. I think most peopleare on occasion, you know, once
in a while going and hitting anAPI to go update a one resource,
and that's it.
Right? And so it doesn't reallymatter for them. It's not, like,
critical if they fake it out orif they don't. But in this
particular application for you,Jason, like, everything you're
doing is basically gluingtogether somebody else's repo to

(24:10):
a cloud provider. So it's likeeverything is API interactions.
Everything is like that. So howdo you do that? How do you, you
know, view the UI without havingthose actual APIs? And so now
the need has arose for you guysto be like, we gotta figure out
a better way to do this, at thesame place I had to be, like, 6
years ago when we were trying tofigure this stuff out. So, it is

(24:31):
just interesting how you end uparriving at some of the same
conclusions and some of the samepatterns.
What I would really like to do,I hear you saying somebody's
extracting this. So thinkingabout extracting this to a
package. I don't know ifTaylor's accepting talk
proposals for LairCon for nextyear yet, but I was talking to a
couple people for about, maybemaking this into a talk idea.

(24:53):
Because I really do thinkthere's a lot of interesting
patterns around this and how youcould introduce some of the
benefits of this in a way that,I think would be really
beneficial, not even in apackage. You know, like, if I
like, in my state machine stock,I never talked about a package.
I think it's because in someinstances, you don't need one.
Right? In this instance, I don'tnecessarily know that you need
1, and I don't know that there'sa one size fits all solution for

(25:15):
this sort of thing. But if youunderstand the concepts, it's
not that hard to introduce ityourself. Yeah.

Jason (25:23):
Yeah. Yeah. The the code is really simple. Like, it's not
complicated at all

Jake (25:30):
Mhmm.

Jason (25:30):
But it's so powerful. And, like, before, like I was
saying, like, I couldn't, like,do anything hardly in the app,
but now you can literally getclawing the repo, set it up like
a normal AOL app, and you can goregister an account and start
clicking around, doing anythingyou want pretty much, and it all

(25:51):
just works. Like, isn't actuallydoing anything, but, like, you
can do all the front endinteractions locally, and it
just works. It's pretty sweet.

Jake (26:03):
Yeah. I know. Incredibly powerful. So, Jason, if if, you
know, you're you're thinkingthrough, like, for Michael,
like, if he's interacting withSalesforce, you know, just kind
of using what you guys did as areference maybe for, like, the
deployment thing. You know, hedoesn't have, like, multiple
drivers necessarily, but, like,he just has this one thing he's
interacting with.
Like, what would you suggest as,like, maybe a path or, like,

(26:26):
even, like, a first step to,like, how could they start to
implement this pattern? Whatwould be, like, the first thing
they would need to do in orderto be able to make, like, maybe
a fake Salesforce thing? Yeah.

Jason (26:41):
I guess it depends on how your current code is
architected. If you have, like,a Salesforce class that's doing
all the interactions, you have abunch of methods on there that
calls out to Salesforce and doesstuff. Extracting an interface
that that implements would bethe first step. Then you could

(27:03):
create the fake implementationof that interface and then
probably just toggle them basedon the AMD key or however you
wanna do it in your serviceprovider.

Jake (27:18):
Mhmm.

Jason (27:21):
That would be the most straightforward thing. If you're
not using, like, a Salesforceclass or something, I don't
know.

Jake (27:33):
How are you doing it, Michael?

Jason (27:34):
Extract 1.

Michael (27:35):
We're we're using like a 3rd party package that does
it, which actually complicatesthe process even further because
all of this stuff is like it'sbuilt for Laravel, but
everything is just bound to thecontainer. And we actually have
2 two different Salesforceinstances that we need to, like,
dynamically switch with. So it'slike this this this whole
debacle around even just usingthe package on its own. But I I

(28:02):
conceptually, yeah, I'd say, youknow, we're gonna have to we'd
have to abstract over the top ofit. We'd have to

Jake (28:08):
You would.

Michael (28:08):
Inject this stuff. We'd have to create our own
interfaces and service classesand whatever else so that we can
handle swapping it over. Becausethere's it's a bit more involved
than just saying, like, use thisthing. Because using this thing
also goes and, like, handlesauthentication tokens and, like,
authenticating with the API toget request tokens and handling
refresh tokens and all that kindof stuff. And so it's it's not

(28:33):
architected in a way that'smeant like, I assume whoever
wrote this package, like, builtit for their use case and it
kind of got out of hand whereeveryone started using it, but
it was not really considered as,like, people are going to use
this.
It's like, I built this thingand off it goes. And so

Jake (28:47):
Yeah. Sure.

Michael (28:48):
You know, there's there's a lot of stuff out there
like that. And unfortunately,the overhead of trying to
implement this all ourselvesfrom scratch is just, you know,
you make do with what you've gotavailable sometimes. But I think
yeah. I it it seems at a highlevel to to kinda summarize
simple enough. Right?
You create an interface, youcreate your implementations, and

(29:09):
then use container binding, toto switch them out whether based
on environment or based on, youknow, the environment that
you're running in or somespecific environment variable or
things like that orconfiguration switch and and and
going from there. Yeah. Like, Idon't I don't think there's
anything crazy or wild or beyondthe norm for a Laravel

(29:33):
application. It's just a matterof, like, deciding at the
outset, like Jake did with thewith the Stripe stuff. Okay.
This is how we're going toimplement each of these things
so that we can just swap themout on the fly if we have to.
And and, like, that's the effortthat you need to go to, which,
you know, it it introduces thisthird avenue of, like, fake data

(29:54):
where lots of us are probablyalready doing this. Like, here's
our application and here's ourHTTP fake that we're using in
our tests. But this is kind oflike giving that HTTP fake in
the context of looking at theapplication inside of the of the
browser in a

Jake (30:11):
non production environment. Exactly correct.

Michael (30:13):
Yeah.

Jake (30:13):
Yes. It's like a third leg on that stool. People typically
consider, like, my productionand dev environment as, like,
one thing and then testing iscompletely different thing.
Right? So, like, in your tests,yeah, you use the HTTP fake and
then assert what should comeback and all that stuff.
Right? So you you mean you areyou're doing the same thing.
You're faking the data in thetest. Effectively. Yeah.

(30:34):
Effectively. And so like whatyou said is you're basically
allowing yourself to do that inthe in the local layer. And so
it's it's hugely beneficial. Theone thing I will say that's
really actually nice about thispattern too is if you are if you

(30:54):
have not yet figured out the APIlayer implementation so quick
example. We have an API layerthat we're integrating with, but
we have to wait to get approvalfor this API.
We don't actually have the APIyet. It's we're not sure what it
is. But what we've been able todo is we've been able to create

(31:15):
the gateway, create a fakeversion of it, and then shape
the data how we think it willcome back and interact with it
that way. So we're basicallystubbing out what we think it's
going to look like. And thenwhen we actually get access to
the real API, we can shape thedata coming back from the API to
look like what we expected it toin our fake.
Right? We can sort of marrythose up. We can say, well, this

(31:37):
is what we've been coding to.This is sort of the interface
that we created that we said itshould look like about like
this. And so when we get thereally API, let's say that
there's, like, one more keyabove that level of entries.
Well, I just strip that off andnow I just return the entries.
You know what I'm saying? No bigdeal. So it allows me to, as a
developer, to developindependently of the actual
implementation of the API,especially if I don't know what

(31:59):
it's going to be yet. Or if I'mtrying to figure out what I want
the shape of it to be.
Like, if I'm the one responsiblefor creating the API that
eventually will be used, I canplay around with what I want the
shape to look like as I'mconsuming it and then later go
implement what the what thatshould I write the code to
actually make that happen. Youknow what I'm saying? So I get
to sort of decide in advancewhat I want that API layer to

(32:21):
look like, and then I can codeit to work that way.

Michael (32:24):
Mhmm. Yeah. Are are you just returning, like, arrays of
strings? Have you got, like,typed data in there? Are you
using, like, read only DTO,like, plain plain on Good

Jake (32:37):
good questions. In some of them, we're just returning
arrays. In the some of the moreserious apps that we have, we
are returning DTOs, typed DTOs.

Michael (32:46):
Mhmm.

Jake (32:46):
And then, in each of those sort of DTOs, in some of those
cases, we'll have, like, fakeversus a lot of DTOs so that we
can assure that in productionand in our fakes that they come
back with the same shape ifthey're larger objects and
things like that. But I thinkthat when we're starting yeah.
Just arrays and strings.

Michael (33:01):
Yeah. I think the DTOs are nice because it doesn't
matter what your third partiesare returning. Like, you are
shaping the data into what youwant to consume in your
application. And so if you'rejust coming up with that
interface, you're saying, I wantthis, this, this, this, and this
in these, you know, these fieldsto be available. Then when it
comes time to mapping the actualAPI responses, you don't have to

(33:26):
worry about how that data iscalculated or where it comes
from or if it's like in a nestedobject somewhere in the API
response because you're alwaysgetting back a DTO in the shape
that your application expects.
And I think this is somethingmaybe if people are using DTOs
for the first time, they kind ofget themselves in this trap of

(33:47):
just mapping 1 to 1, what theYeah. What is being returned
from the API response ratherthan mapping the stuff that you
actually need in a way that youwant to be able to access it.
So, yeah, I think that's that'sa pretty good approach. And,
like, PHP makes it really easyto to create these, like, read
only classes now that, you know,just takes I

Jake (34:09):
forgot about that.

Michael (34:10):
Yeah. So, like, we do it a lot where we would just
have, like, a read only classwith a constructor that just set
some properties, and that'sabout it. You know, for for a
lot of things, especially thingsthat we're passing around inside
the application, anything thatthat breaches the, like, request
response, border. Like, if we'resending stuff back to our front

(34:32):
end, for example, we use thesparsysdto package because then
we can do all the TypeScriptconversion and things like that.
But anything that's justbouncing around between the
request that goes, you know,from a controller into an action
or it gets passed around tosomewhere else, a lot of the
time, we're just using theseread only classes just so that
we've got some structured datato to fling around.

(34:53):
And those may then convertthemselves into to spaCy DTOs
when they get sent back. Byhandling them internally, it
means you get, like, IDEsupport, you get type
completion, all of this kind ofstuff, or type support and IDE
completion the other way around.And it means you you entirely
control the shape of that thing.And it's just a matter of

(35:14):
instantiating that based onwhatever you have available. And
then it doesn't matter if it's afake or if, you know, or in this
example, it's GitHub and GitLaband Bitbucket.
And then the fake is everythingis returning the same structured
data. And how you compose thatcan vary, you know, in an
infinite number of ways becauseyou're not conforming to any
individual providerspecification.

Jake (35:36):
Yeah. I'm curious how you guys are doing that, Jason.
Like, when you have thedifferent providers, is is there
some sort of standard responsethat you guys are formatting it
to? Or how does that work? Youknow, when you say, like, I
wanna talk to GitLab or wannatalk to Bitbucket or when I
wanna talk to whatever.
When you're getting back thatdata, that's the list of
repositories. Yeah. Is thattypically just returning an

(35:57):
array, or is it returning somesort of shaped object?

Jason (36:01):
Right now, we're basically just returning arrays.
Mhmm. But we are shaping them tosome extent. But, yeah, we're
not using

Jake (36:10):
Like, inside the different implementations inside the
different implementations of thedrivers, you're just basically
saying, like, whatever comesback, I just want this array of
the repos.

Jason (36:18):
Yeah. So, yeah, the repository's, method on this
GitHub thing goes and gets some,and then we're looping over each
one, mapping it to the structurewe want, and just return an
array of arrays, basically.

Jake (36:33):
Mhmm. Mhmm. Yep. And then the other ones, like, the
Bitbucket driver would basicallydo the same thing. It would
kinda go get it, and whateverthe response is, it's gonna
massage it into this shape thatyou're that you're wanting to
see there.
Okay. Yep. Okay. Interesting.Yeah.
Michael, your suggestion of,like, you know, always having a
DTO there, I think it justdepends on where you're at in,

(36:58):
like, the journey, I guess.Like, if you're if you're really
wanting to be positive or ifit's you know, for example,
like, in this case, if you'rejust returning an array of,
like, the items, like, probablynot that critical. But if the
shapes of the data that you'redealing with are quite complex,
if, you know, if you're needingto grab 20 keys off of this one
object that's returned and youneed to make sure that they're

(37:20):
there or have some errorhandling in the case that they
aren't there or whatever orhave, like, a null response, you
know what I mean? Those sorts ofthings, then I think it's worth,
it's worth sort of extractingsome sort of DTO there and then
always returning that regardlessof if it's coming from the fake
or from your real one.

Michael (37:36):
Yeah. I mean, obviously, it depends on your
team, your makeup, your youknow, where you're at, as you
say. I think it's just it's soeasy to to create these objects
to shape the data. And that way,you don't run into these
situations of, like, forgettinga key or trying to reference a
key that doesn't exist or havinga typo and then, like, these
things bubbling up as exceptionsbecause you're accessing keys of

(38:01):
arrays that don't exist andthings like that. Like, you know
when it's an object that it'sthis object and it's going to
have these things in there.
And it just like gives you asane kind of structure to bounce
around in the application. Yeah.And and like

Jason (38:17):
I said have

Jake (38:20):
I was

Jason (38:20):
gonna say these only have, like, 4 keys, but Mhmm.
With them being, like, the samestructures copied across 4
different Mhmm. Providers,there's a pretty good argument
already that this could be aDTO.

Jake (38:36):
Mhmm. So you're saying with each one of the
repositories that's returnedfrom that array, like, each one
of those items has, like, 4 keysthat you're that you're hoping
that they have? Yep. And rightnow, it's kind of just up to the

Jason (38:51):
Yeah.

Jake (38:53):
Go ahead. You were you were gonna say I'm guessing
you're just gonna just say thedifferent keys and stuff.

Jason (38:58):
Yeah. It's got a full name, is private, a name, and
then a default branch. Mhmm.Yeah.

Jake (39:06):
Yep. So the different yeah. And so it's basically
right now, it's just up to thedeveloper who's implementing
these to make sure that they'reconsistent across the board.
Right? Which is Yep.
I mean, you got high qualityteam members. Right? So they
hopefully, when somebody goes tochange one of them, they
remember to change all of them.Right? But that's Yeah.
That's sort of the danger.Right? Is that if there's some
new key that you need off of it,you're gonna have to remember to

(39:30):
implement that on all of them.And if you forget one of them,
then you're not gonna know untilit bites you. You know?
Yep.

Michael (39:36):
Yeah. So Yeah. Again, comes down to the team where
you're at, you know, that it is4 different implementations that
are all the same thing. When youcreate a new one, you know,
you're just going and copypasting the existing things and
doing the mapping, and and youmake the assumption that it's
there. So, like, it's notcritical.
But then, you know, depending onyour team, you're then in this

(39:59):
situation where you're usingPhpDoc to annotate the shape of
your returned arrays instead ofjust returning a DTO. So,

Jake (40:07):
Right. Right.

Michael (40:07):
Like, a million different ways to to implement
the same things, and, like, makethe decision that that is
suitable to you. I just think nomatter how simple it is, it's so
easy to just create theseobjects now. And it's and it's
it's more resilient, to toreturn those things than it is

(40:32):
to just, like, hope that youdon't make a typo. And like,
yeah, you write your test, andyou make sure that things exist
and and whatever else. But I'dI'd like, it's so so easy to do
that it's Yeah.
You know, you'd have to you'dhave to have a a really good
reason to not do it. Like, yes,before everything was just
erased because everything in PHPwas always erased and that was

(40:53):
fine. But it's like as I said,because it's so easy to do,
there's like no overhead. Youdon't have to like, we've got
auto loading. These things canall just exist and they just
work nicely.
So, yeah. Do do whatever youwant. I'm not I'm not your dad.
I'm not I'm not the one that'sgonna be rejecting your PRs.

Jake (41:11):
Yeah. Right. Right. If I can make one more pitch for the
DTO thing on this side, I'llI'll say this is the last thing.
When you are doing fakes insideof your tests, a lot of times,
like, if you're doing, like, anHTTP fake, for example, you're
just returning, like, arbitrarystrings of data data.

(41:33):
Right? And the danger for me inthose is those things can change
shape relatively quickly, andit's hard to keep them
consistent across the board.Whereas if you use this sort of
architecture that we're talkingabout, what we've done in some
instances where I've said I knowI've called them more are are

(41:54):
more serious apps. And what Imean by that is apps that are
dealing with, like, financialinformation or or, you know,
payments or things like that.When we're doing that, what
we'll do is we'll return a DTOfrom each of the different
methods on the contract, whichis great because you can just
say this method always returnsthis sort of DTO.
But then what we'll do is in ourtests, we can just say facade,

(42:16):
which is like Laravel Cloud, youknow, colon colon, should
receive or expects, create newserver. That's the method. And
then we say and return. And thenwe have that DTO, and we say
double colon fake. Right?
And so we would we basicallyhave on each of these DTOs,
we've we've implementedsomething that says, you must

(42:37):
have a method that's fake onthis, which returns essentially
like a factory. You know what Imean? Here is a default version
of what we would expect this DTOto look like. Mhmm. And, and
then anybody who's using it youknow what I mean?
If you're ever needing to testthat in your actual tests,
that's where you're gonna getthat data from. And and you can,
you know, you can then modifyit. So you basically have these

(42:59):
DTO fakes, which, again, arevery much like database
factories where you have, like,methods you could call on them
to say, like, I would expectthis one to be like a failure or
I would expect this DTO to belike a whatever. Right? And so,
it does give you a sort ofanother layer of confidence to
know that, you know, you'realways going to be returning

(43:20):
that shaped data in a way thatis going to be consumable to all
your other stuff.
And in your tests, you have alot of confidence to know that,
you know, you're not justreturning arbitrary data from,
like, a HTTP fake. This iswhat's gonna come back, and it's
gonna be this shape. And so thatfeels really nice. It feels like
it gives you a lot ofconfidence.

Michael (43:38):
We've also done things with static constructors to,
like, dtocoloncolondefault. Youknow, if we have something that
wants to return some defaultstate. And then you can just
call that if you want to usethat for for whatever reason.
You know, you can do thesethings. You can extend them
locally, I guess, if you're notusing final classes.
And, like in your testenvironment, say like this thing
extends this existing DTO, andit will always return, like,

(44:03):
failing data or successful dataor whatever I was trying to say.
So, yeah, there's there'sdefinitely some nice approaches
to it. I mean, yeah, with withan array, you can just say,
like, whatever returns thisstatic array of data. Yeah. A
million ways to skin the cat.

Jake (44:19):
Jason, I do have one more pretty critical question on this
front for you. So exceptionswith these different drivers.
I'm curious if in each one ofthose little, you know, in your
contract, you define these arethe methods that we're gonna use
to interact with this Gitprovider. Right? If there's an

(44:43):
error when we're interactingwith one of those, is it just
chuck an exception up and letthe let the calling code catch
it?
You know what I mean? Or, youknow, because I know Laravel
has, like, the I I don't knowhow you guys are doing it, and
you don't necessarily have totell me. You know, I know that
there's probably some things youcan't maybe say. Laravel has,
like, the HTTP stuff, which youcan use, which is just guzzle

(45:05):
under the hood. And then youcould say, you know, by default,
it doesn't throw anything.
It'll just you have to check theresponse to see if it was a
failure or not. But that's notalways the case. Sometimes if
you're using, like, a GitHubintegration, SDK sort of thing,
it'll chuck an exceptionregardless of if you want to or
not. So I'm just curious as,like, you know, is each one of

(45:25):
those returning, like, a customtype of exception that is
handled specifically by thecalling code? You know, because
it's like maybe GitHub throws adifferent type of exception than
Bitbucket than GitLab.
You know? How is how are youguys doing error handling in
those?

Jason (45:42):
Yeah. I didn't write these, so I'm looking at it now.
Each of these, providers has,like, a client method on it that
sets up the HTTP client. Sowe're using that HTTP You're
using HTTP. Cool.
And looks like each one has atags on a throw method, which

(46:04):
returns a, GitHub requestexception. So Okay. We're making
custom exceptions for each one.

Jake (46:13):
Okay. Alright. Sweet. So that's that's helpful to me too
because I've always wondered onthose as well. Like, do I you
know, we've almost played withthe idea of, like, creating a
DTO error response as well.
Like, saying if we're gonnathrow or, you know, I guess an
exception is is it's not a DTO,but, you know, having a
consistent exception that wethrow from each one of those.

(46:33):
Like, if if it's going to throw,it's going to throw an exception
that looks like this, and theexception is going to have this
type of message. But, yeah,that's interesting. Okay. Very
cool.
So so the the you set up aclient and then inside of the
method itself, you're calling a,you know, you're calling post or

(46:55):
you're calling get or you'recalling whatever. And then on
that, you're tacking on throw.And then if there's an
exception, it'll throw a customGitHub exception or a custom
Bitbucket exception or customwhatever exception. And then
Yeah. Yeah.
Whatever's calling that isprobably gonna catch it, display
that to the user, maybe reportit, something like that. Okay.
Interesting. Well, I'm gonnahave to I'm gonna have to, pair

(47:17):
with either you or Nunos sometime and, like, dig around in
there. I'm so curious.
I'm so curious what this codebase looks like. Yeah. I have
to, like, I have to sign an NDAand, to contact, you know, the
big dogs. I have to contact, Tomand Taylor and be like, hey. Any
chance I could take a look atthis?
Just curious. It's probablygonna be a no, but, might as

(47:40):
well try. Right? They told me nowhen I said it when they when I
asked if, they needed a sub fora basketball game. Right?
Like, I text Taylor ahead of thetime. It's like, hey. If you
need to there was like, yeah.No. That's okay.
Thanks. And then they ended upasking. So, hey. The worst I can
say is no. Right?
And then maybe they soften uplater and let me take a look at
it. I don't know. Well, Jason,it's been, it's been super nice

(48:01):
having you on, man. I told youthat we wouldn't keep you until
after midnight, and I've brokenthat promise. So the first time
is this the first time we've hadyou on the podcast?

Jason (48:08):
It's the first podcast ever.

Jake (48:10):
The first hey. I am honored. 1st podcast you ever
been on and the host lied to youand said we wouldn't keep you
after midnight. It is aftermidnight right now. So,

Jason (48:21):
Eric, I

Jake (48:21):
wanna thank

Jason (48:21):
you for coming after me for Oh. To get on his podcast
forever. So Dude. I got itfirst.

Jake (48:27):
Well, I'm glad that we are the first, and then he can be
the second. So, you know, it'sfine. We broke the ice. We broke
the ice for you. Yeah.
But it's been great having youon, man. Thanks for taking some
time and and talking with usabout this. This is super
interesting. And if there's anyfuture developments that you
guys make, you know, there's abunch of smart people on your
team over there. So I would be,forever grateful if you guys are

(48:50):
coming up with a really coolsolutions to this and can share
some of that knowledge, onTwitter or just personally.
That'd be that'd be great.

Michael (48:56):
So It would be it would be nice to see more stuff now
that the team has grown theengineering blog to to, like,
start talking about some ofthese interesting challenges
where possible. I think that'dbe cool.

Jason (49:07):
Mhmm. Or

Jake (49:08):
put them on Laravel News. I think

Jason (49:10):
Glau is kinda like the 3rd iteration of these apps.
Like, Forge and Envoy were kindof one version. Vapor was a
second, and then, like, Nuno hasworked on all of them. Nuno and
Joe and Mohammed, they've workedon all of them. So, they're
kinda learning from the firstcouple iterations and bringing

(49:34):
in some nice patterns for cloud.
So it's been pretty cool to seehow they work. Yeah.

Jake (49:41):
That is very interesting. Yep. Well, thanks for sharing
some of that knowledge, man. Ireally appreciate it. Jason, if
anybody wants to follow you onTwitter, where can they find you
at?

Jason (49:51):
Yeah. It's, twitter.com/jasonlbags.

Jake (49:55):
Awesome. And what, you have anything you're selling?
You have a website or anythingthat we can send people to as
well?

Jason (50:00):
I guess cloud.laravel.com.

Jake (50:03):
There you go. That'll work. Awesome. Michael, what
episode are we on again? 163.
163. Folks, you can find shownotes for this episode at
northmeetsouth.audio/163. Hit usup on Twitter at jasonlbeggs,
Jacob Bennett, or MichaelDorinda, or North South Audio.
And, if you have any questions,feel free to hit us up on there.

(50:23):
Rate us up in your pod catcherof choice.
5 stars would be amazing. Jason,it was a pleasure, my friend.
Thanks so much. Folks, we'll seeyou in 2 weeks. Peace.
Bye.
Advertise With Us

Popular Podcasts

Stuff You Should Know
24/7 News: The Latest

24/7 News: The Latest

The latest news in 4 minutes updated every hour, every day.

Crime Junkie

Crime Junkie

Does hearing about a true crime case always leave you scouring the internet for the truth behind the story? Dive into your next mystery with Crime Junkie. Every Monday, join your host Ashley Flowers as she unravels all the details of infamous and underreported true crime cases with her best friend Brit Prawat. From cold cases to missing persons and heroes in our community who seek justice, Crime Junkie is your destination for theories and stories you won’t hear anywhere else. Whether you're a seasoned true crime enthusiast or new to the genre, you'll find yourself on the edge of your seat awaiting a new episode every Monday. If you can never get enough true crime... Congratulations, you’ve found your people. Follow to join a community of Crime Junkies! Crime Junkie is presented by audiochuck Media Company.

Music, radio and podcasts, all free. Listen online or download the iHeart App.

Connect

© 2025 iHeartMedia, Inc.