<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Craig Kerstiens]]></title>
  <link href="http://www.craigkerstiens.com/atom.xml" rel="self"/>
  <link href="http://www.craigkerstiens.com/"/>
  <updated>2012-05-07T10:44:02-07:00</updated>
  <id>http://www.craigkerstiens.com/</id>
  <author>
    <name><![CDATA[Craig Kerstiens]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Why Postgres Part 2]]></title>
    <link href="http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2/"/>
    <updated>2012-05-07T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2</id>
    <content type="html"><![CDATA[<p><em>This post is a list of many of the reasons to use Postgres, much this content as well as how to use these features will later be curated within <a href="http://www.postgresguide.com">PostgresGuide.com</a></em></p>

<p>Last week I did a post on the <a href="http://www.craigkerstiens.com/2012/04/30/why-postgres/">many reasons to use Postgres</a>. My goal with the post was two fold:</p>

<ul>
<li>Call out some of the historical arguments against it that don&#8217;t hold any more</li>
<li>Highlight some of the awesome but more unique features that are less commonly found in databases.</li>
</ul>


<p>Once I published the post it was clear and was immediately pointed out in the comments and on <a href="http://news.ycombinator.com/item?id=3910743">hacker news</a> that I missed quite a few features that I&#8217;d mostly come to take for granted. <em>Perhaps this is due to so much awesomeness existing within Postgres.</em> A large thanks to everyone for calling these out. To help consolidate many of these, here&#8217;s a second list of the many reasons to use Postgres:</p>

<h2>Create Index Concurrently</h2>

<p>On most traditional databases when you create an index it holds a lock on the table while it creates the index. This means that the table is more or less useless during that time. When you&#8217;re starting out this isn&#8217;t a problem, but as your data grows and you then add indexes later to improve performance it could mean downtime just to add an index. Not surprisingly Postgres has a great means of adding an index without holding that lock. Simply doing <a href="http://www.postgresql.org/docs/9.1/static/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY"><code>CREATE INDEX CONCURRENTLY</code></a> instead of <code>CREATE INDEX</code> will create your index without holding the lock.</p>

<p><em>Of course with many features there are caveats, in the case of creating your index concurrently it does take somewhere on the order of 2-3 times longer, and cannot be done within a transaction</em></p>

<h2>Transactional DDL</h2>

<p>If you&#8217;ve ever run a migration had something break mid-way, either due to a constraint or some other means you understand what pain can come of quickly untangling such. Typically migrations on a schema are intended to be run holistically and if they fail you want to fully rollback. Some other databases such as Oracle in recent versions and SQL server do support, this. And of course Postgres supports wrapping your DDL inside a transaction. This means if an error does occur you can simply rollback and have the previous DDL statements rolled back with it, leaving your schema migrations as safe as your data, and your application in a consistent state.</p>

<h2>Foreign Data Wrappers</h2>

<p>I talked before about other languages within your database such as Ruby or Python, but what if you wanted to talk to other databases from your database. Postgres&#8217;s Foreign Data Wrapper allows you to fully wrap external data systems and join on them in a similar fashion to as if they existed locally within the database. Here&#8217;s a sampling of just a few of the foreign data wrappers that exist:</p>

<ul>
<li><a href="http://pgxn.org/dist/oracle_fdw/">Oracle</a></li>
<li><a href="http://pgxn.org/dist/mysql_fdw/">MySQL</a></li>
<li><a href="http://pgxn.org/dist/redis_fdw/">Redis</a></li>
<li><a href="http://pgxn.org/dist/twitter_fdw/">Twitter</a></li>
</ul>


<p>In fact you can even use <a href="http://multicorn.org/">Multicorn</a> to allow you to write other foreign data wrappers in Python. An example of how this can be done, in this case with Database.com/Force.com can be found <a href="http://blog.database.com/blog/2011/11/21/a-database-comforce-com-foreign-data-wrapper-for-postgresql/">here</a></p>

<!-- more -->


<h2>Conditional Constraints and Partial Indexes</h2>

<p>In a similar fashion to affecting only part of your data you may care about an index on only a portion of your data. Or you may care about placing a constraint only where a certain condition is true. Take an example case of the white pages. Within the white pages you only have one active address, but you&#8217;ve had multiple ones over recent years. You likely wouldn&#8217;t care about the past addresses being indexed, but would want everyones current address to be indexed. With <a href="http://www.postgresql.org/docs/9.1/static/indexes-partial.html">Partial Indexes</a> becomes simple and straight forward:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>CREATE INDEX idx_address_current ON address <span class="o">(</span>user_id<span class="o">)</span> WHERE current IS True;
</span></code></pre></td></tr></table></div></figure>


<h2>Postgres in the Cloud</h2>

<p>Postgres has been chosen by individual shops and been proven to scale by places such as <a href="http://media.postgresql.org/sfpug/instagram_sfpug.pdf">Instagram</a> and <a href="http://ontwik.com/python/disqus-scaling-the-world%E2%80%99s-largest-django-application/">Disqus</a>. Perhaps even more importantly it&#8217;s becoming easy to use Postgres due to the many clouds that are running Postgres as a Service, such as:</p>

<ul>
<li><a href="http://postgres.heroku.com">Heroku Postgres</a></li>
<li><a href="http://www.vmware.com/products/application-platform/vfabric-data-director/features.html">VMware vFabric</a></li>
<li><a href="http://www.enterprisedb.com/">Enterprise DB</a></li>
<li><a href="https://www.cloudpostgres.com">Cloud Postgres</a></li>
</ul>


<p><em>Full disclosure, I work at <a href="http://www.heroku.com">Heroku</a>, and am also a large fan of their database service</em></p>

<h2>Listen/Notify</h2>

<p>If you want to use your database as a queue there&#8217;s some cases where it just won&#8217;t work, as heavily discussed in a <a href="http://mikehadlow.blogspot.se/2012/04/database-as-queue-anti-pattern.html">recent write-up</a>. However, much of this could be discarded if you included Postgres in this discussion due to Listen/Notify. Postgres will allow you to <a href="http://www.postgresql.org/docs/9.1/static/sql-listen.html">LISTEN</a> to an event and of course <a href="http://www.postgresql.org/docs/9.1/static/sql-notify.html">NOTIFY</a> for when the event has occurred. A great example of this in action is <a href="http://www.twitter.com/ryandotsmith">Ryan Smith&#8217;s</a> <a href="https://github.com/ryandotsmith/queue_classic">Queue Classic</a>.</p>

<h2>Fast column addition/removal</h2>

<p>Want to add a column or remove one. With millions of records this modification in some databases could take seconds or even minutes, in cases I&#8217;ve even heard horror stories of adding a column taking hours. With Postgres this is a near immediate action. The only time you pay a higher price is when you choose to write default data to a new column.</p>

<h2>Table Inheritance</h2>

<p>Want inheritance in your database just like you have in with models inside your application code? Not a problem for Postgres. You can have one table easily inherit for another, leaving a cleaner data model within your database while still giving all the flexibility you&#8217;d like on your data model. The Postgres docs on <a href="http://www.postgresql.org/docs/9.1/static/ddl-inherit.html">DDL Inheritance</a> do a great job of documenting how to use this and giving a very simple but clear use case.</p>

<h2>Per transaction synchronous replication</h2>

<p>The default mode for Postgres streaming replication is asynchronous. This works well when you want to maintain performance, but also care about your data. There are cases where you want your replication to be <a href="http://www.postgresql.org/docs/current/static/warm-standby.html#SYNCHRONOUS-REPLICATION">synchronous</a> though. Furthermore, for some cases asynchronous may work well enough where as other data you may care more about the data and want synchronous replication, within the same database. For example, if you care about user sign-ups and purchases, but ratings of products and comments is less important Postgres provides the ability to treat them as such. With Postgres you can have per transaction synchronous replication, this means you could have strong data guarantee on your user and purchase transactions, and less guarantees on others. This means you only pay the extra performance cost where you really care about versus an all or nothing approach you have with other databases.</p>

<h2>Conclusion</h2>

<p>Hopefully you&#8217;re convinced on why Postgres is a great tool, if not take a look back at my <a href="http://www.craigkerstiens.com/2012/04/30/why-postgres/">previous post</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Feedback for Conference Organizers]]></title>
    <link href="http://www.craigkerstiens.com/2012/05/04/feedback-for-conference-organizers/"/>
    <updated>2012-05-04T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2012/05/04/feedback-for-conference-organizers</id>
    <content type="html"><![CDATA[<p>First a huge thanks to all organizers of conferences, but especially for those that organize not-for-profit conferences. I do understand its a great amount of work, and in nearly all cases have greatly appreciated the experience made available by the work they put into it.</p>

<p>As for some guidance. I&#8217;ve been on nearly all sides of the conference with the exception of organizing, so again organizers please don&#8217;t take offense to the feedback.</p>

<h2>First on timeline</h2>

<p><em>Please publish this early on your site and on <a href="http://www.lanyrd.com">lanyrd</a></em></p>

<ul>
<li>Deadline for CFP</li>
<li>Deadline for Call for Sponsorship</li>
<li>Publish speaker list</li>
<li>Early bird registration ends</li>
<li>Regular registration ends</li>
</ul>


<!-- more -->


<h2>As a sponsor</h2>

<h3>Early dates and times</h3>

<p>As a sponsor please give very early notice of your conference times. As an attendee I can determine within a couple months or even sometimes a few weeks if I&#8217;m able to make it to the conference. As a sponsor unfortunately I&#8217;m more restricted by budgets and timelines.</p>

<h3>Give me options on sponsorship</h3>

<p>A prospectus is great, and often times I&#8217;m completely happy with it. Other times there&#8217;s things I may want to sponsor that are not on the list. If videos aren&#8217;t already being recorded I&#8217;d love to see the content live on, and this is an immediate place that jumps out as valuable to sponsor. Often times flexibility doesn&#8217;t cause me to sponsor or not, but it does leave a clear reminder of my experience.</p>

<h3>Location of exhibit hall</h3>

<p>Sometimes the exhibit hall is hidden away and only visited by attendees that really seek it out. Obviously this is less than ideal for a sponsor with a booth. The obvious solution is a central expo hall, but many conferences can go one further and put lunch and the expo hall in the same area. Having foot traffic near and through the expo hall gives slightly more exposure, letting sponsors get a better value.</p>

<h2>As a speaker</h2>

<h3>Have previous years talks available</h3>

<p>If you are interested in attracting new speakers to your conference, please include last years talks. As a speaker there&#8217;s often a new conference I&#8217;d be interested in attending, if I&#8217;d not attended or spoken I may not know appropriate context. Keeping last years speaker list and talk topics helps me elect whether it might be a fit.</p>

<h3>Publish the CFP</h3>

<p>This is especially key to have on <a href="http://www.lanyrd.com">lanyrd</a>, above all the other timelines. There&#8217;s currently no better place for me to look today to get an idea of when CFPs are coming up. As a tip for others looking to submit talks to conferences check out their list of <a href="http://lanyrd.com/calls/">upcoming calls</a>.</p>

<p><em>Bonus if you give me a signup form to get notified via email when the CFP is open</em></p>

<h3>Turnaround</h3>

<p>I understand there&#8217;s a lot to do when organizing a conference. As much as possible keep the turnaround fast on these. There&#8217;s a lot of effort involved in reviewing talk submissions, so I understand that its not a 1 day activity. However, far too often I&#8217;ve reviewed talks for conferences and given feedback, and seen most of the activity occur in a mad sprint at the end of the planned time. If this is going to occur at least compress that time.</p>

<h3>Speaker dinner</h3>

<p>As a speaker, I&#8217;ll be missing a few talks as I prep for mine and of course give mine. Additionally there&#8217;s a lot in common with other speakers at the conference often. A good speakers dinner with an opportunity to connect with them can be what sets the conference apart for me. Of course good food and drinks always helps this, but most importantly it does a good job of bringing all the speakers together.</p>

<h3>Notice</h3>

<p>If your CFP is well in advance of the conference, advertise it early and often.</p>

<h2>As an attendee</h2>

<h3>Power and Internet</h3>

<p>Power any and everywhere. Internet that works. I understand its hard, but everyone remember when it works well, so its one straight forward way to make your conference stand out.</p>

<p><em>If you really want to deliver a great experience, have a charging valet, let attendees drop off a device and pick it up an hour later.</em></p>

<h3>Hallway Tracks</h3>

<p>Talks are awesome, but give opportunity to connect with everyone there. Many of the people at a conference I see once at year at that particular conference. If my choice is between a talk and catching up with an old friend, the old friend may win out. Give me the opportunity to do both.</p>

<h3>Evening events</h3>

<p>I don&#8217;t want to get into the debate about drinking (coffee or alcohol), but evening events encourage socialization. <a href="http://max.adobe.com/">Adobe&#8217;s MAX</a> conference was a great example of this, while there was beer, I never saw over the top drinking at the after conference event. To keep it fun there were Xboxes, PS3s, Segway obstacle courses and much more. If this isn&#8217;t something the conference wants to condone or organize itself, there&#8217;s likely an event happening somewhere, help with the publicity of those. With any luck the non-conference evening events are well done, and the conference spirit continues into the evening.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Why Postgres]]></title>
    <link href="http://www.craigkerstiens.com/2012/04/30/why-postgres/"/>
    <updated>2012-04-30T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2012/04/30/why-postgres</id>
    <content type="html"><![CDATA[<p><em>This post is a list of many of the reasons to use Postgres, much this content as well as how to use these features will later be curated within <a href="http://www.postgresguide.com">PostgresGuide.com</a>.</em></p>

<p><em>UPDATE: A <a href="http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2/">part 2</a> has been posted on <a href="http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2/">Why Use Postgres</a></em></p>

<p>Very often recently I find myself explaining why Postgres is so great. In an effort to save myself a bit of time in repeating this, I though it best to consolidate why Postgres is so great and dispel some of the historical arguments against it.</p>

<h2>Replication</h2>

<p>For some time the biggest argument for MySQL over Postgres was the lack of a good replication story for Postgres. With the release of <a href="http://www.postgresql.org/docs/8.4/static/high-availability.html">8.4 Postgres&#8217;s</a> story around replication quickly became much better.</p>

<p><em>While replication is indeed very important, are users actually setting up replication each time with MySQL or is it to only have the option later?</em></p>

<h2>Window functions</h2>

<p>This is a feature those familiar with Oracle greatly missed in Postgres. In fact even SQL Server had some form of them, though it was with T-SQL, which adds a bit more complexity to the feature. This is a feature that once you have you can&#8217;t live without; the other options that existed before were slower and much more complicated. With the release of <a href="http://www.postgresql.org/docs/9.1/static/tutorial-window.html">8.4</a> window functions were added to bring Postgres on par with Oracle in this area. For more info on using them check the Postgres docs above or <a href="http://postgresguide.com/tips/window.html">PostgresGuide.com</a>.</p>

<h2>Flexible Datatypes</h2>

<p>Creating a custom column is simpler in Postgres than any other database I&#8217;ve used by far. Excluding custom datatypes, even Postgres&#8217;s out of the box datatypes make Postgres stand out far ahead of other databases. In particular the ability to create a column as an <a href="http://www.postgresql.org/docs/9.1/static/arrays.html">Array</a> of some datatype. Want to store a game of tic-tac-toe in a database, or an array of 1 user&#8217;s phone numbers? It simply becomes a single column that can contain multiple phone numbers for a user.</p>

<!-- more -->


<h2>Functions</h2>

<p>Need to do some logic outside of standard SQL? Postgres likely has a function already available to do it for you. What about the time you wanted to take all rows returned by a query and combine them into a function? Give <a href="http://www.postgresql.org/docs/9.1/static/functions-aggregate.html">array_agg a look</a>. Need to split a string and grab a part of it or some other string action, there&#8217;s a <a href="http://www.postgresql.org/docs/9.1/static/functions-string.html">function for that</a>.</p>

<h2>Custom Languages</h2>

<p>Want to use another language inside your database? Postgres probably supports it:</p>

<ul>
<li><a href="http://www.postgresql.org/docs/9.1/static/plpython.html">Python in Postgres</a></li>
<li><a href="https://github.com/knu/postgresql-plruby">Ruby in Postgres</a></li>
<li><a href="http://www.joeconway.com/plr/">R in Postgres</a></li>
<li><a href="http://code.google.com/p/plv8js/wiki/PLV8">V8 in Postgres</a></li>
</ul>


<h2>Extensions</h2>

<p>Need to go beyond standard Postgres? There&#8217;s a good chance that someone else has, and that there&#8217;s already an extension for it. Extensions take Postgres further with things such as Geospatial support, JSON data types, Key Value Stores, and connecting to external data sources (Oracle, MySQL, Redis). I could easily have a full post on extensions available alone, fortunately someone else has already created an awesome one - <a href="http://blog.railsware.com/2012/04/23/postgresql-most-useful-extensions/">PostgreSQL Most Useful Extensions</a>.</p>

<h2>NoSQL gives flexibility</h2>

<p>I don&#8217;t want to get too NoSQL versus SQL debate&#8230;. no matter which side you fall on you can get both in Postgres. With hstore and <a href="http://code.google.com/p/plv8js/wiki/PLV8">PLV8</a> you&#8217;ll get the flexibility in your data that you would with Mongo along with all of the above features. <a href="http://www.twitter.com/leinweber">Will Leinweber</a> has a talk that he&#8217;s given at several conferences recently that highlights <a href="http://ssql-railsconf.herokuapp.com/">Schemaless SQL</a>.</p>

<h2>Custom Functions</h2>

<p>Didn&#8217;t find the function you wanted in the above? Try creating it yourself:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>CREATE FUNCTION awesomeness<span class="o">(</span>varchar<span class="o">)</span> RETURNS boolean
</span><span class='line'>    AS <span class="s1">&#39;CASE WHEN $1 == \&#39;postgres\&#39; THEN TRUE ELSE FALSE END;&#39;</span>
</span><span class='line'>    LANGUAGE SQL
</span><span class='line'>    IMMUTABLE
</span><span class='line'>    RETURNS NULL ON NULL INPUT;
</span></code></pre></td></tr></table></div></figure>


<h2>Common Table Expressions</h2>

<p>Often times when exploring data or creating a new view you&#8217;ll want to load data into a temporary table. When exploring data you only need this for a temporary time. Why actually go through the effort of putting it into a temporary table, especially if you only need it for a single query. <a href="http://www.postgresql.org/docs/8.4/static/queries-with.html">Common Table Expressions</a> let you accomplish just that.</p>

<h2>Development Pace</h2>

<p>For some period of time MySQL and Postgres were both moving at fast paces. In recent years though Postgres has rapidly picked up its pace of how much gets packed into a single release. Just take a look at the  <a href="http://en.wikipedia.org/wiki/PostgreSQL#Major_releases">Major Releases</a>.</p>

<h2>Conclusion</h2>

<p>Hopefully you&#8217;re convinced on why Postgres is a great tool. Next take a visit to <a href="http://www.postgresguide.com">PostgresGuide</a> if you need some direction on where to start or how to use many of the above features.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Apps to Services]]></title>
    <link href="http://www.craigkerstiens.com/2012/04/13/apps_to_services/"/>
    <updated>2012-04-13T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2012/04/13/apps_to_services</id>
    <content type="html"><![CDATA[<p><em>Update the talk for this is now viewable on YouTube <a href="http://www.youtube.com/watch?v=ztGpK-v2Oow">here</a></em></p>

<p>When I first came across Django I was an immediate fan. It featured:</p>

<ul>
<li>Good documentation</li>
<li>Steady but stable progress</li>
<li>Community around apps which encouraged <em>DRY</em></li>
</ul>


<p>I&#8217;ve been a user off and on depending on my needs for nearly four years since discovering it, and throughout that time all of the above have remained true. However, as I&#8217;ve worked on and encountered more complex applications there&#8217;s one thing that has time and again broke down for me, which is the Django apps model. It hasn&#8217;t broken down due to Django only though, I&#8217;ve seen it break down in Ruby (Rails), Java, .Net, take you&#8217;re pick of language or framework.</p>

<p>The breakdown of this model is due to several things:</p>

<!-- more -->


<ul>
<li>Successful applications grow which mean more complex applications and more developers</li>
<li>More complex applications often mean larger code bases

<ul>
<li>Deprecating code is good, but not always easy in large code bases</li>
<li>More code means more testing, but slower releases</li>
</ul>
</li>
</ul>


<p>At Heroku one way we often describe the platform to others is <em>&#8220;A distributed Unix in the cloud.&#8221;</em> There may be many reasons for this, but one of which is that we love the Unix approach and philosophy of <em>Small sharp tools</em>. Sticking to that, many of our internal pieces are small individual apps that talk across defined contracts or APIs.</p>

<p>Back to Django&#8217;s app structure&#8230; Many people build apps and re-use them and often share them with the world. This is truly great for re-usability, which means you can focus on building key features. However, this does not enable your application to be more maintainable in the future nor does it enable scalability. Yes, you can absolutely scale a monolithic application, but it doesn&#8217;t mean you should. This doesn&#8217;t mean the app structure is entirely broken, it just means that it is a partial step to where you should be. The real solution is to build more of these pieces of your greater application as services.</p>

<p>A Django app is defined as <em>A web application that does something. I.e. Weblog, Poll, Ticket system</em>. Within Django an app contains:</p>

<ul>
<li>Models</li>
<li>Views</li>
<li>URLs</li>
</ul>


<p>I couldn&#8217;t find a great definition of a Service that was succinct and also said something of value (If you have one please pass along as I&#8217;d love to have a definition from a source other than myself). For the sake setting something in place I&#8217;m defining a service as <em>Method of communication over the web with a provider using a defined contract</em>. By this definition a service contains:</p>

<ul>
<li>Provider</li>
<li>Endpoint</li>
<li>Contract</li>
</ul>


<p>Let me clarify this a bit further&#8230;</p>

<p>Tangible example/parable:</p>

<p>Django Apps::</p>

<ul>
<li>Ticket</li>
<li>FAQ</li>
</ul>


<p>Company Teams::</p>

<ul>
<li>Support</li>
<li>Community Evangelist</li>
</ul>


<p>You start with two apps, that maybe share a little code. Moreover they at least exist in a central code base. Then you deploy something and the Ticket app can no longer create FAQ, due to a change in one or the other. There&#8217;s no finger to point, but more importantly, you don&#8217;t know how to contact to resolve. Neither team wants to deploy, so you test more. Before every deploy you run tests&#8230; and validate a build&#8230; and deployment slows&#8230; well maybe not with two teams. But as you get to 5 teams it does, and more so with 15, and more so with 30 teams. Then you hire a build master and release master, who really wants that?</p>

<p>So within Django maybe you go from apps all in the same codebase to releasing private versions of apps&#8230;</p>

<p>Your requirements.txt for a main site looks like:</p>

<figure class='code'><figcaption><span>requirements.txt</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">FAQ</span><span class="o">==</span><span class="mf">0.2</span>
</span></code></pre></td></tr></table></div></figure>


<p>You have 3 apps which depend on it, support, marketing, billing. You bump a version <code>FAQ==0.3</code> but then all three or no teams have to upgrade the version to the new APIs. However if your interface was:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'><span class="err">‘</span><span class="n">question</span><span class="err">’</span><span class="p">:</span> <span class="err">“</span><span class="n">my</span> <span class="n">question</span><span class="err">”</span><span class="p">,</span>
</span><span class='line'><span class="err">‘</span><span class="n">source</span><span class="err">’</span><span class="p">:</span> <span class="mi">123</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="n">requests</span><span class="o">.</span><span class="n">POST</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="err">‘</span><span class="n">FAQ_API</span><span class="err">’</span><span class="p">]</span> <span class="o">+</span> <span class="err">‘</span><span class="o">/</span><span class="n">v1</span><span class="o">/</span><span class="n">create</span><span class="err">’</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>You could also have:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'><span class="err">‘</span><span class="n">question</span><span class="err">’</span><span class="p">:</span> <span class="err">“</span><span class="n">my</span> <span class="n">question</span><span class="err">”</span><span class="p">,</span>
</span><span class='line'><span class="err">‘</span><span class="n">source</span><span class="err">’</span><span class="p">:</span> <span class="mi">123</span><span class="p">,</span>
</span><span class='line'><span class="err">‘</span><span class="n">related</span><span class="err">’</span><span class="p">:</span> <span class="p">[</span><span class="mi">456</span><span class="p">,</span> <span class="mi">789</span><span class="p">]</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="n">requests</span><span class="o">.</span><span class="n">POST</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="err">‘</span><span class="n">FAQ_API</span><span class="err">’</span><span class="p">]</span> <span class="o">+</span> <span class="err">‘</span><span class="o">/</span><span class="n">v2</span><span class="o">/</span><span class="n">create</span><span class="err">’</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Then you can easily support both, deprecate v1, and track its usage easily. This doesn&#8217;t guarantee, but it does enable <em>re-usability</em>, <em>scalability</em>, <em>maintainability</em>. And of course continues to let you build features instead of maintaining software.</p>

<p>In the next post I&#8217;ll go into a bit more detail of how a real example looks with apps in both forms, using a set of Django Apps and using a set of Services built on Django Apps.</p>

<p><em>Slides from a corresponding talk at DjangoCong are <a href="http://bit.ly/djangocong">here</a></em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Sphinx Build Pack on Heroku]]></title>
    <link href="http://www.craigkerstiens.com/2012/01/25/sphinx-buildpack/"/>
    <updated>2012-01-25T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2012/01/25/sphinx-buildpack</id>
    <content type="html"><![CDATA[<p>Heroku&#8217;s latest Cedar stack supports running anything. Heroku&#8217;s officially supported languages actually have their buildpacks public via <a href="http://github.com/heroku/">Heroku&#8217;s github</a>, you can view several of them at:</p>

<ul>
<li><a href="https://github.com/heroku/heroku-buildpack-python">Python Build Pack</a></li>
<li><a href="https://github.com/heroku/heroku-buildpack-ruby">Ruby Build Pack</a></li>
<li><a href="https://github.com/heroku/heroku-buildpack-scala">Scala Build Pack</a></li>
</ul>


<p><em>There have even been some created as fun weekend hacks such as the <a href="http://github.com/hone/heroku-buildpack-jsnes">NES Rom Buildpack</a>.</em></p>

<!-- more -->


<p>Recently at Heroku my teams have started exploring new forms of collaborating and documenting. In particular editing a wiki for communication is contrary to our regular workflow. Much of our day is spent in code and git. To edit a wiki within a web browser and using some markup we&#8217;re less familiar with is an overhead we were aiming to reduce. As a result we&#8217;ve tried a few things, the first was simply using a github repo to edit markdown.</p>

<p>Personally I have always been a fan of Sphinx documentation. However, Sphinx has no means to secure a site out of the box. Generating the static site then running it being a Rack app to secure it seemed like a few extra steps that would hinder workflow. As a result I set out to build the Sphinx buildpack which would let you push a Sphinx project to Heroku and automatically run your documentation. The buildpack itself supports two modes, public documentation and a private documentation. To have your documentation secured in private mode you simple need to add your google apps domain as a config var <code>heroku config:add DOMAIN=mydomain.com</code>.</p>

<p><em>If you need more information about setting up OpenID check out my recent post <a href="http://www.craigkerstiens.com/2012/01/23/securing-your-organization/">Securing your organization with OpenID </a></em></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>sphinx-quickstart
</span><span class='line'><span class="nv">$ </span>git init .
</span><span class='line'><span class="nv">$ </span>git add .
</span><span class='line'><span class="nv">$ </span>git commit -m initial
</span><span class='line'><span class="nv">$ </span>heroku create -s cedar -b http://github.com/craigkerstiens/heroku-buildpack-sphinx.git
</span><span class='line'><span class="nv">$ </span>git push heroku master
</span><span class='line'><span class="nv">$ </span>heroku open
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Securing your Internal Organization with OpenID]]></title>
    <link href="http://www.craigkerstiens.com/2012/01/23/securing-your-organization/"/>
    <updated>2012-01-23T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2012/01/23/securing-your-organization</id>
    <content type="html"><![CDATA[<p>I&#8217;ve recently been amazed at the number of companies that are still using a VPN or other means to manage their apps/network. Not just large enterprisey companies, but small agile startups. I fully understand that it works, but 95% of these places are also using another key tool for access inside their company&#8230; <em>Google Apps</em>. I fully expect companies to use google apps, its more of the former that surprises me most. For a long time OpenID wasn&#8217;t at a usable point, even today it still isn&#8217;t without its faults. However, it does make for a much cleaner workflow once in place than having your users login to something with they&#8217;re used to using elsewhere.</p>

<p>In our personal lives we use email as our keys to the kingdom. In fact I now almost refuse to sign up for any service that doesn&#8217;t let me use oauth, so why should a work place be much different. So I inquired with a few companies to see if they were fine with securing things like documentation or wiki&#8217;s being google auth, they indeed were. Yet they still seem to have users keep one more username and password for their VPN to be able to login to access internal docs/tools.</p>

<!-- more -->


<p>Most tech centric companies grow their own apps for many things they do within a company. Even the heavier adopters of SaaS still end up building a lot of internal systems. So why not secure them with your email domain just as you commonly would if it were a public service?</p>

<p>The problem comes in that OpenId with google has an initial setup overhead, but after that works unbelievably well.</p>

<h2>The catch</h2>

<p>In some cases you currently have to identify your domain as an OpenId provider. This means that @yourname.com is an OpenId provider. This simply means creating a url route for openid in your base site similar to the below:</p>

<figure class='code'><figcaption><span>http://heroku.com/openid</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;xrds:XRDS</span> <span class="na">xmlns:xrds=</span><span class="s">&quot;xri://$xrds&quot;</span> <span class="na">xmlns=</span><span class="s">&quot;xri://$xrd*($v*2.0)&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="nt">&lt;XRD&gt;</span>
</span><span class='line'>    <span class="nt">&lt;Service</span> <span class="na">priority=</span><span class="s">&quot;0&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>      <span class="nt">&lt;Type&gt;</span>http://specs.openid.net/auth/2.0/signon<span class="nt">&lt;/Type&gt;</span>
</span><span class='line'>      <span class="nt">&lt;URI&gt;</span>https://www.google.com/a/craigkerstiens.com/o8/ud?be=o8<span class="nt">&lt;/URI&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/Service&gt;</span>
</span><span class='line'>  <span class="nt">&lt;/XRD&gt;</span>
</span><span class='line'><span class="nt">&lt;/xrds:XRDS&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p><em>This is due to an issue of OpenID discovery which you can read more on at: https://groups.google.com/group/google-federated-login-api/browse_thread/thread/4a7dd2312a47a082/9285cec18a30b9d3?lnk=gst&amp;q=apps+discovery&amp;pli=1#9285cec18a30b9d3. In short, setting up the above can save you a lot of time</em></p>

<h2>Setting up in apps</h2>

<p>Most web frameworks have libraries that make it easy to secure your apps with openid/oauth. In particular Django and Rails both make this pretty easy. To make this even simpler for you below is code to actually secure an internal app for both Django and Rails. You can do similar with Flask or Sinatra as well.</p>

<h3>Rails</h3>

<div><script src='https://gist.github.com/1555489.js?file='></script>
<noscript><pre><code>class ApplicationController
  def admin?
    session[:admin_user] &amp;&amp; (ENV['ADMINS'] || &quot;&quot;).split(',').include?(session[:admin_user])
  end
  helper_method :admin?

  def admin_required
    redirect_to '/auth/admin' unless admin?
  end
end</code></pre></noscript></div>


<p>In case your admin controller isn&#8217;t already generated:</p>

<figure class='code'><figcaption><span>http://heroku.com/openid</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'>rails g controller admin/users
</span></code></pre></td></tr></table></div></figure>


<p>Then anything you want to secure:</p>

<figure class='code'><figcaption><span>http://heroku.com/openid</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'>module Admin
</span><span class='line'>  class UsersController <span class="nt">&lt; ApplicationController</span>
</span><span class='line'>    <span class="err">before_filter</span> <span class="err">:admin_required</span>
</span><span class='line'>
</span><span class='line'>    <span class="err">def</span> <span class="err">index</span>
</span><span class='line'>      <span class="err">render</span> <span class="na">:text =</span><span class="err">&gt;</span> <span class="s">&#39;Hello from the admin panel!&#39;</span>
</span><span class='line'>    <span class="err">end</span>
</span><span class='line'>  <span class="err">end</span>
</span><span class='line'><span class="err">end</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Django</h3>

<div><script src='https://gist.github.com/1555612.js?file='></script>
<noscript><pre><code>django-openid-auth==0.3
python-openid==2.2.5
</code></pre></noscript></div>


<p>Finally sync your database:</p>

<figure class='code'><figcaption><span>http://heroku.com/openid</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'>python yourapp/manage.py syncdb
</span></code></pre></td></tr></table></div></figure>


<p>Secure any view with the <code>login_required</code> decorator as your typically would with Django.</p>

<h2>Summary</h2>

<p>In short with some very basic app setup you can have an internal workflow thats just as good as what you use in your day to day outside the office.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How Heroku Works - Hiring]]></title>
    <link href="http://www.craigkerstiens.com/2011/12/02/how-heroku-works-hiring/"/>
    <updated>2011-12-02T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/12/02/how-heroku-works-hiring</id>
    <content type="html"><![CDATA[<p>I alluded in earlier posts of <a href="http://www.craigkerstiens.com/2011/11/02/how-heroku-works-teams-tools/">How Heroku Works</a> that we have talented engineers. In fact I would venture to say that there is not a weak link when it comes to our engineers at Heroku. Ensuring we have talented engineers makes it easier for us to find other talented engineers and maintains a level of quality in our product. This means we must be very careful about not diluting our pool of engineering talent, which is where our hiring process becomes especially key. By the time we hire a new employee, we know without a doubt they&#8217;re a fit within our organization.</p>

<p><em>Our goal in hiring is seldom to fill a role, but more commonly to find more talented people share our goal (changing the world for developers).</em></p>

<!--more-->


<p>So what&#8217;s our hiring process look like&#8230;.</p>

<ol>
<li><del>Review Resume/Github Profile</del></li>
<li><del>Initial Screen</del></li>
<li><del>Second Screen</del></li>
<li><del>Starter Project</del></li>
</ol>


<p>While there&#8217;s definitely a process that we follow that&#8217;s not what&#8217;s interesting. We way too often get worried about the steps 1, 2, 3&#8230; Instead you should focus on what&#8217;s important: are they a fit? Can they get shit done? Who cares about how many phone screens someone goes through?! Five phone screens instead of two doesn&#8217;t make them a better fit for your company. The short of it is they go through enough screens that you feel comfortable and you progress them through the process. For us at any point in the process if someone is determined to not be a fit the process ends there. If the process does end the hiring manager will relay this in the appropriate form, though always in writing via email as well.</p>

<p>The hiring manager could debatably be the biggest difference between our process and others. When a candidate applies to a position it goes to the hiring manager (<em>not an HR person</em>). The hiring manager will be your manager once at Heroku it&#8217;s one in the same and this ensures from the start of the process the candidate and the manager mesh well. Yes, having the manager of a group review github profiles and resumes is extra effort, but who better to judge from a quick glance than engineers. In general as a manager you&#8217;re evaluated on the success of those you manage, as such you should be invested heavily in those you hire. In addition to this we find a big difference in the on boarding process and how quickly someone can succeed. We have used many approaches, but the success of someone at Heroku based on having their hiring manager and manager be the same individual is best highlighted below:</p>

<p><img src="http://f.cl.ly/items/462y1J3G0L3q1f3v1o1U/hiring-1.png" alt="Hiring Manager = Manager" /></p>

<p>While every step in the hiring process is valuable starter projects may be the most valuable to ensuring quality. The final step with nearly everyone we hire is to invite them to come hack with us. Instead of parading someone around for a day long interview we get down to business and write some code. It could be something internal to Heroku, it could be an open source project we use, it could be something interesting that the candidate feels would add value to Heroku. Starter Projects vary slightly between each hiring manager.</p>

<p>Several of our managers prefer to lay out several potential interesting projects, talk through them with the candidate, and then let the candidate decide what they&#8217;d like to work on. Sometimes there&#8217;s a pressing need that the candidate can jump right in and add some value. It&#8217;s <strong>always</strong> important that the starter project is achievable, if it&#8217;s too broad of difficult for a 1-2 day period then the manager has failed in the hiring process. Regardless of the project it&#8217;s far more than an exercise on a white board, it&#8217;s actually what life is like at Heroku. We have lunch at the <a href="http://www.flickr.com/photos/teich/4928103311/">same table</a> that we eat at every other day, we interact just as we normally would, and after work there may or may not <a href="http://drunken-samurai-42.tumblr.com/">be drinks</a> just like any other day.</p>

<p><em>As a slight aside, we even conduct starter projects when current Herokai move from one team to another</em></p>

<p>Starter projects usually last anywhere from a day to several days. At the end of a starter project the candidate presents what they did, in a similar fashion to weekly demos that occur at workshop (more on that some other time). In earlier days it was nearly the entire company that would sit in, ask questions and give feedback. Now it&#8217;s a bit harder for all us to fit into one conference room, though there&#8217;s an open invite and anyone that wishes can sit in (often 10-20 Herokai). At the end of the starter project there&#8217;s no question that the candidate fits or doesn&#8217;t, often from both sides. Of course if it&#8217;s a fit we make an offer and welcome them into the family.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How Heroku Works - Maker's Day]]></title>
    <link href="http://www.craigkerstiens.com/2011/11/07/how-heroku-works-maker-day/"/>
    <updated>2011-11-07T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/11/07/how-heroku-works-maker-day</id>
    <content type="html"><![CDATA[<p>In my earlier post on <a href="http://www.craigkerstiens.com/2011/11/02/how-heroku-works-teams-tools/">Teams and Tools at Heroku</a>, I mentioned how we value engineers&#8217; time; their work has enabled us to build a great platform. As a result of what we&#8217;ve built, we&#8217;ve had great growth both of our platform and of our teams internally. With that growth inevitably comes different distractions on engineers&#8217; time. Despite how a manager may plan things, engineering work needs long periods of uninterrupted time. To ensure that no matter what, an engineer has plenty of opportunity to do the work he or she was hired to do, Heroku has Maker&#8217;s Day.</p>

<!--more-->


<p><em>Maker&#8217;s Day ensures that engineers get a full day of uninterrupted time to focus on making things.</em></p>

<p><img src="http://www.craigkerstiens.com/images/makerday.png" alt="Maker's Day" /></p>

<p>The more consistent interruptions are throughout an engineer&#8217;s day, the more time will be lost due to context switching in addition to the time spent on those other activities. These interruptions may include a quick question from a manager, a question on a code problem someone else is working through, or an email or IM from a coworker. Regardless of the type of interruption, it causes an engineer to lose focus. According to <a href="http://www.amazon.com/gp/product/0932633439/ref=as_li_tf_tl?ie=UTF8&amp;tag=mypred-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0932633439">Peopleware: Productive Projects and Teams</a>, in a study regarding productivity among engineers, the top performers when surveyed said they were interrupted regularly 38% of the time versus the bottom performers, who were interrupted 76%. Context switching should be counted as fully wasted time for an engineer, and all too often as the number of meetings increases, the time involved with context switching is increased similarly to the following:</p>

<p><img src="http://www.craigkerstiens.com/images/contextswitch.png" alt="Cost of context switching" /></p>

<p>For more on how interruptions or context switching decreases productivity, Jeff Atwood has a great post about <a href="http://www.codinghorror.com/blog/2006/09/the-multi-tasking-myth.html">The Multi-Tasking Myth</a>, which demonstrates &#8230;</p>

<p>Most people understand that context switching is bad, but another team may still have valid demands on your time. Pushing back against another team or manager isn&#8217;t always feasible; after all, we do work together, and each team at times may need something from another team. This is where Maker&#8217;s Day starts to come in. Every Thursday at Heroku is Maker&#8217;s Day.</p>

<p><strong>Maker&#8217;s day is meant for making shit. Meetings don&#8217;t happen on Maker&#8217;s Day</strong>. If someone asks if that time on your calendar works for a meeting, the simple response is no&#8211;it&#8217;s Maker&#8217;s Day. Because Maker&#8217;s Day has been ingrained into our culture, engineers have no problem giving that response when there&#8217;s a request on their time on Maker&#8217;s Day. If someone in marketing, sales, or another non-engineering role wants to book meetings, they’re welcome to do so, but they&#8217;re going to be without engineers. However, even for non-engineers, Maker&#8217;s Day is equally invaluable; uninterrupted hours of focus at a time are amazing for productivity in any role.</p>

<p>Maker&#8217;s Day varies in how it is executed from person to person. Often the office is slightly less busy due to some engineers working from home or coffee shops to maximize their productivity. To an outsider, the office may appear business as usual: engineers sit at their desks, working. At lunch, everyone is sitting around the lunch table eating together. To the unobservant eye it may appear to be just any other day, but the engineers notice the difference. There will be significantly less interruptions by someone walking over to your desk, you won&#8217;t be pulled into meetings that distract you from features, and you know it&#8217;s an opportunity to accomplish a bulk of work laid out from your weekly planning meeting.</p>

<p>As Heroku has grown, meetings have increased, and the value of Maker Day&#8217;s has increased exponentially.</p>

<p>Whether you&#8217;re in the early stages of bootstrapping a company or at a large company of thousands of engineers, one of the best practices anyone can put into place is dedicated quality time for engineers to produce code. Maker&#8217;s Day is a fantastic way to ensure this happens on a weekly basis.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[More Advanced Dependencies]]></title>
    <link href="http://www.craigkerstiens.com/2011/11/03/moreadvanceddependencies/"/>
    <updated>2011-11-03T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2011/11/03/moreadvanceddependencies</id>
    <content type="html"><![CDATA[<p>So we walked through setting up your <a href="http://www.craigkerstiens.com/2011/11/01/installingpythonpackages/">virtualenv and installing some packages</a>. The basic workflow for installing packages will work 95% of the time, however part of the time you will need a little more. Below are several cases that may require extra effort. Its likely worthwhile to skim these and only reference them when needed as they likely wont be part of your everyday workflow (with the exception of using mirrors).</p>

<p>Most packages you install should be on pip and an actual released version of a package. There are times however when you may need to test out a package that is still being worked on. For these cases there&#8217;s what developers commonly do and what you should do.</p>

<!--more-->


<p>If you must install a package from git then you might use something similar to the following:</p>

<figure class='code'><figcaption><span>requirements.txt</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>git+https://github.com/kennethreitz/requests.git#egg<span class="o">=</span>requests
</span></code></pre></td></tr></table></div></figure>


<p>Even more ideal is specifying the version:</p>

<figure class='code'><figcaption><span>requirements.txt</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>git+https://github.com/kennethreitz/requests.git<span class="o">==</span>0.6.0#egg<span class="o">=</span>requests
</span></code></pre></td></tr></table></div></figure>


<p><em>The above should never be done when deploying to production, it reduces predictable behavior and requires that github is available for you to deploy. You should never be dependent on more than PyPi and your own system to deploy.</em></p>

<p>Instead when you deploy to production you should point to an internal link. This looks something similar to:</p>

<figure class='code'><figcaption><span>requirements.txt</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>--find-links http://path/to/package/
</span></code></pre></td></tr></table></div></figure>


<p>The other item thats not currently (though will be soon) a default behavior is mirrors. For those not familiar, a mirror is essentially a copy of a site (in this case <a href="http://pypi.python.org/">PyPi</a>). At some point in the future the site may be down preventing you from installing packages or deploying code. If this is the case you&#8217;re able to use a flag to use these mirrors. If you simple add the flag below it will automatically use the mirrors, allowing you to continue:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>pip --use-mirrors install Django
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How Heroku Works - Teams and Tools]]></title>
    <link href="http://www.craigkerstiens.com/2011/11/02/how-heroku-works-teams-tools/"/>
    <updated>2011-11-02T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2011/11/02/how-heroku-works-teams-tools</id>
    <content type="html"><![CDATA[<p>Heroku is a largely agile company, we work in primarily small teams that talk via api and data contracts. Its also a company comprised primarily of engineers, even product managers often write code. Heroku as a platform drives many of the features not from top down, but from bottom up based on engineers desires or skunkworks projects. There&#8217;s many valuable insights into how Heroku runs efficiently for engineering.</p>

<p>I&#8217;ll be diving into many various practices that enable Heroku to put quality engineering above all else, but first let me highlight the team structure and tools that enable this.</p>

<!--more-->


<p>Heroku is comprised of many small teams internally, each team operates much like an individual entity. The team chooses its own tools and best method for communication, though as a whole some form of Scrum is run throughout teams. Think of the unix philosophy of small sharp tools <a href="http://www.amazon.com/gp/product/0131429019/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;tag=mypred-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0131429019">as in The Art of Unix Programming</a> applied to teams and people.</p>

<p>For most teams this involves a weekly planning meeting earlier in the week. In such a meeting teams may conduct a retrospective, opportunities to improve the process the coming week, and of course plan tasks for the coming week. Its <b>very</b> important to note that planning tasks for the week doesn&#8217;t necessarily involve planning the deadline for them, but rather simply laying out what people are working on (more on this in a future post). Each team will record and track this in a tool of their own choosing. Several use <a href="http://www.pivotaltracker.com">pivotal tracker</a>, one uses <a href="http://www.scrumy.com">scrumy</a>, some use email to distribute and track against personal to do lists. The method for tracking issues is again entirely up to the individual team. A one person team may choose to use a simple to do list, larger teams commonly use <a href="http://www.github.com">github</a> issues and pull requests. Given the team is the one responsible for their own productivity the team is the one to choose what tools they use.</p>

<p>Meeting loads vary from person to person depending on what is the demands are on their time, though everyone at Heroku participates in some form of standup. Most teams do these daily as quick status stand-ups of what was worked on the day before and whats to be worked on the next day. In addition to the planning meeting and stand-ups, there is often collaborative engineering, and company wide gatherings.</p>

<p>Collaborative engineering once again varies depending on which engineers are working together. Engineers may get in front of a white board or in front of machines and simple collaborate. For engineers together in the office this is often the most productive way. These practices work the same for remote employees, though slightly modified for the high touch interaction. For remote employees this often works as pair programming via Skype. Skype is indispensable for allowing remote workers to feel far less remote. Skype alongside <a href="http://typewith.me/">typewith.me</a> and you have an unbelievable easy to collaborate not just with 1 other, but with multiple parties to work through a document on a given topic. For smaller activities of communication asynchronous is key. This ranges from <a href="http://campfirenow.com/">campfire</a> most commonly during common working hours when someone is likely to be at a machine, to email when the return on a request may take slightly longer.</p>

<p>Finally there is the all common company wide meeting, which occurs weekly. The structure of this varies from status updates to broader ongoings. Its often the perfect time for engineers to hear about what sales is doing or get updates on teams you don&#8217;t commonly interact with. Along with common status updates there will be broader company updates.</p>

<p>Consistently across all teams you&#8217;ll find these principles which allow us to ensure the quality of engineering as we continue to grow:</p>

<ul>
<li>Small teams that talk across defined API&#8217;s and data contracts</li>
<li>Teams using the tool that they believe is best for the job</li>
<li>Frequent asynchronous communication</li>
<li>Collaboration (including for remote employees)</li>
</ul>


<p>The key in Heroku running efficiently is primarily allowing each team to run as it chooses. Heroku works because we have talented engineers, the best thing we can do for those engineers is allow them to work productively. Often only they know the best way to accomplish this, so who better to let them accomplish it than themselves.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing Python Packages]]></title>
    <link href="http://www.craigkerstiens.com/2011/11/01/installingpythonpackages/"/>
    <updated>2011-11-01T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2011/11/01/installingpythonpackages</id>
    <content type="html"><![CDATA[<p>Now that you have you system and project environment all setup you probably want to start developing. But you likely don&#8217;t want to start writing an entire project fully from scratch, as you dive in you&#8217;ll quickly realize theres many tools helping you build projects and sites faster. For example making a request to a website there&#8217;s <a href="http://docs.python-requests.org/en/latest/index.html">Requests</a>, for handling processing images there&#8217;s <a href="http://www.pythonware.com/products/pil/">Python Imaging   Library</a>, or for a full framework to help you in building a site there&#8217;s <a href="http://www.djangoproject.com">Django</a>. With all of these there&#8217;s one simple and common way to install them. But first a little more on how it all works.</p>

<!--more-->


<p>All major Python packages are hosted on <a href="http://pypi.python.org/">PyPi</a> (Pronounced Pi-P or Cheeseshop). When you use a common python installer it will:</p>

<ol>
<li>Search for the package you specify</li>
<li>If you specify a version will use it, otherwise will use the latest</li>
<li>Will download the source for that package</li>
<li>Install it into your Python environment</li>
</ol>


<p>Now for actually installing&#8230; Lets get started with installing the three packages below. At this point you should at least have a fresh Python environment, however you don&#8217;t have an immediate way to install packages. The defacto Python package installer is <a href="http://pip-installer.org">pip</a>.</p>

<p>Earlier we setup virtualenv to help isolate our python packages we were working with. First lets go ahead and create a folder for our project then setup a new environment for the project we&#8217;ll work on:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>mkdir myapp
</span><span class='line'><span class="nv">$ </span><span class="nb">cd </span>myapp
</span><span class='line'><span class="nv">$ </span>virtualenv --no-site-packages venv
</span></code></pre></td></tr></table></div></figure>


<p></p>

<p>If we list the contents of the directory you&#8217;ll now see a folder venv. Within this folder you&#8217;ll find all the parts of the environment that virtualenv just created:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>ls
</span><span class='line'>venv
</span><span class='line'><span class="nv">$ </span>ls venv
</span><span class='line'>bin   include lib
</span></code></pre></td></tr></table></div></figure>


<p>Now you&#8217;ve got a sandboxed environment that exists but you haven&#8217;t loaded it. You can now activate and deactivate this any time you like. Once you do this it customizes your path to use the packages you&#8217;ve installed for this environment. To load your environment when in the myapp directory:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span><span class="nb">source </span>venv/bin/activate
</span></code></pre></td></tr></table></div></figure>


<p>To deactivate this simple:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>deactivate
</span></code></pre></td></tr></table></div></figure>


<p>Now that we&#8217;ve got your environment loaded installing your packages should be pretty simple. Ensure that you have your virtualenv loaded and then run:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>pip install requests
</span><span class='line'><span class="nv">$ </span>pip install PIL
</span><span class='line'><span class="nv">$ </span>pip install Django
</span></code></pre></td></tr></table></div></figure>


<p>Now that you&#8217;ve installed your packages you want to be able to share this with others to make it easy to get setup. You could provide a list of everything your application needs to run manually, or because its Python you can expect it to make it easy for you. Pip has a wonderful command freeze that will show all of your packages and their versions that are installed. Simply run:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>pip freeze
</span></code></pre></td></tr></table></div></figure>


<p>However, this only outputs the information. Along with this pip has a canonical form for listing requirements and installing them from a file. The filename is commonly a requirements.txt. To create this we simply pipe the results of pip freeze to this file.</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>pip freeze &gt; requirements.txt
</span></code></pre></td></tr></table></div></figure>


<p>Next we&#8217;ll talk about a few more advanced items in dependency management, then finally we&#8217;ll get started on building an application.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Getting Setup with Python]]></title>
    <link href="http://www.craigkerstiens.com/2011/10/27/gettingsetupwithpython/"/>
    <updated>2011-10-27T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2011/10/27/gettingsetupwithpython</id>
    <content type="html"><![CDATA[<p>This is the first of a multipart series to getting started with Python. Throughout this guide we&#8217;ll walk you through a full setup. For starters if you&#8217;re a mac or linux user you already have <a href="http://python.org">Python</a> on your system. You should be able to confirm you have python my opening up a terminal window and running:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>python --version
</span><span class='line'>Python 2.7.2
</span></code></pre></td></tr></table></div></figure>


<!--more-->


<p>As long as you see a Python version 2.5.x-2.7.x you should be fine to continue. From here we&#8217;re going to work through setting up your Python project environment. For this we&#8217;re going to use <a href="http://virtualenv.org">virtualenv</a>. For those of you not familiar <a href="http://virtualenv.org">virtualenv</a> is a self-contained python environment. It holds its own copy of python and any libraries you install. This allows you to work on multiple projects with different versions of libraries.</p>

<p>While we&#8217;re installing virtualenv we&#8217;re also going to go ahead and setup PostgreSQL as we&#8217;ll be using it later. If you&#8217;re on a mac you&#8217;ll first need to setup homebrew. Homebrew is used for installing various system packages. If you&#8217;re on linux, in particular Ubuntu you can skip down to the steps for setting up your environment.</p>

<p>First for Mac users lets setup homebrew which will allow us to install various system packages:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>/usr/bin/ruby -e <span class="s2">&quot;$(curl -fsSL https://raw.github.com/gist/323731)&quot;</span>
</span></code></pre></td></tr></table></div></figure>




<h2>OSX with Brew:</h2>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>curl -O http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg | sh setuptools-0.6c11-py2.7.egg
</span><span class='line'><span class="nv">$ </span>easy_install virtualenv
</span><span class='line'><span class="nv">$ </span>brew install postgresql
</span></code></pre></td></tr></table></div></figure>




<h2>Ubuntu:</h2>


<p>Now for setting up your project:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>sudo apt-get install virtualenv
</span><span class='line'><span class="nv">$ </span>sudo apt-get install postgresql
</span></code></pre></td></tr></table></div></figure>


<p>Now you have Python, virtualenv, and postgresql all installed. We can now focus on setting up the initial start to a project.</p>

<p>In the next part we can start with installing some Python packages.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Environment Structure for Django Apps]]></title>
    <link href="http://www.craigkerstiens.com/2011/05/16/environment-structure-django-apps/"/>
    <updated>2011-05-16T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2011/05/16/environment-structure-django-apps</id>
    <content type="html"><![CDATA[<p>I&#8217;ve been writing applications off and on for nearly 4 years now, since before Django 1.0 was even released. I must say the framework could not be better described than by its own tagline &#8220;The Web framework for perfectionists with deadlines&#8221;. Among the things I love about it are:</p>

<ul>
    <li>Amazing documentation, there&#8217;s not 30 different blog posts with different ways to do things, either read the django project documentation or the app documentation</li>
    <li>They don&#8217;t consistently break backwards compatibility. While at times they do this, it is not the norm or standard, which isn&#8217;t the case for some other unnamed frameworks</li>
    <li>DRY, Don&#8217;t Repeat Yourself. If there&#8217;s an app that exists people don&#8217;t have a burning need to recreate the same functionality, resulting in lower number but higher quality pluggable apps.</li>
</ul>


<!--more-->


<p>However, after using the framework for nearly 4 years I&#8217;m just now discovering my preferred way of managing environments. I know there&#8217;s still a bit of back and forth on development environment/IDE, but as far as configuring actual project environment I&#8217;ve become very comfortable with what I&#8217;ve now been using for many months. It also allows for someone else bootstrapping their environment incredible quickly as well. Below is a quick cookbook of how to do this on OSX and Ubuntu.</p>

<h2>OSX with Macports:</h2>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>sudo port install python27
</span><span class='line'><span class="nv">$ </span>sudo port install py27-virtualenv
</span><span class='line'><span class="nv">$ </span>sudo port install postgresql90
</span></code></pre></td></tr></table></div></figure>


<p>Now for setting up your project:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>mkdir example
</span><span class='line'><span class="nv">$ </span><span class="nb">cd </span>example
</span><span class='line'><span class="nv">$ </span>virtualenv-2.7 --no-site-packages .
</span><span class='line'><span class="nv">$ </span><span class="nb">source </span>bin/activate
</span></code></pre></td></tr></table></div></figure>




<h2>OSX with Brew:</h2>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>sudo brew install python
</span><span class='line'><span class="nv">$ </span>sudo brew install virtualenv
</span><span class='line'><span class="nv">$ </span>sudo brew install postgresql
</span></code></pre></td></tr></table></div></figure>


<p>Now for setting up your project:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>mkdir example
</span><span class='line'><span class="nv">$ </span><span class="nb">cd </span>example
</span><span class='line'><span class="nv">$ </span>virtualenv --no-site-packages .
</span><span class='line'><span class="nv">$ </span><span class="nb">source </span>bin/activate
</span></code></pre></td></tr></table></div></figure>




<h2>Ubuntu:</h2>


<p>Now for setting up your project:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>sudo aptitude install python
</span><span class='line'>sudo aptitude install virtualenv
</span><span class='line'>sudo aptitude install postgresql
</span></code></pre></td></tr></table></div></figure>


<p>Now for setting up your project:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>mkdir example
</span><span class='line'><span class="nv">$ </span><span class="nb">cd </span>example
</span><span class='line'><span class="nv">$ </span>virtualenv --no-site-packages .
</span><span class='line'><span class="nv">$ </span><span class="nb">source </span>bin/activate
</span></code></pre></td></tr></table></div></figure>


<p>For those of you not familiar virtualenv is a self-contained python environment. It holds its own copy of python and any libraries you install. Now that you&#8217;ve setup your virtualenv we can go through the process of installing django and setting up your repository. This is the same across all of the above platforms:</p>

<p>Add to a .gitignore file:</p>

<figure class='code'><figcaption><span>.gitignore </span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>bin
</span><span class='line'>build
</span><span class='line'>include
</span><span class='line'>lib
</span><span class='line'>.Python
</span><span class='line'>*.pyc
</span></code></pre></td></tr></table></div></figure>


<p>Add to a requirements.txt file:</p>

<figure class='code'><figcaption><span>requirements.txt</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">Django</span><span class="o">==</span>1.3.1
</span><span class='line'><span class="nv">psycopg2</span><span class="o">==</span>2.4.1
</span></code></pre></td></tr></table></div></figure>


<p>Then run:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>bin/pip install -r requirements.txt
</span></code></pre></td></tr></table></div></figure>


<p>This should fully installed any of your required apps and makes it easy for others to do the same to begin contributing to a larger app. Finally if you like you can create your git repo from this an make your first commit:</p>

<pre><code>$ git init
$ git add .
$ git commit -m 'my first django virtualenv'
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Attribution 101]]></title>
    <link href="http://www.craigkerstiens.com/2011/03/18/attribution-101/"/>
    <updated>2011-03-18T00:00:00-07:00</updated>
    <id>http://www.craigkerstiens.com/2011/03/18/attribution-101</id>
    <content type="html"><![CDATA[<p>Continuing with the recent posts on metrics and marketing. I want to give a quick primer on attribution. To any marketing or analytics people out there, simply skip this it would aim to be a primer recap at best for you.</p>

<p>The very general meaning behind attribution is to give credit. When it comes to web products this can be giving credit for lots of things:</p>

<ul>
    <li>A visit to your site</li>
    <li>A purchase to your site</li>
    <li>Other events, such as sign up, referring friends, etc.</li>
</ul>


<!--more-->


<p>Its really wonderful when there&#8217;s a direct mapping in correlation. Take for example the case where:</p>

<ol>
    <li>User sees your ad on facebook</li>
    <li>User clicks on ad</li>
    <li>User signs up for an account</li>
    <li>User pays you money</li>
</ol>


<p>In this case it&#8217;s clear that its worthwhile to advertise on facebook. The hard part becomes when there&#8217;s a non-linear path in some form (which is almost always the case). Now take the case:</p>

<ol>
    <li>User sees your ad on facebook</li>
    <li>User clicks on ad, then leaves</li>
    <li>User comes back a day later directly, and spends 10 minutes on the site reading</li>
    <li>User comes back a day later after searching via google, and creates an account</li>
    <li>User sees a re targeting ad 1 month later and visits</li>
    <li>User pays for account</li>
</ol>


<p>In a perfect world you have case 1 and can give the full credit or attribution of the purchase to your facebook ad. However, in a real world you have case 2 and it becomes more complicated. Perhaps its something like this though:</p>

<ul>
    <li>Account creation - 100% to facebook ad</li>
    <li>Paying for account - 50% to facebook ad, 50% to retargetting?</li>
</ul>


<p>This is where there is not an exact science to attribution, as it could be justified to give 100% of the credit for paying for an account to the re targeting. So if this has you pondering on attribution here&#8217;s the downer part&#8230;. The tools that allow you to attribute a goal or action to multiple sources:</p>

<ul>
    <li>Omniture</li>
    <li>Web Trends</li>
</ul>


<p>Most other tools are the last place the user ever came from, some occasionally are the first place a user came from, but without pony-ing up for a high end product your options on actually getting data don&#8217;t really exist.</p>

<p>&nbsp;</p>

<p><em>Disclaimer: I have little to no formal training in stats or analytics, have simply learned through launching products so take this for what its worth, someone that has been there and done it.</em></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Startup/Bootstrapped Marketing Recap]]></title>
    <link href="http://www.craigkerstiens.com/2011/03/07/startupbootstrapped-marketing-recap/"/>
    <updated>2011-03-07T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/03/07/startupbootstrapped-marketing-recap</id>
    <content type="html"><![CDATA[<p>If you have an hour to spare its well worth it to look back and look back at my series on startup/bootstrapped marketing. But if you&#8217;re short on time and want the high level summary here&#8217;s the quick recap:</p>

<p><a href="http://www.craigkerstiens.com/2011/02/14/bootstrappedstartup-marketing-part-1/">Part 1 - Focus on SEO</a></p>

<ul>
    <li>Ensure you have a sitemap; <a href="http://www.google.com/support/webmasters/bin/answer.py?answer=183668">http://www.google.com/support/webmasters/bin/answer.py?answer=183668</a>
<ul>
    <li>Submit it to google</li>
    <li>Submit it to yahoo</li>
    <li>Submit it to bing</li>
</ul>
<!--more-->
</li>
    <li>Use meta tags and ensure they&#8217;re unique</li>
    <li>Use unique titles and h1/h2 tags in your pages</li>
</ul>


<p><a href="http://www.craigkerstiens.com/2011/02/16/bootstrappedstartup-marketing-part-2/">Part 2 - Find Influencers</a></p>

<ul>
    <li>Find the key bloggers</li>
    <li>Be brief and to the point</li>
    <li>Provide value to them, often by an exclusive</li>
</ul>


<p><a href="http://www.craigkerstiens.com/2011/02/18/bootstrappedstartup-marketing-part-3/">Part 3 - Traditional Advertising</a></p>

<ul>
    <li>Contextual - AdSense, target for competitors</li>
    <li>Demographic - Cast wide net for demographic info, narrow on interests/hobbies</li>
    <li>Vertical - Ensure to filter out noise and focus on brand</li>
</ul>


<p><a href="http://www.craigkerstiens.com/2011/02/22/bootstrappedstartup-marketing-part-4/">Part 4 - Retargetting</a></p>

<ul>
    <li>No matter what do this step, it make&#8217;s you appear to have a larger presence than you do to users</li>
    <li>Most recommended service: <a href="http://www.adroll.com">AdRoll</a></li>
</ul>


<p>Again this is just a very high level recap. If any of these items strikes a chord with you please dive deeper. The amount of time it takes to learn about how to market and target your users is a fraction of the return you get from doing it effectively. Finally, if anyone out there needs direction on how to target and measure more effectively always feel free to reach out to me, i&#8217;m easily found on <a href="http://www.twitter.com/craigkerstiens">twitter</a> among many other services.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Reading Metrics to Evaluate Marketing]]></title>
    <link href="http://www.craigkerstiens.com/2011/03/02/understanding-metrics/"/>
    <updated>2011-03-02T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/03/02/understanding-metrics</id>
    <content type="html"><![CDATA[<p>A short while backed I talked about <a href="http://www.craigekerstiens.com/2011/02/03/tactical-steps-for-startup-metrics/">tactically measuring metrics</a> for your site/company. Recently I talked a bit about <a href="http://www.craigekerstiens.com/2011/02/14/bootstrappedstartup-marketing-part-1/">methods of marketing</a>. A large key to getting the most out of your time and money is to properly report against the intersection of these two items. First I&#8217;m going to make the assumption you&#8217;ve read those posts, if you haven&#8217;t go back and do that. Next this is heavily on the assumption that you&#8217;re using Google Analytics as your primary tool for measuring metrics and have setup goals appropriately.</p>

<!--more-->


<p>Within measuring you&#8217;re metrics you&#8217;ll have abandonment at each level. You may have some visitors that never register, and many that register but never purchase anything. It&#8217;s wonderful if you&#8217;re able to immediately have full insight of the best means of marketing to drive revenue, however realistically it occurs in a more phased approach. The first step is to drive visitors and almost immediate second is to convert those users as registered.</p>

<p><em><strong>Acquisition -&gt; Activation</strong></em></p>

<p>This at a high level makes sense, as does at a high level knowing you should be targeting users in your target market. However, even slightly drilling into this you realize that all traffic is not equal. It&#8217;s often known that CPC and CPA advertising does not convert well for users, though can drive traffic. This may not always be the case. For Registry Stop to make this analysis easier we&#8217;ve created a custom report in google.</p>

<p>To create your own custom report simply click Manage Custom Reports under the Custom Reports area then &#8220;Create new custom report&#8221;. The custom report ability in google gives you much more ability to drill into the data that you already have at a higher level. To track effectiveness of converting visitors to registered users and which sources are effective at this you&#8217;d create something that looks like:</p>

<p><a href="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz024.png"><img class="alignnone size-medium wp-image-366" title="Creating Custom Report" src="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz024-300x205.png" alt="Creating Custom Report" width="300" height="205" /></a></p>

<p>Here while very simple we&#8217;re able to see some very key information quickly. Here&#8217;s an example of how it would appear over a few day period:</p>

<p><a href="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz0231.png"><img class="alignnone size-medium wp-image-368" title="Google Analytics - Goals Custom Report" src="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz0231-300x205.png" alt="Google Analytics - Goals Custom Report" width="300" height="205" /></a></p>

<p>&nbsp;</p>

<p>As you progress in your stage of bootstrapping or growing your startup you&#8217;ll want to grow custom reports that allow you to report against as many <a href="http://www.craigekerstiens.com/2011/02/03/tactical-steps-for-startup-metrics/">metrics</a> as possible. The first and last part of my day is spent pouring over these reports. Having this data readily available allows us to drive our business based on data. Perhaps the hardest part of all of this is admitting when the data is counter to what we expect and following its advice.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Setting up Goals and Funnels - Google Analytics]]></title>
    <link href="http://www.craigkerstiens.com/2011/02/28/setting-goals-funnels/"/>
    <updated>2011-02-28T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/02/28/setting-goals-funnels</id>
    <content type="html"><![CDATA[<p>I had a recent request on how to setup a funnel in Google Analytics. If you&#8217;ve missed by first post on some tips for <a href="http://www.craigekerstiens.com/2011/02/02/events-with-google-analytics-and-tricking-pageviews/">Google Analytics</a> first check that out. With most websites today there is some portion of the site that is event and not page based, meaning you have some workflow on the page based on Javascript. If this is the case you&#8217;ll want to <a href="http://www.craigekerstiens.com/2011/02/02/events-with-google-analytics-and-tricking-pageviews/">fake a page view</a> instead of an event in order to entirely use it in funnels and goals.</p>

<p>A personal recommendation is actually to use both, goals and funnels. The key a funnel is that you need to have successive steps that occur in some order. With regards to metrics tracking this is absolutely needed, but typically you may have 1-2 total funnels with many steps in your site versus goals where you could have 10-15 single goals. For <a href="http://www.registrystop.com">Registry Stop</a> we&#8217;ve structured our site so that our earlier stage goals become the same as steps in later stage funnels. For us in almost all cases the first part of the funnel is the visit, the second is registering for an account. We do have independent goals for visits and registrations as well, but we do not have funnels on those goals.</p>

<!--more-->


<p>A key to getting the most use out of your funnels is to know that there is a <strong>workflow to follow</strong> to getting to that end goal. To highlight this slightly more visually let me walk through an example:</p>

<ol>
    <li><em><strong>User visits your site.</strong></em></li>
Here you&#8217;ll want to create a goal. Likely this is tracking a page view of the homepage.
    <li><em><strong>User registers for an account.</strong></em></li>
Here again, you&#8217;ll create a goal and nothing more. If there is a confirmation page that will be your goal, if there is not, then you&#8217;ll want to <a href="http://www.craigekerstiens.com/2011/02/02/events-with-google-analytics-and-tricking-pageviews/">fake a page view</a> in order to track that goal.
    <li><em><strong>User adds a product</strong></em></li>
This is the first place you want to create both a goal and a funnel.</ol>


<p>With regards to the goal, it should be pretty simple, tracking some page view. For the funnel though you will likely have 4 parts.</p>

<p>The parts of your funnel will be:</p>

<ol>
    <li>User visits your site.</li>
    <li>User registers for an account.</li>
    <li>User begins process of adding a product</li>
    <li>User completes product add</li>
</ol>


<p>For Registry Stop we have a similar funnel for users which includes:</p>

<ol>
    <li>Registering for an account</li>
    <li>Visiting the sync page</li>
    <li>Adding a synced registry</li>
</ol>


<p>Now as for actually setting up a goal or funnel. This is slightly unintuitive as it&#8217;s not from inside a specific site on Google Analytics. At the home level of google analytics you&#8217;ll have all of your sites setup. For each site to the right you&#8217;ll have actions, click the Edit to go to the goal area.</p>

<p><a href="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz011.png"><img class="alignnone size-full wp-image-348" title="Google Analytics Settings - Goals and Funnels" src="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz011.png" alt="Google Analytics Settings - Goals and Funnels" width="125" height="64" /></a></p>

<p>Once here it becomes a bit more intuitive. You can begin by simply adding a goal. Your goal types should seem mostly intuitive, as mentioned in an earlier post you cannot use an Event in a goal. For this reason you can fake a pageview as if it actually occurred and then create your goal against that non-existent page view. If you want a few more details of how to do this check out the previous post . So for an example, we have a goal on <a href="http://www.registrystop.com">Registry Stop</a> that detects when a page view occurs as a result of a registry being synced. Because this workflow is heavily javascript and flow based we fake the page view and track it as if the page was actually visited. The goal itself looks like:</p>

<p><a href="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz012.png"><img class="alignnone size-medium wp-image-350" title="Google Analytics Example Goal" src="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz012.png" alt="Google Analytics Example Goal" width="300" height="75" /></a></p>

<p>For setting up your funnel as we mentioned above its generally a set of page views. A very key item is the check box next to the first item in your funnel. If you check this is means any other steps in the funnel are not counted unless you the first step is completed. If you have a very structured 1, 2, 3 workflow this makes sense. However, if there are various ways for the goal to complete then be very careful about selecting this.</p>

<p>For this same goal above we have a corresponding funnel to track in detail how our conversion flows. The funnel itself looks like this once setup:</p>

<p><a href="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz022.png"><img class="alignnone size-medium wp-image-344" title="Google Analytics Funnel Setup" src="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz022.png" alt="Google Analytics Funnel Setup" width="300" height="127" /></a></p>

<p>This results in a funnel report that looks like:</p>

<p><a href="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz011.png"><img class="alignnone size-medium wp-image-342" title="Synced Registry Funnel" src="http://www.craigkerstiens.com/images/Snapz-Pro-XScreenSnapz011.png" alt="Synced Registry Funnel" width="300" height="250" /></a></p>

<p>&nbsp;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[JQuery and Django Autocomplete]]></title>
    <link href="http://www.craigkerstiens.com/2011/02/25/jquery-django-autocomplete/"/>
    <updated>2011-02-25T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/02/25/jquery-django-autocomplete</id>
    <content type="html"><![CDATA[<p>In a couple of various places I&#8217;ve seen light requests of how to put autocomplete in for a Django web application. Here&#8217;s a really light weight version with a view and autocomplete functionality using:</p>

<ul>
    <li><a href="http://www.djangoproject.com">Django</a></li>
    <li><a href="http://www.jquery.com">JQuery</a></li>
    <li><a href="http://www.jqueryui.com">JQuery UI</a></li>
</ul>


<p>For a view to search within your django model it would look something like:</p>

<figure class='code'><figcaption><span>models.py </span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">simplejson</span>
</span><span class='line'><span class="k">def</span> <span class="nf">autocompleteModel</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
</span><span class='line'>    <span class="n">search_qs</span> <span class="o">=</span> <span class="n">ModelName</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">name__startswith</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">REQUEST</span><span class="p">[</span><span class="s">&#39;search&#39;</span><span class="p">])</span>
</span><span class='line'>    <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
</span><span class='line'>    <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">search_qs</span><span class="p">:</span>
</span><span class='line'>        <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
</span><span class='line'>    <span class="n">resp</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">REQUEST</span><span class="p">[</span><span class="s">&#39;callback&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&#39;(&#39;</span> <span class="o">+</span> <span class="n">simplejson</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#39;);&#39;</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="n">resp</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>For the jQuery autocomplete and call:</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Evaluating Paying for a Blog Post]]></title>
    <link href="http://www.craigkerstiens.com/2011/02/25/evaluating-paying-blog-post/"/>
    <updated>2011-02-25T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/02/25/evaluating-paying-blog-post</id>
    <content type="html"><![CDATA[<p>At a recent meetup I talked a bit about how I&#8217;d been using blog posts on other blogs, both free and paid for as a primary user acquisition tool. I was very shocked, when several were surprised and curious on the method for this. In tech startups coverage is common, but its usually just that press, not paid for press. I must say I love how the tech community doesn&#8217;t force people to pay to get the word out, but it is very much a competition; that might be just as much work as paying.</p>

<p>In contrast the wedding industry is very much a pay to play space. If you give some money you can get some attention.</p>

<!--more-->


<p>First things first, contact the blog you&#8217;re interested in being written up in and ask for their media kit. If they welcome sponsored posts, then it is likely called out in their media kit. However, this isn&#8217;t always the case, if you&#8217;ve noticed posts on their blog that have been sponsored posts but pricing isn&#8217;t called out in their blog then email them explicitly and inquire.</p>

<p>Once you&#8217;ve got their media kit its time to do some digging. My process has first been to validate their numbers. Most blogs include their unique visitors and page views in their media kits. I immediately jump over to compete to check if their numbers are even in the ballpark. To clarify in the ballpark can be somewhere around 1.5x of compete. There are a surprising number of blogs that may be 20x off in the numbers they are stating. This could mean you&#8217;re outright lying on your stats, or that you&#8217;re not running a solid enough business that you know how to effectively track your numbers. It could be, because your blog exists on 5 different domains, while compete I&#8217;m checking only the primary. Regardless, if you&#8217;re numbers aren&#8217;t close, it often means you&#8217;re not as together as we&#8217;d like.</p>

<p>If they pass the first smoke screen of the stats being in the ballpark, then we can move on to evaluating sponsoring a post. Traffic&#8217;s a big factor, unique visitors are important as well as page views. Next we&#8217;ll typically look for how active your users are. Do users actively engage in comments, where there are active commenters there&#8217;s usually opportunity to get a bit more out of your post.</p>

<p>Next would be, how frequent are posts. Are you looking at 1-2 posts that go up per day, or 10. If 10, it simply means your content will be pushed to the bottom of the page pretty quickly, in this case if page views are exceptionally high, it may mean that users only view 1-2 posts per day and miss the others. I&#8217;ve historically done this on a subjective basis, but it could easily be a number that is calculated and factored in.</p>

<p>So you start with this basic methodology for one blog, then do it for a few more. Its pretty simple to compare 3-4 blogs on their potential value, but when you really start expanding this you could be looking at 100 blogs. If that&#8217;s the case it does help to have some structured method. We typically weight their unique visitors, page views, a factor of how accurate they are against compete, their commenter level, and finally their post frequency. We multiply that weight against the cost of a sponsored post and there you have your priority in terms of which blogs to begin advertising on. Its usually best to try 2-3 blogs to determine your return. But even one can give you an idea of results.</p>

<p>A quick recap of the basic formula:</p>

<ul>
    <li>Factor of stated traffic compared to compete traffic</li>
    <li>Post Frequency (less is better)</li>
    <li>User engagement (measured by comments)</li>
    <li>Page views relative to unique visits</li>
    <li>And of course, cost of the post</li>
</ul>


<p>As a tangible example, we&#8217;ve had variations of 2x from something that ranked nearly the same through the above calculation. Another interesting note, is even months after a post we have seen slow and steady referral on some posts. This method is definitely not ideal for all companies to acquire users, but for many should definitely be explored. And remember, you should always track these against your metrics to know true effectiveness.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bootstrapped/Startup Marketing Part 4]]></title>
    <link href="http://www.craigkerstiens.com/2011/02/22/bootstrappedstartup-marketing-part-4/"/>
    <updated>2011-02-22T00:00:00-08:00</updated>
    <id>http://www.craigkerstiens.com/2011/02/22/bootstrappedstartup-marketing-part-4</id>
    <content type="html"><![CDATA[<p>We&#8217;ve talked some about <a href="http://craigekerstiens.com/2011/02/14/bootstrappedstartup-marketing-part-1/">SEO</a>, <a href="http://craigekerstiens.com/2011/02/16/bootstrappedstartup-marketing-part-2/">media/blog posts</a>, adwords, no one of these is a magic bullet. Some work better for different reasons. As I mentioned in the first post, if you haven&#8217;t checked out the post on <a href="http://craigekerstiens.com/2011/02/03/tactical-steps-for-startup-metrics/">tactically measuring metrics</a> then please do. If you have followed those steps and explore each of these options, then you should have an idea of which one works well for you and which doesn&#8217;t. The final piece of marketing may be a bit harder to measure, but is going to do great things towards growing your brand to users and visitors.</p>

<!--more-->


<p><strong><span style="text-decoration: underline;">Retargetting</span></strong>
Retargetting is the idea of showing an ad to a user that has already visited your site. It&#8217;s pretty basic, someone comes to your site and you have a pixel that loads telling your ad network they&#8217;ve visited. From then on they may see your ad when randomly browsing the web. With my most recent venture into the online registry space I was browsing Chiacgo Tribune and Slashdot and came across our ads. There&#8217;s absolutely no contextual relevance there, but I checked and it was due to our retargetting. This will make it appear as if you are everywhere to your users. If you do want to heavily monitor what retargetting is doing for you, the best place to do it is around your retention metric.</p>

<p>How do you do retargetting? Sounds like a complicated process slightly&#8230; Well it&#8217;s simple you don&#8217;t, let one of the major ad networks do it for you. The first step for it, is to use image ads. Text based ads may work great for google and facebook, but on most of the websites your retargetting will run on you want to have images that the blogs typically serve. The 3 key form factors you&#8217;ll want are:</p>

<ul>
    <li>300x250</li>
    <li>728x90</li>
    <li>160x600</li>
</ul>


<p>As for who to use for a service? Google recently launched their service in the past year and called it ReMarketing. I&#8217;ve had mixed results with google with regards to their approval process on images. Many times I&#8217;ve had images sit in a queue for a full month, then finally reached out to their support and have it take another 3 days. For this reason alone, it almost makes it worthwhile to go with the better customer service. I&#8217;ve used <a href="http://www.adroll.com">AdRoll</a> for basic ad campaigns as well as ReTargetting. I must say I absolutely love them for ReTargetting. For standard ad campaigns they do a good amount to optimize performance, but you are also paying a premium for it. Those are the two I&#8217;m most aware of, but if others know of great retargetting services I&#8217;d love to hear about them and give them a try.</p>

<p>If you want your shop to seem like a mom and pop site that has 100 visitors a month, then retargetting will hold absolutely no value for you. But even if you do only have 100 visitors a month, with retargetting they&#8217;ll get some confidence that you&#8217;re a real online brand with a presence.</p>
]]></content>
  </entry>
  
</feed>

