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: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:49
◼
►
I mean, the last time I did regular consulting was probably four or five years ago, something
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: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: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: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.