Archive.fm

North Meets South Web Podcast

Fake drivers with Jason Beggs

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

Broadcast on:
26 Sep 2024
Audio Format:
other

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

Hey I'm Michael Durenda and I'm Jake Bennett and welcome to episode 163 of the Northmead South Web podcast. Hey everybody welcome welcome first question that I want to ask everybody who's listening. Have you ever watched one of our videos on YouTube? If you have and you can reach out to me on Twitter I want to know if you clicked on the link because I had such an incredibly awesome background. Now here's the here's the you know the gist of this. Michael and our guests today Mr. Jason Begg so I'm gonna introduce himself in a minute. We're giving me crap about the fact that I have a white shiplap background and a missing light switch cover on my wall and have for like last forever. For both of our podcasts I mean how long have I been podcasting in front of this wall? Usually I have a happy birthday banner up here too. Michael it's been years. Look at least it's not your bedroom anymore so that's that's true. Step up. That's true that's true. So speaking of cool backgrounds yes Michael's background is looking very nice. And then our guest today Mr. Jason Beggs he's got some guitars back there so everybody welcome Jason Beggs to the show. Jason is a member now officially of the LaRaval team. If you go check him out on Twitter @jasonelbeggs x.com/jasonelbeggs you will see on his cover image he has a picture of the entire LaRaval team and then an arrow pointing that says me and there's Jason and I think Jason just like in the middle of LaRCon accepted a position on Team LaRaval so Jason congratulations. Way to go. Nice job. For anybody who might not know you you've been in the community for quite a long time but tell us a little about yourself kind of what's your background in LaRaval when did you get started and what brought you brought you on to Team LaRaval. What are you doing over there? All those things. All right that's a lot. Let me start easy. How long ago did you start in LaRaval? Yeah so I think probably seven years ago. Seven years. Yeah so I've been working with LaRaval in various JavaScript frameworks and then tailwind for as long as it's been available. Yeah yeah I don't even know how I got involved in all the projects I've helped with but at some point I started I converted the LaRaval new site to tailwind way back I don't know four years ago probably and then after that Taylor hired me to convert the LaRaval.com site to tailwind and I ended up building the redesign and then I built the LaRaval news redesign and I don't know I just ended up building a ton of different designs in the community for LaRaval and other people over the years and they asked me to help with the latest project they're working on. They're a cloud and I did help with it up until LaRaval probably two months before LaRaval started and then right before LaRaval and they decided to invite me to join the team officially finally taught me into it. Nice. We announced it. Yeah. 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 people say this like everything is spot on like to the pixel like margins exactly perfect padding exactly perfect and so you've made a bit of a name for yourself just being the guy who can deliver on getting everything to look exactly as it looks as a designer hands it off give it to Jason Jason will knock it out quickly that's the other thing I've heard you just like knock it out like you just like go after it get it done quickly and it's done perfectly so yeah I think your work has lent itself to giving you lots of great opportunities which is which is pretty cool and I've even tried to hire you a couple times I think at one point I maybe did have you do something for us I think maybe I actually you might have you might have done a tailwind site for me one time I think I had a design and I think you did it maybe that happened once yeah yeah I think that happened one time but anyway so to have you on the show today and actually we're not on the show today with you to talk about like the design aspect of things we actually are on here to talk about something else that you've been working on at Laravel so like the Laravel cloud platform so we can talk about Laravel cloud because it's kind of unveiled and you know it's out there in the public I know however there are some things that we might have to dance around a little bit as far as like how we talk about what we're going to be dealing with today but just to get done to the nuts and bolts of it essentially and I'll put this preface out there it is 11 30 p.m. Jason's time so thank you for coming on the show first of all but we're gonna try and get to the point of this so we can kind of get through some things before before it's midnight but you had put out a tweet the other day that said you know in Taylor's talk at LaraCon everything in his talk was hitting real infrastructure like it was actually spinning up real servers it was actually provisioning new databases it was actually spinning up key workers right all those things were happening from the stage for real on the internet however like some of the difficulty with that is when you're handing things off to someone who's not necessarily going to be interacting with or maybe you don't want them to have to interact with the real version of those things like a designer like yourself or somebody who's dealing with interactions and things like that the question is how do they get the application to function as it would if it was hitting the real thing but without having to give your own credentials for like you have to set up your own you know AWS credentials and do all that nonsense right so that's that's really like the challenge as a as a designer how do I see that modal that pops up after a database is provisioned without actually provisioning the database do I have to do some janky weird sort of you know voodoo magic to get it to pop up and now I can design it and so what you had said is you have since gone back and added fake providers for different things inside of Laravel cloud so that you can basically interact with the application locally without having to ever hit anything outside of your local machine does that sound like a pretty good summarization of what you were saying in that tweet yeah so basically the whole two months before Eric on when I was building a lot of the front end I didn't have access to any of that stuff didn't have any of it set up locally so I was kind of flying blind on some of it I would have to hard code like sort of the database pop up or whatever just temporarily just to be able to see it and then no no he would like tested in the dev environment and stuff where there was actual everything was actually set up or like for good installations like I'd have to like manually go in the get providers table and add an entry just so it would like recognize that there's a repo in there so yeah it's a little bit difficult when you're dealing with a lot of different APIs and different I guess third-party providers that you don't necessarily even if you do have access to them like you don't necessarily want to spend up an AWS server every time you hit deploy locally like if you just if you're only want to test like front end interactions you don't want to have to actually spin up a server and then figure out how to spin it down later and like you're just gonna waste a lot of resources and money doing that kind of thing so yeah new kind of spearheaded that effort he got the get providers set up and then he made the get fake kind of provider so like when you basically how it works is when you first set up an application if it's the first application that you've set up in cloud it'll pop up and so you like connect to GitHub or connect your GitHub account connect your GitLab account connect your Bitbucket account then if you're locally locally now we have a fourth option that's called get fake so if you click that button it kind of just loads a hard-coded list of repos you can choose from and each of those repos has hard-coded branches so you can just kind of select those and go through it and everything just kind of works locally you can even fake the deployment it'll recognize that it's a fake repo basically it'll fake a deployment like go through all the build steps it looks like a actual deployment and everything it's pretty cool how it works but yeah well what it's actually doing on the back end is literally like let's talk through that like get fake one right so yeah you would I'm guessing you have some sort of like driver or something like that where you say like it's it's GitLab it's Bitbucket it's GitHub right is it is that kind of how it works is like you have some driver implementation this is like we are going to talk to this particular type of API endpoint and then you have some sort of like interface their contract that says like it should interact with these particular methods but you're swapping out the drivers that kind of how you're doing that yeah so basically there is a source provider interface that they get lab get hub and Bitbucket classes all implement then there's also the get fake one which basically like each of those has like I don't know get account details methods get repos methods get branches methods that kind of thing and to get fake one basically instead of hitting an API that goes out to get hub it just returns an array of repos so like we have like layerable slash beep layerable slash cloud layerable slash forwards all in there and that's basically the options we get to see select one of those and when it creates the repo in our table or repositories table it'll set that type on the repos table I think it's on that table it could be somewhere it sets a type that's get fake so then every time that repos loaded it knows to use that driver yeah yep so to interact with anything on that particular you know record that that repo record it's going to use the get fake driver to do that no I absolutely love that idea and the one thing I was gonna say and Michael I'd love to hear if you guys have had to do anything similar to this is it also makes it much much easier to test the non happy path right because if you're dealing with a real provider trying to figure out how you get it to actually give you an error like if the username is incorrect or if there is some sort of rate limit that you hit or if you don't have permissions to get access to that particular repo or if there's only right access and now you know there's only read access but not right access or things like that right like what are all the different non happy paths that could exist and they might be different based on which provider it is those are very difficult things to do or to imitate so that you can see the UI when you're dealing with real world implementations and so one of the things that a fake provider does is it allows you to be able to in the way that we've done it in the past and that stripe 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 striped sandbox you put in 42424242 that's a thumbs up successful put in 41414141 it's like that's a CVV error you put in you know for three that's like a insufficient funds no that's not really what it is but those are the ideas right and so with these fake providers you can even have this idea of if I select this particular repo that's getting returned I should get this type of error when I try to do some particular thing you know so that's one of the really nice things I like about those fake those fakes is you can test the non-happy path much easier Michael have you ever implemented this sort of pattern in your own code base no we've I mean we we use a lot of the Saloon library the HTTP requests and so we we fake things but not not like and that's faking them in the context of our test not to the extent right being able to kind of swap these things out with fake responses in the execution of you know opening the application in the browser and I think that's a really good idea especially when you've got other people that need to look at it know whether it's product people or it's you know UX people or QA people whatever in your business where they want to be able to go and just like click through and do some exploratory testing and and test different scenarios there's there's no way of doing that as you say Jake there's no way to kind of fake what a failed response is or something's inaccessible so I like I was really am interested with this this approach that you've got in terms of you know effectively being able to fake out the entire real application in in a dev or a you know QA environment to kind of be able to do that and hand that off and and see what it actually feels like to experience it because it's one thing to write a test with a fake that's like yeah when this happens we hit this endpoint we get back a failure like this is what we expect to see back in the response but in terms of seeing the actual application in the context of like this error comes back where you get this toast or this modal notification or whatever based on the inputs I think that that was what really interested me the most and in a large application where you would have to like retrofit this stuff and figure out like you we certainly haven't people probably don't implement in with this kind of behavior in mind where you can fake out interactions with external parties quite so simply so yeah that's that's why I kind of said you know I'd be interested to hear more about this and and how it might be implemented because I think there's certainly a place for in a lot of these real applications that are they're heating up external services yeah I think it's easier in cases where you have multiple providers anyways because typically you're gonna have some kind of interface that they all adhere to so it's a lot easier to write a fake provider for those cases but there are a couple cases like deployments and stuff where we're just using dependency injection to swap them out always locally no matter whether it's a real repo or not which I might we might change that to where there's a EMB variable or something that you can use to toggle it so you could test real deployments locally if you want to but I love that you're talking about this guys if we have dealt with the same thing we so go ahead and finish your thought if you if you have more to say on that because but I want to loop back to that in just a minute as far as like how you're swapping them out with the ENV as well yeah so so what you're saying there is that you know with the deployment for instance typically you're deploying the same way every time right like you're saying like we're always deploying to this particular location or deployments always act the same way or interact the same way but maybe you've now extracted that sort of to a contract so that you can have a fake deployment driver as well and so this is what we do currently with anything that interacts with a third party API what we do is we always we always do this regardless of if we actually can interact with it for real or not we will create a contract first so I will create let's just say we have a Laravel cloud let's say I'm talking to the Laravel cloud API from my local application so I would create a Laravel cloud contract I just call it Laravel cloud that's that's the contract but that's the that's the class I'm gonna call it actually sorry let me let me let me read we say that I'm thinking through how our how our convention is we call we'd call Laravel cloud contract then we would have a Laravel cloud HTTP gateway and we'd also have a Laravel cloud fake gateway then what we do is in a service provider we bind to that contract either the HTTP version or the fake version depending on whether we're in dev or actually not depending on whether we're in dev if we're in production for in production we bind to HTTP if we're in dev or testing we bind to the fake and then we also have a facade that references that and we would just call that Laravel cloud so that facade would say Laravel cloud so that doesn't service location to go grab out of the container whatever was bound in the service provider and so in that way it's really nice in our tests and in our local dev we just hit we just locally hit it no big deal but in the case that we want to test it with production we do exactly what you're talking about which is we have a ENV that says should fake try to remember how we use it but basically should we use production in local and then in our service provider we just say like if not in production or if in production or should use production in local then we load the HTTP one and so it is nice sometimes to be able to hit from local the real thing but not super often most of the time we're wanting to hit the fake but that's how we do it on almost everything is we always swap them out at the service level or the you know at the service provider level typically because we don't have a lot of things that have four or five or six drivers or two or three even it's usually we just have the HTTP and the fake one but yeah I could I could see that being you know especially where you we only have like the one sort of deploy method you have to extract that to a contract in order to be able to use a fake so you can see that the other way so that's interesting I I'm it validates for me so much of what we've been doing for the last couple years I talked I remember talking to Sam Carrey who built Saloon and asking him these same questions and he was like no we don't do that we don't we don't provide fakes like that that's not something that Saloon does and I was like really because we really need that and so it makes me feel so glad to know that team Laravel is doing the same thing that pattern it makes me feel so happy inside I think a couple people have mentioned like maybe extracting it to a package but I'm like I don't know the different implementations depending on what services you're interacting with are so different like I don't know how you could even start to extract that and provide like good APIs but I don't know maybe somebody smarter than they can figure it out yeah I think I think the in the context of Saloon you'd have to introduce a layer on top of it like everything would have to create like some service class that accepts the connector and that swaps those things out and so you're always going to be building an extra layer on top of it and in order to facilitate that kind of thing where you can kind of switch out like this connector goes here and it returns like fake responses for everything and things like that so it's definitely it's more work but I think what it what it provides you at the end of the day is really good like we have a lot of issues with with Salesforce because we use Salesforce for the CRM component of our main application at work and there's not really a good testing story for it in terms of a UAT environment that you can hear to do things we'd like we have to spin it up and that that environment is run by our product people it's run by our Salesforce developers so it can like change state and things like that all the time whereas if we could swap out how we're connecting to it and just return fake things based on the inputs and things like that that would be a lot easier I suppose it's never really occurred to me to like these these things that we do in testing to swap out the underlying connection to return some fake data to then figure out okay well how do we actually translate this into running the code you know in the browser good for thought though mm-hmm yeah to me I think people typically think well I have like so here's the reason why I don't think it occurs to many people to do this and why it occurred to me so early I'll start with why it occurred to me so early and I'm not saying because like I'm not I'm not patting myself on the back the reason I'm saying this is because we had an application that depended solely on having a connection to an API this API connection was crucial like we could not do anything without this API providing the data that we were going to display on the screen you could think of it almost like an SPA with a API layer back end but it lived like over there so our level application was fetching stuff from this API and then displaying it on the front end well the there was no way this the system that we were interacting with with this API is this crusty old old old old legacy legacy database and so it just became painful so quickly to try and get in there and modify those values in order to get what I needed on the front end I was like there's got to be a better way to do this and so actually I was watching Adam Wavin's course testing Laravel and he talked about this with Stripe way back then so like hey instead of it like interacting directly with Stripe create a gateway that's going to interact with Stripe and then you can create your own implementation locally so you don't have to constantly hit Stripe I was like that's genius so that's what we did and I don't think many people have that I think most people are on occasion you know once in a while going and hitting an API to go update a one resource and that's it right and so it doesn't really matter for them it's not like critical if they fake it out or if they don't but in this particular application for you Jason like everything you're doing is basically gluing together somebody else's repo to a cloud provider so it's like everything is API interactions everything is like that so how do you do that how do you you know view the UI without having those actual APIs and so now the need has arose for you guys to be like we got to figure out a better way to do this at the same place I had to be like six years ago when we were trying to figure this stuff out so it is just interesting how you end up arriving at some of the same conclusions and some of the same patterns what I would really like to do I hear you saying somebody's extracting there so thinking about extracting this to a package I don't know if Taylor's accepting talk proposals for Laracon for next year yet but I was talking to a couple people for about maybe making this into a talk idea because I really do think there's a lot of interesting patterns around this and how you could introduce some of the benefits of this in a way that I think would be really beneficial not even in a package you know like if I like in my state machines talk I never talked about a package I think it's because in some instances you don't need one right in this instance I don't necessarily know what you need one and I don't know that there's a one-size-fits-all solution for this sort of thing but if you understand the concepts it's not that hard to introduce it yourself yeah yeah the self-decode is really simple like it's not complicated at all but it's so powerful and like before like I was saying like I couldn't like do anything hardly in that but now you can literally get cloned the repo set it up like a normal level app and you can go register an account and start clicking around and anything you want pretty much and it all just works like isn't actually doing anything but like you can do all the front end interactions locally and it just works it's pretty sweet yeah I know incredibly powerful um so Jason if if you know you're thinking through like for Michael like if he's interacting with Salesforce you know just kind of using what you guys did as a reference maybe for like the deployment thing you know he doesn'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 even like a first step to like how could they start to implement this pattern what would be like the first thing they would need to do in order to be able to make like maybe a fake Salesforce thing yeah um guess it depends on how your current code is architected if you have like a Salesforce class that's doing all the interactions if you have a bunch of methods on there that calls out to Salesforce and does stuff um extracting an interface that that implements would be the first step then you could create the fake implementation of that interface and then probably just toggle them based on the enbiki or um however you want to do it in your service provider mm-hmm that would be the most straightforward thing uh if you're not using uh like a Salesforce class or something hello how are you doing Michael extract we're we're using like a third party package that does that which actually complicates the process even further because all of their stuff is like it's built for Laravel but everything is just bound to the container um and we actually have two two different Salesforce instances that we need to like dynamically switch so it's like this this whole debacle around even just using the package on its own um but I conceptually I'd see you know we're gonna have to we'd have to abstract over the top of it we'd have to you wouldn't you check this stuff we'd have to create our own interfaces and service classes and whatever else so that we can handle swapping it over because there's it's a bit more involved than just saying like use this thing because using this thing also goes and like handles authentication tokens and like authenticating with the API to get request tokens and handling refresh tokens and all that kind of stuff and so it's it's not architected in a way that's meant like I assume whoever wrote this package like built it for the use case and they kind of got out of hand where everyone started using it but it was not really considered as like people are going to use this it's like I built this thing and off it goes and so yeah sure you know there's there's a lot of stuff out there like that and unfortunately the overhead of trying to implement this all ourselves from scratch is just you know you make do with what you've got available sometimes but I think yeah it seems at a high level to kind of summarize simple enough right you create an interface you create your implementations and then use container binding to switch them out whether based on environment or based on you know the environment they're running you know some specific environment variable things like that or configuration switch and and and going from there yeah like I don't I don't think there's anything crazy or wild or beyond the norm for a larable application it's just a matter of like deciding at the outset like jaded with the described stuff okay this is how we're going to implement each of these things so that we can just swap them out on the fly if we have to and and like that's the effort that you need to go to and which you know it introduces this third avenue of like fake data where lots of us are probably already doing this like here's our application and here's our HTTP fake that we're using in our test but this is kind of like giving that HTTP fake in the context of looking at the application inside of the of the browser in a correct exactly correct yes it's like a third leg on that stool people typically consider like my production in dev environment as like one thing and then testing is a completely different thing right so like in your tests yeah you use the HTTP fake and then assert what should come back and all that stuff right so you mean you are you're doing the same thing you're faking the data in the test effectively yeah effectively and so like what you said is you're basically allowing yourself to do that in the in the local layer and so it's it's hugely beneficial the one thing I will say that's really actually nice about this pattern too is if you are if you have not yet figured out the API layer implementation so quick example we have an API layer that we're integrating with but we have to wait to get approval for this API we don't actually have the API yet it's we're not sure what it is but what we've been able to do is we've been able to create the gateway create a fake version of it and then shape the data how we think it will come back and interact with it that way so we're basically stubbing out what we think it's going to look like and then when we actually get access to the real API we can shape the data coming back from the API to look like what we expected it to in our fake right we can sort of marry those up we can say well this is what we've been coding to this is sort of the interface that we created that we said it should look like about like this and so when we get the really API let's say that there's like one more key above that level of entries well I just stripped that off and now I just return the entries you know what I'm saying no big deal so allows me to as a developer to develop independently of the actual implementation of the API especially if I don't know what it's going to be yet or if I'm trying to figure out what I want the shape of it to be like if I'm all the one responsible for creating the API that eventually will be used I can play around with what I want the shape to look like as I'm consuming it and then later go implement what that what that should I write the code to actually make that happen you know what I'm saying so I get to sort of decide in advance what I want that API layer to look like and then I can code it to work that way yeah are you just returning like arrays of strings if you got like typed data in there using like read-only dto like playing good good questions in some of them we're just returning arrays in the some of the more serious apps that we have we are returning dto's typed dto's and then in each of those sort of dto's in some of those cases we'll have like fake versions of dto's so that we can assure that in production and in our fakes that they come back with the same shape if they're larger objects and things like that but I think when we're starting yeah just arrays and strings yeah I think the dto's are nice because it doesn't matter what your third party is a returning like you are shaping the data into what you want to consume in your application and so if you're just coming up with that interface you're saying I want this this this this and this in these you know these fields to be available then when it comes time to mapping the actual API responses you don't have to worry about how that data is calculated or where it comes from or if it's like in a nested object somewhere in the API response because you're always getting back a dto in the shape that your application expects and I think this is something maybe if people are using dto's for the first time they kind of get themselves in this trap of just mapping one-to-one what the what is being returned from the API response rather than mapping the stuff that you actually need in a way that you want to be able to access it so yeah I think that's that's a pretty good approach and like PHP makes it really easy to create these like read-only classes now that you know just I forgot about that yeah so like we do it a lot where we would just have like a read-only class with a constructor that just sets some properties and that's about it and you know for a lot of things especially things that we're passing around inside the application anything that that breaches the like request response border like if we're sending stuff back to our front end for example we use the sparsity dto package because then we can do all the TypeScript conversion and things like that but anything that's just bouncing around between the request that goes you know from a controller into an action or it gets passed around to somewhere else a lot of the time we're just using these read-only classes just so that we've got some structured data to fling around and those may then convert themselves into to sparsity dto's when they get sent back by handling them internally it means you get like ID support you get type completion all of this kind of stuff or types of an ID completion they'll wear around and it means you you entirely control the shape of that thing and it's just a matter of instantiating that based on whatever you have available and then it doesn't matter if it's a fake or you know or in this example it's a github and gitlab and bitbucket and then the fake is everything is returning the same structured data and how you compose that can vary you know in an infinite number of ways because you're not conforming to any individual provider specification yeah i'm curious how you guys are doing that jason like when you have the different providers is is there some sort of standard response that you guys are formatting it to or how does that work you know when you say like i want to talk to gitlab or want to talk to bitbucket or when i would talk to whatever when you're getting back that data that's the list of repositories um is that typically just returning an array or is it returning some sort of shaped object right now we're basically just returning arrays but we are shaping them to some extent um but yeah we're not using it like inside the different implementations inside the different implementations of the drivers you're just basically saying like whatever comes back i just want this array of the repos yeah so yeah the repositories uh method on this get out of thing goes and gets them and then we're looping over each one mapping it to the structure we want and just return an array of arrays basically yep and then the other ones like the bitbucket driver would basically do the same thing it would kind of go get it and whatever the response is it's going to massage it into this shape that you're that you're wanting to see there okay yep okay interesting yeah uh michael your suggestion of like you know always having a dto there i think it just depends on where you're at and like the journey i guess like if you're if you're really wanting to be positive or if it's you know for example like in this case if you're just returning an array of like the items like probably not that critical but if the shapes of the data that you're dealing with are quite complex if you know if you're needing to grab 20 keys off of this one object that's returned and you need to make sure that they're there or have some error handling in the case that they aren't there or whatever or have like a null response you know i mean those sorts of things then i think it's worth um it's worth sort of extracting some sort of dto there and then always returning that regardless of if it's coming from the fake or from your real one yeah i mean obviously it depends on your team your makeup your you know where you're at as you say i think it's just it's so easy to to create these objects to shape the data and that way you don't run into these situations of like forgetting a key or trying to reference a key that doesn't exist or having a typo and then like these things bubbling up as exceptions because you're accessing um keys of arrays that don't exist in things like that like you know when it's an object that it's this object and it's going to have these things in there and and it's just like gives you a sane kind of structure to bounce around in the application um yeah and i'd like to say these only have like four keys but with them being like the same structures copied across four different providers there's a pretty good argument already then this could be a dta so you're saying with each one of the repositories that's returned from that array like each one of those items has like four keys that you're that you're hoping that they have yep and right now it's kind of just up to the yeah go ahead you were you're going to say i i mean guess you're just like just say the different keys and stuff yeah just got a full name it's private a name and then a default branch mm-hmm yep so the different yeah and so it's basically right now it's just up to the developer who's implementing these to make sure that they're consistent across the board right just i mean you got high quality team members right so they hopefully when somebody goes to change one of them they remember to change all of them right but that's that's sort of the danger right is that if there's some new key that you need off of it you're going to have to remember to implement that on all of them and if you forget one of them then you're not going to know until it bites you you know so yeah again comes down to the team where you're at you know that it is for different implementations that are all the same thing when you create a new one you know you're just going and copy pasting the existing things and doing the mapping and you make me assumption that it's there so like it's not critical but then you know depending on your team you're then in this situation where you're using PHP doc to annotate the shape of your return to raise instead of just returning a dto so right right like a million different ways to to implement the same things and like make the decision that that is suitable to you i just think no matter how simple it is it's so easy to just create these objects now and it's and it's it's more resilient um to to return those things than it is to just like hope that you don't make a typo and like yeah you're right you're testing you make sure that things exist and and whatever else but i i like so it's so easy to do that it's yeah you know you'd have to you'd have to have a a really good reason to not do like yes before everything was just raised because everything in PHP was always a raise and that was fine but it's like as i said because it's so easy to do there's like no overhead you don't have to like we've got auto loading these things can all just exist and they just work nicely so yeah do do whatever you want i'm not i'm not your dad i'm not i'm not the one that's going to be rejecting your ps right right um if i can make one more pitch for the dto thing on this side i'll say this is the last thing when you are doing fakes inside of your tests a lot of times like if you're doing like an HTTP fake for example you're just returning like arbitrary strings of data data right and the danger for me in those is those things can change shape relatively quickly um and it's hard to keep them consistent across the board um whereas if you use this sort of architecture that we're talking about what we've done in some instances where i've said i know i've called them more are more serious apps and what i mean by that is apps that are dealing with like financial information or or you know payments or things like that um when we're doing that what we'll do is we'll return a dto from each of the different methods on the contract which is great because you can just say this method always returns this sort of dto but then what we'll do is in our tests we can just say façade which is like larval cloud you know colon colon should receive or expects um create new server does the method and then we say and return and then we have that dto and we say double colon fake right and so we were just we basically have on each of these dto's we've we've implemented something that says you must have a method that's fake on this which returns essentially like a factory you know what i mean here is a default version of what we would expect this dto to look like and um and then anybody who's using it you know i mean if you ever needing to test that in your actual tests that's where you're gonna get that data from and and you can you know you can then modify so you basically have these dto fakes which again are very much like database factories where you have like methods you could call on them to say like i would expect this one to be like a failure or i would expect this dto to be like a whatever right and so um it does give you a sort of another layer of um confidence to know that you know you're always going to be returning that shaped data in a way that is going to be consumable to all your other stuff and in your tests you have a lot of confidence to know that you know you're not just returning arbitrary data from like a HTTP fake this is what's going to come back and it's going to be this shape um and so that feels really nice it feels like it gives you a lot of confidence we've also done things with static constructors to like dto colon colon default you know if we have something that wants to return some default state and then you can just call that if you want to use that for for whatever reason you know you can do these things you can extend them locally i guess if you're not using final classes and uh like in your test environment say like this thing extends this existing dto um and it will always return like failing data or successful data or whatever else i just say so yeah there's definitely some nice approaches to it i mean yeah with with an array you can just say like whatever returns this static array of data um there a million ways to skin the cat Jason i do have one more pretty critical question on this front for you so exceptions with these different drivers um i'm curious if in each one of those little you know in your contract you define these are the methods that we're going to use to interact with this get provider right um if there's an error when we're interacting with one of those is it just chuck an exception up and let the let the calling code catch it you know what i mean um or you know because i know larval has like the i get i don't know how you guys are doing it and you don't necessarily have to tell me you know i know that there's probably some things you can't maybe say um larval has like the http stuff which you can use which is just guzzle into the hood and then you could say you know by default it doesn't throw anything it'll just you have to check the response to see if it was a failure or not um but that's not always the case sometimes if you're using like a github integration uh sdk sort of thing it'll chuck an exception regardless if you want to or not so i'm just curious is like you know is each one of those returning like a custom type of exception that is handled specifically by the calling code you know because it's like maybe github throws a different type of exception then bit bucket then get lab you know how is how are you guys doing error handling in those um yeah uh i didn't write these so i'm looking at it now um each of these uh providers has like a client method on it that sets up the http client so we're using that http and cool and looks like each one has a tags on a throw method which returns a github request exception so okay we're making custom exceptions for each one okay all right sweet so that's that's helpful to me too because i've always wondered on those as well like do i you know we've almost played with the idea of like creating a dto error response as well like saying if we're gonna throw or you know i guess an exception is is it's not a dto but you know having a consistent exception that we throw from each one of those like if if it's going to throw it's going to throw an exception that looks like this and the exception is going to have this type of message um but uh yeah that's interesting okay very cool so so the the you set up a client and then inside of the method itself you're calling a you know you're calling post or you're calling get or you're calling whatever and then on that you're tacking on throw and then if there's an exception it'll throw a custom github exception or a custom bit bucket exception or custom whatever exception and then yeah whatever's calling that's probably going to catch it display that to the user maybe report it something like that okay interesting well i'm gonna have to i'm gonna have to uh pair with either you or new notice in time and like dig around in there i'm so curious i'm so curious what this code base looks like yeah i'll have to like i'll sign an nda and uh contact uh you know the big dog so that to contact uh tom and taylor and be like hey any chance i could take a look at this just curious it's probably going to be a no but uh might as well try right they told me no when i said it but when they when i asked if uh they needed a sub for a basketball game right like i texted taylor ahead of the time i was like hey if you need to talk there was like yeah no that's okay thanks and then they ended up asking so hey the worst i can say is no right and then maybe they soften up later and let me take a look at it i don't know well jason it's been uh it's been super nice having you on man i told you that we wouldn't keep you until after midnight and i've broken that promise so the first time is this the first time we've had you on the podcast first podcast ever first hey i am honored uh first podcast you ever been on and the host slide to you instead we wouldn't keep you after midnight it is after midnight right now so um what i think you're coming after me for oh to get on his podcast forever so dude not well i'm glad that we are the first and then he can be the second so you know it's fine we broke the ice we broke the ice for you yeah um but it's been great having you on man thanks for taking some time and talking with us about this uh this is super interesting and if there's any future developments that you guys make you know there's a bunch of smart people on your team over there so i would be uh forever grateful if you guys are coming up with a really cool solutions to this and can share some of that knowledge uh on twitter or just personally it'd be that'd be great so it would be it would be nice to see more stuff now that the team has grown the engineering blog to to like start talking about some of these interesting challenges where possible i think that'd be cool mm-hmm or put them on level news say cloud is kind of like the third iteration of these apps like uh forage and envoyer we're kind of one version vapor was a second and then like new notes worked on all of them new note and joe and bahamad they've worked on all of them so uh they're kind of learning from the first couple iterations and bringing in some nice patterns for cloud so it's been pretty cool to see how they work yeah that is very interesting yep well thanks for sharing some of that knowledge man i really appreciate it Jason if anybody wants to follow you on twitter uh where can they find you at yes uh twitter.com slash Jason L. Beggs awesome and what uh you have anything you're selling you have a website or anything that we can send people to as well guess cloud.lerible.com there you go that'll work awesome michael what episode are we on again i'm 63 163 folks you can find show notes for this episode at north meets south dot audio slash 163 head us up on twitter at jason albeggs jake bennett or michael dorinda or north south audio and uh if you have any questions feel free to hit us up on there rate us up in your podcast or choice five stars would be amazing Jason it was a pleasure my friend thanks so much folks we'll see you in two weeks peace so yeah