PodSearch

Under the Radar

4: Unexpected Complexity

 

00:00:00 ◼   ► Welcome back to Under the Radar, a show about independent iOS 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 I think we wanted to talk about probably one of the most common

00:00:15 ◼   ► but yet challenging parts of being a developer, at least in my experience,

00:00:19 ◼   ► and that deals with unexpected complexity.

00:00:23 ◼   ► When you start off working on something and you have kind of an expectation

00:00:27 ◼   ► of how complicated it's going to be to do, what it's going to look like, the effort involved,

00:00:30 ◼   ► the time involved. And then you sit down, you open up Xcode, you start programming, and it turns out

00:00:36 ◼   ► that it's a complete nightmare and it's going to be way more effort and way more work.

00:00:41 ◼   ► And that experience happens so often that I think having a good process and mindset about dealing

00:00:48 ◼   ► with it is one of the very important things of being able to ship software in a reasonable time

00:00:54 ◼   ► and reasonable quality.

00:00:56 ◼   ► And I think we both recently had an experience

00:00:57 ◼   ► that kind of fell into that category,

00:01:00 ◼   ► and so this episode I think will be more

00:01:03 ◼   ► of a case study style in terms of talking

00:01:06 ◼   ► through our experiences.

00:01:07 ◼   ► And so I believe that is the experience that you had

00:01:11 ◼   ► when you were working on the streaming engine

00:01:12 ◼   ► for Overcast, am I right?

00:01:14 ◼   ► - Oh yeah.

00:01:15 ◼   ► I mean streaming as a feature,

00:01:17 ◼   ► so Overcast is a podcast player,

00:01:19 ◼   ► and the built-in Apple APIs for playing media using AVPlayer,

00:01:24 ◼   ► most of that stuff supports streaming out of the box.

00:01:29 ◼   ► You don't really have to do much to enable it.

00:01:32 ◼   ► I mean, depending on how much you want your interface

00:01:35 ◼   ► to behave, you don't necessarily have to do anything.

00:01:37 ◼   ► So it's relatively easy to support streaming media

00:01:41 ◼   ► just as well as you do locally played media

00:01:43 ◼   ► if you're using AVPlayer.

00:01:45 ◼   ► But one of Overcast's biggest selling features,

00:01:47 ◼   ► and one of the things that makes it most compelling,

00:01:50 ◼   ► both to me and to many of the users,

00:01:52 ◼   ► is my custom audio engine with a feature called Smart Speed,

00:01:56 ◼   ► where Smart Speed dynamically adjusts the playback.

00:02:00 ◼   ► And the way it works is there's a processing function that

00:02:06 ◼   ► needs to read in the audio samples

00:02:09 ◼   ► in the middle of the processing stream

00:02:11 ◼   ► and then output possibly a different number of them

00:02:15 ◼   ► if it's speeding up the sound.

00:02:16 ◼   ► So it might take in 500 samples,

00:02:20 ◼   ► and then the middle of it might be silence

00:02:22 ◼   ► as it detects silence, so it might compress that

00:02:25 ◼   ► down to 300 samples.

00:02:26 ◼   ► So you need the ability to inject into the processing stage

00:02:31 ◼   ► a function that can read faster than it can output.

00:02:34 ◼   ► And that is not possible with AVPlayer.

00:02:37 ◼   ► There's no mechanism to do that that I have found at all.

00:02:41 ◼   ► If anyone knows, I'm really curious,

00:02:42 ◼   ► but I have looked many times,

00:02:44 ◼   ► every time there's a new SDK I look,

00:02:46 ◼   ► I've asked Apple engineers at WWDC and in labs and via email, and it really does seem

00:02:51 ◼   ► like it is just not possible with AVPlayer.

00:02:54 ◼   ► So the way I do this is I actually just wrote the, I basically wrote my own AVPlayer.

00:02:58 ◼   ► It's not a small task, and I'm writing at the core audio and audio units levels, and

00:03:06 ◼   ► custom decoding of everything.

00:03:08 ◼   ► And when you go lower level to enable this, the easiest way to do it is something called

00:03:13 ◼   ► called the ext, geez, ext audio file API.

00:03:17 ◼   ► And that is, that only works for locally stored files,

00:03:22 ◼   ► it does not work for streams.

00:03:26 ◼   ► There's a separate API, the audio file stream API

00:03:28 ◼   ► that is lower level than that.

00:03:30 ◼   ► And that you can supply stream data to.

00:03:33 ◼   ► You still have to manage the fetching of the stream yourself

00:03:36 ◼   ► and you have to manage a lot yourself.

00:03:39 ◼   ► So the job of streaming was to convert

00:03:42 ◼   ► from that ext audio file API that only does local files

00:03:46 ◼   ► to the lower level audio file stream API.

00:03:49 ◼   ► And also then build out all the UI behind it,

00:03:52 ◼   ► build out the network fetcher,

00:03:54 ◼   ► the actual streamer that can stream things,

00:03:56 ◼   ► and of course make it all performant

00:03:58 ◼   ► and responsible of data usage and memory

00:04:01 ◼   ► and responsible of the CPU

00:04:04 ◼   ► and also handle a whole bunch of weird edge cases.

00:04:08 ◼   ► And I knew it was gonna be a big job going in,

00:04:11 ◼   ► but I didn't quite realize how big,

00:04:14 ◼   ► how many of those edge cases they would be,

00:04:16 ◼   ► how tricky some of them would be to solve.

00:04:18 ◼   ► And the biggest thing,

00:04:19 ◼   ► like when we're talking about unexpected complexity,

00:04:22 ◼   ► the biggest thing for me is unexpected time that it takes.

00:04:26 ◼   ► You know, this is why our business is historically so bad

00:04:29 ◼   ► at estimating time and ship dates.

00:04:32 ◼   ► And when you're independent,

00:04:33 ◼   ► I don't think we're any better at it.

00:04:34 ◼   ► You know, I think in many ways, it might be worse.

00:04:38 ◼   ► Do you find that you are good at estimating time?

00:04:41 ◼   ► I think the honest answer is that I've stopped estimating time, or even trying to.

00:04:48 ◼   ► I have found that it doesn't actually help.

00:04:52 ◼   ► I have this vague sense of like, sometimes I have, the only deadline I usually have is

00:04:56 ◼   ► a new device is being shipped, or a new OS is being shipped.

00:05:00 ◼   ► There's something specific that like, if I want to be there on day one of the iOS 9 launch,

00:05:05 ◼   ► then I need to have my app ready by the beginning of September.

00:05:10 ◼   ► Other than that, I try hard to not think too much about timelines because every time I've

00:05:16 ◼   ► tried to do that, it never works.

00:05:19 ◼   ► The most universal experience of software engineering is you think it's going to take

00:05:24 ◼   ► two weeks, it ends up taking four weeks.

00:05:27 ◼   ► And that's just the reality of like, you're all like, as you, I mean, I think it sounds

00:05:32 ◼   ► a little bit like you have the same experience.

00:05:33 ◼   ► Like you start off thinking, okay, maybe I can do this with these high level APIs.

00:05:38 ◼   ► like, you know, these things Apple has put together, they're tried and true, whatever.

00:05:43 ◼   ► And you start using it and it's like, okay, it does most of what I need, but it doesn't

00:05:47 ◼   ► do this one critical thing. And you start being like, how critical is that? Well, it's

00:05:52 ◼   ► probably pretty critical. And so you take your next step down, and then you take your

00:05:56 ◼   ► next step down, and then before long, you're just like re-implementing all kinds of crazy

00:06:00 ◼   ► stuff. And you have no way of knowing superficially what that's going to look, how many love

00:06:06 ◼   ► stacks deep, how much rewriting and rebuilding of stuff you're going to need to end up doing

00:06:11 ◼   ► to get what you're going to do.

00:06:12 ◼   ► And so at the end I was just like, I don't know, I'll just sort of hope for the best.

00:06:15 ◼   ► And like other than for iOS 9 things, for those I just tend to say like how much, like

00:06:20 ◼   ► I'll just work until I can't, I run out of time and just try and structure what I'm working

00:06:26 ◼   ► on such that I can like, you know, not be half finished, have like half the things fully

00:06:32 ◼   ► finished rather than all the things half finished.

00:06:35 ◼   ► But yeah, estimating time is a complete nightmare, I find.

00:06:38 ◼   ► - Yeah, totally.

00:06:40 ◼   ► And we're lucky that when we're working for ourselves

00:06:44 ◼   ► on our own products for the most part,

00:06:46 ◼   ► our time estimates aren't that important

00:06:47 ◼   ► 'cause for the most part,

00:06:49 ◼   ► only the users are demanding things, if anybody.

00:06:52 ◼   ► It's not like, when you're a consultant,

00:06:55 ◼   ► the pressure is much stronger on you

00:06:56 ◼   ► to meet the client's deadlines.

00:06:58 ◼   ► Or when you're working for a company,

00:07:00 ◼   ► when you're working directly on your employer's product,

00:07:05 ◼   ► You have similar pressures from that.

00:07:07 ◼   ► But when you're a consultant, you have a whole different aspect of it, which is that

00:07:11 ◼   ► the client is often directly paying you for the time that you are taking.

00:07:15 ◼   ► And that, of course, makes it even more complex.

00:07:17 ◼   ► We are both lucky that we are not currently in that kind of role.

00:07:20 ◼   ► But certainly, I would say from just anecdotal evidence, it seems like the vast majority

00:07:26 ◼   ► of iOS developers are involved in some kind of contract work.

00:07:31 ◼   ► That seems to be the biggest chunk of the iOS work that's out there.

00:07:36 ◼   ► Time estimates are such a nightmare there.

00:07:39 ◼   ► We're both lucky that we can't really talk much about it, because I haven't done it in

00:07:43 ◼   ► forever, and even when I didn't, I didn't do very much of it.

00:07:46 ◼   ► It's been a while since you've done consulting as well, right?

00:07:48 ◼   ► Yeah.

00:07:49 ◼   ► I mean, the last time I did regular consulting was probably four or five years ago, something

00:07:54 ◼   ► like that.

00:07:55 ◼   ► I started out as a consultant.

00:07:56 ◼   ► That was what I was doing initially, but it's been a long time since that made up any kind

00:08:01 ◼   ► kind of significant portion of my business.

00:08:03 ◼   ► And I learned very quickly when I was doing consulting,

00:08:06 ◼   ► though, to not commit to time estimates as much as I could,

00:08:11 ◼   ► because you're always gonna run into that.

00:08:13 ◼   ► There's always some kind of complexity

00:08:15 ◼   ► that you're not expecting.

00:08:16 ◼   ► And if you don't plan for it,

00:08:18 ◼   ► if you don't look at a problem and say,

00:08:20 ◼   ► it's like the old rule of whatever you think

00:08:22 ◼   ► it's gonna take, multiply it by three.

00:08:24 ◼   ► - Yeah, at least.

00:08:25 ◼   ► - You're probably well off, but yeah, I try as best,

00:08:30 ◼   ► Like the first rule, you definitely have that experience when you start off consulting where

00:08:33 ◼   ► you start to say like, "Oh, it's going to take such, you know, oh, that'll only be like

00:08:36 ◼   ► a week's worth of work."

00:08:38 ◼   ► And you commit to the client to do that and then it never ends up being a week's worth

00:08:41 ◼   ► of work.

00:08:42 ◼   ► It's just, that's just the reality.

00:08:43 ◼   ► I mean, even, and I mean, with streaming, I had so many problems with, I would, I started

00:08:49 ◼   ► it, I think three or four times.

00:08:52 ◼   ► And I would get down a certain path or try to try to approach it in a certain way and

00:08:57 ◼   ► and realize that it was just never gonna work.

00:09:00 ◼   ► I was never gonna be able to complete it

00:09:01 ◼   ► in the way I was doing it, or it just was not working,

00:09:05 ◼   ► or I had made too many mistakes,

00:09:07 ◼   ► or I had made too many subtle bugs

00:09:09 ◼   ► that I couldn't find at the very low levels.

00:09:11 ◼   ► And so I would just scrap it and start over again.

00:09:13 ◼   ► And when you're at a big time crunch,

00:09:17 ◼   ► you don't usually have the opportunity to do that.

00:09:19 ◼   ► And that can be a blessing and a curse.

00:09:21 ◼   ► If you do that too much,

00:09:23 ◼   ► then you're wasting a whole bunch of time,

00:09:25 ◼   ► and it's never gonna be perfect.

00:09:27 ◼   ► It's never going to be exactly the perfect design, exactly what you want.

00:09:30 ◼   ► And so if you have too many opportunities to cancel it and start over again, you're

00:09:33 ◼   ► just going to kill tons of time.

00:09:35 ◼   ► But if you don't have any opportunities to do that, which is often the case when you're

00:09:38 ◼   ► under time pressure from a client, say, I feel like it's hard to get good quality work

00:09:43 ◼   ► because you really do learn a lot if you try to do something, then get a chance to throw

00:09:48 ◼   ► it away and do it over again.

00:09:49 ◼   ► Yeah.

00:09:50 ◼   ► Because I think one thing that I was, my experience, like whenever I've encountered these kind

00:09:54 ◼   ► of problems, where I'm trying to deal with something that ends up being much more complicated

00:09:59 ◼   ► than I think. I start off with a mental model for the problem that is straightforward. For

00:10:04 ◼   ► example, the thing that I most recently ran into this with is I did a data syncing and

00:10:08 ◼   ► merging algorithm for Pedometer++. So it takes the steps from your watch and your phone and

00:10:15 ◼   ► gives you a unified view of them in semi-real time. At first I was like, "Oh, the mental

00:10:20 ◼   ► model for this is great. There's HealthKit, right? I can just use HealthKit. And you can't,

00:10:24 ◼   ► because that's not how HealthKit works, because it's not available on the watch in the way

00:10:28 ◼   ► that shows you phone data. So I very quickly discovered that my original mental model was

00:10:33 ◼   ► completely wrong. And so then, what my process tends to be, I have this really straightforward

00:10:38 ◼   ► mental model, it ends up not working, and then I end up going down these crazy paths

00:10:43 ◼   ► of incredibly complicated solutions. All of these really brittle and not really going

00:10:50 ◼   ► to work solutions, like all kinds of crazy algorithms and merging schemes and way of

00:10:53 ◼   ► throwing data back and forth. And you get to the end, and the times I'm most satisfied

00:10:59 ◼   ► with my work, though, are when I end up, after all of that, with a simple solution again

00:11:04 ◼   ► that is informed by all of those crazy paths down the way. Like, you can learn the lesson

00:11:10 ◼   ► and be like, "Okay, actually, I don't need to do all these crazy things. Now that I understand

00:11:15 ◼   ► the problem fully from top to bottom.

00:11:17 ◼   ► I can say, "Okay, I don't need to worry about the data in all these crazy ways.

00:11:22 ◼   ► I can just make all these nice simplifying assumptions about how it is because I've

00:11:28 ◼   ► tested and verified that those work.

00:11:30 ◼   ► And then I can build a solution that's almost as simple as the one I started off with wanting

00:11:35 ◼   ► to build and now that actually deals with all that complexity."

00:11:38 ◼   ► And whenever I'm able to go through that process, it starts simple, it gets horrifically

00:11:42 ◼   ► messy and then it gets simple again.

00:11:44 ◼   ► I know I'm doing it right.

00:11:47 ◼   ► If ever I end up having to stop in that middle state where it's still really messy, I know

00:11:52 ◼   ► it's going to break.

00:11:53 ◼   ► I know it's not going to work.

00:11:55 ◼   ► It needs to be something that I could just describe to myself in just a few sentences

00:12:00 ◼   ► or something's probably gone wrong.

00:12:04 ◼   ► What kind of system did you end up with to address the watchOS2 or watchkit2 sync problem?

00:12:11 ◼   ► Because as you are very well aware,

00:12:14 ◼   ► and as some of our audience might be,

00:12:18 ◼   ► with WatchKit 1 apps,

00:12:20 ◼   ► we're actually fairly straightforward and simple to make

00:12:22 ◼   ► because they couldn't do that much,

00:12:24 ◼   ► and because they were running on the phone

00:12:27 ◼   ► in the app sandbox, in the same sandbox as the iPhone app,

00:12:30 ◼   ► so that you could have a shared container,

00:12:32 ◼   ► and the iPhone app and the Watch app

00:12:35 ◼   ► could literally be reading and writing from the same data.

00:12:38 ◼   ► And that's how I structured the Overcast Watch app,

00:12:40 ◼   ► which is I just move the database file, the SQLite file,

00:12:44 ◼   ► into the app container, and then the communication

00:12:49 ◼   ► between the watch app and the phone app

00:12:51 ◼   ► is limited only to basically commands and status updates.

00:12:55 ◼   ► And all the data, the watch app reads the data

00:12:58 ◼   ► right off the database, and the phone just tells the watch

00:13:02 ◼   ► when it has changed, and the watch reads it.

00:13:04 ◼   ► So it's actually very, quite simple in that way,

00:13:08 ◼   ► 'cause there is no sync issue.

00:13:10 ◼   ► If the watch can't reach the phone at the given moment,

00:13:13 ◼   ► you just can't use the Overcast app,

00:13:15 ◼   ► 'cause it's just, all it is is a remote control

00:13:17 ◼   ► for the phone, so it's great.

00:13:19 ◼   ► With watchOS 2, that shared data container

00:13:23 ◼   ► no longer quite exists the same way, or at all, really.

00:13:26 ◼   ► - It doesn't exist at all, yeah.

00:13:27 ◼   ► - Right, so with watchOS 2, it is like,

00:13:30 ◼   ► you are running two separate apps,

00:13:32 ◼   ► and you need to figure out how they're going

00:13:34 ◼   ► to communicate with each other,

00:13:35 ◼   ► and there's methods to do the basics,

00:13:38 ◼   ► but there is no automatic magical syncing that happens.

00:13:41 ◼   ► So you have to deal with how these things

00:13:43 ◼   ► synchronize their data yourself.

00:13:46 ◼   ► That's one of the reasons why I haven't made

00:13:48 ◼   ► an overcast watchOS 2 app.

00:13:51 ◼   ► Why I just keep having the OS 1 app.

00:13:54 ◼   ► First of all because it works well enough.

00:13:57 ◼   ► WatchOS 2 improved watch kit reliability quite a bit

00:14:00 ◼   ► and so the app works well enough for the most part.

00:14:03 ◼   ► But also that it would be a major undertaking

00:14:06 ◼   ► as you discovered, you know, it's a major undertaking

00:14:09 ◼   ► to all of a sudden tackle these two,

00:14:11 ◼   ► to all of a sudden take something

00:14:12 ◼   ► that used to be a dumb remote and make it a full app

00:14:16 ◼   ► with its own local storage

00:14:17 ◼   ► and the problem of syncing both ways.

00:14:20 ◼   ► And so, you know, if you take the phone away

00:14:23 ◼   ► and you have the watch off by itself somewhere

00:14:24 ◼   ► playing podcasts somehow,

00:14:26 ◼   ► which is its own separate bag of hurt

00:14:28 ◼   ► of like, you know, how capable that is right now

00:14:30 ◼   ► in watchOS 2.0, but if you somehow do that,

00:14:34 ◼   ► then you have to, when upon reconnection to the phone,

00:14:38 ◼   ► you have to sync up that data again

00:14:39 ◼   ► and resolve possible conflicts.

00:14:41 ◼   ► And it's a very, it's a much larger problem

00:14:45 ◼   ► than it seems upon first glance.

00:14:47 ◼   ► Because while the APIs and everything are all very similar

00:14:50 ◼   ► to what they were in Watch Scale 1,

00:14:53 ◼   ► the data model is totally different.

00:14:55 ◼   ► And that's where most of the complexity I think would lie.

00:14:58 ◼   ► And I haven't yet decided that that's worth the investment.

00:15:01 ◼   ► Apps for the Apple Watch are a whole separate topic,

00:15:04 ◼   ► but I have found generally that I'm very scared

00:15:08 ◼   ► to tackle that.

00:15:09 ◼   ► This is one of the few times where I've spotted

00:15:10 ◼   ► that complexity ahead of time,

00:15:13 ◼   ► and possibly wisely, I don't know,

00:15:16 ◼   ► but possibly wisely I'm avoiding it.

00:15:18 ◼   ► - Yeah, 'cause I think what I've ended up having to do

00:15:21 ◼   ► in WatchOS 2 is essentially you have to build

00:15:25 ◼   ► two completely independent, can-run-on-their-own apps.

00:15:31 ◼   ► Like the watch app has to be able to run entirely on its own without being able to phone home

00:15:35 ◼   ► to the phone.

00:15:36 ◼   ► And the phone app obviously needs to be able to run without the watch, which isn't that

00:15:40 ◼   ► much of a stretch because that's what it does if you don't own a watch.

00:15:44 ◼   ► And then you have to do these funny things because the communication between the two

00:15:49 ◼   ► is not reliable, both in terms of sometimes the watch is just physically not close enough

00:15:56 ◼   ► to the phone in order to communicate.

00:15:59 ◼   ► And also, sometimes, just the APIs and things, I think it's because they're trying to do

00:16:04 ◼   ► so much about power management and sometimes certain types of messages only go through

00:16:10 ◼   ► if it's a good thing from an energy perspective to be able to do.

00:16:14 ◼   ► Like the radios are all turned up and fired up, so hey, let's go ahead and send it right

00:16:17 ◼   ► away.

00:16:18 ◼   ► If they're not, maybe we'll wait and see if we are going to fire up the radio anyway for

00:16:22 ◼   ► the next, in the next second.

00:16:24 ◼   ► If not, then maybe we'll do it.

00:16:25 ◼   ► And so you have to build the system that

00:16:30 ◼   ► makes no assumptions about being able to talk to the other part,

00:16:34 ◼   ► but still gives your user a consistent experience

00:16:37 ◼   ► across both.

00:16:38 ◼   ► And that's where, like for this project that I was working on,

00:16:41 ◼   ► became the really crazy thing.

00:16:42 ◼   ► Because a pedometer, in some ways, is very simple.

00:16:45 ◼   ► Like both devices have a motion processor on it

00:16:49 ◼   ► that tells you how many steps they took

00:16:51 ◼   ► in a particular time period.

00:16:52 ◼   ► Like that's all they do, and that's

00:16:54 ◼   ► most of what the app is doing.

00:16:56 ◼   ► And so I could run completely independently in terms of,

00:16:59 ◼   ► if I could just showed you the watch's steps on the watch app

00:17:03 ◼   ► and just showed you the phone steps on the phone app,

00:17:05 ◼   ► it'd be trivial.

00:17:06 ◼   ► But what I want to be able to do is obviously

00:17:08 ◼   ► merge those together and say, which

00:17:09 ◼   ► one is a better representation of what you're doing?

00:17:13 ◼   ► And that is where all the crazy complexity comes in.

00:17:16 ◼   ► Because I had a couple of things that I was like,

00:17:19 ◼   ► so many of conflict resolution strategies

00:17:21 ◼   ► don't really work in this scenario.

00:17:23 ◼   ► because I can't just do simple things like who updated most recently or things because

00:17:28 ◼   ► if I can ever, for example, make someone's step count go down, I guess I could, but conceptually

00:17:34 ◼   ► I've always had that be like a rule for the app that if I ever, even if it was like slightly

00:17:38 ◼   ► in error, if I ever showed you a step count, like for example, you hit your goal, right?

00:17:42 ◼   ► Like you got 10,000 steps, confetti comes down from the screen, hooray, you did it.

00:17:46 ◼   ► I don't want you to then like sync up with your watch and say like, oh, actually now

00:17:49 ◼   ► we think that you did 9,000 steps.

00:17:51 ◼   ► Like, that would be terrible, right?

00:17:53 ◼   ► You have to withdraw somebody's confetti.

00:17:55 ◼   ► Yeah, like, I'm sorry, your confetti now goes back up to the top of the screen and...

00:17:58 ◼   ► Animated in reverse.

00:17:59 ◼   ► I think that'd be awful, right?

00:18:02 ◼   ► Play like a sad trombone.

00:18:03 ◼   ► Yeah, and so you have to, like, a lot of my syncing stuff is about saying, like, what's

00:18:07 ◼   ► the biggest number of steps that you've shown the user for the particular time period that

00:18:12 ◼   ► we're looking at?

00:18:13 ◼   ► And syncing that up so that if I ever needed to show, sort of add extra steps, I know what

00:18:20 ◼   ► I need to add. And also I need to do that, but it's not just as simple as who's shown

00:18:26 ◼   ► more because the nature of these devices is which one of them is going to be showing you

00:18:31 ◼   ► a better view of the user's activity probably at any one time. When I'm walking and pushing

00:18:36 ◼   ► my daughter in a stroller, my phone in my pocket is going to be a better idea of how

00:18:40 ◼   ► many steps I am because my wrist is actually not moving. It's attached to a stroller pushing

00:18:44 ◼   ► it along. But when my phone is in a backpack, or my wife runs into this a lot, her phone

00:18:51 ◼   ► will be in her purse, but her watch is on her wrist, so then her watch is the better

00:18:55 ◼   ► indicator of steps. So it's like having to work out a scheme that is in real time

00:19:00 ◼   ► dynamically working out which one, based on the information we have, which we may or may

00:19:04 ◼   ► not have all the time, looking at the two data streams and merging them together. That's

00:19:12 ◼   ► that's the minimum threshold for having this thing work,

00:19:16 ◼   ► is you have to have built a system that can do all that.

00:19:19 ◼   ► And that was the complexity for me that just became like,

00:19:21 ◼   ► wow, this is a whole bigger thing

00:19:23 ◼   ► than I ever imagined it would be.

00:19:25 ◼   ► - Yeah, and that's like one of the things

00:19:29 ◼   ► that makes these unexpected complexities

00:19:32 ◼   ► so frustrating or so powerful,

00:19:34 ◼   ► is that, again, they're unexpected.

00:19:38 ◼   ► You have no idea when in a project

00:19:41 ◼   ► you're going to hit something like this

00:19:42 ◼   ► until you hit it.

00:19:43 ◼   ► And so like, you know, the more experience you get

00:19:47 ◼   ► as a developer or just as a person who lives in life,

00:19:52 ◼   ► the more experience you get,

00:19:53 ◼   ► it becomes a little bit more likely

00:19:55 ◼   ► that you'll spot them ahead of time

00:19:57 ◼   ► and be able to possibly either avoid them

00:19:59 ◼   ► or at least like budget for them.

00:20:01 ◼   ► But there's still always like stuff that you hit

00:20:04 ◼   ► that's unexpected and it can totally throw a project off.

00:20:07 ◼   ► So like, you know, one thing that I do to manage this

00:20:11 ◼   ► is if I can tell something's going to be a big hairy mess,

00:20:15 ◼   ► a lot of times I'll just cut the feature.

00:20:17 ◼   ► I'll just avoid it.

00:20:19 ◼   ► I'll say, "Sorry, that's not worth doing."

00:20:21 ◼   ► With Overcast, I knew streaming was gonna be a big deal,

00:20:24 ◼   ► so for version 1.0, I just didn't include it.

00:20:27 ◼   ► I couldn't ship it in time.

00:20:30 ◼   ► I estimated that it would be a better idea

00:20:32 ◼   ► to ship the app without streaming

00:20:34 ◼   ► than to wait another six months to a year to add streaming.

00:20:39 ◼   ► That turned out to be correct.

00:20:41 ◼   ► And in the case of my watch app now,

00:20:43 ◼   ► where I have the watchOS 1 app,

00:20:45 ◼   ► the watchOS 2 app would be a ton of work

00:20:48 ◼   ► and would be different and might not be better.

00:20:51 ◼   ► It might just be different.

00:20:53 ◼   ► I've calculated so far that at the moment

00:20:56 ◼   ► it isn't worth investing the time in that.

00:20:57 ◼   ► And it might never be, I don't know.

00:20:59 ◼   ► But certainly right now it isn't worth

00:21:01 ◼   ► investing the time in that,

00:21:02 ◼   ► when I could instead be doing something

00:21:04 ◼   ► with the same amount of time,

00:21:05 ◼   ► I could instead be doing something like the Apple TV app

00:21:08 ◼   ► or a major new feature, or even a brand new app

00:21:13 ◼   ► if I wanted to.

00:21:14 ◼   ► You have to really decide what's worth sinking

00:21:17 ◼   ► all this time into, and sometimes it isn't

00:21:20 ◼   ► the big hairy problem in front of you.

00:21:21 ◼   ► Sometimes that problem is best off just staying unsolved.

00:21:26 ◼   ► That feature might be better off staying unimplemented,

00:21:29 ◼   ► or that app might be better off not being made,

00:21:32 ◼   ► and you might be better off spending that time

00:21:34 ◼   ► in other ways, because you can do a lot

00:21:37 ◼   ► of low-hanging fruit in other parts of your app

00:21:40 ◼   ► or as other apps in the same amount of time

00:21:42 ◼   ► that you could tackle one big hairy problem in one app,

00:21:45 ◼   ► and it might not be worth it.

00:21:46 ◼   ► Our sponsor this week is Need.

00:21:48 ◼   ► Go to neededition.com.

00:21:50 ◼   ► Need is a curated retailer and lifestyle publication

00:21:53 ◼   ► for the modern gentleman.

00:21:54 ◼   ► Each week, Need launches new collections

00:21:56 ◼   ► of exclusive clothing, literature, furniture, and more.

00:22:00 ◼   ► Now earlier this month,

00:22:01 ◼   ► coinciding with the company's second birthday,

00:22:03 ◼   ► Need launched an all-new site expanding its availability

00:22:05 ◼   ► into 43 countries in Europe, South America, Asia, and the Middle East. Shipping is flat

00:22:11 ◼   ► rate for all international orders and free for all orders to the US, Canada, and Mexico,

00:22:16 ◼   ► and all returns are free no matter where you are all over the world.

00:22:20 ◼   ► This month, Neve has launched three collections, including their Holiday Gift Guide, featuring

00:22:24 ◼   ► dozens of gift ideas for the holidays, many of which are under $40. Neve is designed to

00:22:29 ◼   ► be simple, straightforward, and uncomplicated. They include prepaid return labels with all

00:22:34 ◼   ► They offer 24/7 support and there aren't any subscriptions or stylists or other gimmicks

00:22:39 ◼   ► to deal with.

00:22:40 ◼   ► It's just a straightforward retailer.

00:22:42 ◼   ► Simply come along to NeedEdition.com, peruse the latest collections and shop.

00:22:46 ◼   ► Or don't, your choice.

00:22:48 ◼   ► For listeners of this show, use coupon code radar for 20% off.

00:22:52 ◼   ► That is coupon code radar at NeedEdition.com for 20% off anything.

00:22:56 ◼   ► Thank you so much to our friends at Need for sponsoring Under the Radar.

00:23:00 ◼   ► Getting back to one thing that you just said that I think is probably a good place to be

00:23:05 ◼   ► winding down this discussion is, I think the thing that I've learned most, like this

00:23:09 ◼   ► is the battle-hardened wisdom of dealing with complexity, is making sure that I'm solving

00:23:18 ◼   ► the problem for the right reason.

00:23:21 ◼   ► I think most of us who get into software engineering, or whatever you want to call what we do, we

00:23:26 ◼   ► We like solving problems, and the problems that we like solving most are the most difficult,

00:23:31 ◼   ► interesting, tricky problems. Like, that is, I think I'm in my element the most, I'm the

00:23:37 ◼   ► most engaged, I'm the most excited about what I'm doing when I'm solving a really interesting

00:23:41 ◼   ► problem. Like, if I'm just writing boilerplate code, that's not nearly as exciting and something

00:23:47 ◼   ► I want to really, like, wrap my arms around and get, you know, sort of get up in the morning

00:23:50 ◼   ► to dive into. And so the thing that I, though, then always have to keep in the back of my

00:23:54 ◼   ► my mind when I find a problem like this, when I'm working along on a task and I find that

00:23:58 ◼   ► there's this big unexpected bump in complexity. Like you were just saying, sometimes you're

00:24:02 ◼   ► just worth not doing it. The thing I know I've had to teach myself some discipline with

00:24:07 ◼   ► is that when I see a problem like that, when I seize an opportunity to really go crazy

00:24:11 ◼   ► spelunking, dive deep down into some crazy low APIs and build this crazy cool clever

00:24:17 ◼   ► system, make sure that I'm not just doing it because it would be intellectually fun

00:24:23 ◼   ► and interesting. Sometimes there's a place for that, but I've definitely caught myself

00:24:28 ◼   ► sometimes just building things because I think it would be fun and it wouldn't actually make

00:24:32 ◼   ► my customers happier. It wouldn't actually make my products better. It would just be

00:24:37 ◼   ► fun for me to do. I end up just going down these crazy rabbit holes and doing all these

00:24:41 ◼   ► things and often the reality is it isn't actually as fun as I thought it was going

00:24:46 ◼   ► to be. It's fun for the first few hours, first few days, and then you're just like

00:24:51 ◼   ► It's like you're in this point where,

00:24:53 ◼   ► like I always want to avoid where,

00:24:54 ◼   ► it's like I started working on my car

00:24:56 ◼   ► and I've taken it completely apart.

00:24:57 ◼   ► And then I come to discover

00:25:00 ◼   ► the fun part was taking it apart.

00:25:02 ◼   ► The fun part is not putting it back together.

00:25:05 ◼   ► And now I don't have a car anymore.

00:25:06 ◼   ► That's the part where I have to catch myself

00:25:09 ◼   ► and be like, am I really doing this for the right reason?

00:25:11 ◼   ► Is this complexity worth the effort?

00:25:14 ◼   ► And having that kind of taking a step back from your work

00:25:18 ◼   ► is a sort of a habit and a discipline

00:25:20 ◼   ► I've found has been very helpful in me making sure that I'm staying on track.

00:25:23 ◼   ► And especially being like a one-man shop, like there's no one, I don't have a supervisor

00:25:27 ◼   ► being like, "Huh, yeah, yeah, we're just going to cut that feature."

00:25:30 ◼   ► That's too much.

00:25:31 ◼   ► It has to be something that I have the ability to not just get totally sucked down these

00:25:36 ◼   ► rabbit holes and say like, "Yes, of course, I need to do this thing because it's really

00:25:40 ◼   ► interesting and really hard."

00:25:42 ◼   ► Like, I need to be able to say like, "Will my customers notice if I do this?"

00:25:47 ◼   ► And if they won't, like am I just doing this for myself?

00:25:50 ◼   ► And if I am, like that's kinda sometimes fun,

00:25:55 ◼   ► but that's really not a way that you're gonna be able

00:25:57 ◼   ► to reliably ship quality products.

00:25:59 ◼   ► You're just gonna end up with a lot of kind of like

00:26:01 ◼   ► crazy half-built things that probably will end up

00:26:04 ◼   ► making your app more complicated and harder to use

00:26:07 ◼   ► for your customers in the end.

00:26:08 ◼   ► - Yeah, that's a fantastic way to look at it.

00:26:11 ◼   ► And we all face that dilemma because I mean look,

00:26:14 ◼   ► we're all geeks, we all like interesting things,

00:26:17 ◼   ► We all like keeping our brains interested

00:26:18 ◼   ► and trying new things and approaching problems in new ways

00:26:21 ◼   ► or doing things in better ways

00:26:22 ◼   ► than what we did in the past.

00:26:24 ◼   ► It's not that you should never do that,

00:26:25 ◼   ► but that there's a balance to be struck

00:26:27 ◼   ► and that doing that has significant time costs

00:26:31 ◼   ► that may not be worth it.

00:26:32 ◼   ► And doing a major rewrite of something that already works

00:26:36 ◼   ► might also introduce brand new bugs,

00:26:37 ◼   ► in fact, it almost certainly would,

00:26:39 ◼   ► brand new bugs that you didn't have before

00:26:42 ◼   ► then you'd have to go fixing that.

00:26:44 ◼   ► And so it's just a balance.

00:26:45 ◼   ► You need to keep yourself happy and learning

00:26:48 ◼   ► and intellectually satisfied.

00:26:50 ◼   ► But you also need to ship products

00:26:52 ◼   ► and it's important to find that balance.

00:26:55 ◼   ► And that's something that I think mostly just comes

00:26:57 ◼   ► with experience and wisdom over time.

00:27:00 ◼   ► It's not that you can never have fun,

00:27:02 ◼   ► but that you should know when to have fun

00:27:05 ◼   ► and when it's no longer fun and you need to get back to work.

00:27:09 ◼   ► - Yeah, and I think the best lesson I've had about that

00:27:12 ◼   ► is it's trying to have customer-focused development

00:27:15 ◼   ► that way. It's like the time to do that, the time to solve interesting problems, is to

00:27:19 ◼   ► find features or find apps or find ideas that solving a difficult problem will make a customer's

00:27:27 ◼   ► life better. And like the intersection of those two things, like a really interesting

00:27:31 ◼   ► technical problem and a real honest need or pain point in someone's life, like that's

00:27:37 ◼   ► where really interesting and fun work happens. And if you can't sort of honestly say that

00:27:43 ◼   ► that it's both interesting to build

00:27:45 ◼   ► and useful for a customer,

00:27:47 ◼   ► then you're probably not in a place

00:27:49 ◼   ► that it's actually worth building.

00:27:51 ◼   ► - All right, thanks a lot for listening, everybody.

00:27:53 ◼   ► Please tell your friends about the show,

00:27:55 ◼   ► help us spread the word,

00:27:56 ◼   ► recommend us on Overcast,

00:27:58 ◼   ► and we'll see you next week.