Developing Perspective

#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:36   scenario.

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:07   it.

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:19   technical.

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   cases.

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:53   about that.

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:37   basically.

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.