Under the Radar

220: The Danger Zone


00:00:00   Welcome to Under the Radar, a show about independent iOS app development.

00:00:04   I'm Mark Arment.

00:00:05   And I'm David Smith.

00:00:06   Under the Radar is never longer than 30 minutes, so let's get started.

00:00:09   Alright everybody, so we gotta put on our leather jackets, jump on our motorcycles,

00:00:13   hit play on the Kenny Loggins, 'cause we're going to the danger zone.

00:00:16   That's right.

00:00:17   We're talking about dangerous migrations in code today, and that's where we're going.

00:00:23   Is this like an update without a where clause on a live server?

00:00:28   Not quite. It's a little bit more, though the stakes, I think,

00:00:32   those are the stakes of this migration that I'm going to talk you through,

00:00:35   is I think the most high-stake bit of programming I think I have ever done in my entire career.

00:00:40   So I've been doing this professionally for like 20 years.

00:00:43   I 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.

00:00:50   And so it seemed like something that was definitely worth the topic, both, I think it's an interesting thing to talk about,

00:00:55   and then I am also very eager to essentially talk through my thought process with this,

00:01:00   and make sure that there's nothing that jumps out to you as someone who also has 20 years of programming experience,

00:01:06   to, you know, that I'm doing something horribly wrong, and then also do this before I roll it out,

00:01:10   so that if our listeners out there are thinking of anything that I'm doing,

00:01:14   and they're like, "Oh no, don't do that," or "Make sure you do this," like,

00:01:17   I'm all ears 'cause it's a little scary.

00:01:21   So the general sort of story begins last September when Widgetsmith launched,

00:01:28   and much to my surprise, it turned out to be very successful and popular,

00:01:33   and people loved Widgetsmith, which is great.

00:01:36   But what I had no concept for at that time was that the thing that people would really, really want to do

00:01:41   is the photos aspect of it.

00:01:44   So in the first version of Widgetsmith, all you could do was point Widgetsmith to an album of photos,

00:01:51   and it would randomly show you a different photo from that album throughout the day,

00:01:56   which is a feature that's still in there, and sort of works alright.

00:02:00   But what people actually wanted was to use it like a photo album, where they choose a photo,

00:02:04   and then show that one photo indefinitely in a slot on their home screen.

00:02:09   That was the feature that people actually wanted.

00:02:11   I think it was maybe a day after it had kind of had this explosive growth,

00:02:16   I'd remember just sitting down and just like doing my best to build out that feature as quickly as I possibly could.

00:02:22   And I didn't really have the time or thought to be able to really think this through,

00:02:27   I just sort of built it and got it working.

00:02:29   And the approach I had taken at that point was that you choose a picture,

00:02:34   and then what I did is I took that picture,

00:02:37   and I sort of down-sampled it to be the size of the widget that you were going to be showing.

00:02:42   So if the widget was going to show a picture that could be 600 by 600 pixels,

00:02:48   I would resize it so it would be 600 by whatever the most constrained dimension is,

00:02:53   this would be 600, and then it would be wider than that in the other one,

00:02:56   or taller than that if it was portrait.

00:02:59   And it would show that on the screen.

00:03:01   And that worked.

00:03:02   And it was something I think I probably built in less than a day,

00:03:05   and put that in the app, and it's been wildly successful.

00:03:07   People love it.

00:03:08   It works well for a lot of people.

00:03:11   But it turns out, almost a year on now,

00:03:15   that that approach and that solution that I had done in those first few days of the app being launched

00:03:21   left me in a place where I'm kind of stuck now with what I can do with that feature.

00:03:27   And there are a lot of things that I wish I could do that I can't based on my original implementation.

00:03:31   And specifically something that I want to be able to do is give you kind of a full zoom and pan of the image,

00:03:39   which in retrospect is obvious, but in my frantic building back last September,

00:03:44   I didn't think about it.

00:03:46   Or if you pinch on the picture, you should be able to zoom it in and position it arbitrarily inside of the widget,

00:03:53   which is something that you just can't do now.

00:03:55   And so people have to either pre-crop their images, or there's all kinds of weird hacks or turn things,

00:04:00   but it's not great.

00:04:01   And it's something that really, if this is the marquee feature that people use this app for, I can do better.

00:04:06   And similarly, it's something that I also thought of that I think a lot of people use this widget for,

00:04:10   is to show people.

00:04:12   And so I wanted to use the vision framework in iOS to automatically suggest a crop for you.

00:04:18   So if you have a picture that involves people, you can hit a button and it can kind of automatically zoom

00:04:24   to a reasonable zoom, showing those people nicely, which is just a nice little thing

00:04:28   and a kind of a fun way to experiment with the vision framework, which I hadn't used before.

00:04:33   And also, subsequently, I also want to be able to allow you to change this over time,

00:04:39   so that if you want to change your zoom or change your pan, you can do that later without having to re-add the picture.

00:04:46   Because the problem I have now is, all I have is this very scaled-down version of your image.

00:04:51   So if I want to do anything to it, it involves a loss of quality.

00:04:55   And similarly, we have things like the extra-large widget now for the iPad,

00:05:01   and situations like this where my old downscaling version would be, means that I can't offer any kind of obvious

00:05:09   or easy upgrade path between widgets or things like that.

00:05:12   So this is where I am. And so what I need to do is then go ahead and build this new version.

00:05:19   So that's what I did, is I sat down and I wrote a new version of this,

00:05:23   and at first I wrote it in a completely self-contained testing application,

00:05:27   where I could kind of just get the gesture and get the, you know, adding a picture and all that stuff built out.

00:05:32   And I actually built this for WatchSmith's last update, and used it in there for the complication of the,

00:05:38   with the photos complication I did there, which incidentally turned out to be really complicated,

00:05:43   because in SwiftUI there is no good way to do a pinch gesture.

00:05:46   And so I ended up having to do this weird hybrid approach where some of it is a wrapped UI view,

00:05:51   and some of it SwiftUI, and there was a lot of pain and suffering there, but it's built now, and it's fine.

00:05:57   But this is the point where it starts to get complicated, and this is the point that I think,

00:06:02   you know, now we're entering the danger zone, is the, what do I do?

00:06:07   I have this old implementation, and I have this new implementation, and in some ways,

00:06:13   there's a certain compatibility between them, where the old one, I could treat the old, you know, photos widget

00:06:19   as a sort of, a simple case of the new one, where the new one has a big image, a zoom factor,

00:06:27   an offset factor within that, and I could kind of, as suits, just take the old ones and say,

00: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."

00:06:37   And I could adjust the offset factors between them, and I could do it that way, and just sort of treat it

00:06:43   like it's an unzoomed thing. Or I could work out a different approach.

00:06:47   And this is the place where the terror begins, and the, I think, when I had one of those moments where,

00:06:53   I don't know if you've ever had this, where you sit down, and you're like, "I wonder if there's a number,

00:06:57   or something you're kind of, you know you need to look up, and you need to kind of look at,

00:07:01   but you're kind of scared about what the answer is going to be."

00:07:04   [Laughter]

00:07:06   Like, I knew I wanted to know how many photo widgets are out in production, because it's just a helpful tool for me,

00:07:13   to just decide this. But I kind of didn't want to know the answer, because my initial, my vague sense

00:07:19   is that it would be a large number. In fact, it would be a very large number.

00:07:23   And so, but I was a little bit like, I didn't want to look for it. I didn't want to look,

00:07:29   but I actually felt like I need to. And so I did a bit of back of the envelope math.

00:07:34   You know, I collect very limited analytics inside Widgetsmith, but I collect enough that I could kind of

00:07:39   estimate what this number probably is. And it ends up that I think there's something on the order,

00:07:45   this is a conservative estimate, but I think on the order of about a hundred million photo widgets

00:07:49   deployed out in the world right now. [Laughter]

00:07:54   Which, exactly, right? So like, you can either laugh, or you can cry if you're thinking of changing

00:08:03   the code that underlines the display of something on that many people's home screens. Like, on their

00:08:09   phone, with them doing nothing, they could just, an update could appear in the App Store that could somehow

00:08:14   horribly destroy something that's on their home screen, and it could do it tens of millions, if not

00:08:20   a hundred million times. So like... So wait, let me pause you here for a second. I'm very glad you looked up this number,

00:08:26   because that was a great moment for us. However, it blows my mind a little bit, but why did you need

00:08:32   to know the number? I think for me, it's getting the degree of difficulty for this, right?

00:08:40   And I mean, in some ways, maybe you're right. I can see where it doesn't actually matter. But in the sense of,

00:08:47   ultimately, 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

00:08:53   problematic for ten thousand people, any more than it would for something that would be problematic for ten million people.

00:08:59   But 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

00:09:05   cut any corners or get, like, you know, sort of get a little too fast and loose with this, because in some ways,

00:09:12   that's what put me in this problem in the first place, by not being thoughtful, by not going through as much

00:09:16   thoughtfulness as I could on this, and to make sure that I had an appropriate amount of terror sitting behind me

00:09:24   while 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

00:09:30   something that I would be able to sort of, like, undo or fix in a good way, if I do something kind of horribly wrong.

00:09:38   So, already, I mean, that number scares the crap out of me, and I don't even have any skin in this game.

00:09:44   Already, I'm already thinking of the approach you should take, if it were me. And if, I can tell you right now,

00:09:52   what I would do in this kind of context is, I would not touch a single line of code about the old widgets,

00:09:58   and I would just make a new photo widget type, and I would hide the old one from being available when creating new widgets.

00:10:08   So let the old widget type persist, and for new people who create new photo widgets, that follows a different code path.

00:10:16   Which is not the most, like, in the most ideal case, people with the old widget should just, it should just work,

00:10:22   and it should just get better over time. But the risks are so high here, as you said, I think in that kind of context,

00:10:28   I would just make a whole new one that's a totally separate class, totally separate code paths, and if people write in asking,

00: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."

00:10:42   And I think that's, it's not like the most elegant solution in the world, but I think it's the most pragmatic,

00:10:48   because it protects you, like, nerve-wise and liability-wise from accidentally disrupting all those widgets out there,

00:10:56   and I think people would be fine with that. I think most people are not going to care about the lack of grace on that,

00:11:01   and they're, you know, this is something like, they would care quite a bit if you broke their photo widget,

00:11:07   but if they want some new features and have to recreate it, I don't think they're going to care that much about that.

00:11:13   I'm very glad you said that, because that is exactly what I did.

00:11:16   Oh, awesome!

00:11:18   That is a strong encouragement to me that I did the right thing in this, and especially for you to say that,

00:11:23   because I feel like you have a bit more, like, I think you have less of a comfort, often with sort of like the hacks,

00:11:32   or doing things halfway, or feeling like that, like you tend to be a very complete developer,

00:11:38   whereas 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,

00:11:44   because basically, yes, I had the same, my thought was, I first, like, I built out a little bit of the version

00:11:49   where 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,

00:11:56   but then the more I thought about it, I'm like, something is going to go wrong here, and so I just took the,

00:12:00   instead took the approach of, there's, you know, if the widget has the old data, it uses the old system,

00:12:06   and, but as soon as you, if you add a new widget, or you add a photo to a one that had a photo before,

00:12:14   you know, so if you have, if you, you essentially have to go through the image picker again,

00:12:18   which I have to do anyway, because I need, I don't have the full resolution anymore,

00:12:23   so if you go through that, then you switch over to the new system, but it's like they are totally separate inside the code,

00:12:29   and they do nothing with each other, and if you, you know, if you did the, if you did this upgrade,

00:12:34   and never added another photo widget ever again, or even never launched the app again,

00:12:39   like, 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,

00:12:46   if 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,

00:12:52   and I think there's the issues of user communication, but obviously now, like, even a messaging for what features are available,

00:12:58   or 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,

00:13:04   that 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,

00:13:14   and so I'm going to just need to support it indefinitely, which is fine, I think probably, and I think obviously,

00:13:21   and 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,

00:13:32   at least in a debug mode, so that I can make sure I can, when I'm doing my testing and compatibility stuff,

00:13:38   and 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,

00:13:46   that 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,

00:13:52   nope, 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,

00:14:01   because the risk primarily is obviously that I somehow in the switch between the old and the new, I get something wrong,

00:14:06   but 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,

00:14:14   rather 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.

00:14:24   And 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,

00:14:31   it 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.

00:14:38   So all of those, the old data should persist, and so if somehow it all goes horribly wrong and I need to roll it back,

00:14:44   I can roll back to the old widget system and it should be completely unchanged as a result.

00:14:49   Yeah, 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,

00:14:57   like 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,

00:15:05   like then there's all these weird conditions that you'd have to accommodate for in order to do that safely at a large scale.

00:15:11   I 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.

00:15:23   He did, I have this in my notes to talk about later.

00:15:26   Oh yeah, about how,

00:15:27   Go ahead, yeah.

00:15:28   Yeah, 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,

00:15:38   and then roll it back, and I guess report back whether it worked or not.

00:15:42   And so like, I feel like if you were going to do that kind of migration at this kind of scale for something so important,

00:15:48   you would have to do something like that, where like, you would test a migration to a new system without actually removing the old data.

00:15:57   And being super careful about it to first make sure that all the data migration stuff succeeded and everything,

00:16:04   and wrap the whole thing in a giant try catch block, and just do everything possible to like, okay, try to do this,

00:16:13   but if it fails, fail silently and just tell me somehow.

00:16:17   And to be able to avoid that is very good.

00:16:23   Anyway, we are brought to you, talk about figuring out when you have problems. We're brought to you by Pingdom from SolarWinds.

00:16:30   While you've been listening to this podcast, how would you know if your website had gone down?

00:16:35   Would you know if customers couldn't click your buy button or fill out a trial form?

00:16:39   You might stumble across the problem by luck, just by like hitting refresh on your site occasionally,

00:16:43   but that means you've already lost out on who knows how many new customers.

00:16:46   You need something to tell you everything is running smoothly on your site, and more importantly, you need to know when it's not.

00:16:52   So you need Pingdom.

00:16:54   Pingdom detects around 13 million outages every month, more than 400,000 every day.

00:17:00   And for as low as $10 a month, Pingdom helps keep your sites online.

00:17:04   Whether you're a one-person company or a Fortune 500, you need real-time alerts about critical website issues,

00:17:11   and customization of how you're alerted, whether it's SMS, email, your team's collaboration apps, push notifications, whatever it is,

00:17:18   Pingdom lets you customize all of that.

00:17:20   They even track and analyze your website's load time so you can see what's affecting the user experience.

00:17:25   If you have a website or web service, you need Pingdom.

00:17:28   Take charge of monitoring your site in minutes?

00:17:31   Go to Pingdom.com/RelayFM right now for a 30-day free trial with no credit card required.

00:17:38   When you sign up, use the code RADAR at checkout to get 30% off your first invoice.

00:17:43   Thanks to Pingdom from SolarWinds for their support of this show and RelayFM.

00:17:48   So 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.

00:17:55   I'm glad that we both have agreed on the way forward from a technical perspective.

00:18:00   And then now it's these sort of like, how do you-- there's still some risk.

00:18:04   There's still some amount of danger involved in what I'm doing.

00:18:07   And 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,

00:18:14   and the way I'll test it, and the way I'll beta test it, and so on, because I think that's--

00:18:19   obviously the scale of the issue that I'm running into is pretty big.

00:18:23   I mean, there is one other angle to consider here, though.

00:18:27   A lot of times we as developers, we see some flaw in the way things are, and we think, I have to fix that.

00:18:35   I have to clean that up, modernize it, rewrite it, refactor it, whatever it is.

00:18:41   I have to fix this inadequate or hacky thing that's already there and working.

00:18:47   But do we? Do we really have to fix it? I feel like so often we don't ask that question of ourselves enough,

00:18:55   but a lot of these things, like, if the current thing is working, we probably shouldn't go messing with it.

00:19:01   Or it's not worth the risk, or it's not worth the effort, or it's not worth having to rewrite something

00:19:09   and then refix all the bugs that we fixed the first time and all the shortcomings,

00:19:12   because we wanted to do it in the new language or the new framework or whatever.

00:19:15   So often we pour tons of effort into something and take lots of risks in order to clean something up

00:19:23   or modernize something that the reality is, just leaving it alone would probably have been more pragmatic,

00:19:29   and at the end of the day, you're spending a lot of effort modernizing something that your customers

00:19:33   might not even notice or care about.

00:19:35   And so I feel like it's very important to ask ourselves that kind of question much more than we do now.

00:19:40   Ask ourselves when we're looking at a migration.

00:19:42   Because I'm facing all sorts of possible migrations and rewrites and everything that are on my wish list/to-do list,

00:19:49   because every to-do list is actually more of a wish list.

00:19:51   But I look at that and I think I could spend six months doing this,

00:19:56   or I could push this change out to the way I do things in the servers

00:20:01   and possibly cause a giant bad server day for myself, or I could just leave it alone.

00:20:07   And would that really be that bad to just leave it alone?

00:20:10   Yeah, and I will say I had the same thought with this feature,

00:20:13   and certainly in some of the more challenging parts of this process,

00:20:17   and the realization part where I was realizing the scope of the challenge that I was undertaking.

00:20:24   And I think it's a very good point and a good reminder, because I think it is definitely an area to be very thoughtful,

00:20:30   and make sure that if you're undertaking a dangerous migration or something that has a high-risk coding situation,

00:20:37   that you're doing it for a reason that isn't selfish.

00:20:44   Isn't something that is going to make the app better for the end user, not better for you.

00:20:51   That if it was something that I just need to deal with and manage going forward,

00:20:56   that me dealing with it and me taking that risk is in some ways irresponsible

00:21:01   if it only benefits me and isn't actually benefiting my customer.

00:21:04   Because ultimately what I'm doing is I'm making software to make people's lives better, to make them happy.

00:21:09   And if I am something that's just like there's this one little thing in it that annoys me,

00:21:17   and in the end I ruin someone's day because they had their widgets all set up the way they loved them,

00:21:22   and I do something that messes with that, those are disproportional. Those are not good things.

00:21:28   So I think it's definitely a good point. I will say I went through that with this,

00:21:31   once I really got down to, is this worth doing?

00:21:35   And 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,

00:21:42   and it makes photo widgets better.

00:21:45   And 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,

00:21:50   I don't think I could go back to the old version.

00:21:52   Because I love that when I add a picture of my kids to my widget, I can zoom in nicely on them,

00:21:59   just very easily and obviously.

00:22:02   And so it makes it that little bit more personal and a little bit more friendly.

00:22:07   And ultimately that's most of what I use the photo widgets for,

00:22:11   is if I have pictures of my family and friends and us on vacation or places we've been,

00:22:16   and being able to frame those pictures exactly the way that I would want has made the app better.

00:22:22   And so I don't think I could go back, but I think what you're saying is definitely a good important thing

00:22:27   and something that I think I'm glad to have gone through that thought process of who is this for

00:22:33   and why am I doing it and is it worth it?

00:22:35   And making sure that it's not just for a reason for me,

00:22:38   that it's ultimately a reason that I think will make people's, my users' lives better as well.

00:22:42   So yeah, and then I think in terms of the things that I'm doing now that I've like here is,

00:22:47   A, the first thing is I'm doing a huge amount of just general testing

00:22:54   in a way that is something that I feel like is so easy to sometimes skip over

00:22:58   when you're in a process like this, but is I'm loading it onto lots of different devices

00:23:02   and I'm downloading the app from the App Store, the previous version,

00:23:07   setting up a bunch of widgets, trying them and then installing the new version

00:23:12   and testing it and trying it and doing it on small phones, on big phones.

00:23:16   Thankfully with this, I don't have to deal too much with old OSes because everything requires iOS 14,

00:23:21   so there's a little bit of that but not too much that I need to worry about.

00:23:24   But it's like doing a lot of that and in some ways also I'm just sort of doing lots of data testing there,

00:23:29   which I think is an important thing to do.

00:23:31   And I think something that ultimately I'm going to do from this is in,

00:23:35   I believe in most versions of Xcode you've been able to do this for a while,

00:23:40   but you can capture a simulator snapshot of a particular configuration

00:23:46   and I'm planning to do a bunch of different snapshots of where the users are

00:23:51   and then I think you can restore that to a simulator for later testing.

00:23:56   But instead of gathering that user data and having those snapshots to be able to do testing with,

00:24:01   I think it's something that's always useful, so you have these baselines to install the new version on

00:24:07   and then run your new thing and make sure it doesn't break.

00:24:10   That's great. I had no idea.

00:24:12   I'll have the link in the show notes to instructions on how to do it,

00:24:16   but it's something I've done before where there's a way to kind of,

00:24:18   you can gather up a snapshot of a simulator, I'm pretty sure.

00:24:21   That was just a feature I dreamed of and it doesn't actually exist, but hopefully it does.

00:24:26   I think this is also a place to think about doing automated testing,

00:24:31   and this is where I'm sure all the unit testing people will be like,

00:24:33   "Yay, Dave's finally discovering unit testing!"

00:24:35   And no, that's not actually what I did.

00:24:37   Sorry, Casey.

00:24:39   What I did is I wrote that testing app that I didn't initially.

00:24:44   I set it up so that it would run a lot of my vision stuff and the new pan and zoom and all that.

00:24:53   It runs it against essentially every photo in my photo library,

00:24:57   which is tens of thousands of pictures.

00:25:00   I can just sit there and quickly go through lots and lots of pictures.

00:25:03   This is something that I found several issues with, which has been really helpful.

00:25:06   It's like the nature of any kind of, A, the vision stuff.

00:25:09   You can have these weird cases where the vision framework gives you back some weird value

00:25:14   that you may not have been expecting.

00:25:16   It's important to test it on lots of different things because it's trying to find a face.

00:25:21   That's what it's ultimately trying to do.

00:25:23   But sometimes it can think that, "Oh, this weird pattern in the corner is a face."

00:25:27   And so you get back a really weird-shaped face or something that when you try and zoom into,

00:25:33   if you don't handle it correctly, or if it's a face that's right on the edge of the frame,

00:25:37   you may accidentally try and over-offset and set the center to somewhere that doesn't exist.

00:25:43   And these are the issues that I found by just having essentially a testing harness,

00:25:47   a testing tool that lets me do that and lets me do it in a manual way that is high velocity.

00:25:55   And the reason I'm not using something like unit testing there is the nature of what I'm doing.

00:25:59   It isn't like there's a precondition and a postcondition that I can easily just put in code

00:26:04   and put down in what I want it to do.

00:26:06   It's a perceptual thing.

00:26:08   It's like when I hit the zoom to faces option, does it zoom to a pleasing crop of this person?

00:26:15   And I suppose I could unit test that it goes from this picture to this rectangle.

00:26:21   That's not actually what I'm worried about.

00:26:23   What I'm worried about is not cutting off people's faces and making people look weird,

00:26:28   which is very aesthetic and not something that I need to write another machine learning model,

00:26:33   I suppose, to validate my first machine learning model or something like that.

00:26:36   It doesn't make any sense.

00:26:39   And then I think the next thing I'm going to do is I think this is called chaos monkey testing,

00:26:44   which I just love the name of.

00:26:46   But essentially I just always do this kind of round of testing before a feature, especially a UI feature,

00:26:51   is just trying to break it by being kind of silly with it.

00:26:55   So like zoom, zoom, pinch, pinch, swipe, swipe.

00:26:57   Just open your phone to the feature and then just go crazy

00:27:01   and just be trying as best you can to do weird and unexpected things

00:27:06   or try and trigger race conditions or threading issues by changing the photo

00:27:13   and then immediately switch to the other view or the background of the app

00:27:16   and do this kind of like just introduce randomness into the use of the app.

00:27:21   And especially this is great to have someone who doesn't know the app or like your kids or someone be like,

00:27:25   "Here, try and break this screen and see if they can do it,"

00:27:29   because that's a good way to find these weird edge cases that you may not find otherwise.

00:27:34   And then lastly, I'm going to do a lot of beta testing,

00:27:36   and I expect there will be a link to a test flight in the show notes for this episode,

00:27:41   and I would appreciate any Under the Radar listeners to download it and try it

00:27:45   and install it, add photos, make sure their old photo widgets don't get broken in the process.

00:27:51   And this is one of those things where I'm very patient with this,

00:27:53   and part of why I'm doing it now is it's kind of this summer period

00:27:56   where I'm working on iOS 15 features long-term,

00:27:59   but in the short-term it's something that I can take my time with over the summer,

00:28:02   test and try, have people beta test for a long time,

00:28:06   not just like, "Oh, put the build out, get a couple hundred people to install it,"

00:28:11   and if it doesn't break or have big crashes, release it.

00:28:16   This is much more of something I want people to live with

00:28:18   and try and make sure there's not weird issues over time.

00:28:21   And then my last little mitigation strategy is I'm certainly going to use the App Store Connect

00:28:27   "Roll this release out slowly" thing, where you can roll it out to, I think,

00:28:32   as half a percent the first day and then one percent and then two percent,

00:28:36   and it slow rolls out so that you can expose this to a relatively small percentage of people initially,

00:28:43   and then watch like a hawk the customer support and all the places that people might talk about it

00:28:48   and make sure that the thing's coming up.

00:28:50   And I think you can even roll it out and then immediately pause the rollout,

00:28:54   which is something I've also done in the past where I can send it out to half a percent of people

00:28:59   and then leave it as half a percent of people for a week

00:29:04   and make sure that nothing comes up subsequently.

00:29:06   So anyway, that's all the things that I'm trying to do to mitigate my terror

00:29:11   and mitigate the fact that this is, I think, I don't think it's an exaggeration to say,

00:29:16   like the highest sort of risk bit of coding I've ever done.

00:29:19   Wow. Well, good luck with this.

00:29:22   Thank you.

00:29:24   We'll talk about this again because this is going to be hopefully a slow roll.

00:29:29   Yes. Hopefully sometime late, late in the summer there will be another episode where I talk about how well it went,

00:29:35   how all the preparation meant that it went off smoothly and effortlessly,

00:29:39   and no one even knew that it happened. It was just perfect.

00:29:42   Best of luck.

00:29:43   Thanks.

00:29:44   Thank you, everybody, for listening, and we will talk to you in two weeks.

00:29:47   Bye.