00:00:00 ◼ ► Welcome to Under the Radar, a show about independent iOS app development. I'm Marco Arment.
00:00:04 ◼ ► And I'm David Smith. Under the Radar is usually not longer than 30 minutes, so let's get started.
00:00:09 ◼ ► So today I want to talk through some things that I recently sort of had to work through in a big update that I did to
00:00:22 ◼ ► intentionally, but I'm not sure if wisely, but I intentionally decided not to implement in the big update that I shipped at the end of
00:00:36 ◼ ► offline hiking maps before you go out for walks. You know, so if you're going to an area that doesn't have great connectivity,
00:00:41 ◼ ► you have the ability to download your map ahead of time so that you can use it, use the navigation and planning features
00:00:53 ◼ ► which has been very well received and I've been very happy with the way that the feature turned out,
00:01:18 ◼ ► challenges in coming up with a way to do downloaded maps. I think there's lots of issues that I think maybe even talked about this
00:01:30 ◼ ► you're solving like three different problems at the same time and very different use cases.
00:01:36 ◼ ► are you going out for a hike that you know you're going to do a particular route and so you want to download the maps around
00:01:40 ◼ ► that route and then how wide around that route? Are you trying to download maps for a particular area just like around you?
00:01:47 ◼ ► But anyway, the end solution which I think works really well that I have now where I have this sort of
00:01:53 ◼ ► semi zoomed in map, but not too much that you can choose sort of blocks to download, which I find is very intuitive, works really well,
00:02:03 ◼ ► But it works well because it's very user focused in terms of it's very much about what are you doing today?
00:02:11 ◼ ► it's based on where you are physically and it's very much set up to the concept of I'm gonna go on this hike,
00:02:19 ◼ ► But the download, the deleting and sort of handling the deletion side of that, I turned out to be something
00:02:25 ◼ ► I found really complicated because I think that mechanism that I have in there now works well on the download side,
00:02:31 ◼ ► but doesn't really work very well on the delete side. And I tried a bunch of prototypes back,
00:02:37 ◼ ► I just couldn't come up with something that I liked and so I got to this point and this is I think the topic that
00:02:48 ◼ ► make sure that the feature is actually well received, that people like it, that it's intuitive,
00:02:54 ◼ ► because the way in which I would solve this problem, not that I knew with a solution at this point,
00:02:59 ◼ ► but I knew that whatever the solution I wanted it needed to sort of coordinate well with the actual,
00:03:06 ◼ ► the downloading part of this and so if I end up changing that because I get lots of feedback that it's super confusing or
00:03:11 ◼ ► doesn't work well or it's, you know, I'm going down this road, that would be problematic.
00:03:19 ◼ ► Or, I mean, there was a slightly naive part of me that hoped that like inspiration would strike
00:03:36 ◼ ► I didn't know how to solve it and it was one of those, I could spin my wheels on this for weeks or months
00:03:42 ◼ ► or who knows how long or I could just punt it and say, you know what, I'm not going to ship with this feature.
00:03:49 ◼ ► And it's, I think there's something interesting about this, about deciding whether a feature is missable.
00:03:55 ◼ ► Like you can just ship, you know, ship the app with sort of this incomplete feature and it'll be fine.
00:04:04 ◼ ► If you had the ability to download podcasts but not delete them, I don't think you could get away with that
00:04:09 ◼ ► because fundamentally like organizing your files is one of the core functionalities of that app.
00:04:16 ◼ ► Whereas for this, it's like you download these maps and the, basically the downside is that there's some extra files
00:04:21 ◼ ► hidden away that you can never see that are taking up space in your iPhone, which isn't great.
00:04:27 ◼ ► Like I totally wish that, you know, that I wasn't able, didn't have to have this consequence to a user
00:04:32 ◼ ► if they download these massive sets of maps that there's no way for them to get rid of them.
00:04:41 ◼ ► As long as the core functionality of your app is doable and you, you know, you can ship features that are on the,
00:04:48 ◼ ► sort of the sides of things that don't, you know, that aren't complete and that create these opportunities.
00:04:55 ◼ ► And I think it's maybe as soon as being honest with yourself that you are going to go and fix it.
00:05:04 ◼ ► So my largest mapping set, which is for the entire Lake District of the, in the UK, which is, I don't know,
00:05:15 ◼ ► Oh, okay. That's, that's significant. Yeah, I was gonna say like, you know, with podcasts, it's, it's, it's necessary
00:05:20 ◼ ► because you can accumulate a large podcast collection on your phone. And that does take up, you know, non-trivial
00:05:25 ◼ ► amounts of space. Whereas like, you know, I feel like a lot of a lot of tendency for us as nerds might be to
00:05:30 ◼ ► over optimize for this and to provide, you know, UI to delete things that are like, you know, 100 megs or
00:05:37 ◼ ► something, which like is like, logically a lot of space, but on a phone, like, you're never going to notice
00:05:42 ◼ ► that compared to like one app update from Uber or something like that. Right. But the other thing I wanted
00:05:48 ◼ ► to ask is like, could you theoretically rely on iOS is purgeable storage system for this?
00:05:54 ◼ ► So no. And specifically, because I once you've downloaded a map, I need the from the user's perspective, it is,
00:06:09 ◼ ► Because if they downloaded something and expect it to be there, then even if it's been a few weeks, and they've
00:06:14 ◼ ► had a, you know, they downloaded a bunch of movies that took up space, and so the purgeable thing, you know,
00:06:19 ◼ ► watchdog kicked off, I don't want it to go and download these files. So as far as the system is concerned,
00:06:24 ◼ ► I've, I am I they are set up as though they are like user documents that are not deleteable are absolutely,
00:06:30 ◼ ► you know, must stay there. Because, in theory, like, it's a safety concern, even that, like, someone is expecting
00:06:36 ◼ ► Yeah, you could like, take a picture on the top of a mountain and that kicks off the purge, and you lose your
00:06:41 ◼ ► Yes. And like that, that would that would not be good. That would that would very much not be a desirable outcome.
00:06:47 ◼ ► And so, yeah, so I had to do something to deal with it. I couldn't rely on the system to be purging these
00:06:53 ◼ ► files or managing them, which is, I think, in very, in a lot of ways, is something that you could reasonably do
00:06:59 ◼ ► for a lot of caches, you know, if you were viewing this more as a cache, then it will then as a user feature,
00:07:06 ◼ ► that was one of the big changes I made is previously, in the version before I did the offline mapping UI, I did
00:07:13 ◼ ► cache the user maps there. But because I was making no guarantees to the user, in that case, it was that kind of
00:07:20 ◼ ► like purgeable, you know, sort of caching store that would could come and go at any point. And the user, I was
00:07:27 ◼ ► making no, you know, expectations with the user that what they were doing would have a persistence. And while I did
00:07:33 ◼ ► persist for most of the time for many people, because unless you happen to download tremendous amounts of or
00:07:39 ◼ ► could, or like, you had to physically visit all of these places. So if you were like, I don't know, hiking for
00:07:44 ◼ ► hours and hours every day, like you're doing a through hike of the Appalachian Trail, maybe you could have
00:07:48 ◼ ► accumulated gigs of cached maps. But for most people, just would never have gotten to that because you had to
00:07:53 ◼ ► physically go to these places. Whereas now you have the ability to, you know, in one button push, you could
00:07:59 ◼ ► download, you know, areas, you know, hundreds of square miles of mapping tiles. And so it was a very different
00:08:05 ◼ ► problem at the once I reached that point. But I think it's one of these things that it's like, it's okay to not ship
00:08:11 ◼ ► something complete, which I think is weird, as something that I think very often we think about our designs as
00:08:16 ◼ ► wanting to be complete. And I think the difference is just one of these things that is, you know, bouncing around
00:08:20 ◼ ► my head this week, as I should ship this update, was this, like, it's that difference between a, it's better for
00:08:27 ◼ ► something to be missing than to be sort of bad, I think, generally, that I what I didn't want was to ship a bad
00:08:36 ◼ ► implementation of this. And we'll can talk through some of the actual things that I eventually was able to do to
00:08:40 ◼ ► this. But it's like, I think it was better to wait, and only ship something when I could actually be confident
00:08:46 ◼ ► that it was good that I'd found the solution that I wasn't just trying to shoehorn some solution into this problem,
00:08:52 ◼ ► because I felt like it was, you know, the app wasn't complete without it. It's like, it's better for it to be
00:08:56 ◼ ► complete. And like, as far as I know, I think I had one report in the last like, four months, five months, that this
00:09:03 ◼ ► app has been out there that people were like, complaining that they couldn't download the maps. And so like, it
00:09:08 ◼ ► turns out that was the right choice that I missing this feature was fine, until I could be confident that I actually
00:09:13 ◼ ► had the best solution. And I feel like this is one of the things I feel like we often run into with the way we talk
00:09:19 ◼ ► about Apple approaching problems is they don't necessarily they tend to not ship, sort of half baked solutions, they
00:09:25 ◼ ► tend to wait until they're fully baked. And once they're fully baked, then they release them rather than sort of
00:09:31 ◼ ► only, it's like, it's better for it to be missing and you know, just not there, and to ship the wrong thing and have
00:09:39 ◼ ► Yeah, it takes a certain level of patience and a little bit of gusto, I'd say, to be willing to do that. And, and the
00:09:46 ◼ ► thing is, like, you can do that badly, and it can blow up in your face to like, because it, the reason it takes a bit of
00:09:52 ◼ ► courage to ship, you know, to ship something that's lacking in certain features, or the same complete is that you got
00:10:00 ◼ ► to be really sure that's the right move. Because you're going to be judged by your customers and by reviewers, if
00:10:06 ◼ ► you're lucky to get reviews and stuff like that, you're going to be judged by what's there when you when you ship it.
00:10:10 ◼ ► And like that, like those one star reviews, or those press blog posts or whatever could be there for months or years
00:10:19 ◼ ► afterwards as what people see when they search for your app. So you have to really be sure that that whatever you are
00:10:25 ◼ ► intentionally omitting or deferring is not that important and is not like that, that not that many users are going to go
00:10:33 ◼ ► looking forward, expecting it to be there. And so I think in your case, I think you did find that balance and your
00:10:37 ◼ ► feedback shows that. But But certainly, this is not like a blanket lesson that like, oh, just ship that half your stuff,
00:10:42 ◼ ► and it'll be fine later. It's like, well, think about it firstly, be be a little careful about what what you are omitting
00:10:49 ◼ ► before you before you make that leap. And I think something like this, where it's like, I'm accommodating an edge case. I
00:11:01 ◼ ► Or similarly, I think there's an element of waiting until it's like this problem would get worse over time as people
00:11:07 ◼ ► download more maps. And so it isn't a problem. The first week I shipped the app, it's a problem months later, when they
00:11:13 ◼ ► have lots and lots of maps. And so it becomes this in some ways you can have been there's sometimes also benefits,
00:11:18 ◼ ► benefits where you can omit a feature that you know, won't be a problem until later. As long as you're disciplined in
00:11:25 ◼ ► actually getting it shipped before it becomes a problem, you can potentially also do that as well.
00:11:28 ◼ ► Yeah, or it could be you know, some kind of like technical detail. Like if I if I built a search index with every
00:11:33 ◼ ► episode you ever viewed and overcast, and I just never deleted anything from that search index, that wouldn't be a
00:11:38 ◼ ► problem. You know, it would be a couple 100 megs for a decent size podcast collection for a little while. But then after
00:11:44 ◼ ► like after 10 years, that could be a few gigs. And so like, you'd have to have some mechanism eventually, but you
00:11:51 ◼ ► could get away with it for a little while and it'd be fine. Yeah. All right, we're brought to you this episode by
00:11:55 ◼ ► Indeed. We're driven by the search for better when it comes to hiring, the best way to search for a candidate isn't to
00:12:01 ◼ ► search at all. Don't search match with Indeed. If you need to hire you need Indeed. Indeed is your matching and hiring
00:12:09 ◼ ► platform with over 350 million global monthly visitors according to Indeed data, and a matching engine that helps you
00:12:15 ◼ ► find quality candidates fast. So ditch the busy work, use Indeed for scheduling, screening and messaging. You can
00:12:21 ◼ ► connect with candidates faster. And Indeed doesn't just help you hire faster. 93% of employers agree Indeed delivers the
00:12:28 ◼ ► highest quality matches compared to other job sites, according to a recent survey by Indeed. Leveraging over 140 million
00:12:36 ◼ ► qualifications and preferences every day, Indeed's matching engine is constantly learning from your preferences. So the
00:12:41 ◼ ► more you use Indeed, the better it gets for you. Join more than 3.5 million businesses worldwide that use Indeed to hire
00:12:49 ◼ ► great talent fast. Listeners of the show get a $75 sponsored job credit to get your jobs more visibility at Indeed.com/undertheradar.
00:12:58 ◼ ► Just go to INDEED.com/undertheradar right now and support our show by saying you heard about Indeed on this podcast.
00:13:07 ◼ ► Indeed.com/undertheradar. Terms and conditions apply. Need to hire? You need Indeed. Our thanks to Indeed for their
00:13:17 ◼ ► So the actual solution I came up with, which is probably the next thing that's worth talking into, I think is interesting
00:13:23 ◼ ► as well, insofar as the reason I was stuck and the reason I felt like I needed to postpone this feature or omit it from the
00:13:29 ◼ ► start is because of this week, sort of there was a, there was a there was a step in the middle that like, you know, it's
00:13:35 ◼ ► like I had the had the problem, I sort of knew what I wanted the solution to be. But in the middle, there was the step
00:13:40 ◼ ► that was like, you know, just like in my notes that are just written as like, do the magic, like do the, like, there's this
00:13:47 ◼ ► thing of what I would do, because ultimately, what I want is to be able to present the user with a clear list of the
00:13:53 ◼ ► areas that they've downloaded as offline. But they've been downloading maps kind of higgledy-piggledy however they want,
00:14:00 ◼ ► whenever they were moving around, you know, there's all kinds of different mechanisms by which they can download them.
00:14:05 ◼ ► And so I didn't want this to be this issue. And this is the thing that reason I was going down this road is I get very
00:14:11 ◼ ► frustrated with other apps, like even Apple Maps or Google Maps, one of those when you have offline map sets is you
00:14:17 ◼ ► go to a similar place multiple times. And you end up with these like weird overlapping rectangles of, you know, this trip,
00:14:24 ◼ ► I went to this place. And so I downloaded it over here, and then this one over there. And you end up with these multiple
00:14:29 ◼ ► map sets that sometimes over set overlap, sometimes don't overlap. And if you delete one, will it delete the other map
00:14:34 ◼ ► set, even if it overlaps or intersects, like, you end up with these really awkward questions that I just didn't like that
00:14:40 ◼ ► kind of UI, but I wanted the conceptual sort of version of, you know, do I want to download the maps, or delete the maps
00:14:48 ◼ ► that I've downloaded for this particular place. And do the magic part is like coming up with that list of places that you
00:14:55 ◼ ► have maps for because, you know, they aren't specifically the user is not choosing the places I need to do the magic to
00:15:02 ◼ ► come up with them. And so that was the end of the end was like the reason I put, you know, pushed off is because I didn't
00:15:08 ◼ ► know how to do the magic or I didn't wasn't sure what the magic would look like. And but in the end, I think I was
00:15:12 ◼ ► actually able to get there. And I mean, and functionally, what I do at a technical level now is, I look through your
00:15:18 ◼ ► offline mapping, you know, tile sets, and I run an algorithm that sort of cleverly groups them together into what seemed
00:15:26 ◼ ► to be, you know, related places, you know, geographically, and into clusters that you can then look at and delete. So if
00:15:34 ◼ ► you, you know, went to a trip in whatever you went to Yosemite Valley, and your first time you only stay down in the
00:15:39 ◼ ► valley, but then the next trip you went and climbed Half Dome. And so now you have this extra sort of set of maps that
00:15:44 ◼ ► extend out from your first set, those will become, you know, a single set, and that becomes your Yosemite set or, you
00:15:51 ◼ ► know, but if you only visited a place once or you have, you know, you did only explored a very small area, it'll just group
00:15:58 ◼ ► that together and say that that's a particular set. And like that was the end, the magical step that that I think was
00:16:05 ◼ ► transformative and making this into something that works, where I can give you that kind of grouped UI, easy to delete,
00:16:11 ◼ ► easy to manage, you know, make it very easy to just, you know, say, Oh, well, you know, I don't want these maps from
00:16:16 ◼ ► Yosemite, because I'm not going to be there anymore, you just hit delete, and it'll clear them all out, rather than you
00:16:20 ◼ ► having to manage all the multiple trips, you may have gone there or the different places, it's sort of this slightly
00:16:25 ◼ ► smarter grouping mechanism. And once I was able to do that, like working out technically how to do that magic, then I
00:16:33 ◼ ► had the, you know, the now I had the UI, I wanted, I could do it, I could do it in a very performant way I could, like,
00:16:38 ◼ ► there's all these things that, you know, were the hard part that I just needed that data. And I think so often, it was
00:16:44 ◼ ► also the sort of the confirmation that the version of downloading was very well received. And so I was confident that I
00:16:51 ◼ ► needed a solution that didn't require the user to choose and name and manage the areas themselves. Because that was the
00:16:59 ◼ ► thing that I was trying to stay away from. And it seemed like it worked. And it seems like it's really been very well
00:17:04 ◼ ► received. Because obviously, if it's if the end solution was that I needed to end up doing what Apple Maps and Google
00:17:08 ◼ ► Maps do, where you build these like named areas, and you have all these overlapping rectangles, and if I had to go down
00:17:14 ◼ ► that road, because that's what users ultimately really wanted and demanded, then like, the deleting problem is super
00:17:20 ◼ ► easy. In some ways, you just like delete the thing that the user, you know, tells you to delete. But in my case, that
00:17:26 ◼ ► wasn't the case. And so once that was confirmed by user experience, then I just needed to do the work to build an
00:17:35 ◼ ► Jared Ranere: Yeah, and the UI that you came up with, like, I think what's what's great about like the the mechanic that
00:17:42 ◼ ► you found and implemented here is that when you see it, it looks totally obvious, like, of course, that's how this
00:17:48 ◼ ► should be done. And that's like, one of the great things about about good design is that that's like the the result of
00:17:55 ◼ ► good design always seems so obvious that no one quite appreciates the iteration and thought that went into it. Like,
00:18:04 ◼ ► because what you arrive at is like, Oh, of course, this is this is easy. Like, this makes total sense. This is the only way
00:18:11 ◼ ► it could possibly be done. It is that obvious. But it might have taken you quite a lot of iteration and time to get
00:18:17 ◼ ► there. But yeah, like, and I like, I like how you, you really are focusing on getting things working, getting things
00:18:26 ◼ ► shipped and getting things out there, even if it is not the most like, technically ideal solution at that moment,
00:18:33 ◼ ► because that's what indies have to do a lot of the time. I mean, that's what all companies have to do a lot of time,
00:18:38 ◼ ► honestly, but, you know, like, that's, that so often holds us back, like, we might optimize, you know, premature
00:18:45 ◼ ► optimization is the root of all delayed projects. We often try to optimize for things that, you know, for technical
00:18:53 ◼ ► purity or elegance at levels that it doesn't matter. And it's not to say that there are no levels that it does matter.
00:19:00 ◼ ► Like, you know, one of the major things I'm working on with the Overcast rewrite is performance when you have very
00:19:06 ◼ ► large podcast collections. The existing Overcast app that's been out there for 10 years is really not very
00:19:12 ◼ ► performant at all in certain areas once you have, if you have like a few hundred podcasts that you've ever listened to or
00:19:18 ◼ ► subscribed to. It, and that's something that like, when I was first making the app and designing all the data structures
00:19:25 ◼ ► and the concurrency model and everything, when I was first doing all that 10 years ago, I never considered somebody
00:19:30 ◼ ► might have 200 podcast subscriptions. I was like that, I was thinking maybe you'd have 20 or 10 or five, you know, not a
00:19:37 ◼ ► lot of people had hundreds of podcast subscriptions in, you know, 2014. But now many people actually have accumulated
00:19:46 ◼ ► that many. And so now the app is very, very slow. And so now I know which areas I had to optimize. And that's what I'm
00:19:54 ◼ ► doing with the rewrite. But there's other areas of the app where like, if I optimize something like crazy for something
00:20:01 ◼ ► like the display of a setting screen, nobody will ever care, no one will ever notice. It is not a good use of my time. And
00:20:10 ◼ ► even and again, going back to earlier, even the areas like for instance, if you are slow with with large collections, even
00:20:17 ◼ ► that, I really didn't need to do that for the first six or seven years of Overcast. Really, like, that's something that I was
00:20:26 ◼ ► able to ship something that was not necessarily incomplete, but certainly not ideal for large collection management. And it
00:20:33 ◼ ► did work fine and continues to work fine for many people. But it took until many years in before I had any any non
00:20:42 ◼ ► trivial number of customers who actually had large collections, and who actually and so where that would actually matter. So
00:20:49 ◼ ► it was fine for me to ship it in a simpler way with dumber, slower algorithms and simpler models inside the app. That was
00:20:57 ◼ ► fine 10 years ago. And now I can fix it now and I can improve it now with the rewrite. But I didn't really need to do all
00:21:05 ◼ ► that upfront back then. I mean, I wish I had in certain ways. But but you know, I couldn't have known that then. And then I
00:21:11 ◼ ► was focused on, let's get this app out there. And and I wrote the entire initial app in something like a year. And it it
00:21:19 ◼ ► now like the idea like I've been working on the rewrite now for so long, way longer than a year. So now the idea of that is
00:21:24 ◼ ► kind of kind of mind blowing, but be like I did learn back then. Or I learned now, looking back at what I did, like, that was
00:21:33 ◼ ► the right move back then to ship what I had back then with what I knew back then, even though it was incomplete in some ways,
00:21:40 ◼ ► there were many slow, slow, simple algorithms for certain things. But it worked. Yes. And there's, there's so many
00:21:47 ◼ ► opportunities for like, micro optimizations that we have today, that once you actually run them on a device, you realize this
00:21:54 ◼ ► does not matter at all. So you know, for instance, like, if you need to, you know, keep keep like, you know, an array versus a set,
00:22:02 ◼ ► and you want to see like, all right, I want to see if I've if this element already exists in the collection. That's way faster, in
00:22:09 ◼ ► most cases, if you use a set instead of an array. But unless you're dealing with large collections very frequently in some kind of,
00:22:15 ◼ ► you know, tight loop in your app, you probably won't notice that difference. And so if there's some other big advantage to that
00:22:22 ◼ ► thing being an array, instead of a set, when you have to test membership here and there, it's probably going to be fine. Like, you
00:22:28 ◼ ► know, and so and there are so many instances where we kind of get lost in the weeds with algorithmic purity and algorithmic
00:22:35 ◼ ► idea, ideology, almost really, for things that really don't matter very much, while maybe not having enough time as a result to
00:22:48 ◼ ► Jared Ranere: Yeah, and I think there's something that's, I ran into this so many times when I was doing my like magic bit in the
00:22:53 ◼ ► middle, where my computer, like I did have a bachelor's degree in computer science. And so like, I'm, you know, I'm trained for
00:23:01 ◼ ► what I do, which I know is not everyone who's a developer, has that background, where they actually were sort of trained in the
00:23:08 ◼ ► sort of the theory of computer programming and algorithms and those kinds of things. And sometimes I feel like that background
00:23:15 ◼ ► comes back to bite me, because I have in the back of my mind that there's, you know, what I think about the old, you know, sort of
00:23:25 ◼ ► Jared Ranere Exactly. And that was, this is the, that is the exact thought that I had when my first solution to my like grouping
00:23:32 ◼ ► algorithm for working out, you know, where are the areas that you have offline maps. And the first version I came up with was
00:23:38 ◼ ► this very naive, like, just compare the various points to all this, it's not like, you know, it's not quite every point to every
00:23:46 ◼ ► other point, but it's not that much far from that. It's a slightly clever version of that. But it's like, rather than having this
00:23:52 ◼ ► very, like I started in, you know, investigating these, all these algorithms you can do with this, you know, convex hull
00:23:58 ◼ ► creation of things that works out, and how does it work when the groups are combining and all like, it's got very complicated
00:24:03 ◼ ► very quickly. And I was like, oh, like, I only sort of understand this algorithm that I'm reading about. And if I only sort of
00:24:10 ◼ ► understand it, the chances of me implementing it successfully and correctly go down dramatically. So let's just start off by,
00:24:17 ◼ ► let's throw away the complexity and just do the super simple basic thing. And I have a very large offline map down, you know,
00:24:23 ◼ ► database with, you know, just thousands and thousands of square miles of mapping tiles. Let's see how fast it is to run. And I
00:24:31 ◼ ► build that very straightforward, simple version that does this, you know, this sort of simple grouping, and then the groups
00:24:35 ◼ ► combine if you have a point exists in multiple groups, and very straightforward, like the whole thing is maybe like 40 lines
00:24:42 ◼ ► of Swift, like very easy to understand, like straightforward algorithm. And I take it and I run it on an iPhone 10 R with my
00:24:50 ◼ ► full, you know, database. And the whole thing took, I think it was 0.2 seconds to run. And it's like, all right, that is, that is
00:24:58 ◼ ► good enough. Yeah, that is, that is too. And it's, especially because it's not an operation that the user is doing very often,
00:25:05 ◼ ► if at all. And that's on the oldest phone, essentially, that I support. If I run it on my, you know, my iPhone, whatever, I have
00:25:16 ◼ ► It is. And like I run it on that, it's, you know, it's rather than 0.2 seconds, like 0.02 seconds, like it's, it's essentially
00:25:24 ◼ ► instantaneous. And it's like, Oh, right, that this algorithm is totally fine. I don't need to make this more, you know, more
00:25:32 ◼ ► computationally pure and elegant and fancy. This version is fine. And that's amazing. And that's not to say that you should
00:25:38 ◼ ► never do the fancy algorithm like I have, you know, in my mapping engine, like the thing that actually is rendering the map
00:25:46 ◼ ► to the user, which is shown on the Apple Watch is shown on the iPhone showed in live activities, like there's all these places
00:25:51 ◼ ► that this mapping engine is used. I do a lot of the really tricky, complicated, you know, algorithm work, because that's
00:25:58 ◼ ► being updated, like once per second, and potentially on devices where battery life is really important. And so like, I need
00:26:04 ◼ ► that code to be super clever, to be super optimized to rather than, you know, any kind of waste or inefficiency, I want to get
00:26:12 ◼ ► out of it as much as I can so that it's super fast and important. Great, do it there. But it was interesting this time when I
00:26:18 ◼ ► started going down this, like, you know, I tend to do this thing where I'm starting to read, not like, you know, sort of
00:26:23 ◼ ► articles or Wikipedia posts or things about different algorithms and trying to decide which one makes the most sense. And in
00:26:28 ◼ ► the end, it's like, no, don't like just do the simple, obvious, basic thing that, you know, I can understand and then seems to
00:26:35 ◼ ► work great. And start there. And if that, you know, somehow that hadn't worked, if I'd run that on my massive offline
00:26:41 ◼ ► database, and it had, you know, taken 10 seconds to run, it's like, okay, well, that's not going to work, I'm going to need to
00:26:46 ◼ ► do something faster or better, or I need, you know, more magic or a different kind of magic in the middle. But it was
00:26:52 ◼ ► definitely a learning experience for me to like, just I shouldn't lean too heavily into those, you know, these courses I took,
00:26:58 ◼ ► whatever it was, like 25 years ago, at college, they were telling me, Oh, you know, if you anytime you have an n squared
00:27:03 ◼ ► algorithm, it's bad. It's like, no, it's probably fine. Like, even for reasonably large version, it depends on what n is. It
00:27:11 ◼ ► depends on how, like, even that, like, I maybe I'm doing 10,000 comparisons, or 100,000 comparisons. Like, maybe that's what
00:27:19 ◼ ► I'm doing. Like, it could be a relatively big number or a million comparisons, I don't even know. But the, the chips that my
00:27:24 ◼ ► app is running on can do a million comparisons in a fraction of a second. And so it's just not a problem that you need to
00:27:31 ◼ ► solve necessarily, unless it's an operation that is happening lots and lots of times, I wouldn't want to be inefficient
00:27:36 ◼ ► every second for 12 hours of a hike, that would be foolish. But if you're going to do it be slightly inefficient for two
00:27:44 ◼ ► tenths of a second, once every couple of weeks, that's probably fine. And that helps get the app out the door, it helps,
00:27:50 ◼ ► like me finish off this feature that I've been, you know, lingering around before and it means I can move on to, you know,
00:27:57 ◼ ► other features and, you know, focusing on things like the UI of the feature, which is way more important in many ways than
00:28:03 ◼ ► the, you know, the algorithmic purity of the way that I'm, you know, creating this data.
00:28:07 ◼ ► Jared Ranere: And rest assured, too, every single other app on your customers phones is going to be burning all that, like,
00:28:14 ◼ ► you know, wasted bandwidth, it's going to be burning that every single time they open the app, just like focusing, but like
00:28:19 ◼ ► reporting back to their analytics servers and running their own, like incredibly heavyweight everything operations that
00:28:24 ◼ ► they're doing to track every single possible thing you're doing and serve you ads, like, what you're doing is a drop in the
00:28:31 ◼ ► bucket. And I find like, it's helpful for me to, to actually like, you know, load up like I have, I have a couple of
00:28:38 ◼ ► overcast test accounts that I can log into that have hundreds of thousands of podcast episodes, like just huge
00:28:45 ◼ ► collections that, like, for the most part, I don't think any any user would actually have a collection that big. And I
00:28:50 ◼ ► can load it up in the old code where it just basically freezes and crashes. And I could load it up in the new code where
00:28:57 ◼ ► it's a little heavy, but it works. And I'm like, okay, now, like, now I've tried the extreme, like, that's the thing,
00:29:03 ◼ ► you try the extreme with something that you think is going to be too slow. And if the extreme case is usable, you're
00:29:09 ◼ ► probably okay. Especially like when you then go back to the common case, and it takes 0.2 seconds, like, it's fine,
00:29:14 ◼ ► you're gonna be fine. That's the theme of this episode is like, get it get it to work, it's probably fine, and move on, you