0:00:00Welcome to Under the Radar, a show about independent iOS app development.
0:00:04I'm Mark Arment.
0:00:05And I'm David Smith.
0:00:06Under the Radar is never longer than 30 minutes, so let's get started.
0:00:09Alright everybody, so we gotta put on our leather jackets, jump on our motorcycles,
0:00:13hit play on the Kenny Loggins, 'cause we're going to the danger zone.
0:00:16That's right.
0:00:17We're talking about dangerous migrations in code today, and that's where we're going.
0:00:23Is this like an update without a where clause on a live server?
0:00:28Not quite. It's a little bit more, though the stakes, I think,
0:00:32those are the stakes of this migration that I'm going to talk you through,
0:00:35is I think the most high-stake bit of programming I think I have ever done in my entire career.
0:00:40So I've been doing this professionally for like 20 years.
0:00:43I don't think I've ever done any kind of sort of migration or change in any of my apps that is as high-stakes to me as this particular one.
0:00:50And so it seemed like something that was definitely worth the topic, both, I think it's an interesting thing to talk about,
0:00:55and then I am also very eager to essentially talk through my thought process with this,
0:01:00and make sure that there's nothing that jumps out to you as someone who also has 20 years of programming experience,
0:01:06to, you know, that I'm doing something horribly wrong, and then also do this before I roll it out,
0:01:10so that if our listeners out there are thinking of anything that I'm doing,
0:01:14and they're like, "Oh no, don't do that," or "Make sure you do this," like,
0:01:17I'm all ears 'cause it's a little scary.
0:01:21So the general sort of story begins last September when Widgetsmith launched,
0:01:28and much to my surprise, it turned out to be very successful and popular,
0:01:33and people loved Widgetsmith, which is great.
0:01:36But what I had no concept for at that time was that the thing that people would really, really want to do
0:01:41is the photos aspect of it.
0:01:44So in the first version of Widgetsmith, all you could do was point Widgetsmith to an album of photos,
0:01:51and it would randomly show you a different photo from that album throughout the day,
0:01:56which is a feature that's still in there, and sort of works alright.
0:02:00But what people actually wanted was to use it like a photo album, where they choose a photo,
0:02:04and then show that one photo indefinitely in a slot on their home screen.
0:02:09That was the feature that people actually wanted.
0:02:11I think it was maybe a day after it had kind of had this explosive growth,
0:02:16I'd remember just sitting down and just like doing my best to build out that feature as quickly as I possibly could.
0:02:22And I didn't really have the time or thought to be able to really think this through,
0:02:27I just sort of built it and got it working.
0:02:29And the approach I had taken at that point was that you choose a picture,
0:02:34and then what I did is I took that picture,
0:02:37and I sort of down-sampled it to be the size of the widget that you were going to be showing.
0:02:42So if the widget was going to show a picture that could be 600 by 600 pixels,
0:02:48I would resize it so it would be 600 by whatever the most constrained dimension is,
0:02:53this would be 600, and then it would be wider than that in the other one,
0:02:56or taller than that if it was portrait.
0:02:59And it would show that on the screen.
0:03:01And that worked.
0:03:02And it was something I think I probably built in less than a day,
0:03:05and put that in the app, and it's been wildly successful.
0:03:07People love it.
0:03:08It works well for a lot of people.
0:03:11But it turns out, almost a year on now,
0:03:15that that approach and that solution that I had done in those first few days of the app being launched
0:03:21left me in a place where I'm kind of stuck now with what I can do with that feature.
0:03:27And there are a lot of things that I wish I could do that I can't based on my original implementation.
0:03:31And specifically something that I want to be able to do is give you kind of a full zoom and pan of the image,
0:03:39which in retrospect is obvious, but in my frantic building back last September,
0:03:44I didn't think about it.
0:03:46Or if you pinch on the picture, you should be able to zoom it in and position it arbitrarily inside of the widget,
0:03:53which is something that you just can't do now.
0:03:55And so people have to either pre-crop their images, or there's all kinds of weird hacks or turn things,
0:04:00but it's not great.
0:04:01And it's something that really, if this is the marquee feature that people use this app for, I can do better.
0:04:06And similarly, it's something that I also thought of that I think a lot of people use this widget for,
0:04:10is to show people.
0:04:12And so I wanted to use the vision framework in iOS to automatically suggest a crop for you.
0:04:18So if you have a picture that involves people, you can hit a button and it can kind of automatically zoom
0:04:24to a reasonable zoom, showing those people nicely, which is just a nice little thing
0:04:28and a kind of a fun way to experiment with the vision framework, which I hadn't used before.
0:04:33And also, subsequently, I also want to be able to allow you to change this over time,
0:04:39so that if you want to change your zoom or change your pan, you can do that later without having to re-add the picture.
0:04:46Because the problem I have now is, all I have is this very scaled-down version of your image.
0:04:51So if I want to do anything to it, it involves a loss of quality.
0:04:55And similarly, we have things like the extra-large widget now for the iPad,
0:05:01and situations like this where my old downscaling version would be, means that I can't offer any kind of obvious
0:05:09or easy upgrade path between widgets or things like that.
0:05:12So this is where I am. And so what I need to do is then go ahead and build this new version.
0:05:19So that's what I did, is I sat down and I wrote a new version of this,
0:05:23and at first I wrote it in a completely self-contained testing application,
0:05:27where I could kind of just get the gesture and get the, you know, adding a picture and all that stuff built out.
0:05:32And I actually built this for WatchSmith's last update, and used it in there for the complication of the,
0:05:38with the photos complication I did there, which incidentally turned out to be really complicated,
0:05:43because in SwiftUI there is no good way to do a pinch gesture.
0:05:46And so I ended up having to do this weird hybrid approach where some of it is a wrapped UI view,
0:05:51and some of it SwiftUI, and there was a lot of pain and suffering there, but it's built now, and it's fine.
0:05:57But this is the point where it starts to get complicated, and this is the point that I think,
0:06:02you know, now we're entering the danger zone, is the, what do I do?
0:06:07I have this old implementation, and I have this new implementation, and in some ways,
0:06:13there's a certain compatibility between them, where the old one, I could treat the old, you know, photos widget
0:06:19as a sort of, a simple case of the new one, where the new one has a big image, a zoom factor,
0:06:27an offset factor within that, and I could kind of, as suits, just take the old ones and say,
0:06:32"Oh, you know, they're just the size of the image is smaller, and you can't zoom it in very far as a result."
0:06:37And I could adjust the offset factors between them, and I could do it that way, and just sort of treat it
0:06:43like it's an unzoomed thing. Or I could work out a different approach.
0:06:47And this is the place where the terror begins, and the, I think, when I had one of those moments where,
0:06:53I don't know if you've ever had this, where you sit down, and you're like, "I wonder if there's a number,
0:06:57or something you're kind of, you know you need to look up, and you need to kind of look at,
0:07:01but you're kind of scared about what the answer is going to be."
0:07:04[Laughter]
0:07:06Like, I knew I wanted to know how many photo widgets are out in production, because it's just a helpful tool for me,
0:07:13to just decide this. But I kind of didn't want to know the answer, because my initial, my vague sense
0:07:19is that it would be a large number. In fact, it would be a very large number.
0:07:23And so, but I was a little bit like, I didn't want to look for it. I didn't want to look,
0:07:29but I actually felt like I need to. And so I did a bit of back of the envelope math.
0:07:34You know, I collect very limited analytics inside Widgetsmith, but I collect enough that I could kind of
0:07:39estimate what this number probably is. And it ends up that I think there's something on the order,
0:07:45this is a conservative estimate, but I think on the order of about a hundred million photo widgets
0:07:49deployed out in the world right now. [Laughter]
0:07:54Which, exactly, right? So like, you can either laugh, or you can cry if you're thinking of changing
0:08:03the code that underlines the display of something on that many people's home screens. Like, on their
0:08:09phone, with them doing nothing, they could just, an update could appear in the App Store that could somehow
0:08:14horribly destroy something that's on their home screen, and it could do it tens of millions, if not
0:08:20a hundred million times. So like... So wait, let me pause you here for a second. I'm very glad you looked up this number,
0:08:26because that was a great moment for us. However, it blows my mind a little bit, but why did you need
0:08:32to know the number? I think for me, it's getting the degree of difficulty for this, right?
0:08:40And I mean, in some ways, maybe you're right. I can see where it doesn't actually matter. But in the sense of,
0:08:47ultimately, I need to do what is best, and if it was, if, you know, I wouldn't want to go down a path that would be
0:08:53problematic for ten thousand people, any more than it would for something that would be problematic for ten million people.
0:08:59But yeah, I wanted to have a sense of it, I think honestly, in some ways, to keep me honest, and make sure that I don't
0:09:05cut any corners or get, like, you know, sort of get a little too fast and loose with this, because in some ways,
0:09:12that's what put me in this problem in the first place, by not being thoughtful, by not going through as much
0:09:16thoughtfulness as I could on this, and to make sure that I had an appropriate amount of terror sitting behind me
0:09:24while I'm working on this feature, to make sure that I do it right, and do it right the first time, because it is unlikely to be
0:09:30something that I would be able to sort of, like, undo or fix in a good way, if I do something kind of horribly wrong.
0:09:38So, already, I mean, that number scares the crap out of me, and I don't even have any skin in this game.
0:09:44Already, I'm already thinking of the approach you should take, if it were me. And if, I can tell you right now,
0:09:52what I would do in this kind of context is, I would not touch a single line of code about the old widgets,
0:09:58and I would just make a new photo widget type, and I would hide the old one from being available when creating new widgets.
0:10:08So let the old widget type persist, and for new people who create new photo widgets, that follows a different code path.
0:10:16Which is not the most, like, in the most ideal case, people with the old widget should just, it should just work,
0:10:22and it should just get better over time. But the risks are so high here, as you said, I think in that kind of context,
0:10:28I would just make a whole new one that's a totally separate class, totally separate code paths, and if people write in asking,
0:10:36"Hey, I'd love to be able to zoom my photos or whatever," you can say, "Alright, here, just recreate the photo widget, and it'll have that ability now."
0:10:42And I think that's, it's not like the most elegant solution in the world, but I think it's the most pragmatic,
0:10:48because it protects you, like, nerve-wise and liability-wise from accidentally disrupting all those widgets out there,
0:10:56and I think people would be fine with that. I think most people are not going to care about the lack of grace on that,
0:11:01and they're, you know, this is something like, they would care quite a bit if you broke their photo widget,
0:11:07but if they want some new features and have to recreate it, I don't think they're going to care that much about that.
0:11:13I'm very glad you said that, because that is exactly what I did.
0:11:16Oh, awesome!
0:11:18That is a strong encouragement to me that I did the right thing in this, and especially for you to say that,
0:11:23because I feel like you have a bit more, like, I think you have less of a comfort, often with sort of like the hacks,
0:11:32or doing things halfway, or feeling like that, like you tend to be a very complete developer,
0:11:38whereas I think my tendency is to be a bit more fast and loose, and so it's encouraging to me that you took the same approach,
0:11:44because basically, yes, I had the same, my thought was, I first, like, I built out a little bit of the version
0:11:49where I would take the old photo data and kind of move it into the new system, and then, and then it sort of, it worked,
0:11:56but then the more I thought about it, I'm like, something is going to go wrong here, and so I just took the,
0:12:00instead took the approach of, there's, you know, if the widget has the old data, it uses the old system,
0:12:06and, but as soon as you, if you add a new widget, or you add a photo to a one that had a photo before,
0:12:14you know, so if you have, if you, you essentially have to go through the image picker again,
0:12:18which I have to do anyway, because I need, I don't have the full resolution anymore,
0:12:23so if you go through that, then you switch over to the new system, but it's like they are totally separate inside the code,
0:12:29and they do nothing with each other, and if you, you know, if you did the, if you did this upgrade,
0:12:34and never added another photo widget ever again, or even never launched the app again,
0:12:39like, the old code paths are the only thing that will ever be run, because all of the new stuff is all kind of hidden behind,
0:12:46if you're using the new stuff, use this, if you're using the old stuff, use that, and, as I said, it's a bit inelegant,
0:12:52and I think there's the issues of user communication, but obviously now, like, even a messaging for what features are available,
0:12:58or like, help screens and things, and I think that's fine, and then it's also a little bit of a sad thought that's like,
0:13:04that code for the old original photos is going to be with me forever, like, there's no way for me to ever realistically expect to retire that code,
0:13:14and so I'm going to just need to support it indefinitely, which is fine, I think probably, and I think obviously,
0:13:21and it's mostly a question of, in the future, my big concern was making sure that I preserve a way to sort of create those widgets,
0:13:32at least in a debug mode, so that I can make sure I can, when I'm doing my testing and compatibility stuff,
0:13:38and making sure that SwiftUI 3 doesn't break them, like, I could do it, I'm going to end up in a circumstance where there's user data that exists in the world,
0:13:46that I can't easily recreate myself, but I'm delighted to hear that you took the, your mind went to the same place of like,
0:13:52nope, we're just going to keep these systems totally separate and take that approach and, you know, as best as we can, minimize the risk there,
0:14:01because the risk primarily is obviously that I somehow in the switch between the old and the new, I get something wrong,
0:14:06but that feels like a much lower surface area switch, because it is very clear when you're in one case or when you're in the other,
0:14:14rather than if I tried to kind of have a hybrid approach or do a data migration or do something that is much more sort of high risk in that way.
0:14:24And I think also I love the thought that I'm doing nothing, I'm in no way changing the data of the old method, you know,
0:14:31it uses a different file, like file structure when I'm saving things, and it's stored in a different place in the user's configuration.
0:14:38So all of those, the old data should persist, and so if somehow it all goes horribly wrong and I need to roll it back,
0:14:44I can roll back to the old widget system and it should be completely unchanged as a result.
0:14:49Yeah, that's good, because like, the last thing you want in a migration like that is for, like if you were trying to migrate old stuff to new stuff,
0:14:57like so much weird stuff can happen, like if the device is low on disk space, or any of that, like one of your file rights fails in the middle,
0:15:05like then there's all these weird conditions that you'd have to accommodate for in order to do that safely at a large scale.
0:15:11I would even say like, I do remember back when Apple was announcing APFS, there was some remark, I think maybe Federighi might have said on the talk show.
0:15:23He did, I have this in my notes to talk about later.
0:15:26Oh yeah, about how,
0:15:27Go ahead, yeah.
0:15:28Yeah, about how like, for the previous few releases of the OS, one thing they would do as part of the upgrade process was basically test a migration to the new file system they were developing,
0:15:38and then roll it back, and I guess report back whether it worked or not.
0:15:42And so like, I feel like if you were going to do that kind of migration at this kind of scale for something so important,
0:15:48you would have to do something like that, where like, you would test a migration to a new system without actually removing the old data.
0:15:57And being super careful about it to first make sure that all the data migration stuff succeeded and everything,
0:16:04and wrap the whole thing in a giant try catch block, and just do everything possible to like, okay, try to do this,
0:16:13but if it fails, fail silently and just tell me somehow.
0:16:17And to be able to avoid that is very good.
0:16:23Anyway, we are brought to you, talk about figuring out when you have problems. We're brought to you by Pingdom from SolarWinds.
0:16:30While you've been listening to this podcast, how would you know if your website had gone down?
0:16:35Would you know if customers couldn't click your buy button or fill out a trial form?
0:16:39You might stumble across the problem by luck, just by like hitting refresh on your site occasionally,
0:16:43but that means you've already lost out on who knows how many new customers.
0:16:46You need something to tell you everything is running smoothly on your site, and more importantly, you need to know when it's not.
0:16:52So you need Pingdom.
0:16:54Pingdom detects around 13 million outages every month, more than 400,000 every day.
0:17:00And for as low as $10 a month, Pingdom helps keep your sites online.
0:17:04Whether you're a one-person company or a Fortune 500, you need real-time alerts about critical website issues,
0:17:11and customization of how you're alerted, whether it's SMS, email, your team's collaboration apps, push notifications, whatever it is,
0:17:18Pingdom lets you customize all of that.
0:17:20They even track and analyze your website's load time so you can see what's affecting the user experience.
0:17:25If you have a website or web service, you need Pingdom.
0:17:28Take charge of monitoring your site in minutes?
0:17:31Go to Pingdom.com/RelayFM right now for a 30-day free trial with no credit card required.
0:17:38When you sign up, use the code RADAR at checkout to get 30% off your first invoice.
0:17:43Thanks to Pingdom from SolarWinds for their support of this show and RelayFM.
0:17:48So I think for the rest of the episode, I think what might be interesting to talk through is some of the approaches I'm taking now.
0:17:55I'm glad that we both have agreed on the way forward from a technical perspective.
0:18:00And then now it's these sort of like, how do you-- there's still some risk.
0:18:04There's still some amount of danger involved in what I'm doing.
0:18:07And it's sort of the strategies that I'm coming up with to minimize those and the things that I'm doing in the run-up to this release,
0:18:14and the way I'll test it, and the way I'll beta test it, and so on, because I think that's--
0:18:19obviously the scale of the issue that I'm running into is pretty big.
0:18:23I mean, there is one other angle to consider here, though.
0:18:27A lot of times we as developers, we see some flaw in the way things are, and we think, I have to fix that.
0:18:35I have to clean that up, modernize it, rewrite it, refactor it, whatever it is.
0:18:41I have to fix this inadequate or hacky thing that's already there and working.
0:18:47But do we? Do we really have to fix it? I feel like so often we don't ask that question of ourselves enough,
0:18:55but a lot of these things, like, if the current thing is working, we probably shouldn't go messing with it.
0:19:01Or it's not worth the risk, or it's not worth the effort, or it's not worth having to rewrite something
0:19:09and then refix all the bugs that we fixed the first time and all the shortcomings,
0:19:12because we wanted to do it in the new language or the new framework or whatever.
0:19:15So often we pour tons of effort into something and take lots of risks in order to clean something up
0:19:23or modernize something that the reality is, just leaving it alone would probably have been more pragmatic,
0:19:29and at the end of the day, you're spending a lot of effort modernizing something that your customers
0:19:33might not even notice or care about.
0:19:35And so I feel like it's very important to ask ourselves that kind of question much more than we do now.
0:19:40Ask ourselves when we're looking at a migration.
0:19:42Because I'm facing all sorts of possible migrations and rewrites and everything that are on my wish list/to-do list,
0:19:49because every to-do list is actually more of a wish list.
0:19:51But I look at that and I think I could spend six months doing this,
0:19:56or I could push this change out to the way I do things in the servers
0:20:01and possibly cause a giant bad server day for myself, or I could just leave it alone.
0:20:07And would that really be that bad to just leave it alone?
0:20:10Yeah, and I will say I had the same thought with this feature,
0:20:13and certainly in some of the more challenging parts of this process,
0:20:17and the realization part where I was realizing the scope of the challenge that I was undertaking.
0:20:24And I think it's a very good point and a good reminder, because I think it is definitely an area to be very thoughtful,
0:20:30and make sure that if you're undertaking a dangerous migration or something that has a high-risk coding situation,
0:20:37that you're doing it for a reason that isn't selfish.
0:20:44Isn't something that is going to make the app better for the end user, not better for you.
0:20:51That if it was something that I just need to deal with and manage going forward,
0:20:56that me dealing with it and me taking that risk is in some ways irresponsible
0:21:01if it only benefits me and isn't actually benefiting my customer.
0:21:04Because ultimately what I'm doing is I'm making software to make people's lives better, to make them happy.
0:21:09And if I am something that's just like there's this one little thing in it that annoys me,
0:21:17and in the end I ruin someone's day because they had their widgets all set up the way they loved them,
0:21:22and I do something that messes with that, those are disproportional. Those are not good things.
0:21:28So I think it's definitely a good point. I will say I went through that with this,
0:21:31once I really got down to, is this worth doing?
0:21:35And ultimately what I ended up on is I did it and then I've been using it myself on my own phone for a while,
0:21:42and it makes photo widgets better.
0:21:45And it makes them better in ways that I, now that I sort of, it was one of those features that now that I've done it,
0:21:50I don't think I could go back to the old version.
0:21:52Because I love that when I add a picture of my kids to my widget, I can zoom in nicely on them,
0:21:59just very easily and obviously.
0:22:02And so it makes it that little bit more personal and a little bit more friendly.
0:22:07And ultimately that's most of what I use the photo widgets for,
0:22:11is if I have pictures of my family and friends and us on vacation or places we've been,
0:22:16and being able to frame those pictures exactly the way that I would want has made the app better.
0:22:22And so I don't think I could go back, but I think what you're saying is definitely a good important thing
0:22:27and something that I think I'm glad to have gone through that thought process of who is this for
0:22:33and why am I doing it and is it worth it?
0:22:35And making sure that it's not just for a reason for me,
0:22:38that it's ultimately a reason that I think will make people's, my users' lives better as well.
0:22:42So yeah, and then I think in terms of the things that I'm doing now that I've like here is,
0:22:47A, the first thing is I'm doing a huge amount of just general testing
0:22:54in a way that is something that I feel like is so easy to sometimes skip over
0:22:58when you're in a process like this, but is I'm loading it onto lots of different devices
0:23:02and I'm downloading the app from the App Store, the previous version,
0:23:07setting up a bunch of widgets, trying them and then installing the new version
0:23:12and testing it and trying it and doing it on small phones, on big phones.
0:23:16Thankfully with this, I don't have to deal too much with old OSes because everything requires iOS 14,
0:23:21so there's a little bit of that but not too much that I need to worry about.
0:23:24But it's like doing a lot of that and in some ways also I'm just sort of doing lots of data testing there,
0:23:29which I think is an important thing to do.
0:23:31And I think something that ultimately I'm going to do from this is in,
0:23:35I believe in most versions of Xcode you've been able to do this for a while,
0:23:40but you can capture a simulator snapshot of a particular configuration
0:23:46and I'm planning to do a bunch of different snapshots of where the users are
0:23:51and then I think you can restore that to a simulator for later testing.
0:23:56But instead of gathering that user data and having those snapshots to be able to do testing with,
0:24:01I think it's something that's always useful, so you have these baselines to install the new version on
0:24:07and then run your new thing and make sure it doesn't break.
0:24:10That's great. I had no idea.
0:24:12I'll have the link in the show notes to instructions on how to do it,
0:24:16but it's something I've done before where there's a way to kind of,
0:24:18you can gather up a snapshot of a simulator, I'm pretty sure.
0:24:21That was just a feature I dreamed of and it doesn't actually exist, but hopefully it does.
0:24:26I think this is also a place to think about doing automated testing,
0:24:31and this is where I'm sure all the unit testing people will be like,
0:24:33"Yay, Dave's finally discovering unit testing!"
0:24:35And no, that's not actually what I did.
0:24:37Sorry, Casey.
0:24:39What I did is I wrote that testing app that I didn't initially.
0:24:44I set it up so that it would run a lot of my vision stuff and the new pan and zoom and all that.
0:24:53It runs it against essentially every photo in my photo library,
0:24:57which is tens of thousands of pictures.
0:25:00I can just sit there and quickly go through lots and lots of pictures.
0:25:03This is something that I found several issues with, which has been really helpful.
0:25:06It's like the nature of any kind of, A, the vision stuff.
0:25:09You can have these weird cases where the vision framework gives you back some weird value
0:25:14that you may not have been expecting.
0:25:16It's important to test it on lots of different things because it's trying to find a face.
0:25:21That's what it's ultimately trying to do.
0:25:23But sometimes it can think that, "Oh, this weird pattern in the corner is a face."
0:25:27And so you get back a really weird-shaped face or something that when you try and zoom into,
0:25:33if you don't handle it correctly, or if it's a face that's right on the edge of the frame,
0:25:37you may accidentally try and over-offset and set the center to somewhere that doesn't exist.
0:25:43And these are the issues that I found by just having essentially a testing harness,
0:25:47a testing tool that lets me do that and lets me do it in a manual way that is high velocity.
0:25:55And the reason I'm not using something like unit testing there is the nature of what I'm doing.
0:25:59It isn't like there's a precondition and a postcondition that I can easily just put in code
0:26:04and put down in what I want it to do.
0:26:06It's a perceptual thing.
0:26:08It's like when I hit the zoom to faces option, does it zoom to a pleasing crop of this person?
0:26:15And I suppose I could unit test that it goes from this picture to this rectangle.
0:26:21That's not actually what I'm worried about.
0:26:23What I'm worried about is not cutting off people's faces and making people look weird,
0:26:28which is very aesthetic and not something that I need to write another machine learning model,
0:26:33I suppose, to validate my first machine learning model or something like that.
0:26:36It doesn't make any sense.
0:26:39And then I think the next thing I'm going to do is I think this is called chaos monkey testing,
0:26:44which I just love the name of.
0:26:46But essentially I just always do this kind of round of testing before a feature, especially a UI feature,
0:26:51is just trying to break it by being kind of silly with it.
0:26:55So like zoom, zoom, pinch, pinch, swipe, swipe.
0:26:57Just open your phone to the feature and then just go crazy
0:27:01and just be trying as best you can to do weird and unexpected things
0:27:06or try and trigger race conditions or threading issues by changing the photo
0:27:13and then immediately switch to the other view or the background of the app
0:27:16and do this kind of like just introduce randomness into the use of the app.
0:27:21And especially this is great to have someone who doesn't know the app or like your kids or someone be like,
0:27:25"Here, try and break this screen and see if they can do it,"
0:27:29because that's a good way to find these weird edge cases that you may not find otherwise.
0:27:34And then lastly, I'm going to do a lot of beta testing,
0:27:36and I expect there will be a link to a test flight in the show notes for this episode,
0:27:41and I would appreciate any Under the Radar listeners to download it and try it
0:27:45and install it, add photos, make sure their old photo widgets don't get broken in the process.
0:27:51And this is one of those things where I'm very patient with this,
0:27:53and part of why I'm doing it now is it's kind of this summer period
0:27:56where I'm working on iOS 15 features long-term,
0:27:59but in the short-term it's something that I can take my time with over the summer,
0:28:02test and try, have people beta test for a long time,
0:28:06not just like, "Oh, put the build out, get a couple hundred people to install it,"
0:28:11and if it doesn't break or have big crashes, release it.
0:28:16This is much more of something I want people to live with
0:28:18and try and make sure there's not weird issues over time.
0:28:21And then my last little mitigation strategy is I'm certainly going to use the App Store Connect
0:28:27"Roll this release out slowly" thing, where you can roll it out to, I think,
0:28:32as half a percent the first day and then one percent and then two percent,
0:28:36and it slow rolls out so that you can expose this to a relatively small percentage of people initially,
0:28:43and then watch like a hawk the customer support and all the places that people might talk about it
0:28:48and make sure that the thing's coming up.
0:28:50And I think you can even roll it out and then immediately pause the rollout,
0:28:54which is something I've also done in the past where I can send it out to half a percent of people
0:28:59and then leave it as half a percent of people for a week
0:29:04and make sure that nothing comes up subsequently.
0:29:06So anyway, that's all the things that I'm trying to do to mitigate my terror
0:29:11and mitigate the fact that this is, I think, I don't think it's an exaggeration to say,
0:29:16like the highest sort of risk bit of coding I've ever done.
0:29:19Wow. Well, good luck with this.
0:29:22Thank you.
0:29:24We'll talk about this again because this is going to be hopefully a slow roll.
0:29:29Yes. Hopefully sometime late, late in the summer there will be another episode where I talk about how well it went,
0:29:35how all the preparation meant that it went off smoothly and effortlessly,
0:29:39and no one even knew that it happened. It was just perfect.
0:29:42Best of luck.
0:29:43Thanks.
0:29:44Thank you, everybody, for listening, and we will talk to you in two weeks.
0:29:47Bye.