#119: Go Big or Ship?
00:00:00
◼
►
Hello and welcome to Developing Perspective.
00:00:05
◼
►
Developing Perspective is a podcast discussing news of note in iOS development, Apple, and the like.
00:00:07
◼
►
I'm your host, David Smith. I'm an independent iOS and Mac developer based in Herndon, Virginia.
00:00:12
◼
►
This is show number 119, and today is Friday, April 12th.
00:00:16
◼
►
Developing Perspective is never longer than 15 minutes, so let's get started.
00:00:20
◼
►
All right, I've got four quick topics to talk through today.
00:00:24
◼
►
And first I was going to start off by talking a little bit about just kind of letting an opinion about the whole thing this week
00:00:26
◼
►
the whole thing this week about app rejections,
00:00:28
◼
►
the App Store policy being pulled,
00:00:30
◼
►
and that kind of came out of the AppGratis,
00:00:34
◼
►
I don't even know, debacle, whatever you want to call it,
00:00:37
◼
►
And if you haven't heard about it,
00:00:38
◼
►
basically there was this app that was doing app promotion,
00:00:43
◼
►
providing an alternate way to find apps
00:00:45
◼
►
that you could pay to buy things.
00:00:48
◼
►
I don't really understand at all exactly how their business
00:00:50
◼
►
model worked.
00:00:51
◼
►
But the reality is, the short version
00:00:53
◼
►
is Apple decided to reject or pull the app from the store for violating two lines in
00:00:59
◼
►
the app review guidelines.
00:01:00
◼
►
And there was a bit of a back and forth about that.
00:01:02
◼
►
Like, what does that mean?
00:01:03
◼
►
It's like, here's this company with many people, a lot of funding, and all of a sudden their
00:01:06
◼
►
business just disappears overnight.
00:01:07
◼
►
Like, that's a little bit disconcerting, rough, especially if you're somebody who makes your
00:01:12
◼
►
business and you're living in the store.
00:01:14
◼
►
It just reminds me of, it's just one of those things of, if you want to work in this business,
00:01:22
◼
►
If you want to make your living in the App Store, it is a simple reality and a truth
00:01:27
◼
►
that that is just the nature of the beast.
00:01:29
◼
►
And I've talked about this many times before, how I like that.
00:01:33
◼
►
As much as it's disconcerting, as much as I think that there are problems and challenges
00:01:36
◼
►
and there are things that Apple doesn't do right, I like that that's the case, because
00:01:40
◼
►
I think in the broad strokes it improves the quality of the store.
00:01:43
◼
►
That generally speaking, what Apple's goal is usually is to make the App Store experience
00:01:48
◼
►
the best as it can possibly be for its customers. And that,
00:01:53
◼
►
broadly speaking, it is a fair system for some definition of
00:01:57
◼
►
fair. And so you just have to understand that if you do
00:02:01
◼
►
anything that gets close to the line, you're you're gambling at
00:02:05
◼
►
that point. It's not and you just have to go into it with
00:02:08
◼
►
that. But that mentality and that mindset, I think, and
00:02:11
◼
►
that's just kind of the way it is. It's like if there's a, you
00:02:13
◼
►
know, it's like high risk, high reward, the closer you get to
00:02:15
◼
►
that line. And it's just interesting because you can, it
00:02:18
◼
►
It doesn't mean that you have to be totally paranoid about it, but it's just understanding
00:02:22
◼
►
that that's what you're doing.
00:02:23
◼
►
And the closer you get, if you read through the app review guidelines and there's a line
00:02:26
◼
►
in there that's getting close to something that you're wanting to do or you think you
00:02:30
◼
►
found kind of this angle or this niche, that's just the reality is that you're putting yourself
00:02:35
◼
►
and your business in a place that could disappear overnight.
00:02:39
◼
►
And that's just the way it is.
00:02:41
◼
►
And I like that in that I think the end result is that it's a better store.
00:02:48
◼
►
The individual cases and the people involved and all that kind of thing can be very difficult,
00:02:51
◼
►
very tragic and very sad.
00:02:54
◼
►
But it's just like staying away from those types of areas and those types of things is
00:02:59
◼
►
one approach to take.
00:03:01
◼
►
And then two is just to accept it, mark it up as a business risk and kind of go with
00:03:08
◼
►
And that's just kind of where you are.
00:03:10
◼
►
It's one of those things that there is no, that doesn't make me, it's never happy when
00:03:15
◼
►
these things happen.
00:03:16
◼
►
happen all the time, or more often enough
00:03:19
◼
►
that it certainly is a pervasive problem.
00:03:22
◼
►
But the reality is, app rejection is just part
00:03:26
◼
►
of having this kind of store experience.
00:03:29
◼
►
And that's, on the plus side, I think is why
00:03:31
◼
►
the app store is so successful, and there's a high degree
00:03:33
◼
►
of user trust and those types of things.
00:03:36
◼
►
You know, and you can get into, like in this case,
00:03:38
◼
►
I think one of the policies is about creating
00:03:40
◼
►
alternate app store experiences and about
00:03:43
◼
►
incentivizing downloads and those types of things.
00:03:48
◼
►
The goal is to make sure that the charts
00:03:51
◼
►
and the store ranking and things are reflective
00:03:53
◼
►
of the actual genuine user interest in applications
00:03:57
◼
►
rather than in just who can write the biggest check,
00:04:02
◼
►
which I think is a good thing.
00:04:07
◼
►
The exact implementation, complicated.
00:04:08
◼
►
But the goal and the spirit behind it, I think, makes sense.
00:04:08
◼
►
And so that's kind of where I come down on those types of things.
00:04:11
◼
►
But I just wanted to sort of put that out there.
00:04:15
◼
►
Next thing I wanted to talk about is something more architectural, switching to much more
00:04:20
◼
►
But it was something that I've been working on a lot in feed wrangler that I thought would
00:04:22
◼
►
be an interesting thing to share, is an approach to building things that I found to be very,
00:04:27
◼
►
very good in terms of performance and structure and sort of reliability maybe is the best
00:04:36
◼
►
way to think about it.
00:04:37
◼
►
And it's the ability to make your application as much as you can into discrete operations
00:04:44
◼
►
that are rerunnable.
00:04:47
◼
►
And this is something that I've been doing for a lot of, I feel there's a lot of operations
00:04:51
◼
►
and things in feed wrangler where this is the case.
00:04:54
◼
►
And as an example of something like this, it's rather than, for example, in feed wrangler
00:04:57
◼
►
when you mark something as red, I could just make the server request to do that.
00:05:01
◼
►
I could just say, you know, whatever, you know, call feed wrangler.net and say, you
00:05:05
◼
►
know, mark as red.
00:05:06
◼
►
And I can do it in a direct call based on,
00:05:09
◼
►
you know, kicked off when the user hits that button.
00:05:12
◼
►
However, if I do that, it creates all these kind
00:05:14
◼
►
of problems and challenges down the road.
00:05:16
◼
►
What if that request times out?
00:05:18
◼
►
If there's a network connectivity problem?
00:05:20
◼
►
If they go into a tunnel and it doesn't get through?
00:05:22
◼
►
Now you have this weird state of how do you show that
00:05:24
◼
►
to your user in a way that is,
00:05:26
◼
►
that A, is reasonable and useful to them.
00:05:30
◼
►
So obviously, if there's an error that happens,
00:05:33
◼
►
maybe that error is actually only gonna happen
00:05:35
◼
►
30 seconds down the road.
00:05:36
◼
►
And the users moved on.
00:05:37
◼
►
The users started doing other things in the application.
00:05:40
◼
►
And all of a sudden, you pop up a message saying, failed.
00:05:42
◼
►
It's like, couldn't connect to server.
00:05:43
◼
►
It's like, that could be totally unrelated.
00:05:45
◼
►
And the server connectivity could actually be back now.
00:05:48
◼
►
And so what I tend to do, what I've been heading towards,
00:05:51
◼
►
is to structure most of my-- as much as I can in my application
00:05:54
◼
►
on more of a queue basis.
00:05:56
◼
►
And that's a queue, you know, Q-U-E-U-E.
00:05:59
◼
►
That what I want to do is make it
00:06:02
◼
►
so that I can just kind of rerun these operations.
00:06:04
◼
►
So I had to sort of destruction my application in that way.
00:06:07
◼
►
And so instead of doing that, when I have this read request,
00:06:11
◼
►
I make an operation.
00:06:12
◼
►
I put it on a queue, and then I try and run it.
00:06:15
◼
►
And it tries to get the server.
00:06:16
◼
►
If it doesn't work, then I'll try it again
00:06:19
◼
►
at various timeouts and things.
00:06:22
◼
►
And obviously, there's a lot of nuance
00:06:23
◼
►
to getting that exactly right.
00:06:25
◼
►
But in general, what I found is that makes
00:06:26
◼
►
my app much more reliable and much more simple in many ways
00:06:29
◼
►
to build, because I don't have to deal with quite as many error
00:06:33
◼
►
There are still certain cases that you need to deal with and show user feedback and things.
00:06:37
◼
►
You know, if there's just no connectivity and they're trying to do a lot of stuff, it's
00:06:40
◼
►
like you need to show them something probably.
00:06:42
◼
►
But generally speaking, it sort of is the app will kind of naturally work itself into
00:06:47
◼
►
a state that is correct over time rather than having sort of constantly badgering the user
00:06:54
◼
►
And so it's just something that I've been doing a lot.
00:06:55
◼
►
And I do the same thing a lot on my website and on the web services side of it as well,
00:07:00
◼
►
which I think I mentioned before.
00:07:01
◼
►
but it works really well there, where rather than,
00:07:04
◼
►
for example, when I'm going out and doing feed parsing
00:07:07
◼
►
and feed aggregation, I'm running out my spiders
00:07:09
◼
►
and they're going off and they're pulling in all,
00:07:11
◼
►
you know, filling in thousands of feeds
00:07:12
◼
►
and parsing them and processing them.
00:07:14
◼
►
Each one of those requests to pull a feed
00:07:18
◼
►
is created as its own distinct operation,
00:07:20
◼
►
put in a queue, and then run.
00:07:22
◼
►
And that means, if anything goes weird with it,
00:07:24
◼
►
if anything gets stuck, it doesn't affect anybody else.
00:07:27
◼
►
They all kind of go their natural way.
00:07:29
◼
►
and if it fails, it can just be put back onto the queue
00:07:32
◼
►
to be retried if I want or not.
00:07:34
◼
►
And I found that that works really well
00:07:36
◼
►
for reliability, for scaling.
00:07:38
◼
►
And another great thing about queuing
00:07:40
◼
►
is an approach and a structure.
00:07:42
◼
►
Because all the operations are atomic,
00:07:44
◼
►
you're designing your app to be parallelizable,
00:07:46
◼
►
which is great, both on the server side and on the device,
00:07:50
◼
►
that if you focus on making it parallelizable,
00:07:53
◼
►
your performance can go up a lot.
00:07:55
◼
►
So for example, with my making network requests,
00:08:02
◼
►
these atomic operations that can be run essentially
00:08:04
◼
►
in any order, as much as I-- to some approximation,
00:08:07
◼
►
I can go and run three of them at a time.
00:08:09
◼
►
And that's OK, because of the way that it's structured.
00:08:12
◼
►
They're not dependent on each other.
00:08:13
◼
►
They're not queuing up.
00:08:15
◼
►
You can make things a lot more performant that way.
00:08:18
◼
►
Next thing I wanted to talk about is something
00:08:20
◼
►
that I've been struggling with a little bit in feed wrangler
00:08:22
◼
►
that I thought was an interesting question.
00:08:25
◼
►
And this is understanding perfection or understanding,
00:08:29
◼
►
do you need to ship something perfect, wonderful, exactly
00:08:34
◼
►
what you want it to be?
00:08:36
◼
►
Or is it more important to ship?
00:08:38
◼
►
And this is a complicated question.
00:08:39
◼
►
This is something that I've been really wrestling with recently.
00:08:42
◼
►
I think I mentioned in the last episode
00:08:43
◼
►
that I'm trying to ship the iOS version of Feed Wrangler today.
00:08:46
◼
►
It's Friday, and I'm trying to get it out
00:08:48
◼
►
by the end of the week.
00:08:49
◼
►
And that's entirely an artificial timeline
00:08:51
◼
►
and pressure that I'm putting on myself.
00:08:54
◼
►
And the goal of that, obviously, is like,
00:08:55
◼
►
feed wrangler is kind of a unique situation
00:08:57
◼
►
where it's specifically trying to target a market that
00:09:01
◼
►
is time limited.
00:09:03
◼
►
On July 1st, Google Reader is going to go away.
00:09:06
◼
►
And so I'm trying to create a replacement for that,
00:09:10
◼
►
unintentionally in some ways.
00:09:11
◼
►
But the reality is I'm creating something
00:09:14
◼
►
that will be a replacement for that for many people.
00:09:16
◼
►
And so I want to get that out in enough time
00:09:19
◼
►
to kind of make that migration.
00:09:20
◼
►
And so I'm kind of putting myself
00:09:21
◼
►
under somewhat of an artificial constraint to do that.
00:09:25
◼
►
But it's a challenging thing to understand
00:09:29
◼
►
what's good enough and where do you draw those lines?
00:09:31
◼
►
Where do you decide?
00:09:34
◼
►
And generally what I've been trying to do is
00:09:35
◼
►
I'm taking the approach that,
00:09:38
◼
►
I have a couple of parameters.
00:09:39
◼
►
One, I don't ever really like the concept
00:09:41
◼
►
of charging people money for anything
00:09:44
◼
►
that I would label as beta software.
00:09:46
◼
►
And I've seen this happen a couple of times.
00:09:47
◼
►
You kind of hear people ship things,
00:09:49
◼
►
it's like, oh, it's still in beta.
00:09:50
◼
►
It always feels weird to me if you're charging for that,
00:09:52
◼
►
because in my mind anyway, what beta means is
00:09:54
◼
►
I know it's broken in some way.
00:09:58
◼
►
And if I know it's broken in a way that's enough
00:10:01
◼
►
that I'm really kind of calling it a beta,
00:10:02
◼
►
that feels a little funny to then take money for that.
00:10:04
◼
►
And so what I'd rather do is scale the application down
00:10:09
◼
►
to a point that it's, I would say it's production ready,
00:10:13
◼
►
charge for that, and then grow it out.
00:10:15
◼
►
And that's generally, I think, the approach
00:10:16
◼
►
that I've been taking with FeedWrangler,
00:10:18
◼
►
and I think it generally works,
00:10:19
◼
►
that rather than worrying about having,
00:10:21
◼
►
I have this long list of features and things
00:10:23
◼
►
that I'm working on and things that will come down the road,
00:10:25
◼
►
or approaches or things that I can do
00:10:27
◼
►
that will just come naturally down the road.
00:10:31
◼
►
And I'm thinking rather than being too focused
00:10:33
◼
►
on making sure they're all in there before I ship,
00:10:35
◼
►
I'm saying, okay, I'm going to narrow that down,
00:10:38
◼
►
polish, refine as much as I can,
00:10:40
◼
►
make it really reliable, solid, and then ship that.
00:10:43
◼
►
And know that I've got a lot of good fodder for 1.1, 1.2, 1.3.
00:10:49
◼
►
And this is something I didn't check the weather that I think was really well received, where
00:10:52
◼
►
if you get into this habit of, you know, once you've launched an app to ship updates pretty
00:10:56
◼
►
quickly, I think it builds a lot of trust and endearment from your users, because it
00:11:01
◼
►
feels like you're really engaged and you're really responsive to what they're saying,
00:11:04
◼
►
to the problems they're having, and to fixing those things.
00:11:07
◼
►
So that's kind of what I'm doing.
00:11:08
◼
►
It's sort of like, rather than going big, I'm just trying to ship a solid kernel that
00:11:14
◼
►
works exactly how I want it.
00:11:17
◼
►
and then I'll add in some more bells and whistles
00:11:19
◼
►
based on what users want.
00:11:21
◼
►
And that also speaks to a little bit of the problem of
00:11:23
◼
►
whenever you ship something,
00:11:26
◼
►
no matter how many beta feedback you get,
00:11:29
◼
►
your customers are gonna use your application
00:11:31
◼
►
in ways that you never expected or imagined.
00:11:33
◼
►
And that's a good thing.
00:11:34
◼
►
It can create opportunities and drive it in directions
00:11:37
◼
►
that you may not necessarily have expected,
00:11:39
◼
►
and that can often be really, really helpful
00:11:41
◼
►
for deriving the product.
00:11:42
◼
►
And so you can end up spending time on features
00:11:44
◼
►
that no one will use.
00:11:45
◼
►
Or, on the flip side, alternatively better,
00:11:48
◼
►
to spend that time polishing things that you think,
00:11:51
◼
►
that you know people will use that are core functionality,
00:11:54
◼
►
and then building the extra things
00:11:55
◼
►
based on what people really want,
00:11:56
◼
►
what are the needs people have.
00:11:58
◼
►
And then when you give it to them, people feel great,
00:12:00
◼
►
because they feel like they just got a bonus,
00:12:01
◼
►
that they got something in addition,
00:12:02
◼
►
it's like they bought X and they just got X plus Y,
00:12:05
◼
►
which is kinda cool.
00:12:07
◼
►
All right, and the last thing I wanted to talk about
00:12:09
◼
►
is just a quick mention of some changes that Linode did.
00:12:12
◼
►
This week, I think I've mentioned many times,
00:12:14
◼
►
I'm a big Linode fan,
00:12:15
◼
►
where I host almost all my stuff.
00:12:17
◼
►
And it's kind of fascinating to me
00:12:18
◼
►
how web services just continues the march towards cheaper
00:12:23
◼
►
and better, just keeps going.
00:12:25
◼
►
And it's kind of remarkable to me,
00:12:27
◼
►
where I was looking at it this week.
00:12:29
◼
►
They've done this whole series of different upgrades
00:12:31
◼
►
and changes to their servers.
00:12:33
◼
►
And the most recent one they announced
00:12:35
◼
►
is that they're changing the way that-- their memory pricing,
00:12:38
◼
►
And they doubled the memory for the same price,
00:12:41
◼
►
essentially, for all of their machines,
00:12:44
◼
►
that you can rent.
00:12:46
◼
►
And the kind of crazy part for that for me
00:12:48
◼
►
is that essentially what they did is in one blog post,
00:12:52
◼
►
they halved my hosting costs for almost all of what I do.
00:12:56
◼
►
For example, right now my recipe book is about $300 a month
00:13:00
◼
►
is what I pay for the service that I have there.
00:13:02
◼
►
And it'll go to $160 after I migrate over
00:13:05
◼
►
to the new structure because for me, the majority of what I do
00:13:08
◼
►
is memory bound rather than CPU, network, bandwidth, storage,
00:13:12
◼
►
those types of binds.
00:13:13
◼
►
And so if they were giving double the memory
00:13:16
◼
►
for the same price, for almost all my things,
00:13:20
◼
►
I can just bump down one tier, migrate over to that,
00:13:23
◼
►
and have exactly the same machine that works perfectly
00:13:25
◼
►
and does exactly what I want, but for half the cost.
00:13:28
◼
►
Obviously, for some people, it would make sense.
00:13:30
◼
►
They'd rather just have twice the memory,
00:13:31
◼
►
and that'd be great.
00:13:33
◼
►
But for what I do, most of it, the memory
00:13:35
◼
►
is the limiting factor, but it's in a way
00:13:37
◼
►
that I want to still have multiple machines.
00:13:39
◼
►
So the limiting factor for the number of requests
00:13:42
◼
►
that a lot of my web services can handle
00:13:45
◼
►
is fairly memory oriented for a lot of what I do,
00:13:48
◼
►
but I still want to have multiple machines for redundancy
00:13:50
◼
►
and for latency and those types of things.
00:13:52
◼
►
So it's just kind of one of those fascinating things
00:13:54
◼
►
how web services are just more and more
00:13:57
◼
►
heading in that direction.
00:13:58
◼
►
And it creates this delightful pressure and competitiveness
00:14:02
◼
►
among hosting providers that I just think is really cool.
00:14:04
◼
►
So anyway, that's it for today's show.
00:14:06
◼
►
Hopefully I'll be shipping Feed Wrangler this afternoon.
00:14:08
◼
►
So wish me luck for that.
00:14:10
◼
►
And hopefully, again, launching probably in about two weeks.
00:14:14
◼
►
So I'm looking forward to that, and I'll
00:14:15
◼
►
have a lot to say on the show.
00:14:17
◼
►
If you have any comments, just let me know on Twitter.
00:14:19
◼
►
Underscore David Smith there.
00:14:20
◼
►
On AppNet, I'm David Smith.
00:14:22
◼
►
And otherwise, have a great weekend.
00:14:23
◼
►
Happy coding, and I will talk to you later.