Your internet sucks.

I've been very disheartened with the internet recently.  Between Twitter's Nazis and Facebook's data collection, ad policies and democracy manipulation, I've begun to feel like the internet that I loved was gone.  And as more people almost exclusively spend time using services that are run by corporate entities, these services are systematically killing off third party access to their content in order to lock you into an experience that they control.

While there are the easy targets of Facebook and Twitter it goes so much deeper.  Slack has come to control chat, YouTube holds almost the entirety of user-generated video and people's entire photo collections are handed over to Instagram.  And even though my personal email isn't hosted with Google, "Google has most of my email because it has all of yours".

The internet used to be the great equalizer.  It didn't matter what you looked like, how much money you had, or what circles you were a part of.  The nerds and weirdos ran things, and it felt like home.  Now people fabricate their entire lives to impress people on Instagram every day and the business people, celebrities and "pretty people" control things.

So instead of just watching the real internet that I cared about fade away, I put my time and money where my mouth is and picked one thing that meant the most to me.  A piece of the internet that has been there every day for me since the day that I first logged on.  And that's Internet Relay Chat.  So let me quickly talk about IRC.

IRC was first created in 1988.  It's an internet standard, just like FTP, the web or SMTP, IMAP and POP3 is with email.  Anybody can run an IRC server and connect to each other to form IRC Networks.  There have been networks of IRC servers that have been around longer than the web has.  But in general, regular people have left IRC.  And that's no surprise.  When IRC was at its peak the internet was less mainstream.  As the internet matured the corporately controlled destinations popped up and one by one people spent less time on IRC and went to where not only their online friends would be, but where they could find their real-life friends as well.  Freenode, an IRC network focused on software developers and open source, is the single exception here, where it's actually grown with the explosion of open source software.  But even in this use case, Slack has become the new standard when it comes to new real-time chat communities popping up online.

irc.002.jpg

I've been involved with an IRC channel (chat room) called #TheCabin on EFnet since 1995.  Some of my closest friends I met there, and I still talk to them there daily.  Marriages have taken place because of #TheCabin,  I've traveled to meet people I knew from #TheCabin, and people have traveled to meet me.

And you know what has changed about IRC all this time?  Absolutely nothing.  You can still log in with any IRC client that you'd like and start chatting with people from all over the world without giving up your name or email address, viewing ads, being profiled, or losing a sense of anonymity.  No profiles, no data leaks.  Just the internet like it used to be.

So if the "modern internet" kind of sucks and #TheCabin on IRC is great, but people still aren't using it, what could I possibly do about it?  Try and make #TheCabin more like the other services.  This means looking at modern internet products and molding #TheCabin into something that resembles it.

I asked myself "What if I were to package, market and treat #TheCabin as if it were a modern product?"  And after a little convincing of my friends in #TheCabin, I put together a plan to put a new coat of paint on a very old cabin.

This starts with all the things any other product would have, beginning with an actual product marketing web page.  And what do you find when you get somebody to this page?  The same thing you'd find with any other product's home page:  Next to all of the bullet points of why you should try it you'll find the links to the iOS, Android and web apps.

And how do you get people to this page in the first place?  You make an ad and you run it where people are.  Ours talks about #TheCabin in comparison with other internet properties and the gratification you get when you have a mix of real friendships, anonymity and not having to play the selfies/fabricated life/followers game.

So while anybody can join #TheCabin with any IRC client that's not what the modern internet user expects.  A certain amount of convenience is required to get people in the door these days, so #TheCabin has a native iOS, Android and web app that make it super simple to join us on IRC.  No servers, no learning about clients, channels, and protocols.  You just go to the App Stores or click on a link like you would with anything else and you'll end up in #TheCabin not even realizing you're taking part in an open service that pre-dates the world wide web.

This isn't the first time I've released an app for #TheCabin, but it is the first time I've released one where the audience is new people instead of existing users, and the first time I've released on three platforms simultaniously.

But I'm not telling you any of this to get you to visit us in #TheCabin.  If you want to, that's awesome, we'd be happy to have you.  You might hate it.  We might hate you.  That's the fun of it. Though if you're somebody that thinks it might be inappropriate to be hanging out there (close connections and family members of existing cabiners, people who only know existing cabiners professionally, etc), then it's probably not appropriate for you to be hanging out there.  But the reason I'm telling you about #TheCabin and our journey is because there's a whole internet out there that isn't controlled by corporate interests, that isn't making you trade privacy for services and isn't trying to sell you anything.  So please, find a piece of that internet that works for you and hold onto it.

I know there's a limit.  I can't seriously suggest we all start hanging out on Usenet, running our own YouTube video hosting service replacment or trying to find a new Gopher server that we'll really love.  But do you use a non-Gmail email provider that you pay for and think provides a quality service?  Tell a friend.  Are you starting a community that requires real-time conversation?  Maybe don't default to Slack and find an open solution instead.  Want to write a blog post?  Make sure you own your content and you're not just handing things over to Medium.  Start your own website.  Don't trust others to keep your stuff safe.  Pay for services.  When you give them money they owe you something in return, while free services have to make you a lower priority.

And as for IRC, there's still a future.  There's a push to give IRC a facelift with IRCv3, something I hope gets widely adopted.  Adding features like supporting threaded messages, extended metadata, native web support, chat history, etc.  All things that people come to expect after being used to things like Slack.

And trust me, I'm not perfect.  I have a Facebook and Twitter account and I'm not looking down on anybody for what they choose to do online.  After years of hosting my own website, I now use Squarespace.  I use a ton of services both paid and not after years of learning what made sense to host myself and what made sense to pay somebody else to do.  Heck, I'm running ads for #TheCabin on the very services I'm complaining about. But I like to think I can use them without giving my life to them, but I know it's a slippery slope for all of us, so maybe I'm wrong.  One day you're using Gmail because it's free and the next thing you know there's only four email providers left in the world that are federating between each other.  You write one medium post and soon it owns all of your written content.  You rely on Facebook 100% for your internet presence and overnight they change their algorithm and hide your posts.  And before we all know it all we can do is use the Wayback Machine to remember all that we lost, and what the internet used to be.

Why I love developing for the Apple TV

tvOS isn’t getting the credit it deserves. I've found Apple TV the platform that I’ve had the most fun developing for in a long time.

The television is the physically largest canvas currently available.  What has been a central point of the living room has historically been the most difficult thing to break into.  The number of people willing to build awkwardly horrible “Samsung apps”, for example, are very few.  Even the Roku, previously the most accessible developer platform, has a very small developer footprint.  I wrote about developing for Roku previously.  Having the power, flexibility and ubiquity of UIKit allowing you to turn this canvas into anything you can imagine is really very gratifying.

But just being able to build for the big screen alone isn't why I enjoy developing for the Apple TV.  There are real things that make tvOS apps better than their mobile counterparts.

As a developer, how many times have you sat with your designer talking about the tap target sizes of UI elements in your iOS application?  I’ll venture to guess it’s more than you’d like.  But this isn’t a problem with tvOS’ Focus Engine.  Anything that’s selectable is made obvious via the elements as you explore each screen with your remote.  It doesn’t matter how small the element is, with the Focus Engine it’ll jump out at you.  The defaults with UIKit elements literally make these items larger when selected, and with UICollectionView, you can directly manipulate them via remote gestures.  This is even better than direct manipulation on a phone or tablet surface where your figures cover up the element you’re interacting with.

 Image courtesy of https://medium.com/@flarup/designing-for-the-apple-tv-5992c3aab1e4#.71q02v28u

Image courtesy of https://medium.com/@flarup/designing-for-the-apple-tv-5992c3aab1e4#.71q02v28u

I'll be the first to admit the navigation paradigms of iOS applications have a lot to be desired.  It really does cause cognitive overhead for a user as sometimes screens “come from the side” in a Navigation Controller stack, but others “come from the bottom” as a presented modal.  And then there’s nav stacks within modals and gestures with custom transitions all adding a whole other level of what seems like no rhyme or reason to the user.  This has been simplified with tvOS.  If you navigate to a new screen, regardless of how the developer is presenting it, there is no difference in the appearance.  Pushing to the stack looks the same as if you’re presenting a view controller.  And what’s best, the Menu button always brings you back to where you came from, regardless of how you got there.  The developer may be forking you off in any number of navigation trees, but the user doesn’t have to know or care about it.  You can save those discussions about your overly complex navigation architecture and go get a nice coffee with this time instead.

Of course there are exceptions to everything I've stated.  You could easily create custom focused appearances that makes something hard to find, or any number of crazy navigation schemes.  But the point is that tvOS was built for simplicity.  Sure, every mobile app developer will tell you they're trying to get you to the most important thing in the least number of taps possible, but it's obvious that's only partially true.  iOS applications don't usually adhere to the "If it's not important, leave it out" category.  tvOS apps (at least currently) do.  Content is the priority, not share sheets, find friends and "OMG Rate Me on the Appztore Plz" popups.

I've only had the privilege of building one application for The Apple TV, the same one I built for Roku, The Bat Player, and it's been a fantastic experience.  I encourage you if you have an idea that works for the big screen to build it.  Especially applications, since there's currently a ton of games, but not a lot else.

Feel free to reach out if you're building something cool for the Apple TV, I'd love to hear about it.

Goodbye, Rdio

Like everybody else, I felt like I had heard every song on Pandora by the time I discovered Rdio.  I was user number 4075, a paid unlimited user, signing up on June 6, 2010.  I was really happy to hear anything I wanted.  I used the Rdio Desktop client to create a collection on the service with my local iTunes Library.  I listened to it a lot.

Like many others, I moved to Spotify once it finally came to the US.  I don't recall why exactly, but if I know myself like I think I do it was simply because I wanted to try something else.  But I always thought as Rdio as the service for music lovers.

I ended up with a role at Rdio due to an acquisition.  They were bringing in the TastemakerX team.  There were other places the TMX team could have landed, but I wanted it to be Rdio.  It was perfect.  Just the right size, opportunities for growth, and most of all I'd be working on a product that people really, really loved.

I worked on handful of very different things while at Rdio.  When I joined they were midway through a major redesign.  I jumped in cranking out parts of the UI that still needed to be done.

I did a hardware integration for Jaguar/Landrover using Bosch's technology.  I doubt many people have seen that work, but it was cool to be working with hardware.

I think I was the only engineer that started and finished the Rdio Live project.  Live wasn't a popular feature within the company, and I understand that it only happened for political and business reasons.  But by the the time it launched people thought it was cool.  And it was.  We got terrestrial radio seamlessly integrated into an on-demand service.  It worked way better as an experience than I thought it would.  It even brought in new users.  I was told it was the most friction and hassle free launch in Rdio's history.  So that's something.

The mobile team was small.  Probably too small.  But I preferred it that way.  I got to work on every piece of the codebase.  Sure, the original app was in C#, due to a decision by people no longer at the company, to utilize Xamarin, but the current team didn't want it, or like it.  So we started rewriting it.  We were building from the ground up, in Swift (with some Objective-c), a new iOS application that will never see the light of day. I was focusing on the playback engine, something I've never done a deep dive into before.  As a side effect of Swift being new, and C# being new to me, this means I developed in two new languages in under a year and a half on a daily basis.  So again, that's something.

I may be the only person who received an offer from Pandora who feels about 50/50 if they will accept it or not.  I always told people Rdio is about as large of a company as I'd want to be at.  When I started I think it was just around 150 people.  It's probably closer to 200 globally now.  Pandora touts 1800+ employees.  I asked representatives to explain how I won't get lost in a sea of engineers.  They couldn't tell me I wouldn't.  They couldn't tell me I'd matter.

There's a possibility I'm more touchy about this than the rest of my team because this is the second time I've been acquired in two years.  Maybe I feel like I'm being pushed around with no control over my own destiny.  That I can be bought and sold to the highest bidder.  I don't actually feel this way, I can walk away at any time.  But the fact that it's come to mind at all means there might be something to it.

Rdio's shutdown isn't just a loss to me, or the people I share an office with every day.  It's a loss to the world of music.  Rdio was the service for music lovers, by music lovers.  In this world of The Streaming Services vs. The Music Business it's not enough to love music to keep the lights on.  There's no guarantee Pandora can do any better.  They're the ones, prior to their IPO, who were petitioning the copyright royalty board every few years saying they'd go out of business if rates were hiked up.  They're trying to pay less to artists.  The same artists who are already trying to put the streaming services out of business.  So I'm not sure how this can end well.

Regardless of any of this, Rdio will be a thing of the past soon.  A story about a fantastic product sold in a fire sale because the music streaming industry is brutal.  But I'm really lucky to have been a part of it, even for a short time.  Goodbye, Rdio.  You had too much empty whitespace.

Launching The Bat Player on the Roku Store and its aftermath

After a year of development The Bat Player went live on Roku's Channel Store.

The Bat Player first went public in September of last year.  This means if you knew the right Roku Channel Code you could install it on your device.  I put up a web site to make this easier, and shared it with a couple specific communities like the Roku forums and Reddit's Roku subreddit.

My goal all along was to get it available in their mainstream directory.  But between their approval delays (It can take months for them to get you in their queue) and many requested change iterations, it took some time.  Add a period early this year where I took time off trying to get it approved, and you'll see why it took so long.

But that's not what this post is about.  It's about what happened after it went live.

But first let's quickly go over how The Bat Player works.

As far as the audio aspects go it's a pretty dumb application.  It doesn't really know much.  Due to Roku's limitations with streaming protocols it doesn't know even when a song changes.  To overcome this I built a service, known as The Bat Server that can be ping'ed with a URL to find the title of what's playing on a station via a variety of different methods.  This part I actually broke out in to my first public Node.js module.

Easy enough, but that's not what I wanted The Bat Server for.  I wanted contextual, useful information.   So knowing the artist name allows me to grab some relevant information from Last.FM's API.  That too, is easy enough.

Song information is more difficult.  I query a few different services (Last.FM, Discogs, Gracenote, Musicbrainz) to get an array of possible albums a track could be from.  Then I try to make an educated guess based on available information.  This whole song and dance is pretty expensive.

On top of this the client makes separate calls to The Bat Server to do some image manipulation for a few things (dynamic header images, station icon resizing, building backgrounds and artist images) via ImageMagick on the fly. 

All this happens every time a new song is seen by The Bat Server.  It's not efficient, it doesn't work at scale, and it was living on one tiny server.  But I only had about 800 installs.  So I figured eventually when I got approved for the Channel Store I'd get a couple hundred installs more one day, half of those people would try it, and things would level off and I could reassess down the road if needed.  I underestimated the Roku Channel Store.

Once it was available thousands of new users brought The Bat Server to its knees the first day.  My single t2.small EC2 instance was not up to the task, though in retrospect I did have a few things early on that I'm really thankful for now.  

I cached everything.  Data gets saved to Memcache, so an Artist, Album, Song only gets processed once.  Also, images get pulled through Amazon Cloudfront.  So those crazy dynamic images eventually make it to the edge servers and won't touch my server again.  And lastly I put Varnish in front of the Node.js service as a way to have a handle on how long a previous request can stay as a cached result before we go to the internet radio station to determine what's playing again.  If all fails I can dial up the cache duration.

I also added centralized logging and Analytics not just from the service, but also from the clients themselves. I did this with an Amplitude library I released and a syslog client I built into the client. Both written in Brightscript.  I wanted insight on what was going out in the field.

But no amount of caching or logging was going to save this.  Luckily I was already using EC2 for my existing instance, but now it was time to put myself through a self-run AWS Bootcamp.

First off, I needed to handle the new load.  So I created a new t2.large and an Elastic Load Balancer.  I pointed DNS for the existing server to the load balancer and put the two servers behind it.  Things became much happier quickly, but I knew this was only a stop-gap measure.  I needed some auto-scaling action.

Since I added the t2.large I bought myself some time to figure out what the best AWS CloudWatch metrics would be in my situation to scale capacity.  At first my alarms were a bit too aggressive, causing servers to go in and out pretty frequently, but I eventually leveled them out, finally feeling confident enough to pull the t2.large out of the load balancer and let the system manage itself.

With this new infrastructure I needed some insight into it, so between Runscope for API monitoring (I so love this service), New Relic for server monitoring, Papertrail for the above logging, Rollbar for Node.js application error reporting, and Datadog I was able to put it all into one nice little interface.  Add Zappier and Pushover with some webhooks and I now get custom alerts right to my Apple Watch.  But man am I paying for a lot of services now.  I hope once some time passes without any incident I can get rid of some of these services.

So now what?  Well obviously things aren't perfect yet.  Each server has its own instance of Varnish, so that's pretty stupid.  But that's a side effect of my reactive-scaling.  So maybe I'll [Varnish] -> ELB -> [Servers], but that would require an additional, full time EC2 instance just for caching, plus I read that putting an ELB behind Varnish isn't terribly awesome.  I never thought I'd miss managing F5 BIG-IPs!

So what did I learn?  The obvious, really.  If you're going to build a single-homed, power hungry service, be prepared to scale horizontally.  And what I did to fix it wasn't novel, it's what these AWS resources were created for.  I also learned that the extra effort I put in up front both for analytics and logging made it easier to know what was going on.  And lastly, utilizing the Right Tools For The Job™, in this case memcache, varnish, and the array of services from AWS, really allowed me to take something that would have only handled a few hundred users initially to something that I feel confident I can scale out to any size.

Enjoy the tunes! 

Developing for Roku

Ask yourself, "Do I know anybody who's developed anything for the Roku Media Player?"  More than likely the answer is no.  If you ask others you might get get some response, but more than likely nobody you know has done it either.

And that's why I wanted to throw up a little piece about building for the Roku.

Chapter 1: I want to listen to Streaming Internet Radio.

 Marantz audio reciever

Marantz audio reciever

For me it started innocently enough.  I wanted to listen to streaming internet radio.  I had been listening using my Marantz home theater receiver.  This was ok, I guess.  The interface looked like this:

Not awesome.

My next thought was the AppleTV.  I use my AppleTV for everything else.  The interface is pretty good, but not great.

 AppleTV

AppleTV

But then I learned of a major deal breaker: You can't add your own stations.

So I looked at other options.  Run an iOS app and AirPlay mirror it to the AppleTV?  While that works that's not elegant in any stretch of the imagination.  Build an HTPC?  Get a Raspberry Pi?  All valid options.  But then I remembered that Roku had a ton of available content.  Surely it must have what I'm looking for.  Next thing you know I have a Roku 3 on order.

It turns out I was right.  The Roku had a ton of applications (they call channels) that focused on music and streaming audio.  Here are some of them:

With the SHOUTcast Radio application being the only one I could find that I could add my own stations, I was a step further than I was before.  But, as you can see, a lot of Roku apps have a very templated feel to them.  I later learned why this was.

I started thinking of other features I'd really like.  Last.FM Scrobbling, Adding to Rdio playlists, updating my room lighting with my Philips Hue system.

Chapter 2: Why Don't I Just Build My Own?

Before I knew it I was browsing around the Roku Developer portal.  Things I learned right away:

  1. They have an open SDK.  Cool!
  2. You write in a language called BrightScript.  WTF is BrightScript!?
  3. Callbacks and async stuff happens through a "message port".
  4. You have to support SD and non-widscreen TVs.
  5. They have an approval process like Apple to get on their channel store.

Sounds fair enough.  Let's go through this.

But here's my disclaimer:  I've developed one Roku channel, and there are people who know much more about it than I do.  I did about as well as anybody who's building something for the first time with a technology would, and I'm only giving my initial thoughts.

BrightScript is fundamentally a bastardized version of BASIC.  It's a language so obscure often a Twitter search for the word will bring up zero results.  Roku's SDK provides you a limited set of native objects like Arrays, Associative Arrays, an HTTP client, Bitmaps, etc.  You create one of these objects with a simple syntax of

myArray = CreateObject("roArray")

Everything starts with ro and it's weird to create an object by it's string name.  But whatever.

But those objects are it.  You can't subclass, you can't create your own first class citizens, and you are at the mercy of the SDK.  

So without being able to specify custom objects it seems that any Object Oriented approaches are out the window.  Oh no my friend.

This is where your new best friend, the roAssociativeArray comes into play.  You'll use it for everything.  And you'll use it for this too.

Let's say we wanted to build a simple cache class.  We'd do something like this:

So let's go over this.

  • Your "class" is really just an associative array.  ( {} is the AA shortcut, like in other languages).
  • m is a weird magical variable that points to your associative array as long as the function was fired via the declaration in your "class".  In this case you obviously just can't call "cache_add" directly, you'd have to call YourCacheInstance.Add in order to get the magical m.
  • But cache_add is still completely pubic and accessible and totally confusing to people who may be reading your code.  You shouldn't access it directly, but that doesn't mean you can't.

Ok, so what's this port?  It's roMessagePort.  And it's stupid.

Have you ever written a video game using a game engine?  You have the game loop, where every cycle of the loop you can do things like move a sprite, check for collisions, make the blue box turn red... that kind of thing.  Where in modern application development that kind of thing is abstracted from you this is mostly how Roku applications work.  With one big event loop.

So if you have a screen that you expect user interaction with first you create a roMessagePort object, assign it to the port of your screen, and then start the loop waiting for something to happen.

Here's a simple example:

And yes, you don't use double equals for comparison.

"But what if you make multiple roUrlTransfer requests and they start coming through a port.  How do you know what each is connected to!?" you're currently saying in disgust.  Well our friends at Roku has come with a way to work around that obvious oversight.  They added a GetIdentity to its interface so you can compare request data coming in to the original request to see who owns it.  Otherwise you'll be saving FancyPhoto.jpg's data to a file called importantdata.json.  So you'll have to keep the original request data around somewhere while you wait for responses to come in.  (If it's an async request you have to keep an active reference somewhere or it'll die in transfer anyway, but that's besides the point).

So with the basics of how you work with data out of the way let's talk about the UI.

Remember seeing a bunch of screenshots above that all look similar?  Say hello to roSpringboardScreen.  Just another piece of the SDK.  You pass it some data and it lays it out to look like that.  It's easy, it's fast, and it gets the job done.  Roku supplies a ton of screens that do this type of thing.  roParagraphScreen, roPosterScreen, etc.  The obvious downside is almost every Roku application looks the same.

So I took the approach early on that I wanted to do something different, especially for the "Now Playing" screen.  So I jumped at roImageCanvas.  It does what it sounds like.  You can put images on the screen wherever you want.

roImageCanvas has a lot of niceties.  A built in HTTP client so you can point to URLs instead of having to download things and handle local files yourself and being able to pass a simple array of things to draw are two of them.  For most things this really should be good enough.  But once I implemented my Now Playing screen with it I found I wanted even more control and flexibility.  This is when things got dark.

Working with Roku's roScreen is taking that game loop comparison to the next level because it's literally for building games on the Roku.  But there's no middle ground between roImageCanvas and roScreen.  If you want to do any kind of dynamic visuals on your screen you're giving up doing things Roku's easy way.

So let's talk about how to do some simple things with roScreen.

  1. Want to move a box across the screen?  There's no way to ask an object where it's location is, so when you draw something to the screen keep note of its coordinates.  Next time the loop hits you increment that number.  Then redraw the object with the new coordinates.
  2. Want to fade something in?  Draw it to the screen as completely transparent.  Then much like the previous example, keep incrementing the alpha value at the rate you want until it gets to the alpha you want.

But you better watch out.  Doing things like drawing text and drawing alpha'ed regions are expensive for the Roku to handle.  Luckily roScreen does double buffering so you don't see a flicker while it's cranking through all of that heavy work like making words appear.

For example, you'd want to do this on every loop if you want to do any movement.

But if it's static, and you have no reason to keep redrawing the screen, you don't have to.

This is when that requirement of supporting SD and non-widescreen displays comes into play.  You have to make sure your UI within this screen lays out properly.  Where if you were using any of the SDK canned screens like roSpringboardScreen all this would happen magically for you.  Even roImageCanvas has support for this kind of thing.

Chapter 3: Testing Your Channel

And how do you test on old screens?  Well if you have a Roku 3 it doesn't support analog/non-widescreen/SD, so you'd be like me and purchasing a second Roku, a Roku 2.  After discovering there are major performance differences between the Roku 2 and Roku 3 you'll probably also want to purchase a Roku Streaming Stick in order to verify your application on all the hardware.

But after all that hard work you'll want others to try it out.  And much like the Apple App Store, having your work publicly available is a source of personal pride.

Unlike Apple, anybody who builds a Roku channel can make it publicly available.  You upload it to the Roku developer portal and they give you a link.  Via that link anybody can install it on their device.  This is great for getting a small group to test all your hard work.

The packaging process is simple.  You zip it up, you upload it to your personal Roku, you type in a password that was generated previously, and you download it from your Roku to upload to their portal.

Chapter 4: Distribute On The Roku Channel Store

But just having it available isn't enough.  You want it on their Roku Channel Store.  Just like the Apple App Store that's where people discover new applications and where you'll get the users.  But it'll have to get approved first.

With Apple a worst case scenario is about two weeks unless there's some special reason they aren't approving you.  With Roku, let me put it this way: I uploaded my application on September 11th.  That's right, it's been 88 days since I submitted for approval.

I did hear from them once about a month in asking me if I could upload a new version that listened on a different HTTP port number in my code.  I did, and then I never heard from them again.  I email them about once a week asking for an update, but never a response.  This kind of treatment is enough for me to say "Screw Roku!" and why I'd probably never build a second application on their platform.

All this on top of the small things you might forget about when building for an obscure platform.  Anything you've built before probably has a drop in analytics library so you can get your Google Analytics or whatever going without any effort.  For me I ended up building a BrightScript analytics package for Segment.IO.  Want other 3rd party features?  Those SDKs they provide aren't going to work here.  For me I integrated Rdio, the above Segment analytics, Philips Hue and Last.FM on top of my own custom APIs.

So in closing, I'm certainly not saying that you shouldn't develop for the Roku if you're thinking about it.  On the contrary, it's a really fun challenge to build using an environment that's probably completely different than you're used to.  And if it's a pure numbers game, there are more Rokus attached to TVs than Nexus Android Players or Fire TV boxes combined by an order of magnitude.  It's not even close.  But keep your expectations in check, keep your feature set low, and expect to get creative with the solution you come up with.

Or just wait until you can write for the AppleTV.