Jon (00:01.972) Welcome back to another Gone Mobile. Alan, do you like my new purple office? Allan (00:07.063) Well, I didn't think you were going to open with that, but yes, sure. For what I can see, I can still see your Mario. You pretty much tried to clone the back of your office. Jon (00:12.494) Yeah, it's not it. Yeah, I pretty much just moved it. I moved it over, but now I have like 120 % more echo in here too. hopefully, hopefully the, you know, while I seek out sound treatment for the room, things are not too echoey. Allan (00:29.774) You're a little bad today. A little bad. You were in padded room before, right? And they've let you out now? Jon (00:32.286) so I, well, it should be, it should be an abatted room. The, the, the other thing that I just noticed today, this is totally unrelated, but I was looking because I wanted to see, if I don't know if my stuff's all backwards, right? Like mirrored now. Does it, does my, do my letters look mirrored? Allan (00:44.418) Bye. Allan (00:55.296) No. Jon (00:55.926) Okay. I it's just, it's just me. Then it's one of those settings where I guess you see the mirror image. So I was searching on YouTube for gone mobile so that I could see if it looked like that properly on the past videos. Do you know what comes up if you put in gone mobile and YouTube and I don't know, we have to fix this. don't know how yet. Well, it's not like, you know, it's, it's G rated. it's a bunch of videos about like Ford transit camper vans. Allan (01:14.239) Do I wanna know? Allan (01:26.841) Let's see, I'm interested. Well, no, on mine, see, I'm using Google. Microsoft's forcing you to use that. That's what they call a search engine. it's YouTube. Okay, because if I look on Google, okay. Jon (01:28.684) Yeah, so like. Jon (01:33.964) No, this is searching just inside YouTube itself. Yeah, like I'm on the site and it's all just like some dude in his Ford Transit camper van and different years and reviews or something like it's. Allan (01:47.849) yeah, gone mobile vans. man. Jon (01:49.944) To be fair, he's got a lot more views than we do. I mean. Allan (01:54.486) Maybe we were in the wrong business. I bet you he can't take one of those to Maui Jon (01:56.728) Yeah. Yeah. Jon (02:01.326) Probably not. But maybe he made an app for it, you don't know. Allan (02:05.452) Maybe, with .NET MAUI. Jon (02:08.312) So what are we talking about today? Allan (02:13.206) Well, that wasn't a very good lead in for one, but it's because it's I think this is considered the show where I talk a lot. You're going to interrupt me and make sure that I stay on track. So. Jon (02:22.978) Well, and I talked about my migration of my office. You migrated phones recently. Allan (02:28.458) Yes, I did. I did migrate to a newer iPhone. Jon (02:32.962) You know, I'm kind of surprised that you didn't, cause like we're not that far away from new phone announcing season, right? Allan (02:40.821) But you see, I always get the deals on the the previous year's phone. So it's about to be pretty usually August, I get the new iPhone and I do that on purpose. I've been waiting for the flip phone, but I can't wait for it. I know. I know. And I'm it it hurts my soul because I really want it's going to come next year. Just let me have this, John. Let me have this. You're you're you're wounding me. Jon (02:48.62) Yeah, okay. Jon (02:53.975) It's not coming. Jon (03:03.211) No. Allan (03:10.019) to the very core. Jon (03:10.538) It's gonna be a long time yet. Or never, maybe. Allan (03:13.587) Maybe we'll see. We'll see. But if it was, I know it's not coming this year, so I didn't hold out hope, but I needed a new phone. I didn't break mine. John and I have been running the naked iPhones. This was a challenge that John made about six months ago. Jon (03:23.394) What... What were you... yeah. Jon (03:30.2) Why dive for you? Sure. I've always like, yeah. Allan (03:33.225) No, no, you said no, I'm caseless on this one. And if it breaks, I'll just buy a new toy. It was like your excuse to buy a new toy if you needed it. Oops, I dropped my phone. Jon (03:40.248) Yeah, no, no, that's what I'm saying. I don't use cases. I haven't used cases for a long time. Allan (03:45.674) Okay, well, fine. I'll give you the benefit of the doubt. My flip phone still coming, but that's fine. So no, I did once and the chance it was a brand new iPhone six, like brand new same day. And I was doing construction in my basement and it fell about, you know, I was, I was actually laying down on my back trying to, to pull a wire through a wall to the long story. Jon (03:50.414) And I've never broken a front screen. Jon (04:13.827) Yeah. Allan (04:14.803) Anyhow, it fell from my pocket at the front. about. I don't know. I want to say about that. And it hit just the corner and it completely shattered that screen like not even a You could not see anything. It had shattered it so much. The only time I've never broken anything else, my iPhones have been great. Jon (04:20.078) 6 inches. Jon (04:30.446) That's very unfortunate. Jon (04:36.696) Cause I dropped phones from way high up and done stupid things and you know, worst I've, so I, on a Nexus four back in the day, I dropped it enough times and it broke the back glass. That was one of the first phones that had like a back glass, but then I just bought one of those like skins to put over it. And it was like, problem solved. Allan (04:40.33) Yeah. Allan (04:57.909) Well, if you remember the iPhone 6, they kind of had like that beveled glass. They were into the pretty at that point. They weren't into the, let's think this out because we can do, you know, this phone won't be very durable, but it looks pretty. And so that one was like all the, think they were starting to get into the no bevel. And so it had like those routed glass corners and yeah, that thing, it was destined for doom if it was going to happen. Jon (05:04.118) Yeah. Jon (05:11.714) Yeah. Jon (05:18.295) Mm Allan (05:26.697) Now this one is titanium. I don't even know if you have to put a case on them. Jon (05:28.834) Yeah. Wow. mean, I think the, interesting thing is, I mean, I know, I know some people that, you know, where they work and stuff like, yeah, okay. It makes sense to put something on your phone. Cause you might, if you work in like construction or farming or whatever, yeah, maybe you're gonna, you're gonna drop it a bunch, but like, I feel like most people don't give them enough credit anymore. Like they work pretty well without breaking. Now I did break. Allan (05:49.13) Yeah. Jon (05:59.022) the back again on, was it the 13 Pro? What's that? No, I said the front glass. Yeah. Yeah. So I broke the back glass. Just one hairline crack on, I think it was the 13 Pro, which, yeah, no, it was fine. But the thing that was annoying was I was gonna trade it in because I'm just like, have so, I have literally two behind me, two drawers full of full. Allan (06:01.557) thought you just said you'd never break a phone. You just said you'd never broken a phone. you did, you chose your words carefully, okay. All right. Allan (06:15.175) Meh. Allan (06:22.293) You Jon (06:28.02) old phones and like, yes, you know, it's nice to keep not as old, but still old phones every once in a while. I usually end up giving my older stuff. Now that's like my own personal ones to family. when they're looking for a new phone, but this one. I was like, okay, I'm going to trade it in. Cause like, I don't need to keep this one around. have, I had like one that was just a year older than that still. I'm like, fine. And I sent it into Apple and it's like, I have whatever I picked, right? It's like not. major damages because I'm like, it's a hairline crack, like whatever. And then they, you know, the appraisal value, you know, before you send it was like, I'm like, yep, that's fine. That'll, that'll do. And then I got sent it there and then they give me the update. They're like, actually we're only going to give you like a quarter of what we said we went for it because it has that crack. the dumb thing is I could have sent the stupid thing into Apple care. Like I had coverage before, you know, while I still broke it, like I should have just at that time said, Allan (07:14.501) You Jon (07:26.862) this is gonna be a problem for me in the future just because of the value of it. Let's send it in, pay the $30 and get it fixed or whatever, right? But I didn't do that. So lesson learned. Yeah. Allan (07:35.176) Yeah, well, Apple. We all pay our price to Apple. So I haven't broken anything since but I tell you last night trying to move the eSIM it failed. And I mean I only have a cellular phone. I don't do the house line anymore. Thank goodness. So it failed to transfer to the phone to the new phone. And but it did transfer off the old phone. So both phones were left in KO'd. So I had no phone. I couldn't get text. do. Jon (08:12.332) You can't even call. Can't even call Rogers. Allan (08:13.884) And the guy gave me an extra eSIM card, but you needed to receive a text to be able to say I want to move to this eSIM. So I was like, my God. And then I had to contact Rogers on their online virtual queue. It was a long night. Jon (08:29.112) website. Jon (08:34.648) Did you, so I'm curious in that case, did if you needed to receive a text, did it have to be at a particular number? Like could you have given them any number? Okay, okay. So come on guys, like I'm trying, I can't access the thing. So send me a text to the thing. Okay, got it. Allan (08:42.6) not my original number. Allan (08:50.098) And then what's better is they don't stop you from moving and the guy tells me, yeah, you can't move the number. Well, then why does it allow me to do it? Because the carrier can get involved. Jon (09:00.866) Yeah, that's silly. Allan (09:03.133) They need to mediate this stuff better. Jon (09:06.414) that was something, some kind of segue. Allan (09:07.395) I got it. Yeah, it was worthy of your stuff. I saw the lead in and I went for it. Jon (09:15.47) I've been actually contemplating, let's call it. I haven't committed yet. Maybe this is the time you can convince me to commit to doing it to maybe possibly potentially in some universe kind of pulling it into my app. Allan (09:21.841) Mm. Y Allan (09:34.216) Well, I failed on RX. I will admit defeat. You're just a stubborn old... I got words. know what I'm... You can read my mind. I'm not going to say it because we're PG rated, but I'm thinking them. Yeah, yeah, yeah. So I failed on that one. I will admit defeat. But you have expressed interest in a mediator. Not so much on the server, even though you've been talking a little bit on the server. Jon (09:38.69) Yeah, get off my lawn. Jon (09:44.008) Mm -hmm. Yeah, stubborn old, awesome person. Yeah, thanks. Jon (09:57.026) Yeah, I, no, my server stuff doesn't really, like I don't do enough things that would even warrant putting it in there, let's say. Allan (10:08.756) It's good for those modular monoliths, the ones that you start small and then you need to break them up later because you're getting a massive amount of traffic. Good place to start. Jon (10:12.685) Yeah. Jon (10:18.222) which I'm not, it's like my, my, my sir. And this is, think, you know, fun little side note. It's an interesting thing to consider like with modern development stuff. It's just like for the first, I don't know how long my app's been around five, six years. I ran everything on one instance of like the lowest tier paid instance that you can buy that allows you to do like SSL certificates and everything on Azure. And that's been fine. was like. I forget how much a month, like super cheap. Yeah. Allan (10:48.527) It's great for growth. mean, really, it's just stupid not to use Azure when you're starting out. And then when you get to that mid level, after that, well, things get debatable. Jon (10:57.462) Yeah. So, so now I'm in the territory where it's like, okay, I had to go finally bump up a level and now it's like a hundred and something a month. it's like, eh, for it's still nothing in terms of what, you know, cost and revenue and everything like fine. it doesn't like, there is this side of me, like the, that never has gone away. That's like, I could stand up a server for like nothing that would run this fine. Right. And it's like, yeah, no, you don't want to do that. Allan (11:03.152) Yep. That's still nothing. Allan (11:15.399) Ha ha. Allan (11:24.253) you could. You'd have to switch to Postgres and get rid of that object database of yours and... yeah, yeah. I mean you're talking... you know, time is money. Business is money. Jon (11:28.015) huh, yeah. That's so much work for so little gain. Jon (11:36.751) Yeah, no, absolutely. Well, and this is, I want to do an episode sometime. That's not today, but I want to talk about like in -app purchases and stuff there. Cause there's another good time is money. Part of the story that is evolving for me. Allan (11:46.672) Yeah. So in case somebody figured it out, we are talking about mediation patterns and kind of a general architecture because this one has become near and dear to my heart. And I don't know, it's a couple of months ago, I was looking at a potential customer and they had a whole whack of issues. Doesn't matter what they were, but mediator patterns are really good at kind of vertically slicing your business, not just your Jon (11:52.92) We'll get there. Allan (12:14.8) your architecture, but your actual business or your domain or right. kind of drawing out lanes of, you know, this is my work orders or jobs. This is my employees, right. Jon (12:21.714) Can you, yeah, I was gonna say, put it into some context of how you would vertically slice up something. Allan (12:28.902) Yep. Yep. And, and the goal is, is that you might have, you might have separate databases, right? So if you think about the whole microservices kind of approach, you know, you, you might have like, this is my employee database. This is their employee data. And then over here, there might be work orders that has an employee ID, probably, but not the employee information. So you might funnel those in together, ship them out. Jon (12:35.895) Mm Allan (12:57.123) It does sound over engineered in a way, it becomes important later on and it becomes easier to test. So for the server, it's pretty straightforward. Stay in your lane, right? From the server architecture, we've I feel like dotnet's got that down to a science at this point, right? There's so many ways to do microservices and kind of keep keep that vertical slice vertical as opposed to going horizontal and touching everything. Probably not what you want, right? Jon (13:07.042) Mm Jon (13:18.638) Mm Allan (13:26.499) So in vertical slicing, another kind of term that usually gets compiled with that is CQRS or command query responsibility segregation. Vertical slice sounds a little bit easier to say. So the main difference between like people go, what's a mediator? Well, it's basically just instead of making signature calls with DI, you're basically sending a message through one little service, right? Just like a service bus. puts message on it. Something may reply if it's a command. So one responder to a command or request. You can also have events which is like send an event in and it could fire to multiple people. But it's just an object. You don't know where it's going. You don't know who's handling it. Somebody's handling it otherwise it can error. But it's very loosely coupled. Jon (14:10.783) Mm Jon (14:21.39) So it's like a traffic cop, right? Like it's kind of sending stuff around. Allan (14:24.432) Could be, could be. Yeah, I'm a person. I want to go that way. Okay, you may go. Jon (14:30.072) Yeah. Now, you know, maybe, maybe it's a bad analogy in the sense that like traffic cop top traffic cop, I can talk sounds a little bit more potential for like, you know, congestion and stuff, right? Like what's the story look like in terms of the mediator? Cause like, conceptually, if things are sort of running through a central service, you know, does that cause any problems with scaling in terms of like how those things are routed and distributed? Allan (14:58.729) not really because it is very light from it to hop from the point of where you're calling it to where it's going. It's it's not really a hotspot. So which is a good question because when we talk about something like one message center in in maui if you're really abusing that thing like i've seen people make bluetooth calls over it or accelerometer sensor stuff that's going over it right that's a lot Jon (15:08.253) Are you basically like... Jon (15:16.45) Mm Jon (15:21.121) yeah. Jon (15:24.76) oof. Allan (15:27.533) People don't realize that even though it's a small little chunk of data, when you're pinging that thing, it's got to be thread safe. So it's going to synchronize that call. It's going to start pumping it. And if you've got a lot of listeners doing a lot of processing, it's all running in sequence. and you're sending that like accelerometers, I think could send data like 30, 40 times a second, like really rapid. If you've got that thing turned up. Jon (15:33.496) Mm -hmm. Jon (15:47.886) yeah, yeah, yeah. Especially, yeah, yeah, you can, and kind of different modes too, right? Like I want, I'm doing a game, I need like low latency, tons of info, like let's go. Allan (15:59.562) Yeah, so messaging, it's not really you need to be a little bit closer to the metal. I still wouldn't do it with a mediator, but mediator doesn't create that hotspot per se. It's just really good at scattering that event if you need to. Jon (16:01.61) Yeah. Jon (16:10.785) Mm Jon (16:14.986) Well, and without getting too deep into implementation details, but Mediator would effectively be a lookup table of, OK, here's the thing. Here's where it goes. It's not really queuing messages so much as just directing them. Sure. Allan (16:29.13) Not really, but you can, right? It's mediators there to kind of just, do I need to route you, right? It's a pretty straightforward thing. People are putting this on everything. The really popular one in .NET right now for kind of the server calls is Medi8R. We've mentioned that, I don't know, half a dozen times on the show, because I loved it. But what it didn't focus on for me was apps. Jon (16:37.037) Yeah. Jon (16:49.932) Mm -hmm. yeah. Allan (16:58.041) And that's fine. It's not maybe maybe it wasn't a good fit for it. But I saw something in apps that that could potentially make mediator a really good thing for dotnetmowy. So we'll get to that. But we'll get to that. Let's down my notes. You can ask what. Jon (17:09.486) So, okay. Okay, okay. Well, I know I was gonna say like, okay, yeah, why do I want it? Tell me on it. Allan (17:17.709) Why do you want it? So one of the big things is, is that I don't know, you're, I've seen pool mass, so you're not really getting into the service overload like a lot of people. And I think, well, some people have like, they'll have like 20 services be injected, right? Like big teams will have like 800 services and you're like, dude, do you like your wrists? Like, do you want carpal tunnel? Like injecting all that stuff is brutal. Jon (17:28.283) I mean, I have enough, but yeah. Jon (17:41.036) Yeah. Well, and this, this gets into where we talked about like, you know, creating like a super kind of service of services kind of pattern too, right? Which is, is what I do. It's not great, but it's fine. Allan (17:49.372) And that's, you can solve it. It's there's nothing wrong with it. It's very common. It's what I usually tell people with D .A. Yeah, there you go. There you go. It's not a bad way to handle those, but you still end up with like those services that are not common. Like some people use repositories. Bird and hell, but repositories they'll go crazy with. And so you'll see like all these repositories coming in like, man, how did we get here? Why? Why are we doing this? Jon (17:56.15) I called it common services actually. Allan (18:21.324) And so you'll have like 20, you'll still have 20 services with that common service, right? So that's a lot of typing. That's a lot of stuff to go in. What if I could just put in one service, a mediator service and send messages through it and it comes back with types and it's all loosely coupled, which is, know, DI people want that and they want to be able to unit test easy. Well, the thing about mediators, you have a message, you have a handler, right? So you might have an event handler, right? Event. Events multiple requests singular right and a request can have a response. So the idea there is that you might have a command that says save my job right or save employee and what you'll do is you'll have a save employee object or contract and you'll ship that through but your your request handler on that can inject your I don't know if you've got a entity framework DB context. Maybe you got some sort of push notification service, email service. I don't know, you name it, right? But you can focus on what the business is going to accomplish and inject a smaller subset of services because even when you've got that base common one, so you've got a base common service, you probably, let's say it's got 10 things in it, you probably realistically use four or five per page common. And then the rest are Jon (19:41.784) Yeah. Yeah. And that's the challenge, right? Cause it's like, some point more slowly creeps into there. Cause you're like, well, I'm using this in like maybe now a third of my pages. Right. And so it's, it starts to get like, what's the tipping point that you're like, okay, let's throw it in common services now. Allan (19:53.504) Yeah. Allan (19:58.963) Now you could say that it's not really a huge, it's not an overhead in terms of performance at all. It's a case of Jon (20:04.618) Right. Especially like in mobile, it's there's these are mostly singletons and stuff, right? It's like just references getting Allan (20:09.855) Exactly. There's nothing there to slow you down. What it does do is go, well, I want to unit test this thing now. Chances are you've got one just giant mock of your base services so you can unit test it. But as you add things there, you keep adding more of these big mocks because you don't know what's hit anymore, right? You don't know what your service is actually using. So that's not really Jon (20:23.128) Yep. Right. Jon (20:29.772) Yeah. Jon (20:34.006) Right. And, and as I, as I've started in, it's kind of, it's a interesting point. Cause as I have started in my own app to like, I, you know, I'm not the best at testing. this was always, it's, it was always funny. Cause like, you know, an old school gone mobile, Greg shackles was the test, you know, I don't know what the right term is, but like you, you tested or you, you weren't friends with him. Allan (21:02.718) Okay? Yeah, no, I get it. I'm kind of on that boat, know, still on the boat. Jon (21:04.302) And, know, great, but it's just like, yeah, yeah, all my tests. -huh. Yeah. I do that. Sure. But when I've gotten better over time, and, I've, I've started, I added a new test project, that's basically like trying to test my view model logic, because, you know, I have UI tests, which is great for some things. but you know, I can do more of the that what I'm trying to accomplish in the UI tests by just testing the view model, right? It's stuff like, if the user enters this value into this field, I want to make sure that the results from this property are such and such. for me, there's a subtle difference between testing the actual calculation itself, which I have a whole suite of tests for that. And I've always had that because that's made sense. Between that and. when I do a thing and or a combination of steps in my app, does it, does it do the right thing? And mostly like I'm trying to backfill these as I fix bugs where I'm like, there's this weird case. If you enter something here and then you skip down here and put this, but then you go back up here and do that the way that like property change notifications and stuff fire. you know, some unexpected result happens here. And it's like, that's a really easy thing to test by just doing the view model logic. But so what's happening now is. Like you said, I have a whole bunch of common services and mocks for them, but like, I don't always want to use the same mock for all the situations. Cause maybe some tests, I don't care about this other service that's here. Right. But like, I actually want to do something differently when I'm testing this other scenario here. So I think to that point, like, yeah, this starts to get really kind of ugly as I go down this in terms of like this whole common thing as I'm adding new services. And so mediator can. can help me with this, guess, if I architect things a little bit differently. Allan (23:04.072) Yeah, because you're just focusing on the thing, right? So this is the business I need this message to accomplish, right? So save an employee, right? I may do some validation. I may do, I don't know, some online check. Like what if it fails? A whole bunch of things, right? So that that's kind of something that you can do at mediator level. And then, you know, you can test all of that code. You're actually testing the pure business of what that thing does. Jon (23:32.077) Yeah. Allan (23:33.962) as opposed to trying to inject 5 ,000 services, figure out that you only need three of them, right? Like you can really kind of hone in on what it is that you're trying to solve. So that's good start. It's a good start. So something else I wanted to look at here was mediator at an app level. You know, again, we have the message center. People tend to abuse it. It doesn't matter. Jon (23:44.716) Mm Allan (24:00.67) You know, it can leak memory. I know that the community tool kits got that weak message center, whatever they call it. Jon (24:05.87) Yeah, we're getting rid of the messaging service that's in, no, that wasn't forms that's in Maui. Like I think for Net9 it might be parked as deprecated, but yeah, I mean, it's a process to do it obviously, we don't want people using that. So don't use that. Allan (24:17.204) Just burn it to the ground. Let it go. No, I get it. Allan (24:25.022) But you know what, you guys were using it for a while because you needed it, right? You didn't have a way of getting things across the pipe. Now that you have DI, you do. And it's a little bit cleaner, right? So you don't have these messages scattering and where they're registered, where they're not, are they leaking? Are they not? Have we unsubscribed? Have we not? Right? So one of the things I wanted to do with kind of this app level was look at events. Like I want my view model, which is Jon (24:27.704) Mm -hmm. Yep. Jon (24:44.289) Yeah Allan (24:53.052) kind of short lived, it may not be in DI, but it's definitely in a navigation stack. What if I wanted it to listen automatically and unsubscribe automatically to events? So that was one of the things I looked in with the Shiny Moderator is or mediator is, you know, what if I just say this view model because it's it's short lived. It wants to listen to say a log out event or I don't know, you name it some sort of event connectivity event if you want to have that. Jon (25:04.163) Mm Allan (25:22.855) Right? So it's going to listen to those and respond to those automatically. And when it pops off the stack, it's not going to listen to them. So, and that works with DI or without DI is fantastic. So your view model keeps working the same way it is because there's a lot of people still that use dotnet Maui that are like, I just want statics. I'm like, okay. So mediator still needs DI, but it can still be dynamically referencing events. Jon (25:42.764) Yeah, yeah. Allan (25:51.485) That was one of the different things that Mediator doesn't like Mediate R doesn't really do because again, it's not looking at apps. Jon (25:55.566) Mm So how are you, I forget how you are accomplishing kind of wiring that all up from a Maui perspective. Allan (26:05.672) So Maui has, obviously it has some globals that I can hook into, right, in terms of, you know, what pages are up. And if you have a page, you can see the binding context, et cetera, right. So. Jon (26:16.822) Mm -hmm. So you're looking at the navigation stack. Allan (26:20.145) Yeah, so I register a service that knows how to look at Maui, right? So there's a separate Maui package that has a whole bunch of stuff which we're going to get to as well. And I can I can say look at the navigation stack every time we fire an event, rip through the nav stack, go through the tab pages and all the tabs and all the navigation pages in there. And see if you can find anything that's that's wanting to know about this event and fire it. And Jon (26:45.55) So are you using, just, are you reflecting at runtime to like look for if the type implements an interface, are you using attributes or how are you doing that? Allan (26:55.507) So in this case, it's an interface. So you'd say eye event, shiny mediator, eye event. Jon (27:00.184) So you're like, if the pages binding context is, know, I event whatever kind of stuff. Okay, cool. Allan (27:06.493) Yep. Run it. And it's it's not reflection, right? It's just a low yield skim through and people go, well, it's going through the nav stack that slow. Not really. How many pages are you going to have on your nav stack? Jon (27:11.437) No, no. Jon (27:15.788) Yeah, how deep is your nav stack? Yeah, if if you hear it like thousands of pages deep, you've got other problems. Allan (27:21.636) Yeah, that's so I'm not worried there. And it's nice and fast. It just goes through and this way you don't have to, you know, unsubscribe, subscribe, etc. It's just dealt with. Right. Jon (27:32.236) So you're basically, when a page is pushed, you found a new thing that you're not tracking already, you kind of add it to your lookup table and get rid of it. Allan (27:41.586) Well, that's what's cool. I don't even bother to do that. Don't need to. Loop it when the event fires. Yep. Jon (27:45.902) you're just like when the, the meet, when the request comes in, go look at the stack and just, okay, cool. So you're not even, yeah, you're not holding references. So like, you're not impacting you. You're not messing things up just by the fact that you're kind of observing them, I guess. Allan (27:59.528) Right. It's just it's you either have the event or you don't. And if you don't, whoopee, I'll iterate you again next time. Again, maybe you have 10, maybe 20 items. If you got big tabs, who knows? Jon (28:11.564) You, I, I feel like, and maybe you haven't done this yet, but it wouldn't be that bad to set up like a, stress test kind of scenario to see like how, you know, I I'm, I'm with you in the camp of it's not a problem, but it might be interesting to see like, okay, how many, how many different like, you know, interfaces are, are, can I register? How many things can I throw on the stack? You know, can I get to a point where I've done enough that it's like, yeah, this look up now because I've got like thousand different pages and 200 different events. Now it takes like 50 milliseconds to walk the whole stack and do something. Allan (28:53.604) Yeah, you know what, until I see a cause, because I'm using it now in my production stuff and until I, you know, I don't want to start optimizing for a problem that doesn't exist yet, but Jon (29:03.182) No, I'm not suggesting the breaking the rule of optimization. It's more like a, it'd be, I always, I always think it's interesting to like see, you know, what, where's the limit kind of, know, where would you actually start having to care about this? Allan (29:11.417) Interesting to know. Allan (29:17.753) Right. Well, I can I can honestly say don't do an event for say something like an accelerometer. Just it's going to pump events. Like it's just too fast, even for messaging center, right? It'll pump them too fast. So you're right. It's interesting to know, but just be smart about it, I guess, in any case, right? Because even Jon (29:25.486) Sure. Allan (29:46.023) Even some events, if you've got a really busy service, if you've got a lot of listeners on it and it's all local in memory, you got to be careful, right? Because you got like 20 listeners and that event's coming in, you know, a thousand times a second, right? You know, vis -a -vis Azure event grid. Right? That's a lot of processing. Jon (30:02.743) Yeah. No, no. Do you like thinking this through? Like one of the things, if I was going to swap this into my app, you know, I know, I know a couple of places where I would maybe want to do it. one of the things I've kind of run into before is I think depending how you, you push stuff onto the nav stack, like I've got, I use, you know, a modal pop -up kind of page, which is just like a normal modal page, but I like make the background transparent and stuff. And so like there's, I've run into scenarios where I push that page, that page maybe is, not watching the actually for anything, but the one below it in the stack, you know, is subscribed to an event for something changing, but because it's still kind of visible, you know, it's kind of the question of like, do I want, do I want it to still listen to those events? So I'm curious for how you kind of reason about like you're walking the stack and you're just doing it on everything in the stack that, or, or you're saying like, no, Only the thing that's visible really should care about the update. Allan (31:06.331) For now, I'm going the whole stack because you may want to notify the lower pages to be ready. So something's happened up top something because normally it's triggered by something up top, right? So maybe the bottoms are aware. Jon (31:17.004) Right, so you might wanna maybe, I guess taking that into your own hands, using your pattern, maybe I would do something like, don't just blindly update the UI when this event comes in, but maybe set a flag that when I know I'm back at the top of the stack, I might wanna do something. Yeah, yeah. Allan (31:36.186) then do a render or change or whatever. Yeah, that's that's normally what we're doing. I have looked at doing an attribute that says only fire if it's if it's actually the top level. It seems like a little bit over engineering right now to do so until I until I have a reason to do it. It's probably something that doesn't need to bear the cost. Now, that's an interesting question anyways, because frequently when an event fires doesn't necessarily mean you're on the main thread. Jon (31:47.69) Mm Jon (31:56.312) Yeah. Allan (32:06.479) So what people tend to, you know, how many people do you see broadcasting to the main thread properly? Cause that's a place where you really want to try catch because if you don't, kaboom, there goes your app. And because you've called the main thread, like the essentials main thread, it kind of swallows the stack a little bit on you. You don't really know some logic crashed because you didn't try catch inside of that. You I've seen people try catch outside of it. Jon (32:06.595) Yeah. Jon (32:11.624) yeah. Allan (32:36.761) but that's hopping threads on you, man. That try catch is going to miss. So I've seen people miss on those try catches. And then the whole darn app comes, you know, bringing down. So and I often notice, you know, not only are people doing the main thread wrong, they're doing the try catches wrong, right? Like on events. So I generally tell people when do you put a try catch, where the thing started, where the action started. Jon (32:39.116) Yeah. Yeah. Jon (32:49.666) Yeah. Yeah. Allan (33:05.773) or where the event is firing, right? Because maybe I tapped on a button or an event is firing, try catch. So the good thing about mediators that you can get into these, these kinds of wrappers or middleware that kind of surrounds all that stuff. So let's say, you know, a request handler, when I request data, if it doesn't work, I want it to, to throw an exception, come back out to me because I can deal with that. With events, often events are kind of like a fire and forget. In the server world, they're definitely fire and forget. But in this app world, a crash is a crash, right? So you gotta, you gotta protect your events. So I, you can do that with middleware that comes built into the shiny mediator right away. Is it'll say, look, this event ran for too long. So we've got some time logging. So this took like three seconds, log an error. This crashed, log an error, but it didn't, it didn't crash the whole app. That event just didn't run. Jon (33:40.066) Yeah. Allan (34:05.209) You can pay attention to those. You could not pay attention to those. Either way, it's going to save your app. So you see that you'll log the misbehavior. What you do with it doesn't matter, but at least it didn't take out your whole app for an event. Jon (34:15.65) Yeah. So let's, I realize that, you we've talked about this a bunch, not on this episode or on other episodes too. I think it might be worth like just taking a slight step back and going over the different like parts of what your implementation looks like. like the pattern, you know, I feel like you've probably well described enough, right? You've got requests and you've got basically like events. Allan (34:45.805) events. And then you've got requests with responses. Jon (34:50.187) Okay, yeah, so like. Allan (34:51.823) There's kind of another one which I'll talk about in a second. Jon (34:53.814) Well, yeah, let's, let's, let's talk about, you know, what that I guess kind of looks like in a, practical sense in an app. Allan (35:00.439) So if well in an app it depends like your contracts can do anything. So let's say I might want to make an HTTP call. Right. Some at some point I want to make an HTTP call. Why would I put it in a meteor? Well one thing is is that I don't know maybe another team owns that service. Maybe they're changing the contract. Who knows. Right. Doesn't matter. Somebody else is implementing that knows how to do HTTP properly. So I want to say Jon (35:05.912) So. Allan (35:30.178) get people as an example. So I call mediator dot request new get people I might pass in some arguments with my contract don't know right they get people age 40 and older who knows. So I would pass that contract and the contract would say your response looks like this you're going to get an I enumerable of some people object or there's also a streamed request Jon (35:31.95) Mm Jon (35:36.44) Mm Jon (35:42.094) Yeah, only with, Allan (35:58.218) So I might like an async enumerable, maybe I want to stream, maybe it's a large results set, who knows, but you can get streams out of it as well if you want. But what that looks like is basically give me an HTTP result of these people. Now people are going to go, why do I need that? I can do that with DI right now, right? That's the first thing you're thinking out of your head, but you have to try catch it. And basically if you're try catching it at the point of a command, right? That's a normal spot to do it. Jon (36:00.558) Mm Jon (36:17.176) Yeah, sure. Allan (36:27.701) or when your view model is becoming visible. You have to try catch and the same thing we do and try catch every time is log it, tell the user, sorry, we screwed up. Or you might have some resiliency, right? You want to build some poly into it so it redos the request because it failed right away or timed out or who knows whatever happened. So you have to add that into the mix, right? Sure. Your service can do that as well. But let's say I want to break in a couple other things. Maybe I want caching on it. Right? Jon (36:35.086) Yeah, yeah. Allan (36:57.856) Maybe I want offline. So now we're getting into all this. It's quickly blowing up on you. Jon (37:03.232) Right. then, and then you're, you're starting to have to kind of think about that implementation for every service that you're implementing separately, right? Unless you create then some kind of generic service of a service, service implementation, right? Like it's. Allan (37:18.85) It gets just that alone. You start thinking like, holy crap, that's a lot of stuff. Right. And so you start building it into your lower tiers only to realize, now it's on everything. And I only want to have a subset of these. Jon (37:32.524) Right, yeah, so like I want to retry with Polly, but only for this, you know, situation. Yeah. Allan (37:37.598) one particular asinine call that that just for whatever reason the server is stupid with it. Who knows, right? Jon (37:42.894) And or and even like maybe maybe even that same call. Sometimes that code path you want to retry and other times you know you don't. Right? So then you then you're coding like some weird OK wrapper around this thing so that sometimes I can pass a flag in to run it through this retry delegate and sometimes not. Allan (37:51.958) deaths. You just you don't know until you know. Allan (38:05.888) Right. So either you end up injecting like, what do we say? We've got cash, we've got resiliency, we got HTTP calls. So we just injected three services and then we've got something that sends a dialogue to the user to say, yeah, we screwed up or you're stupid or something. Right. And then we've got a logging. So there's five services just right out of the bat. Five flipping services, right? What if it's too slow? We want to log that too, right? So it's just, it compounds really quickly. Jon (38:11.811) Mm Jon (38:19.708) Mm Jon (38:32.067) Yeah. Allan (38:35.455) And if you build it into your base layers, it ends up on everything or you end up building this logic around it, which ends up, know, an abstract of an abstract is now really bad. And you can't, it's like a poison. just bleeds through. So this was the key thing with mediator in, done in Maui was what if I could just mark the damn thing like a request handler? So we've already said a request has one handler. right? It's a command. What if I could just put an attribute that says, execute, I want this state for offline. So if there's no connectivity, it's another thing we didn't even talk about. So return the last result you had. So the last result that came back, I serialized it to JSON, saved it on the disk. Connectivity is saying it's offline. So I'm just going to return from disk. I'm not even going to call the request handler. Or I can say you're online. I'm going to get that result from the server. And then I'm going to store it offline. So the next time you're offline, here it is. Jon (39:35.414) Right. And you don't have to think reason about, you know, doing that yourself in your service. Allan (39:40.177) Right. And you just you put a single line attribute on your request handler. That one call. Jon (39:45.386) Now, can you do that dynamically with your pattern yet? Like, can I say, I'm going to send this one request, but I don't want to cache it right now. And I might call the same, send the same request in the future and say, you know, this time I do. Allan (40:02.544) Not really because that would be more on your if you need to get into custom logic at that point then that's more you want to do in the handler. But I think the thing that's important here is that we initially we did offline mode for it in an attribute on a specific request handler. Jon (40:10.273) Okay, yep. Jon (40:16.675) Mm Jon (40:21.26) And you could always, I guess, well, you wouldn't have multiple handlers for that same request though. Yeah, I was just trying to think, can like kind of duplicate things or like make, make another handler that uses the same, you know, implementation, but one cache is one doesn't. Allan (40:32.188) You wouldn't do that, right? But what you could do is if you have multiple parameters, right? And those parameters change like date times or ints or whatever. You could make the request have a key that mediator knows to look at and just like a cache key and it goes, OK, no problem. I'm going to watch it for this key. If this key comes in, that's what I'm going to use as the offline return. So it's smart. One line of code, one attribute on your request handler and on the thing that we said problematic. Jon (40:37.442) Yeah. Jon (40:48.684) Mm Jon (40:55.788) Yep, that makes sense. Allan (41:02.12) The same goes for caching. The same goes for resiliency. It's just, we're just tacking on attributes. The tri catch we were talking about, that's already built in, right? You don't even need to do, it's there, right? So if I have another attribute called user notify, you can give it a string for the pop -up, the page dialogue, the ugly dialogues. Sorry user, we suck. And that's it. If it sees a problem, Jon (41:23.778) Mm -hmm. Yeah. Allan (41:29.969) It'll throw the exception, but it'll try catch for on your behalf, log it, send the page dialogue to apologize to the user. She didn't all he had to do was attributes. To me, this was great because I keep seeing people do try catch. Jon (41:41.198) Are you source generating from those attributes or something? Or is it looking them up at runtime still? Allan (41:46.999) No, because I don't need to middleware is middleware is kind of a difficult thing to wrap in. Because you don't know the scope of it. You don't you know, does it stay in memory? Is it a singleton? Is it a scoped is who knows, right? It gets difficult there. And there's not really a performance headache there. Now I do have source generation for registering all these darn things because you can get a lot of handlers right? Before we had a service that might have like or controller, right? That's another good one. Jon (41:59.661) Mm -hmm. Jon (42:10.358) Mm -hmm. Yeah. Allan (42:17.095) that had like, you know, five or six methods in it that we would call handlers. You can, you can implement multiple handlers on a single class if you want for all the different messages. That's not a problem, but you still have to register it with all those things. So there's some sort of generation to help there to alleviate the calls. We'll link docs and stuff at the end of it. But I still think that that's the pretty cool play here is because the focus on the app Jon (42:40.546) Yeah. Allan (42:46.802) Like we're talking about offline caching resiliency validation. If you need to validate an object, right? Data annotations are fluent validation. You get that with nothing more than an attribute and doing what you were going to do anyways. So to me, it's a, it's a huge win with the middleware alone. I wouldn't compete with mediator at all if I couldn't do that, from an app level. And I think that's the one thing that, that I've offered. That's a little bit, it's a little bit different. Jon (43:16.266) Now, one other one you've got here is a replay. I'm kind of curious to think of where you're thinking of using that and how. Allan (43:24.517) So replay is an async enumerable. what it does is sometimes when you come to a page, you just look, that call is going to take a second. Just give me the last results and then we'll tell the user, yeah, we're waiting for the next one. So there is a case where a lot of companies I work with, they're just like, why could you just show the next one? Okay, well, that's kind of offline, but not really. They're just like, give the last results that were there as we call the server. And then when the server result comes back, replace what's there. So this was an actual specific need for a couple people that I have. It's just like, okay, that's easy to do with a, with an attribute on an async enumerable call or request. Just put an attribute on same thing. Request keys there. It sees the same request key. Here's the last result I have. Call the server. When it comes back, pipe it again, cause you've got an async enumerable now, right? So I can actually return multiple. or calls or results from that and you can bind it however you want in your view model. Jon (44:29.952) Okay, cool. Allan (44:32.389) I think it's pretty awesome. Pretty awesome. What else we got here? Jon (44:36.909) So what else are we missing about? Like I'm curious if there's any other mobile specific parts that we haven't talked about. Allan (44:44.655) Now we talked about the navigation stack, which that one's again unique, kind of all the middleware that's specific to mobile and dotnet maui. There's blazer aspects of all this stuff we've just talked about too. So if you're doing blazer hybrid or you're doing blazer web assembly, a lot of these things work, not all of them yet. There's no such thing as connectivity yet on blazer, but there will be in the near future. And then we can have a service that listens to that. Jon (44:46.786) Mm -hmm. Allan (45:14.415) does all the same things, but in WebAssembly, which is pretty awesome as well. Jon (45:19.284) And how are you finding, like, I don't think this is going to make things worse than how, you know, some things are set up today, but like, I'm curious, like one of the challenges when we start talking about, you know, wrapping things like with Polly or just the, the deeper that you kind of shove an operation into things that are wrapped around it, for things like air reporting and stuff. Like I know I've, I've had my own challenges with like, It's hard to really get a good stack and really tell kind of where, you know, this, actual source of this thing happened. Like what, how does that kind of end up playing out when you use something like this, especially when you start kind of throwing in the, the caching and resiliency and that kind of stuff. Allan (46:04.932) So I think the one thing about mediator is that like when you do this in services, you end up with like a layer or like a stepping stone. And in a lot of cases when we talk about middleware, like people use middleware and ASP .NET Core all the time, right? The concept is exactly the same except ASP .NET Core has the option of returning different results. Whereas in the mediator world, it's like, this is the request, this is the result, like it's known. Jon (46:19.278) Mm Allan (46:33.335) the middleware is kind of like a stepping stones. So it'll go in sequential order. It'll go step, step, step, step. Okay. Call request if you need to write, might have one of those middleware say, no, you know, they're offline. Forget stepping. Don't call the middleware right before we used to have like a before and after, right? I don't know if you remember the early days of, of kind of this middleware ish setup was you'd have, this is before the call. This is after the call and you'd have those interfaces, but you never had a way to say, don't make the call at all. So that it was like sandwich meat, but it wasn't, you couldn't take the meat out. You couldn't replace the meat. So with, with middleware, you can, it's like a, here's a step you decide when to call the next guy, the next guy in line. And if you, if you even want to, right? Like I said, if you're offline, don't go any further, stop right here. And Jon (47:00.92) Right. Jon (47:05.677) Yeah. Jon (47:20.279) or if to. Allan (47:27.669) It sounds kind of like a bad thing. And then by the way, you step out, right? So you step in and then you step all the way back out in the same order. It's like a stack, a pop and a push and a pop. Yeah. The difference is, is that when you do that in services, you're usually passing through signatures in your code. That's what makes it hard to get. Once you've done it, it's hard to get out. But if you have a mediator where we stacked on attributes, the order will still execute like that. Jon (47:36.076) Mm -hmm. Like nesting dolls. Allan (47:56.205) But what you can do is you can just say, I don't want to cash this anymore, or I don't want this to be offline anymore. And you comment out that attribute and it's done. It's gone. Right? So it's a difference between, all these signature calls that you're manually having to make, as opposed to just stacking the things you need on a specific call. Right? And I think that that's pretty, the pretty big sell on mediation is that it is going to look at what's going to happen or what your handler wants to do and either react or not react. you don't have that attribute go away. leave me alone, I'll just execute you. Right, so that's kind of how it looks at it. It looks at the attributes. So it's a stacking effect versus a, I don't know, a kind of push through and you can't get out of it now. You've tangled the spaghetti, you can't get out of it. Whereas you've got a stack of pancakes, I can just remove one of the pancakes and keep going is how you can look at meat eater calls. Jon (48:47.266) Yeah, yeah. And then the other thing that, you know, there's more on the just development side of stuff, like, and I don't think there's an easy answer to this, but there's also like, again, this isn't a new problem, but it kind of got me thinking, you know, how, how could this be solved better? which is like, as you're coding these things, you know, having something loose, intentionally loosely coupled kind of means that it's also loosely coupled in. where the code lives and finding how the pieces kind of link together. Allan (49:17.708) This was kind of one of the good questions you had right out of the gate when you started looking at this, because you're right. When you start using a message, you're like, where does it go? And the system doesn't really know that until runtime, right? So it's built up the dependency injection. Everything's been registered. You're right. That is a hard thing to find, right? Because I mean, one step is you can comment on the contract just like you would like if we were in a message center, we have the same problem, right? Who's listening? Who's publishing it? Jon (49:26.083) Yeah. Jon (49:29.89) Great. Jon (49:45.915) yeah, yeah, absolutely, yep. Yep. Allan (49:48.078) So you end up commenting out the contract to go and find it. So that is a problem with message based systems. You and I kind of had the conversation about looking at stuff like, now I'm losing the context of it, not source generators, but analyzers. They could go and look for it during your dev time to say, yeah, we see it over here. Or hey, we noticed you've got this contract set up, but there's nothing. Jon (50:03.384) Like analyzers, yeah. Allan (50:15.625) we don't see anything down the line in any of your projects that's actually going to handle that. Jon (50:21.346) Yeah. And you can't, you know, I had mentioned too without thinking, right? Like, well, what if you put like an attribute on it? And it's like, yeah, well, no, now you've coupled things together. Yeah. Allan (50:30.259) Yeah, you put the you put the message right back together with the handler, which you know, in retrospect, it's not really a huge issue. But you know, now it requires you changing the contract and having some stuff couple it's Jon (50:43.458) Yeah, it's not, it made things a little bit muddy. Yeah. Yeah. Allan (50:45.873) It's semi defeats the pattern, not fully. So, but I think as we look forward to that, there's ways that I could say, okay, a request, you have to have a handler for the system goes, you know, no, that's it. That's an error condition, right? You called request or send and you sent a request through the mediator and it now doesn't have a handler. That's, that's an error. Events are different, right? You can have zero or you can have many. So that'll, that'll just go, okay, there's Jon (51:12.012) Right. Allan (51:15.657) Great, there's no events, who cares? Jon (51:17.11) Yeah, I think, you know, for me, the thing that hits and I run into this with how I've separated my projects and stuff in my own code too is like, I, it really kind of was an aha, like I I wish there was a better way to either have the tooling infer this kind of stuff. Like it's just code navigation at some point it boils down to it's like, okay, I have, you know, this request, in this interface, right. And so like, I'm, I'm going to. Allan (51:37.428) Yep. Jon (51:45.686) send a request. Well, okay, well, where does that live? Okay, it's over here. Okay, well, who implements that? Okay, these things implement that and they live over here. Okay, now I want to look at what the response looks like. And it's just, it's not hard to do. Allan (51:59.687) The response is part of the request anyways so you know what type is always coming back. You just don't know who's handling it. Jon (52:05.248) Yeah, but is it usually, you if I'm saying that, it usually an interface that I'm, you know, that I'm getting back, right? So like, do I, not necessarily, I guess. It's just a little tedious. And again, this isn't, I'm not saying this is, you know, your library specific problem by any means. More just highlighted like, yeah. Allan (52:15.313) No, not necessarily. Allan (52:27.675) It's a messaging based architecture problem. Jon (52:31.638) Yeah, it's like, would be neat to have a way out. And then I started kind of looking like, I wonder if like, you know, there's any Roslyn stuff that you can hint at and that it doesn't affect, you know, compile time or anything like that. And yeah, no, no answer yet, but it's, it is a problem that would be kind of interesting to think more about and see if there's a way to, to, improve the developer experience around. Allan (52:52.379) I did look at looking at the contracts. The problem is where you look at them, right? Because an analyzer basically focuses on the library it's installed. Right? So you'd only want the analyzer in the absolute global route. And then it would say, that's a contract. Give me all the contracts that are coming in from all the sub projects. Start looking at them and then find the handlers. So first of all, it's going to be slow because you got to look at everything in its mother coming in. Jon (53:00.875) Mm -hmm, yep. Jon (53:11.661) Right. Jon (53:16.781) Mm -hmm. Allan (53:21.233) and you have to be at the root. Otherwise it's going to look at the contracts and go, I don't know. I don't see anything linked to this. And I don't think you can look outwards. You can only look like what's coming in. You can't look what's going where it's going out to. And so it's been difficult. I don't it's not a problem. I know how to solve right now, but you're right. It is a problem. So you have to result. You have to resort to that old school way of of commenting out the thing, finding all of its reference points in your projects and then Jon (53:26.541) Mm Allan (53:50.877) in on that. Jon (53:52.654) Yeah, and maybe somebody listening has an idea that we're not thinking of. Allan (53:56.742) Well, the way the way I generally handle it is in your vertical slice. So if we talked about employees, you have a namespace that you have a namespacing pattern. And I mean, people don't have to follow it. It doesn't care. But if you follow kind of a naming standard, right, like a lot of people like to do view models and they have a view models folder and then they have a views folder. I personally hate that. I'd rather it was by the feature and then the pages right there and then the view models right beside it. But in the cases where you have view models, and then you have the pages in a separate folder or views in a separate folder. You know that naming convention and that naming standards. So you just go, this view model is named this, then there must be a corresponding views slash whatever page on the other side. So you can do that. It works. Pick your battles. Understand how you want to do it. Jon (54:45.762) Yeah, yeah, no, for sure. For sure. I mean, it's yeah, there's pros and cons to doing it any which way generally. Allan (54:48.966) The one other thing I - The one other thing I wanted to come back to is that we talked about, well, what happens with the events? So events also have the middleware that we were talking about. So there's a case where events when they fire, they're not on the main thread. There's also an attribute for that. So you can set main thread and it'll do it properly. It'll do the try catch so that your app doesn't go. Jon (55:11.65) Yeah, does it just call like the Essentials API or like, okay. Cause like one thing you had mentioned was, you know, wrapping up your stack basically. like part of me wonders too, if it's better to go directly more if you could and what that would make the stack look like so that you're not like digging into like, yeah, Essentials main thread, which actually digs into this platform specific that, know, like Allan (55:37.893) I could because you can register. Technically, it's when you're registering your handlers or even your middleware. If you compile it as an Android site or an iOS site or whatever platform you want on your own and it registers, it's all the same stuff, right? It just your left side on Android does. What's their stupid thing? What they call their main thread? Looper, looper, main looper. And then on the iOS side, it's the. Jon (55:43.553) Yeah. Jon (56:00.264) the runnables or loop. Yeah. mean, yeah, the looper with the rumble. Allan (56:07.13) Dispatch? No. Jon (56:08.846) It's like you I think you grab a view any kind of view and you invoke on main thread from it or something Allan (56:15.01) No, they have something new, Newer. I don't remember. Doesn't matter. See, memories are gone. We're too old for this. We're too old for this. Jon (56:21.644) Yeah. Allan (56:26.192) And I guess the last plug is one of the things if you're using mediator, if you're using API endpoints, a lot of people end up with like these controllers or all their middleware, like the minimal API registrations only to inject mediator and then call it and all that binding that drove me nuts. So for mediate R I had code that would go looking at all of the handlers that were registered with mediate R and then register the Jon (56:41.647) yeah. Allan (56:57.017) Minimal API's for me because that was just like boilerplate and it was a lot of duplication I hated that so I brought that forward because I wanted in my package. That's the mediate our stuff was My own my own thing. I kept it to myself. I was greedy John and Now it's in it's it's of course in my package so I could plug it be like hey Hey, save some save some boilerplate Jon (57:20.11) share the wealth so you're gonna throw a bunch of links on the show notes for this one? yeah Allan (57:25.614) I will. I will. This is good architecture. I hope people look at it. I hope you have convinced you for once. Jon (57:31.704) The, the, the one, the area that I'm contemplating putting it into start. mean, there's, there's two actually, the one is, is maybe less of a savings. Like I use events in some places kind of to do the same, right? And you know, I subscribe and unsubscribe properly, like a good person. but the one that gets kind of squirrely is with, subscriptions, like in app purchase stuff where I want to. Yeah, I can, I call it from a bunch of places. So I request it from a bunch of places and I wire up the event handler in a bunch of places because I want to know when that status changes, which it can happen at a bunch of different times where generally most of my app, I'm like, I know when I, when you know that the places that something like, the, the, your pool that you're viewing is going to change are fairly well known and minimal and subscription stuff is like, Apple can call back into your app at any point in time, basically, and say, here's a change, right? Android is kind of the same too. And, and I also like on Android, I'm like, if, you, if, if you're near your expiry date and, I'm going to go like Android, you don't have to prompt the user necessarily to check some of this, the information. So I use that to my advantage. I'm like, if it's near this, date, like go out and check, but that's an asynchronous thing. And so it can come back at any time. Allan (58:28.72) Isn't that lovely? Allan (58:42.936) It's like. Jon (58:55.86) yeah, there's just a bunch of like in and outs for where this stuff can happen. I'm like, this probably would be a good place to make use of it. Allan (59:03.288) And that's because you've got a lot of, I guess you could be navigating through the pages and then all of a sudden you're like, I'm on this page. I need a modal to pop up and warn the user. So there's obviously other ways to handle it too, but it's, know, if you just pipe that event out, you publish the event, who's ever on top that needs to listen because you need some sort of UI interaction. It's it's not a bad way to do it. I was hoping you were going to use the request handlers. I want, I want you. Jon (59:09.261) Right. Jon (59:27.628) Yeah. So that's, that's, that's where I'm looking to introduce it. and then looking to introduce it because, cause I Allan (59:32.688) The request handlers are the big one. think that, dude, I'm doing this all because of the middleware. That's where I was like, why? Yeah, I could have built this into Mediator, I believe, but I just had so many ideas when I started creating this. I was like, this is gonna work for me. Jon (59:48.81) Well, the middleware is nice for this too, in some ways. tell me if I'm maybe using it wrong to do it like this. But like one of the things that I think of immediately is, let's, let's make some middleware that checks to see like if, the request, does the middleware, yeah, it runs on the response, right? Like I could hook it up so that when there's a, an event that, you know, is fired because the subscription status changed that status might be containing like the receipt information from the purchase, if it was a purchase. Well, maybe I want to send that out to my server too. And I don't really want to like, where else do I register that? Right? Like I don't want to do that as, maybe that's not a good middleware use. I don't know. I'm just trying to think. Allan (01:00:34.763) No, that's probably not a middleware use, but you're going to listen to some event that's not mediator based. But what you could do at that point is say, you got that data in, you don't want it to fail. That's the other thing. If your server fails, you got the notification somehow, you need to store it so that next time, that could be a middleware thing. Your handler could just say, look, under no circumstances, if this guy fails, can this call be lost? Jon (01:00:38.573) Yeah. Jon (01:00:49.048) Right. Jon (01:00:52.77) Yeah, I wanna keep trying. Allan (01:01:04.481) it needs to call later. So if we fail, no big deal, we're to wrap it up. But the point is, is that it knows don't, don't die. Don't lose this stuff. Cause otherwise that's it. The server doesn't know. Jon (01:01:14.478) Don't die, yeah. and like connectivity stuff and all the fun things, right? Like throw that all in and just like make this thing, make sure it works. Allan (01:01:22.008) Right. And then once you know that that's propagated to the server, you might mediate your event right after that almost like transactional base to say, yep, servers now aware you're good. Notify the UI until the user they good do your stuff. Probably not middleware. Probably not, but it could be. Jon (01:01:39.778) Yeah, okay, fair. I'm sure I'll bug you with more questions as I get closer to doing that. That's one of my next big tasks for the app is figuring out my subscription stuff because, man, Apple and Google, they keep changing things and they're already terrible. So. Allan (01:01:55.349) Well, you can do offline now without bringing in shiny jobs. Yeah, just caching some calls. It goes to disk like you want. Jon (01:02:01.068) Yeah, good, okay. Well, you know that's the first thing I'm gonna look at when I go to install this thing, right? It's like, hmm, what are you bringing in with you? And if you fail that test, immediately gone. Allan (01:02:10.42) not bringing RX. That was the immediate thing you said to me. You can look at the actual references. I don't think I actually bring in any references to be honest other than DI. You already have that there. DI and logging is the only things I bring in. Yeah okay. I went light. I didn't put an RX John because I know you're just you're an impossible sale to it. Jon (01:02:23.394) Yeah, I already have that there. I'll be, I'll be checking. I'll, I'll let you know if I find otherwise. Jon (01:02:32.462) Perfect. That's right. I wouldn't use it then. And I'm very close to maybe actually using this now. So all right, we'll let you know how it goes. Allan (01:02:39.926) All right, do it, do it. So if anybody else has cool libraries out there, I mean, I don't mind plugging my stuff. I really think this is a cool one. I hope people use it. But if you've got a cool product out there or cool open source library, tell us. We'll talk about it. We may even bring you on. Jon (01:02:49.432) Yeah. Yeah, tell us about the ones that you have, the ones that we don't know. Like there's a few that are neat and that we've maybe mentioned even already and ones that I know of, but every once in a while still I'll see like, that's cool. Somebody will show off something and like, didn't know that existed. So we want to know, everyone wants to know. Allan (01:03:09.47) Yeah. I mean, I'd like to see stuff that's innovative. there's a couple UI libraries out there that I think are pretty jiggy. But if you've got something like this, this I think was pretty innovative. I don't think this exists anywhere else in our ecosystem. That's why I kind of wanted to selfless plug on it. But if you've got other stuff, I love architecture. Bring it. Let's see it. Jon (01:03:33.474) Yeah. And you can go figure out how to send that to us at gonemobile .io, the website. I don't know if we link, I'm sure there's a link to the, yeah, there's a link to all the different podcast directories. So certainly pick the one that you like or just go find it on your app. And we're still gonna keep asking for those five star reviews. So please consider. Allan (01:03:57.195) See, John didn't have a bad joke this week, but he won't have bad jokes if you let us know. Or more. More bad jokes. Jon (01:04:03.744) Or if you like the bad jokes, yeah. Vote with your stars or ratings or thumbs up. Who knows what units they use and any emails yet. We all, still have, we still have the one that we got to, we missed this show. Maybe next episode. Yeah. Allan (01:04:11.305) or emails. Let us know what's going on. Allan (01:04:17.951) You're gonna get some of those reviews on here, but we'll talk about them. He had an issue. A couple of them had some interesting questions about what is this good or this bad. If it works for you, man, it's good. Jon (01:04:28.366) unless it's rx or something then. Allan (01:04:30.293) But it's still working. Still working. Damn it, John. That was a bad closer. I'm gonna go swear at him now. Once this goes offline, I'm gonna... Jon (01:04:36.236) Yeah, that's all right. Yeah, he's got the the bleep button ready. Allan (01:04:43.817) Yeah, I can hear it. Jon (01:04:45.97) no. All right. Well, before we devolve anymore from where we already have gone, I think that'll do it this week. Thanks everyone for listening and we'll see you next time. Allan (01:04:56.309) See ya.