YunoJuno 101
How we roll
As a gentle introduction to our blog, I thought I'd begin with a brief outline of our technology stack.
We have already published a colophon detailing our stack, and we also publish our git commit log as a changelog, but we will be using this blog as a longer form narrative around our working practices, the tools we use (and how), and also the problems we encounter and how we tackle them (head on, mostly).
I come from a .NET / Windows background, and so a lot of what I am about to say (here and in future posts) was new to me at the time; I've had to learn this 'on-the-job', and so I'll hopefully bring a fresh, outside, perspective to what a lot of seasoned Django developers would consider second-nature.
First off, YunoJuno is a Django app. ("Why?", a VC asked recently. I had a very hard time thinking of a reason why beyond - 'because I wanted to'. I am going to post on this decision at some point, when I've thought of a good reason.)
It is hosted on Heroku. Originally I had thought of hosting the site on AppEngine, having had some experience of running AppEngine sites, and being mightily impressed with it - it would still be my go to solution for simple apps, and in fact our Trello-HipChat bridge runs on AppEngine, but more of that in a later post.
Ultimately, I felt we couldn't go with AppEngine as we had requirements coming down the line that would have meant things like PCI-compliance and financial transaction handling, which meant that having a portable, vanilla Django app was a more practical solution. However, the AppEngine experience meant that I really had no interest in a plain hosting solution (e.g. EC2), and was looking for a more rounded Platform-as-a-Service solution. Heroku fit the bill perfectly, having announced their support for Python not long before, and having proved their commitment to the cause by their recruitment of Kenneth Reitz requests fame, amongst others things). Their 'add-on' model also looked great (too good to be true if I'm honest), and the fact that we could get something up and running for $0 was the clincher. So Heroku it was.
So. We have a Django app and it runs on Heroku. We use the following add-ons:
- Postgres (of course),
- RedisToGo (queueing async processes, which are picked up by an Heroku worker process), and
- Memcachier.
We also use a bunch of other add-ons for operational purposes:
- DeployHooks for posting deployment data to HipChat,
- LogEntries for centralised logging, SendGrid for out and inbound mail.
(Aside: one of the best things about Heroku is that you can add add-ons so easily that trying out services is a cinch. For instance, I knew we wanted centralised logging, but couldn't decide between Loggly, LogEntries and PaperTrail. So I installed all of them, tried them all for a month, and then dropped Loggly and PaperTrail in favour of LogEntries (clearer UI, easier to navigate IMO).)
We have four main environments running on Heroku - dev, demo, uat and live. They should be pretty self-explanatory - suffice to say they do what they say. Because of the Heroku 12-factor app philosophy, the codebase is identical across all environments, with connection strings and 'secrets' being stored in environment variables.
We use Fabric everywhere to automate anything that can be: setting Heroku environment variables (which are stored in source control, but separate from the main codebase); deploying the app to any environment; migrating the live data to another environment (and anonymising it on the fly); and all the standard django_admin commands - syncdb, migrate, collectstatic etc. Pretty much everything we need to do is a shell command away.
Locally, the dev team are all [freelancers])https://www.yunojuno.com/humans.txt), and have a variety of tools and tricks up their sleeves. We do now have a Vagrant VM set up to mirror (ish) the Heroku environment, so it is possible to develop with just Sublime Text and VirtualBox running, albeit I seem to be the only person who feels the need to do that.
We store our code in BitBucket (Git), and have four repositories set up:
- docs - documentation, in markdown format
- config - Heroku configuration settings (env vars) for all environments, along with Fabric scripts for all Heroku related tasks - deployments, configuration etc.
- vagrant - our vagrant provisioning scripts and Fabric scripts for all VM related tasks - reloading Nginx configuration, bringing down a copy of the live (anonymised) data for testing, interacting with the Django admin commands on the VM.
- website - the code itself. Clean and simple, no 'secrets' or live configuration information, no extraneous cruft.
And that's pretty much it, for now. I haven't really talked about our team workflow here - that's for another time.
Making Freelance Work