Building Jaded Gamer
Taking a stab at building a web app, fully hosted in the cloud.
This isn't so much about the technical aspects of building a modern web app, as it is about my own personal experiences and decisions when choosing the services I did when bootstrapping my site, Jaded Gamer.
It’s kind of amazing how many different choices there are for hosting these days. Gone are the days of requiring dedicated server hosting to run apps that aren't built in Perl, PHP, or static html. With platforms like Amazon Web Services, Heroku and other “cloud hosting providers”, its now relatively cheap to bootstrap an app written in Node JS, Ruby or python.
For Jaded Gamer, I decided to go with Heroku for the time being, mainly because it’s nothing new to me. I worked with python on Heroku ever since I was an early beta tester for the platform. For little to no money, anyone can get started developing their app.
After hosting was decided, the first real roadblock I encountered was DNS for hosting an app in the cloud. The suggested route is to setup a cname at the subdomain level- www.yourdomain for example, and forward your root domain to the subdomain. The reasoning for this is hosting on AWS or Heroku, your app isnt exactly tied to a single IP address, so that means having to resort to CNAME instead of APEX (A) records. While you technically can use a CNAME on your root, I’ve come to discover most providers don't actually allow it, as it can break other parts of the DNS, like MX (mail) records.
Because I wanted to host my app at the root, without doing any forwarding, this drastically shortened the list of DNS providers. I eventually chose CloudFlare, mainly because they offer a free plan, as well as additional benefits I'll touch on later. With some magic on Cloudflare’s part (Amazon’s Route 5 also provides a similar solution), I’m able to setup a CNAME on my root, without worrying about any other DNS settings breaking.
It’s funny how much we take email for granted these days. Only a few years ago every hosting plan came with pop/imap support and email with the typical Horde web client or some inhouse interface. It wasn't even that uncommon to have pop/imap that didn't require authentication, initially.
So for Heroku to not offer any sort of Email service felt a little strange, as they already offer a number of other services like Database hosting. They do however provide a number of third party plugins including Mailgun and Sendgrid. For Jaded, I chose Sendgrid as it’s never let me down before. Both however offer near identical services and quality for all their pricing tiers.
It isn't always the case, but the great thing with using various SAAS providers is it’s relatively easy to swap out providers to others assuming you use the same configurations. If I ever need to switch from Sendgrid to Mailgun, it’s as simple as changing a few variables in Settings.py to point to the other service.
Search with Django, is sadly somewhat limited. A lot of people seem content with just relying on Bing or Google for search results in their sites. I experimented with both, as well as a few other basic solutions, but nothing short of rolling my own came close to Haystack. Haystack is, as far as I know, the only production capable django application to provide quality search. Early on I paired it with solr, as it seemed to be the most widely recommended, and supported. Dealing with a couple hundred thousand news items quickly proved to be a little cost ineffective for what I needed it for though.
After shopping around, I eventually chose Elasticsearch offered by Searchly. Besides it being cheaper, Searchly’s documentation was well done, and easy to work with. While their dashboard is straightforward, it offered everything I needed.
Elasticsearch has been nothing short of being amazing to develop with. Once it was set up, there wasn't even a need to rebuild the search index on a routine basis. News stories are updated in real time. In terms of time spent setting up Elasticsearch, it didn't even require any more work to get running than solr did.
Within the first month of having Jaded running, accumulating hundreds of stories every day, I discovered speed would be an issue early on. When it takes close to 30 seconds to load a list of the latest news stories for a given tag or site, you learn to optimize your queries quickly. Even then, when dealing with more complex lists like ranking or generating lists of related stories, it sometimes just takes too long. One of the Django’s greatest features, in my opinion, is it’s cache framework. Between template fragment caching and it’s low level cache API, it made it incredibly easy to implement Redis into the mix. The first time a story is viewed, the related stories get generated and stored to Redis for quick retrieval from then on. It’s still not exactly ideal as it still takes a few extra seconds the first time, but it’s a start.
Additionally, I added Johnny Cache to the mix, and set up a cache whitelist to grab some of the most commonly used queries (the latest feeditems for the week, for example), without needing to rewrite anything. According to New Relic, it saved about 3-6 extra seconds, which I'll take as a win.
As I mentioned earlier, I decided to use Cloudflare because of some of the features they offered. One of which is their ability to cache static assets to speed up the site, again, for free. No need to setup additional services like Cloudfront from Amazon. Thanks to their simple interface, it’s also easy to manage just how strict their service is, ranging from simple to aggressive levels. A pretty amazing and simple service to offer for free.
Initially, the idea was to make the entire site free, and supported by ads. This is still the case. Jaded Gamer was never really designed a s startup to make money. It was always just a hobby. While building the site though, I decided the idea of premium accounts wasn't completely out of the question, and began looking at ways to integrate payment processing.
I didnt want to rely on anything that took too much control from me. I didnt want to require additional signups from something like Paypal. All I wanted was a simple, secure way to process credit cards. Turns out this area is also surprisingly limited when it comes to alternatives. Wepay, Google Checkouts, Shopify, nor Paypal really offered what I wanted. Eventually, I did find Stripe, which so far seems to meet all my criteria. Not only is there a Stripe API for Python, django-zebra also exists, providing forms, widgets, and even template tags for django apps to use. best of all, important information like Credit card numbers arent even stored on Jaded’s database. Instead, a token is generated for each user, tieing them to the purchase through Stripe.
When doing any kind of payment processing online, SSL has become a basic requirement any site should have. If you're building a not so traditional app, running in “the cloud” though, it turns out this can be a little pricey. If you use heroku, youre almost restricted to use their addon, running you $20 per web app. Not exactly a lot compared to what some places will charge for SSL. But, I also didn't want to be stuck with Heroku. Once again, Cloudflare to the rescue. For the same price as heroku, they also provide the same level of SSL per domain. But unlike Heroku, every additional domain is only $5 after the initial $20.
Analytics & Tracking
From Google Analytics, Gaug.es, and Mixpanel, to name just a few, there’s no shortage of analytics services. I've used Google Analytics for years, so it feels only natural to use it. I experimented with both Mixpanel and Gaug.es as well, but ultimately I settled for building my own.
In order to create the trending section, I needed a way keep track of link clicks easily, without having to rely on a third party API to hook into and collect the data. All news items are hooked into the internal app, which records a referral link, timestamp, IP, and if possible, username. From that, I have all the data I need to really do anything I want, from creating the trending section, to generating suggested reading lists for users. I could go on, but I'd rather write a more in depth post about it soon.
I never really set out to build a new startup. It just sort of happened along the way. I'm still not actually even sure I like calling it a startup. It was really more of a learning experience in bootstrapping a modern web application. If nothing else, it makes for an interesting conversation topic.