PodSearch

Under the Radar

47: Data Persistence

 

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

00:00:04 ◼   ► I'm Marco 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:10 ◼   ► So today we wanted to dive a little bit into the weeds,

00:00:14 ◼   ► go all the way down the stack, you know, as you kind of, you know,

00:00:18 ◼   ► if you were drawing one of those silly, what is it, OPML?

00:00:21 ◼   ► No, there's a fancy name for those kind of charts that you learn about in school,

00:00:26 ◼   ► but they never actually draw ever again.

00:00:28 ◼   ► How do you not know this?

00:00:30 ◼   ► I mean, I don't know what you're talking about, but I figured you are the master of charts.

00:00:33 ◼   ► You should know this.

00:00:34 ◼   ► Well, it's not a chart. It's like drawing. I'm terrible at drawing.

00:00:38 ◼   ► You're like a flow chart?

00:00:39 ◼   ► Well, I'm thinking of the one, you know, you go all the way down,

00:00:42 ◼   ► there's like, the database was always that cylinder that you would draw.

00:00:47 ◼   ► I don't know why it was a cylinder.

00:00:48 ◼   ► Like, is this back from the days when you had tape disks or something?

00:00:51 ◼   ► It was probably to represent like a hard disk.

00:00:53 ◼   ► Maybe. So, you have, when you draw your infrastructure diagram,

00:00:59 ◼   ► you always end up in the back with a little cylinder, and that's your database.

00:01:03 ◼   ► And it's, you know, an important part of applications in certain ways,

00:01:10 ◼   ► but I think the role that persistence has played, and even as you just noticed there,

00:01:15 ◼   ► I switched from using database to persistence,

00:01:17 ◼   ► is the way in which we think about storing data to then get back later

00:01:21 ◼   ► has certainly evolved over the last, you know, the last eight years of iOS

00:01:26 ◼   ► and of the App Store.

00:01:28 ◼   ► And I think it seems something that's worth getting into,

00:01:30 ◼   ► because there's such a variety of approaches that you can take for this,

00:01:34 ◼   ► where you go all the way on the one extreme to things like raw SQLite.

00:01:39 ◼   ► You can then take wrappers around SQLite.

00:01:43 ◼   ► You can have things that are like core data using SQLite,

00:01:47 ◼   ► which are Realm or all kinds of other kind of middlemen that are wrapper,

00:01:53 ◼   ► like very sophisticated wrappers.

00:01:55 ◼   ► You can start to get into systems where you have your own persistence system

00:02:01 ◼   ► that is writing files to disk.

00:02:03 ◼   ► You can start to get into just using NSUserDefaults and Keychain

00:02:08 ◼   ► and very lightweight things,

00:02:10 ◼   ► and then you can go all the way to the other extreme of having no persistence at all,

00:02:14 ◼   ► and I know of a variety of apps that are entirely unpersisted,

00:02:18 ◼   ► that other than like a user token, the app is entirely unpersisted.

00:02:23 ◼   ► And that flexibility is, I think, in many ways a direct result

00:02:29 ◼   ► of the increasing capability and connectivity of the devices

00:02:33 ◼   ► that we're writing apps for,

00:02:35 ◼   ► where I think if you imagine an app as this thing all on its own,

00:02:41 ◼   ► it's going to need a fairly sophisticated persistence system

00:02:44 ◼   ► because that is where the apps--

00:02:47 ◼   ► it needs to be able to function on its own,

00:02:49 ◼   ► and it needs to be able to do it in a way that,

00:02:51 ◼   ► if we go back in the day when you only had a 3G connection

00:02:54 ◼   ► connected to your iPhone,

00:02:56 ◼   ► you really couldn't expect the user to be able to download information very often,

00:02:59 ◼   ► so it has to be fairly self-contained,

00:03:01 ◼   ► whereas you can imagine now there are certain kind of applications

00:03:03 ◼   ► that are essentially just displaying a JSON blob to the user,

00:03:10 ◼   ► and maybe the data is in some ways also time sensitive.

00:03:15 ◼   ► Showing the data that you had cached a week ago would be kind of irrelevant.

00:03:20 ◼   ► So say, for example, like a weather app.

00:03:22 ◼   ► It's an example of an app I've written that has essentially no persistence

00:03:25 ◼   ► because the app's data is completely useless.

00:03:30 ◼   ► But I think it's an interesting thing to think about.

00:03:32 ◼   ► Where we--

00:03:34 ◼   ► Hi, I'm David Smith. My app's data is completely useless.

00:03:37 ◼   ► Hey, you know, sometimes-- I'm saying it's useless as soon as it's old.

00:03:43 ◼   ► Yeah, it's immediately out of date, basically.

00:03:45 ◼   ► It's immediately out of date. It's necessary.

00:03:47 ◼   ► As soon as I have my blob of weather data,

00:03:51 ◼   ► it's already starting to get out of date and fall out.

00:03:55 ◼   ► But anyway, getting back on my train of thought,

00:03:58 ◼   ► the other thing that has made persistence I think so interesting now

00:04:01 ◼   ► is the rise of extensions,

00:04:04 ◼   ► and this is something that I've been struggling with a lot this summer

00:04:07 ◼   ► of trying to keep all the various parts of our applications in sync.

00:04:12 ◼   ► So, Podometer++, for example, has an iPhone app,

00:04:16 ◼   ► it has a widget extension,

00:04:18 ◼   ► it has a watch extension, which actually is two parts.

00:04:22 ◼   ► One of them is just the UI, and the other part's the actual watch extension.

00:04:26 ◼   ► It has a SiriKit extension, and it has an iMessage extension.

00:04:30 ◼   ► And so I have five different sort of things that I have to keep data in sync now

00:04:35 ◼   ► that isn't syncing to a server, that is just syncing locally.

00:04:39 ◼   ► And so persistence is a really interesting and tricky problem now,

00:04:42 ◼   ► and I think what I find myself typically doing now

00:04:45 ◼   ► is I'm trying to simplify as much as I can my persistence

00:04:51 ◼   ► to a point that essentially most of my persistence now is just dictionaries

00:04:56 ◼   ► and sort of having these blobs of data that I can very easily move around

00:05:01 ◼   ► in a very lightweight way because I need to get data

00:05:04 ◼   ► so that when the watch app updates its step count,

00:05:08 ◼   ► that watch, that step count needs to, via watch connectivity,

00:05:11 ◼   ► find its way down into my phone,

00:05:14 ◼   ► which needs to find itself into the iPhone app,

00:05:16 ◼   ► it needs to find its way into the iMessage app,

00:05:18 ◼   ► it needs to find itself into the widget so that everything can stay in sync.

00:05:21 ◼   ► And so having some big heavyweight persistence scheme

00:05:24 ◼   ► that is doing some kind of really heavy database-oriented transactional things

00:05:30 ◼   ► or things just doesn't work, it's too heavyweight.

00:05:33 ◼   ► And so I'm starting to more and more just shift myself away from that

00:05:36 ◼   ► into dictionaries and that kind of stores.

00:05:40 ◼   ► And so far I've found that to be pretty effective.

00:05:43 ◼   ► Have you had to run into any of these kind of problems with Overcast

00:05:47 ◼   ► in terms of keeping various parts of the app in sync?

00:05:49 ◼   ► Oh, absolutely.

00:05:50 ◼   ► And in fact I've kind of gone the opposite direction as you over the years.

00:05:53 ◼   ► Well, sort of.

00:05:54 ◼   ► So with Instapaper early on, I was just using raw SQLite API in C

00:06:01 ◼   ► because I thought the speed and performance would matter.

00:06:04 ◼   ► And maybe at the time it did.

00:06:06 ◼   ► That was back on the iPhone 1, so it might have mattered back then.

00:06:09 ◼   ► I've slowly moved first into using FMDB

00:06:14 ◼   ► and then later on building on top of FMDB my own FC model system,

00:06:19 ◼   ► which is kind of a lighter weight than core data persistence layer

00:06:24 ◼   ► built on top of SQLite.

00:06:26 ◼   ► And for different apps that were not like my big app,

00:06:31 ◼   ► things like the magazine and Bugshot,

00:06:34 ◼   ► I've used different things there, either no persistence

00:06:37 ◼   ► or in the case of the magazine I first started out with just using

00:06:40 ◼   ► a bunch of plists that I would just write to disk.

00:06:43 ◼   ► And having dictionaries in plists is enough for a lot of apps.

00:06:49 ◼   ► And as you mentioned, kind of going towards that kind of area

00:06:53 ◼   ► with a lot of your apps, there's a lot to be said for that.

00:06:56 ◼   ► Just having very simple dictionaries in files,

00:07:00 ◼   ► there's a lot to be said to that.

00:07:02 ◼   ► The setup cost, the amount of effort it takes to start working on that

00:07:07 ◼   ► is extremely low.

00:07:09 ◼   ► The amount of complexity in the app is extremely low.

00:07:12 ◼   ► The bug potential in most cases, but not all, is extremely low.

00:07:17 ◼   ► And it's also just really fast. There's a lot to be said for that.

00:07:21 ◼   ► However, when you go to the more sophisticated database-backed systems,

00:07:26 ◼   ► things like core data, then you get a lot, you view it as heavy

00:07:33 ◼   ► or as maybe over-designed for your needs,

00:07:36 ◼   ► depending on what your needs are for the particular app.

00:07:38 ◼   ► But database systems give you a lot for free

00:07:42 ◼   ► that if you are using a file-backed system,

00:07:45 ◼   ► or a more manual or simple system,

00:07:47 ◼   ► that you have to either go without and hope it doesn't bite you

00:07:51 ◼   ► or you have to write it yourself, which is probably not a good idea.

00:07:55 ◼   ► So things like concurrent access to the same file not corrupting the data.

00:08:01 ◼   ► Things like, in your extension contexts,

00:08:05 ◼   ► having the data be able to be updated by one process

00:08:07 ◼   ► and then notifying the others that might be accessing it at the same time,

00:08:11 ◼   ► notifying them of the changes.

00:08:13 ◼   ► There are things like this that the good persistence layers will do already for you.

00:08:19 ◼   ► You don't have to write it.

00:08:21 ◼   ► And if you use them even for simple tasks,

00:08:23 ◼   ► it might be worth getting those features.

00:08:25 ◼   ► Now, they do bring complexity, for sure.

00:08:28 ◼   ► Core data, I'm not a huge expert in core data

00:08:31 ◼   ► because I only used it for basically the second half of the magazine

00:08:34 ◼   ► after I stopped using my P-list system.

00:08:36 ◼   ► So I used it very little and not recently.

00:08:39 ◼   ► So all this with a grain of salt.

00:08:41 ◼   ► But there are obviously complexities.

00:08:43 ◼   ► There's things like concurrent access from different threads

00:08:45 ◼   ► that you have to really be careful with.

00:08:47 ◼   ► Although, again, same thing.

00:08:49 ◼   ► You have to be careful when you're writing files, too.

00:08:51 ◼   ► There's things like dealing with schema migrations

00:08:55 ◼   ► that a lot of these layers do not make easy.

00:08:58 ◼   ► Possible crashes, like if the migration fails on an upgrade or whatever else,

00:09:03 ◼   ► or the database gets corrupt.

00:09:05 ◼   ► A lot of apps can't or don't handle that very well.

00:09:08 ◼   ► So there's lots of complexity if you take on some of the bigger systems

00:09:13 ◼   ► that you have to deal with.

00:09:14 ◼   ► But I would posit that in most cases for most apps,

00:09:18 ◼   ► if you're doing things like extensions or concurrent threads in one app,

00:09:24 ◼   ► you probably want those big systems

00:09:26 ◼   ► because they will take care of problems

00:09:29 ◼   ► that you would have to worry about if you were doing it yourself

00:09:32 ◼   ► with plists and stuff in your own app.

00:09:35 ◼   ► Does that make sense?

00:09:36 ◼   ► Yeah, it is such an interesting tension

00:09:39 ◼   ► that I feel like you find with these types of questions.

00:09:42 ◼   ► The thing that I hate,

00:09:44 ◼   ► one of the things I really don't like when I'm developing an app

00:09:47 ◼   ► is whenever I make a decision that is setting me on a path

00:09:51 ◼   ► where it will be difficult to change down the road.

00:09:54 ◼   ► So if I go file a new project in Xcode,

00:09:59 ◼   ► and it says, "Would you like to check the box to use Core Data?"

00:10:03 ◼   ► Now obviously that checkbox itself is not the--

00:10:07 ◼   ► I can obviously take it out or put it back in later.

00:10:09 ◼   ► But conceptually, I agonize over whether I'm going to push that button

00:10:14 ◼   ► because it feels like I'm setting myself--

00:10:17 ◼   ► I'm making a choice that has a lot of implications down the road.

00:10:20 ◼   ► And it's like I'm choosing which adventure I'm going to be going on.

00:10:26 ◼   ► Am I going to be going on the Core Data adventure

00:10:29 ◼   ► of finding weird threading issues

00:10:31 ◼   ► and dealing with merging in the background?

00:10:34 ◼   ► Whenever I've done Core Data, and I've done a lot of Core Data,

00:10:36 ◼   ► that seems to be the adventure you're on,

00:10:38 ◼   ► where the bugs you're going to have are related to that.

00:10:41 ◼   ► Or am I going to go down the road of a letter-weight file-based solution

00:10:46 ◼   ► where my bugs and issues are going to be cache invalidation or freshness,

00:10:51 ◼   ► those types of issues.

00:10:52 ◼   ► I'm just choosing which one I'm doing.

00:10:55 ◼   ► And really awkward is if your app involves any amount of user data,

00:10:59 ◼   ► as soon as you have that first version out in the world,

00:11:03 ◼   ► suddenly you are going to be responsible for maintaining that--

00:11:07 ◼   ► in some ways indefinitely, not truly indefinitely.

00:11:10 ◼   ► But you then have to start dealing with,

00:11:13 ◼   ► "Well, if I ever change my mind and want to do something different,

00:11:16 ◼   ► I'm going to have to build some kind of big migration.

00:11:19 ◼   ► I'm going to have to test it like crazy.

00:11:21 ◼   ► And I'm going to have to work really hard

00:11:23 ◼   ► to make sure that I don't break any user's data."

00:11:26 ◼   ► Because that's the nature of persistence.

00:11:30 ◼   ► You're trying to take something, put it on your phone,

00:11:32 ◼   ► and have it last indefinitely.

00:11:35 ◼   ► And so I really hate these kind of decisions

00:11:38 ◼   ► that we have to make in development, where it's not just like,

00:11:40 ◼   ► "Oh, Core Data isn't really working out for me right here.

00:11:43 ◼   ► I think I want to go to SQLite. Let me just do that."

00:11:46 ◼   ► It's like, well, there goes three months of my life,

00:11:48 ◼   ► transitioning from pulling the data out

00:11:51 ◼   ► and switching it into something else.

00:11:53 ◼   ► And that kind of a heavyweight decision, I think, is so awkward.

00:11:56 ◼   ► And also, it's probably also a fair thing to say,

00:11:58 ◼   ► that I think it is good to have the awareness that

00:12:01 ◼   ► because these decisions tend to have such high switching costs,

00:12:06 ◼   ► the discussion about which one you should use.

00:12:10 ◼   ► So if you are talking online,

00:12:12 ◼   ► or you're reading documentation or blog posts about these things,

00:12:15 ◼   ► people often become very passionate about them.

00:12:19 ◼   ► It's the old ViEmacs kind of problem,

00:12:22 ◼   ► where you become very passionate about your thing

00:12:25 ◼   ► and very defensive of it,

00:12:27 ◼   ► because the thought of having--

00:12:29 ◼   ► If someone else is actually correct,

00:12:31 ◼   ► in terms of, oh, some new persistent scheme comes out

00:12:34 ◼   ► that is objectively better than what you have

00:12:37 ◼   ► and what you've been using,

00:12:39 ◼   ► you have a problem, and you have a serious problem,

00:12:41 ◼   ► and you have this weird issue that you then feel bad about.

00:12:44 ◼   ► And so discussions with this are always kind of tinged in that way.

00:12:48 ◼   ► And so it's just a good disclaimer to kind of talk about,

00:12:50 ◼   ► because it's just such a high switching cost.

00:12:53 ◼   ► You can't just be like, "Yeah, you know, maybe I will use that.

00:12:56 ◼   ► Maybe I will drop this and switch to that."

00:12:58 ◼   ► I've done migrations like that,

00:13:00 ◼   ► where I've gone from one kind of data system to another.

00:13:03 ◼   ► And it is usually-- That is the worst part of my job ever,

00:13:07 ◼   ► and I try as best I can.

00:13:09 ◼   ► Once I make the choice, it's like, I'm just going to go with it,

00:13:12 ◼   ► and I'm just going to do the best I can.

00:13:14 ◼   ► I have a recipe book manager,

00:13:16 ◼   ► which is the most terrifying of my persistence needs,

00:13:19 ◼   ► because people are literally putting their family recipes,

00:13:23 ◼   ► things that are very emotionally important to them, into my app,

00:13:29 ◼   ► and they expect them to be there.

00:13:31 ◼   ► And I've had issues where I do a bad data migration in Core Data,

00:13:35 ◼   ► which is what I use for that app.

00:13:37 ◼   ► I do a bad data migration, and it corrupts some recipes.

00:13:43 ◼   ► That is terrible.

00:13:46 ◼   ► And so you have to be really thoughtful about these kinds of things.

00:13:50 ◼   ► And I think in some ways, as I go forward,

00:13:53 ◼   ► I'm getting less and less, wanting more and more lightweight things.

00:13:57 ◼   ► I'm almost in some ways trying to make fewer and fewer promises

00:14:00 ◼   ► and trying to have fewer situations

00:14:05 ◼   ► where I am really responsible inside of my app code

00:14:09 ◼   ► for taking care of something that's important to somebody,

00:14:11 ◼   ► that as soon as I can, like in my recipe book now,

00:14:15 ◼   ► I added a free sync system to it that takes all the--

00:14:19 ◼   ► essentially, I call it sync, most people just use it with one app.

00:14:23 ◼   ► It's just backup.

00:14:25 ◼   ► So I have a live backup of all their user data out into a database

00:14:29 ◼   ► that I can keep for them,

00:14:31 ◼   ► so that now when weird things happen to users' devices

00:14:34 ◼   ► and the persistence scheme goes crazy and Core Data gets--

00:14:37 ◼   ► it's not uncommon for me to get a request from somebody

00:14:40 ◼   ► that when I ask them for the crash log and it comes back

00:14:43 ◼   ► and I get the thing and it's just like,

00:14:45 ◼   ► it's a Core Data error that just says the SQLite file has become--

00:14:48 ◼   ► is malformed and cannot be opened.

00:14:51 ◼   ► And that happens all the time on iOS devices.

00:14:53 ◼   ► Like it happens-- one of the biggest culprits on iOS devices

00:14:57 ◼   ► is if the disk runs out of space,

00:14:59 ◼   ► then weird things can happen with your persistence layer,

00:15:01 ◼   ► depending on how it's done and what its settings are,

00:15:04 ◼   ► and that very frequently can corrupt SQLite databases.

00:15:08 ◼   ► It shouldn't, but in practice it does.

00:15:10 ◼   ► Or things like, you know, sometimes like,

00:15:13 ◼   ► when writing to the app container,

00:15:15 ◼   ► the share container between extensions,

00:15:17 ◼   ► sometimes those writes will just fail for some reason.

00:15:20 ◼   ► Or they'll be denied in some weird permissions error or something.

00:15:24 ◼   ► And it's like, well, then like,

00:15:26 ◼   ► if a write fails to your persistence layer,

00:15:28 ◼   ► then like that can also potentially corrupt the data that's there or something.

00:15:31 ◼   ► And it's like, this stuff happens all the time,

00:15:33 ◼   ► and it's so nice if you have the luxury

00:15:35 ◼   ► to be able to have in your app code, as I do in Overcast,

00:15:37 ◼   ► if the database file is corrupt,

00:15:39 ◼   ► just delete it and resync everything from the server.

00:15:41 ◼   ► Yeah, exactly.

00:15:43 ◼   ► And that's the place where persistence

00:15:45 ◼   ► and the really industrial-grade persistence stuff comes into play.

00:15:50 ◼   ► I love that-- I've been using-- I'm a Postgres guy.

00:15:54 ◼   ► I mean, you know you're a MySQL person,

00:15:56 ◼   ► but like, functionally it doesn't really matter.

00:15:58 ◼   ► Well, it doesn't matter. This is the thing. I don't care.

00:16:00 ◼   ► They're both great. I've just been using Postgres for a long time,

00:16:03 ◼   ► and so I know how to do it.

00:16:05 ◼   ► But the thing is, Postgres, like,

00:16:07 ◼   ► I've done some horrible things to Postgres databases,

00:16:10 ◼   ► and I've never lost data as a result.

00:16:13 ◼   ► You know, I've had weird situations where, you know,

00:16:15 ◼   ► I accidentally powered off the wrong server in the middle of something,

00:16:18 ◼   ► and like, it was in the middle of doing a migration,

00:16:21 ◼   ► and it got canceled halfway.

00:16:24 ◼   ► Like, those types of systems are designed for this kind of recovery

00:16:28 ◼   ► in a way that SQLite, which is, at the end,

00:16:32 ◼   ► what most of the persistence schemes on device use, aren't.

00:16:36 ◼   ► And so it's definitely something that I think now I'm leaning so much towards the,

00:16:40 ◼   ► "Let's get this all onto a nice, safe server somewhere

00:16:43 ◼   ► with some really proper, you know, backup,

00:16:46 ◼   ► whereas I don't have to worry about, like,

00:16:48 ◼   ► it's not the users doing backups and restores.

00:16:50 ◼   ► It's like, I'm doing backup and restore. I'm versioning the database.

00:16:53 ◼   ► I'm making sure that everything is nice and safe

00:16:55 ◼   ► in a way that, on device, like you said,

00:16:58 ◼   ► if something goes wrong, it's like, just say,

00:17:00 ◼   ► "Oh, I'm sorry, I need you to connect to the network

00:17:02 ◼   ► so I can go grab the most recent version of this."

00:17:05 ◼   ► And that, like, coding with that in mind,

00:17:10 ◼   ► I think, makes so many of these problems just go,

00:17:12 ◼   ► either go away or be so much less stressful.

00:17:14 ◼   ► - Yeah, because, and, you know, the reality is,

00:17:16 ◼   ► like, your customers will have, you know,

00:17:19 ◼   ► what if their phone, well, before the iPhone 7,

00:17:22 ◼   ► what if it falls in a toilet or something?

00:17:24 ◼   ► You know, like, they lose everything on their phone,

00:17:26 ◼   ► or their phone gets stolen, or whatever, their phone fails,

00:17:29 ◼   ► and they have to get a new one,

00:17:30 ◼   ► and they have to restore from backup.

00:17:31 ◼   ► Well, do they have a backup? How old is that backup?

00:17:33 ◼   ► And, like, the answer to those questions might be bad

00:17:36 ◼   ► for the data, and so if you just always have everything

00:17:40 ◼   ► synced to a server somewhere that you can always restore

00:17:43 ◼   ► back to the phone as soon as the user logs in,

00:17:45 ◼   ► and whether it's iCloud or your own stuff,

00:17:47 ◼   ► for this purpose, it doesn't really matter,

00:17:48 ◼   ► that is such a better place to be than trying to rely

00:17:51 ◼   ► on storing user data indefinitely,

00:17:53 ◼   ► just locally in the app, as you said.

00:17:55 ◼   ► - Oh, sure, 'cause I mean, even for,

00:17:57 ◼   ► and there's a couple of situations that I run into

00:17:59 ◼   ► that are a bit trickier for me,

00:18:00 ◼   ► because some of my apps use store health data,

00:18:04 ◼   ► and there's some very specific and complicated rules

00:18:07 ◼   ► around storing health-related data.

00:18:10 ◼   ► I mean, it's not like health in the sense of diagnosing diseases,

00:18:13 ◼   ► but, you know, steps, sleep data, activity data,

00:18:16 ◼   ► like, these are things that fall broadly

00:18:18 ◼   ► into the category of health data,

00:18:20 ◼   ► and so I currently, I don't store any of those

00:18:23 ◼   ► anywhere off-device, because if I had a server,

00:18:26 ◼   ► that had stored health data, suddenly there's all kinds

00:18:29 ◼   ► of regulatory things that I don't really know about,

00:18:32 ◼   ► that I'm sure exist, and I really don't want to know about,

00:18:35 ◼   ► that would start to come into play,

00:18:37 ◼   ► and there's rules about not using iCloud, necessarily,

00:18:40 ◼   ► but as a result, I do a lot of my backup and restore

00:18:43 ◼   ► using the either iTunes or iCloud backup system,

00:18:47 ◼   ► and it sometimes doesn't work.

00:18:49 ◼   ► Like, there's just no two ways around it,

00:18:51 ◼   ► where sometimes someone doesn't update.

00:18:53 ◼   ► You know, I've had a couple of these

00:18:54 ◼   ► this last couple weeks, where someone updates to iOS 10,

00:18:58 ◼   ► something goes weird in the update,

00:19:00 ◼   ► they restore from the backup, and the app state is just missing.

00:19:04 ◼   ► And there's nothing I can do.

00:19:06 ◼   ► - That's horrible.

00:19:08 ◼   ► - There's nothing that I can do for that person,

00:19:11 ◼   ► and, you know, and so, but it's a situation

00:19:14 ◼   ► where I wish I did have a means to back that up externally,

00:19:18 ◼   ► because there is nothing better when you have,

00:19:21 ◼   ► like, this has happened dozens of times with my recipe app,

00:19:24 ◼   ► where something happens to someone's device,

00:19:27 ◼   ► and they send an email that is just the, like, the panicked,

00:19:30 ◼   ► like, I have all of my family recipes in this app,

00:19:33 ◼   ► I've been using it, I love it, you know,

00:19:35 ◼   ► my kid threw the iPad out the window and it shattered,

00:19:39 ◼   ► and I didn't have a backup of the device.

00:19:42 ◼   ► Like, is there anything that can be done?

00:19:44 ◼   ► And there is the, it is just absolute,

00:19:46 ◼   ► it is an absolute joy to be able to go into this,

00:19:49 ◼   ► like, go into the admin panel, verify that, you know,

00:19:51 ◼   ► when I last, they last synced their system,

00:19:54 ◼   ► I'd be able to say to them, it's like, you know what,

00:19:56 ◼   ► I have 267 recipes, safe and sound,

00:19:59 ◼   ► whenever you get your new device,

00:20:00 ◼   ► log in with your credentials, and they'll all be back to you.

00:20:03 ◼   ► Like, that is amazing, that is, like,

00:20:05 ◼   ► you just made someone's day, and for what was otherwise,

00:20:08 ◼   ► it was gonna be a really, really bad day.

00:20:10 ◼   ► - I love that we chose to do this episode

00:20:13 ◼   ► on, like, the local persistence schemes that you use

00:20:16 ◼   ► in your app, and meanwhile, our conclusion is,

00:20:18 ◼   ► don't rely on them for anything. (laughs)

00:20:21 ◼   ► - That's true, but I think that is in some ways the point.

00:20:23 ◼   ► This is where I've been going to more and more.

00:20:25 ◼   ► It's like, there's, you can so easily get focused

00:20:28 ◼   ► on what is the best local scheme for doing this,

00:20:31 ◼   ► and the more and more of this I do,

00:20:34 ◼   ► the less and less I think that storing data on device

00:20:37 ◼   ► is a good idea for most apps, that I think most apps

00:20:40 ◼   ► benefit from instead of having their data locally,

00:20:43 ◼   ► pushing it somewhere else, where they, like you said,

00:20:45 ◼   ► whether that's iCloud, whether that's your own servers,

00:20:47 ◼   ► whatever, the more that you can push your data somewhere else

00:20:51 ◼   ► and then be pulling it down as needed,

00:20:53 ◼   ► the better you're gonna be, because there's just

00:20:55 ◼   ► so many issues that you're gonna run into otherwise.

00:20:59 ◼   ► - And if you do wanna run your own servers,

00:21:01 ◼   ► our sponsor this week is perfectly timed, it's Linode.

00:21:05 ◼   ► So Linode, Linode is a wonderful web host

00:21:08 ◼   ► with high performance Linux SSD servers,

00:21:10 ◼   ► spread across eight data centers around the world.

00:21:12 ◼   ► They're a fantastic solution for your server infrastructure.

00:21:15 ◼   ► Linode offers servers that you can get up and running

00:21:17 ◼   ► in just under a minute, with plans starting at just $10

00:21:20 ◼   ► a month, and that now gets you two gigs of RAM

00:21:22 ◼   ► for 10 bucks a month, so that could be, I mean,

00:21:24 ◼   ► look, these servers are powerful, these are really fast,

00:21:26 ◼   ► we use them, I have, I think 12 Linode instances

00:21:29 ◼   ► that I run Overcast on, plus one for market.org,

00:21:31 ◼   ► plus one for some accessory stuff, I have lots of Linodes.

00:21:34 ◼   ► I bet most apps could get away with the $10 a month plan

00:21:38 ◼   ► for all of their user data.

00:21:40 ◼   ► It's really, you get a lot for the money here.

00:21:42 ◼   ► Anyway, Linode is great for other tasks.

00:21:44 ◼   ► Also, things like if you wanna run your own private

00:21:46 ◼   ► Git server, if you wanna host large databases,

00:21:49 ◼   ► like 267 recipes, if you wanna run a mail server,

00:21:52 ◼   ► if you wanna operate powerful apps, and so much more.

00:21:55 ◼   ► With industry-leading native SSD storage

00:21:58 ◼   ► and access to a 40 gigabit network,

00:22:00 ◼   ► you will have all the power you need

00:22:01 ◼   ► to get your tasks done at Linode.

00:22:03 ◼   ► Now, if you're a listener of this show,

00:22:05 ◼   ► sign up at Linode.com/Radar.

00:22:08 ◼   ► You'll not only be supporting us,

00:22:09 ◼   ► but you'll also get $20 towards any Linode plan.

00:22:12 ◼   ► You can also use code radar20 at checkout

00:22:15 ◼   ► to get that same deal.

00:22:16 ◼   ► So, there's a seven-day money-back guarantee.

00:22:17 ◼   ► There's nothing to lose.

00:22:18 ◼   ► Go to Linode.com, spelled like Linux, but Linode.

00:22:21 ◼   ► Linode.com/Radar to learn more,

00:22:24 ◼   ► sign up and take advantage of that $20 credit

00:22:26 ◼   ► or use promo code radar20 at checkout.

00:22:29 ◼   ► Thank you so much to Linode for supporting this show.

00:22:32 ◼   ► So, I think it's worth also mentioning,

00:22:35 ◼   ► you mentioned at the end of the last segment

00:22:37 ◼   ► about how it's actually becoming more and more useful

00:22:39 ◼   ► to not store anything on the device

00:22:41 ◼   ► and just always fetch it from the server.

00:22:43 ◼   ► Back when I first started developing,

00:22:45 ◼   ► which was Instapaper back then,

00:22:47 ◼   ► offline access was a big deal, especially for that app.

00:22:50 ◼   ► That was kind of the point of it,

00:22:51 ◼   ► and that was a major feature of it.

00:22:54 ◼   ► And I think over time, we've slowly had times

00:22:58 ◼   ► in which we are offline have slowly eroded

00:23:01 ◼   ► out of people's lives, and they're still there.

00:23:03 ◼   ► There are still occasions where people are offline,

00:23:06 ◼   ► but that is getting really few and far between.

00:23:09 ◼   ► I mean, now, you can now even use devices on planes

00:23:13 ◼   ► during takeoff and landing.

00:23:15 ◼   ► You can be online for the entire middle part

00:23:17 ◼   ► of the flight if you want to,

00:23:19 ◼   ► and that's only gonna get more and more common over time.

00:23:21 ◼   ► A lot of subways, like underground transit systems,

00:23:25 ◼   ► where there was no reception 10 years ago,

00:23:29 ◼   ► they're starting to get cell reception, cell coverage

00:23:31 ◼   ► in a lot of them now.

00:23:32 ◼   ► There's more and more areas where people

00:23:34 ◼   ► have more and more connectivity.

00:23:36 ◼   ► Offline access is one of the only reasons

00:23:40 ◼   ► why you would store data locally

00:23:42 ◼   ► for a lot of server-backed apps,

00:23:44 ◼   ► and I think it's very reasonable for a lot of apps today

00:23:48 ◼   ► to just be like, "Sorry, we don't work offline,"

00:23:50 ◼   ► because the actual demand for getting the app

00:23:54 ◼   ► to work offline is just shrinking dramatically over time.

00:23:58 ◼   ► - Yeah, and I think there's something, too.

00:24:01 ◼   ► It's changing the user's expectations,

00:24:05 ◼   ► and it changes from a persistence problem

00:24:07 ◼   ► to a caching problem, because I think of even an app,

00:24:10 ◼   ► say like the app like Instagram, right,

00:24:12 ◼   ► or Tweetbot, I think is another app sort of like this,

00:24:14 ◼   ► where you have these apps that are essentially server-based.

00:24:18 ◼   ► What you're showing by its nature is somewhat time-bound,

00:24:22 ◼   ► and so you're always going to want to get the latest stuff.

00:24:25 ◼   ► And my expectation for that app, though,

00:24:27 ◼   ► is that when I open it, if I'm offline,

00:24:30 ◼   ► that something reasonable happens.

00:24:32 ◼   ► It's not just like frowny face, "Sorry."

00:24:36 ◼   ► Instead, what I see in both of those apps

00:24:38 ◼   ► is they show some kind of cache of whatever it is.

00:24:42 ◼   ► It's the last data that they showed you.

00:24:44 ◼   ► It's some version of that,

00:24:47 ◼   ► and I think it's a difference in framing,

00:24:50 ◼   ► but I think that is a significant difference

00:24:52 ◼   ► in user expectation, where if you can change the mindset

00:24:56 ◼   ► from true persistence, from it being a peer with your server

00:25:01 ◼   ► to being just a sort of a dumb client that does caching,

00:25:05 ◼   ► and it's not persistence, really, it's just caching.

00:25:08 ◼   ► You know, caching is certainly a problem.

00:25:10 ◼   ► It's what they always say.

00:25:12 ◼   ► It's one of the three biggest problems in computer science

00:25:14 ◼   ► is cache invalidation.

00:25:16 ◼   ► It's not an easy problem, necessarily,

00:25:17 ◼   ► but it's something that is definitely more straightforward,

00:25:22 ◼   ► where if you always assume that the server is in charge

00:25:25 ◼   ► and you can reasonably have access to it most of the time,

00:25:29 ◼   ► you get away with it, you cache and show

00:25:31 ◼   ► whatever you last had otherwise.

00:25:33 ◼   ► And I've definitely built apps where sometimes this can even get

00:25:36 ◼   ► really, really simple, and I love when an app can--

00:25:39 ◼   ► like, there's a really easy, elegant solution

00:25:41 ◼   ► for something like this, where if your app just persists--

00:25:44 ◼   ► you know, downloads JSON and shows it to the user,

00:25:48 ◼   ► well, why don't you just go ahead and cache

00:25:50 ◼   ► your JSON requests as you do them,

00:25:52 ◼   ► and you can use exactly the same logic if you're offline

00:25:55 ◼   ► when you're online to just load the last JSON blob

00:25:58 ◼   ► that you had and display that to your user.

00:26:00 ◼   ► Like, you don't even need persistence in a way of,

00:26:03 ◼   ► you know, there's some kind of complicated mapping

00:26:05 ◼   ► that's turning it into something else.

00:26:07 ◼   ► It's like, nope, it all just starts at the end of the day.

00:26:09 ◼   ► It's like it all is just these plain text files at the end,

00:26:13 ◼   ► which maybe it's another analog to where, like, blogging

00:26:16 ◼   ► or any of these systems where if you can ultimately end up

00:26:20 ◼   ► just with plain text, you're almost always on the right path.

00:26:23 ◼   ► - Well, also, like, you know, like, that approach

00:26:25 ◼   ► of just using cached things from a server,

00:26:28 ◼   ► you can often get exactly what you need from that

00:26:31 ◼   ► with just the built-in NSURL cache system

00:26:33 ◼   ► that you can access from every network request in iOS.

00:26:37 ◼   ► Like, there is this entire caching layer, like, you know,

00:26:40 ◼   ► if people who make network requests, you ever wonder

00:26:42 ◼   ► what that caching policy option does?

00:26:44 ◼   ► Well, it turns out if you dive deeply into that,

00:26:46 ◼   ► there is a lot of control you have.

00:26:48 ◼   ► You can basically customize the entire layer,

00:26:50 ◼   ► customize every request.

00:26:52 ◼   ► You don't even have to control the API.

00:26:54 ◼   ► You can modify the cache behavior of requests

00:26:56 ◼   ► as they come in.

00:26:57 ◼   ► Like, you can, there is so much you can do

00:26:59 ◼   ► with just effectively basic HTTP caching

00:27:02 ◼   ► and, you know, basic cache and validation headers,

00:27:05 ◼   ► like, you know, the expires headers and ETags

00:27:07 ◼   ► and stuff like that, and that's all built in.

00:27:09 ◼   ► So you don't even necessarily have to think about where,

00:27:13 ◼   ► you know, do I need to write this file to disk

00:27:15 ◼   ► in a certain spot?

00:27:16 ◼   ► You know, how do I expire this data?

00:27:18 ◼   ► No, you can let the system handle it for you.

00:27:20 ◼   ► There's tons of functionality built in

00:27:22 ◼   ► just by using the built-in URL loading system.

00:27:24 ◼   ► Sure, and that's even better.

00:27:25 ◼   ► I mean, that sounds like a wonderful thing.

00:27:27 ◼   ► I mean, now that you're saying that, I'm like,

00:27:29 ◼   ► man, I've been doing this the wrong way for a little bit

00:27:31 ◼   ► because I tend to write the files to disk.

00:27:33 ◼   ► But, yeah, like, the less that you can do, the better.

00:27:39 ◼   ► Yeah, if you can just say, you know, hey,

00:27:41 ◼   ► keep around the last version of a request you made

00:27:44 ◼   ► or, like you said, when you start to get into ETags

00:27:46 ◼   ► and expires headers and things that are, like,

00:27:48 ◼   ► purpose-built for this purpose,

00:27:50 ◼   ► that you're not having to build anything for it.

00:27:52 ◼   ► Like, yours, if you have a well-behaved web service,

00:27:56 ◼   ► it probably is doing a lot of this for you anyway.

00:28:00 ◼   ► The ability to do this kind of stuff,

00:28:01 ◼   ► that you can then just not worry about it,

00:28:03 ◼   ► and your app just makes a request,

00:28:05 ◼   ► and if you're offline, you get the cached data,

00:28:07 ◼   ► and if you're online, you get the fresh data,

00:28:10 ◼   ► and, you know, don't worry about it.

00:28:12 ◼   ► And you've got to be careful, certainly,

00:28:14 ◼   ► as with all these things.

00:28:15 ◼   ► Like, I notice this when I travel internationally.

00:28:18 ◼   ► It's usually when I run into this kind of issue,

00:28:21 ◼   ► where you start to really notice which apps do a good job

00:28:23 ◼   ► of handling poor connectivity situations

00:28:26 ◼   ► or no connectivity situations.

00:28:29 ◼   ► But the reality is, if you worry about those edge cases too much,

00:28:35 ◼   ► you'll end up making your app worse overall, I think.

00:28:38 ◼   ► And so being careful about not getting too worried.

00:28:41 ◼   ► It's like, well, what if someone's going on an epic expedition

00:28:45 ◼   ► and they're going to be not connected to the internet

00:28:47 ◼   ► for a week at a time, should they still be able to use the app?

00:28:51 ◼   ► It's like, well, maybe. I don't know.

00:28:54 ◼   ► It's like, if you have a really compelling reason, great.

00:28:57 ◼   ► But if you don't, don't over-engineer it,

00:28:59 ◼   ► just because you think you maybe should or could.

00:29:02 ◼   ► Right, because any of that engineering,

00:29:04 ◼   ► not only does it take a lot of time and energy

00:29:06 ◼   ► that you could be spending on features,

00:29:07 ◼   ► but it also introduces tons of bug potential.

00:29:10 ◼   ► So the least persistence you can do, the better.

00:29:14 ◼   ► And I think your example there is great.

00:29:16 ◼   ► It's like, if someone's going to be out away from connectivity for a while,

00:29:19 ◼   ► well, is your app really that useful to somebody

00:29:22 ◼   ► if everything in it is stale anyway?

00:29:24 ◼   ► It depends on the app.

00:29:25 ◼   ► If it's something like a podcast player, yes,

00:29:28 ◼   ► people can load up on a podcast and live off them for weeks.

00:29:30 ◼   ► But if it's something like a Twitter client, no,

00:29:32 ◼   ► that's not going to be useful to them.

00:29:34 ◼   ► So it depends on the app, but I think the answer for most apps

00:29:37 ◼   ► is probably you don't really need to worry about it.

00:29:39 ◼   ► Exactly.

00:29:40 ◼   ► All right, well, we're out of time this week.

00:29:42 ◼   ► Thank you, everybody, for listening, and we'll talk to you next week.

00:29:45 ◼   ► Bye!

00:29:46 ◼   ► [BLANK_AUDIO]