<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CRAIG KERSTIENS</title><link>/</link><description>CRAIG KERSTIENS</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 11 Nov 2024 07:57:56 -0800</lastBuildDate><atom:link href="/index.xml" rel="self" type="application/rss+xml"/><item><title>Getting comfortable with psql</title><link>/2024/11/11/Getting-comfortable-with-psql/</link><pubDate>Mon, 11 Nov 2024 07:57:56 -0800</pubDate><guid>/2024/11/11/Getting-comfortable-with-psql/</guid><description>&lt;p>psql is a CLI editor that ships with Postgres. It&amp;rsquo;s incredibly powerful for working with Postgres, and doesn&amp;rsquo;t take too much of a learning curve to start to get comfortable so you can really feel like an expert working with your database.&lt;/p>
&lt;p>Just a rundown of a few things to get you started:&lt;/p>
&lt;p>Once connected in psql you can get an idea of all utility commands available with:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#f92672">?&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A handy thing I use all the time is &lt;code>\d&lt;/code>.&lt;/p>
&lt;p>&lt;code>\d&lt;/code> will describe the tables within database. You can also add a table/index/etc. onto it to describe that specific table such as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>d accounts
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There are a number of options you can set in your psqlrc (config) file to customize your CLI experience. But you can also toggle those when directly working in psql.&lt;/p>
&lt;ul>
&lt;li>&lt;code>\timing&lt;/code> will give you the time it took to run your query&lt;/li>
&lt;li>&lt;code>\x auto&lt;/code> will autoformat your text output&lt;/li>
&lt;li>&lt;code>\pset pager 0&lt;/code> turns off your pager or 1 to turn it back on&lt;/li>
&lt;/ul>
&lt;p>Oh and for editing a query in your editor of choice. Make sure you set your $EDITOR enviroment variable to the editor of your choice, though the only right choice is vim:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>e
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Just a few things to get you started working with psql.&lt;/p>
&lt;video
class="video-shortcode"
preload="auto"
controls
>
&lt;source
src="https://craigkerstiens.b-cdn.net/psql_basics.mp4"
type="video/mp4"
alt="Psql basics"
>
Your browser does not support video
&lt;/video></description></item><item><title>The future of Postgres?</title><link>/2024/10/18/The-future-of-Postgres/</link><pubDate>Fri, 18 Oct 2024 08:50:56 -0800</pubDate><guid>/2024/10/18/The-future-of-Postgres/</guid><description>&lt;p>I&amp;rsquo;m often asked what do I think the &lt;em>future for Postgres&lt;/em> holds, and my answer has been mostly the same for probably 8 years now, maybe even longer. You see for Postgres itself stability and reliability is core. So where does the new stuff come from if it&amp;rsquo;s not in the stable core&amp;hellip; &lt;strong>extensions&lt;/strong>.&lt;/p>
&lt;p>Extensions within Postgres are unlike most other databases allowing you to modify or well extend the standard Postgres behavior. You can build other storage backends, new types, etc. Postgres itself ships with a number of extensions within the &amp;ldquo;contrib&amp;rdquo;. The list of contrib extensions hasn&amp;rsquo;t changed any time recently, but even contrib is a small sampling of what is possible. Beyond core there is a whole world of extensions, I want dig into just a smalls sampling starting with a few in core&amp;hellip;&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://www.crunchydata.com/blog/tentative-smarter-query-optimization-in-postgres-starts-with-pg_stat_statements">pg_stat_statements&lt;/a>&lt;/strong> is to me the most useful extension that exists. It records what queries were run, how long they took, and a number of other details about the queries. A key extension for managing performance of your database.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://www.postgresql.org/docs/current/auto-explain.html">auto_explain&lt;/a>&lt;/strong> another one in contrib that is helpful for performance. For queries that run over a certain period of time will automatically log the explain plan–helpful for performance debugging.&lt;/p>
&lt;p>pg_prewarm useful to prewarming the cache ahead of a failover.&lt;/p>
&lt;p>Let&amp;rsquo;s jump out of contrib a little bit now. Of course that isn&amp;rsquo;t everything that ships with Postgres there is more, explore for yourself.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://github.com/citusdata/citus">Citus&lt;/a>&lt;/strong> is one of the (to date) more advanced extensions ever created. Citus turns postgres into a sharded, distributed, horizontally scalable database. Citus is especially built to work well for B2B style multi-tenant apps, and now after being acquired years ago part of Microsoft.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://github.com/paradedb/paradedb">Pg_search&lt;/a>&lt;/strong> extends Postgres to support elastic-quality full text search directly within Postgres. I often say Postgres can do just about everything and be pretty capable. Things like time series and search it&amp;rsquo;s about 80% as good of some of the best in class options out there, but pg_search takes it further making it a full competitor to elastic, but Postgres.&lt;/p>
&lt;p>Those are some bigger ones, but you&amp;rsquo;ve also got a lot of small focused ones as well.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://github.com/citusdata/pg_cron">Pg_cron&lt;/a>&lt;/strong> is incredibly handy. Created originally by &lt;a href="https://twitter.com/marcoslot">@marcoslot&lt;/a> while at Citus, it&amp;rsquo;s a small extension that does what it sounds like run scheduled jobs within Postgres. It is now a standard across all the major cloud providers. We leverage it heavily at &lt;a href="https://twitter.com/crunchydata">@crunchydata&lt;/a>, but went a little further and built a UI on top so you don&amp;rsquo;t have to worry about crontab styling of the jobs.&lt;/p>
&lt;p>Just yesterday at Crunchy Data we released &lt;strong>&lt;a href="https://github.com/CrunchyData/pg_parquet">pg_parquet&lt;/a>&lt;/strong>. There have been some questions about what about other extensions that sort of do similar but not exact but also do a lot of other things. This allows you to seamless copy to and from Parquet files with Postgres. It follows the linux philosophy of small sharp tools. Marco described the why extremely well:&lt;/p>
&lt;blockquote>
&lt;p>We wanted to create a light-weight implementation of Parquet that does not pull a multi-threaded library into every postgres process. When you get to more complex features, a lot of questions around trade-offs, user experience, and deployment model start appearing.&lt;/p>
&lt;/blockquote>
&lt;p>There is a whole lot of extensions out there. There are big robust ones that have been around forever (yeah I&amp;rsquo;m talking about you PostGIS), there are ones in contrib, there are ones that are literally created as jokes. Some try to do a lot others as I mentioned very narrow focus like pg_cron. Regardless of whether you believe in large complex extensions that do a lot or small ones that do one thing but do it really well, if you want to know where the future of Postgres is I can&amp;rsquo;t imagine a world where extensions do not play a heavy roll.&lt;/p></description></item><item><title>What problem are we trying to solve?</title><link>/2022/11/28/What-problem-are-we-trying-to-solve/</link><pubDate>Mon, 28 Nov 2022 11:23:56 -0800</pubDate><guid>/2022/11/28/What-problem-are-we-trying-to-solve/</guid><description>&lt;p>If you want to seem like the smartest person in the room, wait for a break in conversation, after sitting quiet for 15 minutes, and ask &lt;em>&amp;ldquo;What problem are we trying to solve here?&amp;rdquo;&lt;/em> It works every time.&lt;/p>
&lt;p>We’ve all been there. You walk into a meeting, there are 10 people in it. It gets rolling, different folks chiming in. A few people seem to be taking personal notes, they always do. There is the person that scheduled the meeting, but they’re not the person that usually makes decisions. It’s primarily going back and forth between 3 individuals with 7 others watching on. You’re 15 minutes in, and while there has been lively discussion already… you find yourself back on the original point from minute 1 seemingly lost 14 minutes and you’re unsure to what.&lt;/p>
&lt;p>A healthier environment ideally has an agenda sent out ahead of time. Based on the agenda there is a clear structure planned for the meeting which presumably points to a clear goal. Even without an agenda an alternative structure would be a clearly stated goal in the invite. Within the meeting you &lt;a href="https://www.heavybit.com/library/video/executive-communication">SCQA&lt;/a>-it up live. Huge bonus points if the meeting invite includes a link to the &lt;strong>notes doc&lt;/strong> where meeting notes will be transcribed by an &lt;strong>explicit scribe&lt;/strong> for the meeting, &lt;strong>sent out after&lt;/strong> for folks to agree/confirm as a good record of the meeting.&lt;/p>
&lt;p>As a facilitator as good as you may be, you’re still going to end up in the first situation. Every time wait 10-15 minutes, then ask the question. It seems to be more effective after you’ve had the detour vs. leading off with it in the first 1 minute. Even better internalize the question to yourself vs. just making yourself look good by asking it (which will happen).&lt;/p></description></item><item><title>Gonna use a personal trick/hack? Use it often</title><link>/2022/11/22/Gonna-use-a-personal-trick/hack-Use-it-often/</link><pubDate>Tue, 22 Nov 2022 08:11:56 -0800</pubDate><guid>/2022/11/22/Gonna-use-a-personal-trick/hack-Use-it-often/</guid><description>&lt;p>What do I mean by trick/hack? This can be super flexible, but I’ll toss out a few of my own personal ones.&lt;/p>
&lt;p>One of the rules of my product management philosophy, is if you’re going to use a tool or trick then use it often. This is in fact one of my favorite interview questions for PMs. If you ever interview with me, be prepared it’s coming. It applies for engineering managers and others in leadership roles as well, but I’ve found especially get for PMs.&lt;/p>
&lt;h3 id="getting-a-response-from-team-emails" >
&lt;div>
Getting a response from team emails
&lt;/div>
&lt;/h3>
&lt;p>It’s very common to have a team@ alias within your company, whether for the whole team or for smaller teams. As a PM you may need to email sales@ and get feedback of requested features, or feedback on the roadmap. Chances are you’ll send some good time and effort crafting this email, being concise but also giving enough context for them to give you an informed response. If you’re good you’ve fed the email through hemingway app before you sent it and gotten it down to grade level 7 or lower. You send it middle on a Tuesday around 10am so it’s not lost in Monday triage, and not missed on Thursday that aligns to a long holiday weekend. And then… silence. Nothing. Nada. Zip. Zilch.&lt;/p>
&lt;p>I’m not really sure the reason for crickets, perhaps at best they assumed a bunch of their peers got back to you privately. At worst they’re apathetic and care strictly on closing their next deal and not giving feedback that helps long term growth. But I’m not here to dissect why. How do you get a response?&lt;/p>
&lt;p>Slightly restructure the email to instead of going to the sales@ alias, be targeted to individuals. Pull the emails of everyone on the list, make the opening a generic “Hi,”, and have it go directly to the individuals via a mail merge.&lt;/p>
&lt;p>From experience have had CEOs (who I forgot to omit) email me back when they were out on vacation apologizing for slow response (of hours) and that they’d get me feedback before weeks end.&lt;/p>
&lt;h3 id="turn-a-group-email-into-a-love-fest" >
&lt;div>
Turn a group email into a love fest
&lt;/div>
&lt;/h3>
&lt;p>As much as 1:1 emails are great and will solicit a response. Often you need to send out an announcement to a team. “We’ve got a big announcement tomorrow”. You’ll put the same work and effort into that team email as you did in the above, and again the usual response is crickets.&lt;/p>
&lt;p>My teams know I do this, and yet it still works. Get 1-2 other leaders (not necessarily management) but morale leaders to know it’s coming and chime in on a reply-all to the team@ list with positive comments and praise. The same applies also to new hire announcements that goes to team@. You’re going to end up with folks not wanting to be left out from piling on. It’ll start to get flow of feedback public and private coming in about what is good on the communication and give you a sense of where it can improve.&lt;/p>
&lt;h3 id="what-are-your-hacks" >
&lt;div>
What are your hacks?
&lt;/div>
&lt;/h3>
&lt;p>These are just a few, as I keep writing up some longer form of my personal product philosophies will layer in more of these nuggets. But every good PM I’ve ever worked with has had their own bag of tricks. Again it’s one of my favorite interview questions, I’ve stolen many great tricks from others over the years. But curious, even without needing for us to be in an interview what are yours? @&lt;a href="https://www.twitter.com/craigkerstiens">craigkerstiens&lt;/a>&lt;/p></description></item><item><title>Unfinished Business with Postgres</title><link>/2022/05/18/Unfinished-Business-with-Postgres/</link><pubDate>Wed, 18 May 2022 08:52:56 -0800</pubDate><guid>/2022/05/18/Unfinished-Business-with-Postgres/</guid><description>&lt;p>7 years ago I left Heroku. Heroku has had a lot of discussion over the past weeks about its demise, whether it was a &lt;a href="https://twitter.com/sraney/status/1519516583042818049">success&lt;/a> or failure, and the current state. Much of this was prompted by the recent, and on-going security incident, but as others have pointed out the product has been frozen in time for some years now.&lt;/p>
&lt;p>I&amp;rsquo;m not here to rehash the many debates of what is the next Heroku, or whether it was a &lt;a href="https://news.ycombinator.com/item?id=31373300">success&lt;/a> or failure, or how it could have been &lt;a href="https://news.ycombinator.com/item?id=31373394">different&lt;/a>. Heroku is still a gold standard of developer experience and often used in pitches as Heroku for X. There were many that tried to imitate Heroku for years and failed. Heroku generates sizable revenue to this day. &lt;a href="https://twitter.com/_adamwiggins_/status/1334595784373923840">Without Heroku&lt;/a> we’d all be in a worse place from a developer experience perspective.&lt;/p>
&lt;p>But I don’t want to talk about Heroku the PaaS. Instead I want share a little of my story and some of the story of Heroku Postgres (DoD - Department of Data as we were internally known). I was at Heroku in a lot of product roles over the course of 5 yrs, but most of my time was with that DoD team. When I left Heroku it was a team of about 8 engineers running and managing over 1.5m Postgres databases–a one in a million problem was once a week, we engineered a system that allowed us to scale without requiring a 50 person ops team just for databases&lt;/p>
&lt;p>This will be a bit of a personal journey, but also hopefully give some insights into what the vision was and hopefully a bit of what possibilities are for Postgres services in the future.&lt;/p>
&lt;p>&lt;em>I wasn&amp;rsquo;t originally hired to work on anything related to Postgres.&lt;/em> As an early PM I first worked on billing, then later on core languages and launching the Python support for Heroku. It was a few months in when I found myself having conversations with many of the internal engineers about Postgres. &amp;ldquo;Why aren&amp;rsquo;t you using hstore?&amp;rdquo;, &amp;ldquo;Transactional DDL to rollback transactions is absolutely huge!&amp;rdquo;, &amp;ldquo;Concurrent index creation runs in the background while not holding a lock, this should always be how you add an index.&amp;rdquo; Now we had some great engineers, but it was the typical engineer that interacted through ActiveRecord and didn&amp;rsquo;t want to think about the database.&lt;/p>
&lt;p>As I found myself &lt;a href="https://www.craigkerstiens.com/2012/04/30/why-postgres/">evangelizing Postgres&lt;/a>, suddenly I was being recruited by the lead of the Postgres team to come and do marketing, I didn&amp;rsquo;t know anything about marketing and thought they were joking. A couple months later found myself doing PM and marketing for DoD.&lt;/p>
&lt;h3 id="why-did-heroku-pick-postgres" >
&lt;div>
Why did Heroku pick Postgres?
&lt;/div>
&lt;/h3>
&lt;p>But, I&amp;rsquo;m getting a little bit ahead of myself. How did Heroku even start doing Postgres or why? Running a PaaS (platform as a service) is a lot of work, running a database is a lot of work. In some sense doing both is splitting your focus. And I&amp;rsquo;m increasingly coming to the conclusion that platform companies will do best to &lt;a href="https://news.ycombinator.com/item?id=31185715">focus&lt;/a> on their platform and data companies will do best to focus on the data. Well, way back in the day we had all these Rails developers asking for a database and we thought how hard could it be? (It was more work than we expected). So we&amp;rsquo;re gonna run a database, the question becomes which one? Most folks didn&amp;rsquo;t have strong opinion, but one of our security/ops engineers chimed in &amp;ldquo;Postgres has always had a good record of being safe and reliable for data, I&amp;rsquo;d go with it.&amp;rdquo;&lt;/p>
&lt;p>And with that, we were building and launching Heroku Postgres.&lt;/p>
&lt;p>&lt;em>The first version of Heroku Postgres, no automation, no self service provisioning, you opened a ticket and we’d correspond and ask when you wanted us to set it up for you.&lt;/em>&lt;/p>
&lt;h3 id="before-heroku-postgres-was-postgres" >
&lt;div>
Before Heroku Postgres was Postgres
&lt;/div>
&lt;/h3>
&lt;p>The very first version before we committed to Heroku Postgres was internally known as Shen. The model was much more akin to shared hosting that was common for that time and place. Within a single instance we’d pack in a lot of Postgres databases, simply running createdb, creating a user for you, then giving you access to that DB. This worked fine for those just kicking the tires and building small apps, but despite telling them to not use it for production people continued to.&lt;/p>
&lt;p>While Heroku had Postgres before Heroku Postgres it became a project and its own orchestration layer for databases as a more first class citizen around 2010. The initial codename for the project was &amp;ldquo;&lt;a href="https://gist.github.com/adamwiggins/7d0e0805e0e44870f17f">bifrost&lt;/a>&amp;rdquo;.&lt;/p>
&lt;h3 id="the-original-design" >
&lt;div>
The original design
&lt;/div>
&lt;/h3>
&lt;p>Heroku Postgres was designed to have a central FSM (finite state machine) that would orchestrate the databases. This design pattern to my knowledge came from &lt;a href="https://www.twitter.com/pvh">@PvH&amp;rsquo;s&lt;/a> work and appreciation of video game system design. It felt like a novel approach to the software being built at this time. The fact that it is a more common design patten now shows what a great design it was, and how ahead of its time the level that team was building at.&lt;/p>
&lt;p>It was a basic Ruby application that would go out and check the state databases and go through the needed steps when interacting with either Postgres or AWS APIs. AWS APIs back then were not what they are now and this allowed to build in necessary retries, redundancies, and quality of service.&lt;/p>
&lt;h3 id="sometimes-youre-good-sometimes-youre-lucky" >
&lt;div>
Sometimes you&amp;rsquo;re good, sometimes you&amp;rsquo;re lucky
&lt;/div>
&lt;/h3>
&lt;p>Sometimes you&amp;rsquo;re good, sometimes you&amp;rsquo;re lucky, sometimes it&amp;rsquo;s both. Over time we built out more reliable provisioning and monitoring of databases. In early 2011 we felt a need to continue improving this. It was the early days of EC2 and reliability wasn&amp;rsquo;t the strongest spot, instances could go offline.&lt;/p>
&lt;p>Per &lt;a href="https://www.twitter.com/danfarina">@danfarina&lt;/a> &amp;ldquo;We were thinking about working on replication but skipping over archiving (by more carefully managing state between servers, e.g. by directly moving things through rsync, which was/is still pretty normed postgres stuff predating pg_basebackup) but then one of the shared databases (shen) had a near miss when a disk was lost that caused a rather horrific amount of effort and some nailbiting in restoring from pgbackups.&amp;rdquo;&lt;/p>
&lt;p>&amp;ldquo;We then decided to take previouly rejected approach of building everything up on the archives. the first versions were s3cmd based, and were something of a prototype, upon request from PvH to ship something more raw, but more quickly. We had just got early versions into production when the &lt;a href="https://aws.amazon.com/message/65648/">major disk apocalypse&lt;/a> hit in April 2011, though it was in something of an evaluation period and it was not yet a well-exercised &amp;amp; monitored program, so we crossed our fingers and, thankfully, it worked on every database, once AWS had capacity to spare.&amp;rdquo;&lt;/p>
&lt;p>At the end of the event it was communicated eventually that if we wanted AWS could give us all of the EBS disks back, but it could be all of them were corrupted. As someone we can’t recall adequately described it: &amp;ldquo;It’s like getting a gallon of ice cream, but it may have a turd in it&amp;rdquo;.&lt;/p>
&lt;p>More from @danfarina: &amp;ldquo;Were it up to me at the time, I probably would have moved onto converting it to boto (one of the most mature AWS client bindings at the time, by far) before stopping to deploy the s3cmd near-prototype on every instance, but that would have been a disaster.&amp;rdquo;&lt;/p>
&lt;p>Our applications were resilient because we could leverage multiple dynos and the routing layer available to our system. Databases are a little different, but how could we at scale give the features you most needed for a database:&lt;/p>
&lt;ol>
&lt;li>No data loss&lt;/li>
&lt;li>Improved availability&lt;/li>
&lt;/ol>
&lt;p>Number one was always a core charter for the team and we would prioritize this over features, and over uptime. Uptime mattered, features mattered, but as a data provider if we lost data we&amp;rsquo;d lose trust. Thus that quick prototype became wal-e, which then went on to power many of the future features of Heroku Postgres, and be used for many years, though now has been deemed obsolete in favor of more modern tooling such as &lt;a href="https://pgbackrest.org/">pgBackRest&lt;/a>. But for it’s time and place it was some good execution and some luck on timing.&lt;/p>
&lt;h3 id="thinking-about-the-entire-experience" >
&lt;div>
Thinking about the entire experience
&lt;/div>
&lt;/h3>
&lt;p>As Heroku sat at a central point of app deployment we actively tried to think about the experience end to end. This manifested in some of the small things we actively campaigned for and collaborated with the community members who could make these happen. A few key examples come to mind for this.&lt;/p>
&lt;p>The first was &lt;code>DATABASE_URL&lt;/code>. Some of this originated from the &lt;a href="https://12factor.net">12factor concepts&lt;/a>, others in that having 5 environment variables to define what you were connecting too felt verbose and cumbersome. Why couldn’t Rails just use &lt;code>DATABASE_URL&lt;/code> if it were defined. I don’t recall the specifics here, but suspect this was something we nudged &lt;a href="https://www.twitter.com/hone02">@hone02&lt;/a> to help with.&lt;/p>
&lt;p>The second was around some features of Postgres. At the time Postgres was going well, but most of the core community focused on performance or enterprise-y features. We were coming at it from a different angle with an audience of Rails developers. We were intentional and engaged with some of the Postgres consultancies that employed committers, with a general theme of how can we help contribute, while also advancing Postgres based on the knowledge we have from users. A few highlights here included:&lt;/p>
&lt;ol>
&lt;li>Not just the &lt;code>DATABASE_URL&lt;/code> on the Rails side, but also on the native libpq wire protocol. While we didn’t do the work here, we were spent notable time &lt;a href="https://www.postgresql.org/message-id/CAAcg%3DkWxsUeQ7Rz%3Dto4nvuwHJ%2BVj6ADrNHEcqFrGHnYmMNPznQ%40mail.gmail.com">advocating and engaging&lt;/a> around it.&lt;/li>
&lt;li>pg_stat_statements in my opinion now the most valuable Postgres extension existed before, but was effectively unusable for most applications. Funding this work was foundational to make Postgres have more usable insights natively.&lt;/li>
&lt;li>JSON/JSONB collaboration&lt;/li>
&lt;/ol>
&lt;p>&lt;em>Of note we later hired several contributors to largely focus their time on upstream Postgres itself.&lt;/em>&lt;/p>
&lt;h3 id="dataclips-vs-the-team" >
&lt;div>
Dataclips vs. the team
&lt;/div>
&lt;/h3>
&lt;p>Throughout the history of Heroku Postgres various individuals made a series of bets. First it was @PvH pushing for Wal-E to get out the door as an MVP, which was absolutely the right call in retrospect. Perhaps the one that is most exciting to me and people least associate with Heroku is dataclips. &lt;a href="https://twitter.com/mattsoldo">Matt Soldo&lt;/a>, had this idea of GitHub Gists for your database. But in the early days of Heroku as a PM, like many places as PM you didn’t have an ease to mandate engineers try a thing. You had to campaign and convince for a thing.&lt;/p>
&lt;p>Soldo didn’t build up enough buy in from the team, but had done plenty of awesome things that it was worth letting him run with this. We were all wrong. Dataclips was built by an external consulting company as a separate standalone Heroku app. It was only live for weeks and suddenly it was powering all of our internal dashboards. A live query you could embed into google sheets, suddenly our internal KPI rails app was replaced by dataclips and a google sheet. We didn’t need looker or tableau or other fancy BI tools and this lasted into 100m in revenue for insights into the business. To this day dataclips is one of my favorite features of Heroku, and I look forward to making an experience like that but even better, thanks Soldo for not listening to the rest of us back then.&lt;/p>
&lt;h3 id="names-matter" >
&lt;div>
Names matter
&lt;/div>
&lt;/h3>
&lt;p>For a long time databases haven&amp;rsquo;t been known for being user friendly. We wanted to pull from other paradigms as we were making key database tenets available to people. We looked heavily to git for inspiration around forking/following. Database terms were common as master/slave, but we knew we could do better. Ee wanted to give the user a sense of what they could do with it. Archiving the WAL every 16 MB or 60 seconds (whichever was less) became continuous protection. Forking, was a snapshot as of some point in time. Follower, something that followers a leader node (a read-replica). I still recall an hour long analyst call with Redmonk with &lt;a href="https://www.twitter.com/monkchips">@monkchips&lt;/a> and &lt;a href="https://www.twitter.com/sogrady">@sogrady&lt;/a>–it was mostly wind them up and let them go (for the record &lt;a href="https://www.twitter.com/monkchips">@monkchips&lt;/a> didn&amp;rsquo;t love fork/follow, I think he may have come around now).&lt;/p>
&lt;p>This started even earlier than my time with being intentional about Postgres vs. PostgreSQL. But I’ve covered that one &lt;a href="https://www.craigkerstiens.com/2018/10/30/postgres-biggest-mistake/">before&lt;/a>, and you can even see it in some of the other lobbying around &lt;a href="https://www.postgresql.org/message-id/CAAcg%3DkWxsUeQ7Rz%3Dto4nvuwHJ%2BVj6ADrNHEcqFrGHnYmMNPznQ%40mail.gmail.com">libpq&lt;/a>.&lt;/p>
&lt;h3 id="peacetime-vs-wartime" >
&lt;div>
Peacetime vs. Wartime
&lt;/div>
&lt;/h3>
&lt;p>Things were rolling along well, we were shipping new features. We&amp;rsquo;d added dataclips, fork/follow were in existence for a while–and then we got a note from Amazon they were launching Postgres support for RDS at the next ReInvent. I was in person at that ReInvent and I&amp;rsquo;d never seen a roaring standing applause like that at a tech conference before when the moment was announced. In private channels we heard notes that this was because of us, the excitement and demand for Postgres became too clear for them to ignore and they had to add support.&lt;/p>
&lt;p>We felt vindicated in our choice of Postgres and in what we&amp;rsquo;d built. But we also knew that now we had competition, running a database as a service on another infrastructure provider how can you compete? Well from some years of experience now I can say there are definitely ways and am confident that sharp narrow focus allows you to build amazing products which can be harder to do inside a large giant corporation. It was at one of &lt;a href="https://www.postgresql.org/docs/9.1/datatype-datetime.html#DATATYPE-DATETIME-SPECIAL-TABLE">allballs&lt;/a> (UTC 00:00:00-when the data team would do happy hour on Fridays) that we were drinking beers and discussing how now we really had to focus. @&lt;a href="https://www.twitter.com/pvh">PvH&lt;/a> and @&lt;a href="https://www.twitter.com/danfarina">danfarina&lt;/a> were discussing me personally as a leader–apparently I&amp;rsquo;m okay in peacetime when things are good but in wartime they were willing to bet on me.&lt;/p>
&lt;p>Two weeks later I walked into the exec team meeting with a 2-pager assessment of what may happen, how we could compete, including 3 potential acquisition targets that could allow us to have a more differentiated offering. Within a few months we made one of those acquisitions which later became Heroku Connect. It made a lot of sense for many reasons, including &lt;a href="https://www.twitter.com/adam_g">Adam Gross&lt;/a> was an angel investor in Heroku and knew it well and had helped build Salesforce Platform in early years. That wasn&amp;rsquo;t the end, but was just the beginning of how we could actively compete vs. simply being &amp;ldquo;hosted Postgres&amp;rdquo; vs. a more fully managed experience.&lt;/p>
&lt;h3 id="metrics-and-monitoring-that-almost-was" >
&lt;div>
Metrics and Monitoring that almost was
&lt;/div>
&lt;/h3>
&lt;p>The next vision and goal for Heroku Postgres was to continue to give better ease of use and insights into your database. Postgres itself already has a ton of awesome data inside it about how it’s been used. The catalog tables and extensions like &lt;code>pg_stat_statements&lt;/code> have a wealth of information, but querying it looks like 200 lines of black magic SQL. &lt;a href="https://www.twitter.com/leinweber">@leinweber&lt;/a> was perhaps one of the first, and the best at the team and quickly making something usable for people. The first step on our metrics journey was him making these Postgres insights trivially accessible via &lt;a href="https://blog.heroku.com/more_insight_into_your_database_with_pgextras">pg-extras&lt;/a>.&lt;/p>
&lt;p>Continuing on the journey internal foundational systems were built, in fact we just spent 3 months &lt;a href="https://www.crunchydata.com">@crunchydata&lt;/a> building similar systems that were spiritually aligned, to focus on collection of various meta data from systems and the ability to notify and communicate. I’m blanking on some of the systems, though some were obvious–observatory (I’m not sure if still in use or not) would observe databases.&lt;/p>
&lt;p>These systems started to house a lot of information that then powered pieces within your Heroku Postgres dashboard. Things like slow queries and high IO or CPU load would give good insights when you logged in. The eventual goal was to connect the dots through proactive notifications. It’s one thing to get an alert from pagerduty that things are off, login to a dashboard and fix it. But what if in the early signs of things starting to go south we emailed you that you’ve got an increasing number of sequential scans that are starting to put you at risk of IOPS saturation, and because we understand Postgres you can add an index and resolve this with a single command. We could even give you an easy button in your email to add the index. All the foundations were in place, if you’ve run on Heroku you’ve gotten the notifications about database maintenance, that was powered entirely from the underlying notification system built with this goal in mind.&lt;/p>
&lt;h3 id="postgres-can-still-be-better-for-developers" >
&lt;div>
Postgres can still be better for developers
&lt;/div>
&lt;/h3>
&lt;p>But we never made it there. Some of us shuffled to different teams, some of us moved on to new challenges, and many folks came on after to continue to run and power a great database service. Some of those original engineers Daniel Farina and Will Leinweber (along with PvH) understand the design and why as well as anyone. The goal from early on was that we could do better for developers.&lt;/p>
&lt;p>Two years ago when people asked why I came to &lt;a href="https://www.crunchydata.com">Crunchy Data&lt;/a> I told them I had unfinished business. After the success at Citus tackling scalability problems where the average customer being 40TB in data, I attracted to the idea of returning to the vision we had back at the DoD of bringing a better Postgres experience to developers. Despite the rapid growth of successful DBaaS offerings, there was still something missing - that initial idea of DoD that we still wanted to create.&lt;/p>
&lt;p>Postgres is an amazing database, can handle hundreds of thousands of transactions per second often without batting an eye. Has internal data that you can easily look at to assess and improve performance. Has a rich set of datatypes, indexing, and functionality. The extension ecosystem is vast. But as a developer you don’t have time to become an expert on Postgres.&lt;/p>
&lt;ul>
&lt;li>What if we told you when a N+1 query snuck into your Rails app?&lt;/li>
&lt;li>Connections don’t have to be a limitation on Postgres when you have pgBouncer right there.&lt;/li>
&lt;li>Have excessive indexes from the early stage of building your app? What if we told you about them and with a button click you could drop them.&lt;/li>
&lt;/ul>
&lt;p>One of our &lt;a href="https://www.twitter.com/crunchydata">@crunchydata&lt;/a> customers described it better than I ever could. When working with some of our experts on some deep dives into their database they said “you should take all his Postgres expertise and just bottle it up and send it in email or slack reports to me.” I want that expertise as a &lt;a href="https://crunchybridge.com/register">product&lt;/a>.&lt;/p>
&lt;p>My product strategy isn’t to go and change the world of databases. Postgres is a great database with a community that is making it better daily. I want to help make open source Postgres better and give back to it along the way. My product strategy is to distribute deep Postgres expertise in a consumable form to every customer of ours in the coming years. Oh we’ll ship some cool things along the way too.&lt;/p></description></item><item><title>Guidance for Scaling - Reversible vs. Irreversible Decisions</title><link>/2021/12/29/Guidance-for-Scaling-Reversible-vs.-Irreversible-Decisions/</link><pubDate>Wed, 29 Dec 2021 13:30:56 -0800</pubDate><guid>/2021/12/29/Guidance-for-Scaling-Reversible-vs.-Irreversible-Decisions/</guid><description>&lt;p>Was having a conversation with a founder earlier today and the topic of hiring functional leaders came up. I offered one of my common pieces of advice which was don&amp;rsquo;t hold the reins too tightly once you hire them. It&amp;rsquo;s something I see happen over and over to first time founders. You hire a new VP of Product and then still continue to oversee so much of the product process yourself. It is understandable, it&amp;rsquo;s your baby, you&amp;rsquo;ve spent years building it to this point, they don&amp;rsquo;t love it the same way you do.&lt;/p>
&lt;p>The likely outcome is your new VP of product won&amp;rsquo;t find success. They&amp;rsquo;ll feel they&amp;rsquo;re not able to execute on a vision of their own. They&amp;rsquo;ll feel micromanaged. Even the smallest decisions they&amp;rsquo;ll feel aren&amp;rsquo;t fully theirs and get second guessed.&lt;/p>
&lt;p>Perhaps you could do it better, that&amp;rsquo;s not necessarily the question. What you&amp;rsquo;re focused on is growing and scaling, this is the reason you hired them. So how do you do this without the business careening off tracks? Well first, empower them to make decisions, but beyond that there are a few things you can do so you feel more comfortable entrusting them with their functional area.&lt;/p>
&lt;h3 id="communication-is-key" >
&lt;div>
Communication is key
&lt;/div>
&lt;/h3>
&lt;p>First, clearly communicate your priorities and thought process. This doesn&amp;rsquo;t mean tell them what to do, but priorities&amp;hellip; Bob Iger states it as &amp;ldquo;You have to convey your priorities clearly and repeatedly. In my experience, it’s what separates great managers from the rest&amp;rdquo;. I couldn&amp;rsquo;t immediately find the reference, but recall reading that he started each week with his execs communicating his top 5 priorities across the company. This gives you a line of sight into the leadership&amp;rsquo;s thinking. This could be as simple as:&lt;/p>
&lt;ul>
&lt;li>I&amp;rsquo;m worried about our pipeline for next year&lt;/li>
&lt;li>I&amp;rsquo;m worried about retention and how it affects long term growth&lt;/li>
&lt;li>I&amp;rsquo;m worried that we have the tech stack to scale for next 3 years&lt;/li>
&lt;/ul>
&lt;p>Something similar to that last one came up in the conversation, which led us down a brief conversation of reversibles and irreversibles. In product management one of the most common mistakes I see of folks is not making a decision and heading in a single direction, rather they want all the info before they make a decision which can cause as much harm as good (but I&amp;rsquo;m getting off track).&lt;/p>
&lt;h3 id="reversible-vs-irreversible-decisions" >
&lt;div>
Reversible vs. Irreversible Decisions
&lt;/div>
&lt;/h3>
&lt;p>Communicating to new execs a framework around which decisions are critical to get right and which ones can be recovered from if wrong is huge. Not all decisions are critical to get right. If ship a typo in a blog post, you can easily fix it. If you send a wrong message to a single customer, it could create a bad experience for that customer but not impact all the rest. Knowing the scope and impact of a failure is important in a framework for decision making.&lt;/p>
&lt;p>We discussed that architecture and engineering decisions it&amp;rsquo;s harder to reverse than say marketing. But I&amp;rsquo;m not sure that holds true, if you have a huge PR nightmare from bad marketing it can take years to recover and heavily set back the business just like a bad architecture decision. Even within engineering decisions you can use a framework of how costly is this to commit to and how easy is it to reverse.&lt;/p>
&lt;p>One of the best engineers I&amp;rsquo;ve ever worked with, for going on 15 years now states it as not foreclosing future options. Leaving optionality open in engineering is one of those 10x things. It&amp;rsquo;s not elegant code or overengineering, it&amp;rsquo;s highly immeasurable (at least to me it is), but trying to grow this is huge to enable in your functional leadership as well as more senior individual contributors.&lt;/p>
&lt;p>Which decisions can later be changed and the cost of that is a great framework for how involved you should be vs. not, and the more you can guide your team through that the smoother growing the team will be.&lt;/p></description></item><item><title>Top 5 Product and Management skills: SQL, Excel, Clear Communication, Story, Prioritization</title><link>/2021/04/27/Top-5-Product-and-Management-skills-SQL-Excel-Clear-Communication-Story-Prioritization/</link><pubDate>Tue, 27 Apr 2021 13:30:56 -0800</pubDate><guid>/2021/04/27/Top-5-Product-and-Management-skills-SQL-Excel-Clear-Communication-Story-Prioritization/</guid><description>&lt;p>A few months ago there was a tweet from &lt;a href="https://www.twitter.com/jasoncwarner">@jasoncwarner&lt;/a> about leadership skills/super powers:&lt;/p>
&lt;ul>
&lt;li>SQL&lt;/li>
&lt;li>Excel&lt;/li>
&lt;li>Concise writing&lt;/li>
&lt;li>Story telling&lt;/li>
&lt;li>Prioritization.&lt;/li>
&lt;/ul>
&lt;p>I&amp;rsquo;ve spent quite a bit of time in product management roles, and in recent years more in leadership. I&amp;rsquo;ve found a lot of the skills in product to translate into good leadership skills as well, but maybe I&amp;rsquo;m bluring the lines there. Regardless, with his 5 skills I found myself nodding and have written about each of these some on my blog and then at times on twitter. He long since deleted the tweet, and while I wait for him to republish I thought I&amp;rsquo;d reprise a few of these with my own view point.&lt;/p>
&lt;h3 id="sql" >
&lt;div>
SQL
&lt;/div>
&lt;/h3>
&lt;p>Yeah, I&amp;rsquo;m a &amp;ldquo;database&amp;rdquo; person. But not really, I&amp;rsquo;m a product person. But if I want to answer a question about what our customers are doing 9 times out of 10 the answer to that question is hiding inside a &lt;a href="https://www.craigkerstiens.com/2019/02/12/sql-one-of-the-most-valuable-skills/">SQL database&lt;/a>. If it&amp;rsquo;s not in a SQL database they&amp;rsquo;ve made a SQL like interface to access that data. If you want to feel like you have some magical super power that probably none of your peers posses pick up SQL. How many people working in React know SQL? Know many people that write Go know SQL? Same question if you know Ruby.&lt;/p>
&lt;p>The insights into how many users created their freemium account 3 months ago, but then converted to paying within 30 days, vs converted to paying after 30 days for a cohort analysis of fast converters vs. slow converters I can probably write in SQL before you&amp;rsquo;ve parsed what I&amp;rsquo;m trying to get at and started to write in any other language. That type of insight is powerful.&lt;/p>
&lt;p>Now if you think of how many people on a product team, or a management team know SQL-you&amp;rsquo;re in a unique position. It really is a &lt;a href="https://www.craigkerstiens.com/2019/02/12/sql-one-of-the-most-valuable-skills/">super power&lt;/a>&lt;/p>
&lt;h3 id="excel" >
&lt;div>
Excel
&lt;/div>
&lt;/h3>
&lt;p>This one is more common with MBAs and business types, but nonetheless is still valuable. While I love SQL, a pivot table in SQL isn&amp;rsquo;t quite the same. There are absolutely people that can spin circles around me in Excel (looking at you &lt;a href="https://twitter.com/rstephensme">@rstephensme&lt;/a>). But Excel is way more broad reaching a programming language than literally everything else. It&amp;rsquo;s powerful and rich, and not all data is large and needs a database.&lt;/p>
&lt;p>Proficiency to quickly slice and dice things is huge. As you level up in your career you need to be able to take in a lot of information, ask questions of it, fact check it, and then make a decision on it. Excel is one big tool to help on this.&lt;/p>
&lt;h3 id="writing" >
&lt;div>
Writing
&lt;/div>
&lt;/h3>
&lt;p>My grammar is shit. I know it. But that&amp;rsquo;s mostly okay, I&amp;rsquo;ve explicitly focused on clear communication in my career. Concise and clear communication is huge. While the above are super key, if you can simply listen and ingest information that is not clear and then regurgitate it in a clear manner you can have a career in a lot of industries.&lt;/p>
&lt;p>A few disparate tips here:&lt;/p>
&lt;ul>
&lt;li>My favorite question to ask in any situation &amp;ldquo;What problem are we trying to solve here?&amp;rdquo; It&amp;rsquo;s greatly focusing and if you internalize it&amp;rsquo;ll steer you to better communication&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/mcgd">Michael Dearing&lt;/a> has a great talk on &lt;a href="https://www.heavybit.com/library/video/executive-communication/">executive communication&lt;/a> using SCQA given &lt;a href="https://www.heavybit.com">@heavybit&lt;/a>&lt;/li>
&lt;li>I run all important emails, blogs, etc. through &lt;a href="https://hemingwayapp.com/">hemingway app&lt;/a>, the lower the grade level the better&lt;/li>
&lt;/ul>
&lt;h3 id="story-telling" >
&lt;div>
Story telling
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m actually not quite sure where to start on this one. At some level we all want to be entertained. Hollywood isn&amp;rsquo;t the industry it is because they forced us into it. But story telling is a harder one, I&amp;rsquo;ve never coached/mentored anyone on it, I&amp;rsquo;m not even sure I&amp;rsquo;m expert at it. I definitely know a good story and the value of one. Watch a presentation that is monotone and reads off the slides, and it&amp;rsquo;s not that they&amp;rsquo;re just monotone it&amp;rsquo;s that the story isn&amp;rsquo;t there. I&amp;rsquo;ve found I personally love to follow some of the story board supervisors and animators for Pixar and Disney Animation that talk about story narrative. I&amp;rsquo;m not sure it&amp;rsquo;s made me better at this, but it&amp;rsquo;s entertaining.&lt;/p>
&lt;p>If you can be entertaining you can layer in the valuable pieces.&lt;/p>
&lt;p>But be yourself in the process.&lt;/p>
&lt;h3 id="prioritization" >
&lt;div>
Prioritization
&lt;/div>
&lt;/h3>
&lt;p>So many startups I&amp;rsquo;ve talked to have analysis paralysis. Many management folk in their first tenure have analysis paralysis. If there is literally one thing you can start doing around this, it is to &lt;a href="https://twitter.com/craigkerstiens/status/1381637698193031170">make a decision&lt;/a>, any decision. Measure and course correct later, but way too much time is wasted in deciding and that non-decision is a worse decision in and over itself.&lt;/p>
&lt;p>Now when it comes to prioritizing and making the right decision. I&amp;rsquo;ve used the same tool for over 10 years, other teams I&amp;rsquo;ve trained on it. I&amp;rsquo;ve run the exercise for teams that wanted coaching on it. Is it perfect no. The important part is find a process and stick with it and perfect it. Per friend &lt;a href="https://gist.github.com/neovintage/2fb54c5b0cc403714bb94c621bcdd7fd">Rimas product principles&lt;/a> &amp;ldquo;Be consistent - if you&amp;rsquo;re going to use a trick, use it a lot.&amp;rdquo; One of my tricks is gridding, which is an effort vs impact matrix. You can check out a &lt;a href="https://www.craigkerstiens.com/2013/03/13/planning-and-prioritizing/">part 1&lt;/a> and &lt;a href="https://www.craigkerstiens.com/2013/08/13/the-rule-of-thirds-followup/">part 2&lt;/a> write-up.&lt;/p>
&lt;p>The key here is when you step back with higher level granularity and put things side by side visually a lot of things sort themselves out. We conduct the exercise over a 1-2 hr period, often over an offsite. But have done a lot on zoom over the past year. Keep in mind an important part is make a decision on what you will and won&amp;rsquo;t do. The won&amp;rsquo;t part is as important as what you will.&lt;/p>
&lt;h2 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h2>
&lt;p>Could there be 10 things on the list? Sure. Is there something more important than these? I&amp;rsquo;m not really sure. If you want to round out your skill set for the next few years in product or management-hope this helps. If you think it&amp;rsquo;s crap &lt;a href="https://www.twitter.com/jasoncwarner">@jasoncwarner&lt;/a>, but if you really like it I&amp;rsquo;m happy to take credit &lt;a href="https://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>&lt;/p></description></item><item><title>Exploring a new Postgres database</title><link>/2020/11/14/Exploring-a-new-Postgres-database/</link><pubDate>Sat, 14 Nov 2020 11:30:56 -0800</pubDate><guid>/2020/11/14/Exploring-a-new-Postgres-database/</guid><description>&lt;p>At past jobs I&amp;rsquo;d estimate we had 100 different production apps that in some way were powering key production systems. Sure some were backend/internal apps while others key production apps such as the dashboard itself. At other companies we had a smaller handful of Heroku apps that powered our cloud service, about 5-10 in total. Even just working with those internal apps it&amp;rsquo;s a number of things to keep context on. But when it comes to interacting with something you don&amp;rsquo;t know getting a lay of the land quickly is key. In helping a customer optimize and tune, or even just understand what is going on in their app an understanding of the data model is key.&lt;/p>
&lt;p>As I just started a few months back at &lt;a href="https://www.crunchydata.com">Crunchy Data&lt;/a> I found myself digging into a lot of new systems and quickly trying to ramp up and get a feel for them.&lt;/p>
&lt;p>Over the past 10 years I&amp;rsquo;ve pretty well codified my steps to getting a feel for a new database. While I&amp;rsquo;m not a DBA and a small portion of my job is spent &lt;a href="/2013/01/10/more-on-postgres-performance/">inside a database&lt;/a> being able to quickly navigate one saves me hours each month and days out of the year. I&amp;rsquo;m sure my process isn&amp;rsquo;t perfect, but hopefully it helps other when navigating a new Postgres database for the first time.&lt;/p>
&lt;h3 id="first-the-tooling" >
&lt;div>
First the tooling
&lt;/div>
&lt;/h3>
&lt;p>For any new database my go to tool is psql. The built-in &lt;a href="/2013/02/21/more-out-of-psql/">Postgres CLI&lt;/a> is going to be the quickest thing for me to navigate around. If you use a CLI for anything else then this should be your preference here as well. I&amp;rsquo;m also going to have a &lt;code>psqlrc&lt;/code> file setup that has some good defaults. My go to defaults in my psqlrc are:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>-- Automatically format output based on result length and screen
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">\x&lt;/span> auto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-- Prettier nulls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">\p&lt;/span>set null &lt;span style="color:#e6db74">&amp;#39;#&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-- Save history based on database name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">\s&lt;/span>et HISTFILE ~/.psql_history- :DBNAME
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-- Turn on automatic query timing
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">\t&lt;/span>iming
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="getting-a-feel-for-the-tables" >
&lt;div>
Getting a feel for the tables
&lt;/div>
&lt;/h3>
&lt;p>The first thing I&amp;rsquo;m going to do is just table a look at which objects exist within the database with &lt;code>\d&lt;/code>. This will spit out a mix of tables, views, sequences all within your database. A cleaner version of this may be &lt;code>\dt&lt;/code> which is only tables:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List &lt;span style="color:#66d9ef">of&lt;/span> relations
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">Schema&lt;/span> &lt;span style="color:#f92672">|&lt;/span> Name &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Type&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Owner&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">--------+-------------------------------+----------+----------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> pg_stat_statements &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">view&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> schema_migrations &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> sessions &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> sessions_id_seq &lt;span style="color:#f92672">|&lt;/span> sequence &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> tasks &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> teams &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> users &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#ae81ff">7&lt;/span> &lt;span style="color:#66d9ef">rows&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>dt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List &lt;span style="color:#66d9ef">of&lt;/span> relations
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">Schema&lt;/span> &lt;span style="color:#f92672">|&lt;/span> Name &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Type&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Owner&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">--------+-------------------------------+----------+----------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> schema_migrations &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> sessions &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> tasks &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> teams &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#f92672">|&lt;/span> users &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">table&lt;/span> &lt;span style="color:#f92672">|&lt;/span> postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#ae81ff">5&lt;/span> &lt;span style="color:#66d9ef">rows&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can also use the describe operation (&lt;code>\d&lt;/code>) on specific relations as well such as tables to get a feel for how they look:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>d users
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">Table&lt;/span> &lt;span style="color:#e6db74">&amp;#34;public.users&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">Column&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Type&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Collation&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Nullable&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">Default&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">---------------------------+--------------------------+-----------+----------+--------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> id &lt;span style="color:#f92672">|&lt;/span> uuid &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span> uuid_generate_v4()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> email &lt;span style="color:#f92672">|&lt;/span> text &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>::text
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> encrypted_password &lt;span style="color:#f92672">|&lt;/span> text &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>::text
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reset_password_token &lt;span style="color:#f92672">|&lt;/span> text &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reset_password_sent_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> time &lt;span style="color:#66d9ef">zone&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> remember_created_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> time &lt;span style="color:#66d9ef">zone&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> last_sign_in_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> time &lt;span style="color:#66d9ef">zone&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> created_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> time &lt;span style="color:#66d9ef">zone&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> updated_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> time &lt;span style="color:#66d9ef">zone&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#f92672">|&lt;/span> text &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> team_id &lt;span style="color:#f92672">|&lt;/span> uuid &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">not&lt;/span> &lt;span style="color:#66d9ef">null&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> deleted_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> time &lt;span style="color:#66d9ef">zone&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Indexes:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;users_pkey&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">PRIMARY&lt;/span> &lt;span style="color:#66d9ef">KEY&lt;/span>, btree (id)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;index_users_on_email&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">UNIQUE&lt;/span>, btree (email)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;index_users_on_reset_password_token&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">UNIQUE&lt;/span>, btree (reset_password_token)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">Foreign&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#66d9ef">key&lt;/span> &lt;span style="color:#66d9ef">constraints&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;users_team_id_fkey&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">FOREIGN&lt;/span> &lt;span style="color:#66d9ef">KEY&lt;/span> (team_id) &lt;span style="color:#66d9ef">REFERENCES&lt;/span> teams(id)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="human-readable-output" >
&lt;div>
Human readable output
&lt;/div>
&lt;/h3>
&lt;p>Of course you may want to go one step further and actually get a sense for the data. Here a basic &lt;code>SELECT&lt;/code> tends to work with a limit 1. As you don&amp;rsquo;t quite know the shape of the data this is where having &lt;code>\x auto&lt;/code> setup within your &lt;code>.psqlrc&lt;/code> file is helpful to autoformat the output to your screen. You can also just manually run &lt;code>\x auto&lt;/code> in your SQL session to get cleaner output.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> &lt;span style="color:#f92672">*&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> users
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">LIMIT&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">-&lt;/span>[ RECORD &lt;span style="color:#ae81ff">1&lt;/span> ]&lt;span style="color:#75715e">-------------+--------------------------------------------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>id &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>a7a3cde&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">3613&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">4073&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">86&lt;/span>a7&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">6&lt;/span>a19b4e62bbe
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>email &lt;span style="color:#f92672">|&lt;/span> craig.kerstiens&lt;span style="color:#f92672">@&lt;/span>gmail.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>encrypted_password &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">$&lt;/span>&lt;span style="color:#f92672">#&lt;/span>IJ937Gmsdf00297sEmdfu12234
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reset_password_token &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reset_password_sent_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>remember_created_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#ae81ff">2016&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">07&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">14&lt;/span> &lt;span style="color:#ae81ff">14&lt;/span>:&lt;span style="color:#ae81ff">31&lt;/span>:&lt;span style="color:#ae81ff">01&lt;/span>.&lt;span style="color:#ae81ff">414795&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>last_sign_in_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#ae81ff">2020&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">02&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">12&lt;/span> &lt;span style="color:#ae81ff">21&lt;/span>:&lt;span style="color:#ae81ff">32&lt;/span>:&lt;span style="color:#ae81ff">53&lt;/span>.&lt;span style="color:#ae81ff">629246&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>created_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#ae81ff">2016&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">02&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">18&lt;/span> &lt;span style="color:#ae81ff">03&lt;/span>:&lt;span style="color:#ae81ff">03&lt;/span>:&lt;span style="color:#ae81ff">26&lt;/span>.&lt;span style="color:#ae81ff">403108&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>updated_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#ae81ff">2020&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">02&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">14&lt;/span> &lt;span style="color:#ae81ff">23&lt;/span>:&lt;span style="color:#ae81ff">16&lt;/span>:&lt;span style="color:#ae81ff">16&lt;/span>.&lt;span style="color:#ae81ff">080729&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>name &lt;span style="color:#f92672">|&lt;/span> Craig
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>team_id &lt;span style="color:#f92672">|&lt;/span> d46e864&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1886&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">45&lt;/span>e6&lt;span style="color:#f92672">-&lt;/span>b538&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">8991562&lt;/span>d2e99
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deleted_at &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#f92672">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Time: &lt;span style="color:#ae81ff">91&lt;/span>.&lt;span style="color:#ae81ff">592&lt;/span> ms
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Most databases I work with now leverage JSONB. It&amp;rsquo;s a great tool for mixing semi-structured data with more structured data.&lt;/p>
&lt;p>If you&amp;rsquo;re using &lt;a href="https://info.crunchydata.com/blog/using-postgresql-for-json-storage">JSON&lt;/a> or &lt;a href="https://info.crunchydata.com/blog/using-postgresql-for-json-storage">JSONB&lt;/a> then there is also a handy utility function to clean up that output - &lt;code>jsonb_pretty(yourcolumnhere)&lt;/code>. This will take care of making that huge JSON blob nice and readable.&lt;/p>
&lt;h3 id="feel-more-at-home-when-you-encounter-a-new-database" >
&lt;div>
Feel more at home when you encounter a new database
&lt;/div>
&lt;/h3>
&lt;p>It doesn&amp;rsquo;t take hours of reading an ERD or schema files. In about 5-10 minutes of connecting to a new database I&amp;rsquo;m able to get a sense of how things are structured and able to actually start digging in. Don&amp;rsquo;t get me wrong, I&amp;rsquo;m by no means and expert in that time, but knowing some of these basic commands will really help the next time you encounter a database and are asked to help out or glean insights from it.&lt;/p></description></item><item><title>Spokesperson certification</title><link>/2020/04/21/Spokesperson-certification/</link><pubDate>Tue, 21 Apr 2020 12:55:56 -0800</pubDate><guid>/2020/04/21/Spokesperson-certification/</guid><description>&lt;p>One of my most fascinating work experiences was going through the spokesperson certification process at a large tech co. This isn&amp;rsquo;t some rubber stamp virtual training to not use profanity on stage type training. This is the training they would give to any executive before you were greenlit to talk to press. When I say press I mean Techcrunch, but also Bloomberg, or Jim Cramer, or any major big brand news outlet.&lt;/p>
&lt;p>As a product manager over a specific product line I knew my product well. Put me in front of an unhappy customer and I could lay out our roadmap, listen to their questions, take product input, and get them to a happy place. But this wasn&amp;rsquo;t about my product (only). A person with the spokesperson stamp could be asked any question about an entirely other area fo the company. You had to know every recent product launch, all the key metrics, know where traps may lie, and you had to land the core company messages in addition to the ones you cared about. To study you received about 100 pages of a powerpoint presentation that had key releases from each product, key numbers, customer stories.&lt;/p>
&lt;p>The certification itself was an interview. They flew in a former news reporter. You walked into a conference, the lights were off, except for a bright light focused on the seat you&amp;rsquo;d sit in with a camera rolling. It felt more like an intense interogation room than a big co tech conference room. To ensure light didn&amp;rsquo;t get in and no one stopped walking by the room they put up black paper to completely black out the room.&lt;/p>
&lt;p>Oh, and the worst part of the process&amp;hellip; I was told my our marketing person I could wear my hat&amp;hellip; as I always do during the interview. (I was probably the only person not in a full suit they saw the entire day. And probably the only person that walked in with a ballcap on ever.) Well she said yes of course, turns out they couldn&amp;rsquo;t see my face under the lights, it was just a shadow so I had to take it off. From the outset I&amp;rsquo;d been tricked, but I digress.&lt;/p>
&lt;p>The questions would start with a basic, tell me about yourself and your background. Can you tell whats new and exciting about product x. Then over time it would delve into the other product areas. I told some of the canned stories and some personal ones. &lt;em>I learned on the personal ones, it&amp;rsquo;s up to me but they coach their executives to not said spouses or childrens names, it can only get them in trouble.&lt;/em> For each product line you were supposed to hit major 2 news and announcements, 2 customers, and 2 key stats (&lt;em>i.e. we crossed 1 billion mentions of my name&lt;/em>).&lt;/p>
&lt;p>But it wasn&amp;rsquo;t just softballs. There were traps. You were asked about an executive that recently left, and if the product line was okay or was it a sign of bad things to come during earnings. It&amp;rsquo;s fine though I reassured them they&amp;rsquo;ve made some great contributions to the company, and wanted to spend some time with their family and giving back to their local community. Of course internal speculation was they were cashed out and interested in running for public office.&lt;/p>
&lt;p>As the camera turned off a few of the stories I&amp;rsquo;d told about customers and products the PR team wanted to dig deeper on. Remarking &amp;ldquo;That&amp;rsquo;s amazing, we power that I had no idea.&amp;rdquo; and &amp;ldquo;That&amp;rsquo;s awesome they&amp;rsquo;re able to do that at scale thanks to us.&amp;rdquo;&lt;/p>
&lt;p>In the end I got a stamp of approval, I was cleared to talk to folks. The funny part was the comments from the PR team afterwards. They liked me, I seemed relatable, I nailed all the numbers. I wasn&amp;rsquo;t like any of their other spokespeople and they well weren&amp;rsquo;t quite sure what to do with that. I was used for some very particular media folks in the future that seemed to not want a cookie cutter. I&amp;rsquo;m good with this, hopefully it helped the company.&lt;/p>
&lt;p>In the end it was fascinating experience. The ability to bridge, condense a lot of information (relatable story, customer brand validation, stats, and something quotable) into a single answer all from a question that was meant to be a trap for a juicy story has been easily one of the top work experiences I&amp;rsquo;ve encountered.&lt;/p></description></item><item><title>Lessons from college: Efficient meetings</title><link>/2020/03/17/lessons-from-college-effecient-meetings/</link><pubDate>Tue, 17 Mar 2020 12:55:56 -0800</pubDate><guid>/2020/03/17/lessons-from-college-effecient-meetings/</guid><description>&lt;p>I think back to my time in college, and I learned some valuable things. I also learned some incredibly worthless things (i.e. don&amp;rsquo;t flip a car upside down and then backover&amp;hellip; it&amp;rsquo;ll break the axle so you can&amp;rsquo;t roll it). Even in classes&amp;hellip; the basic approach to a supply/demand curve to maximize profit is cute when done in a classroom vs. the complexities of how things actually work&amp;hellip; I mean I get the idea behind it, but what you learn is so far being able to be translated into being usable. But what surprises me looking back was a couple of skills around running meetings that I find so rare in the workplace that have immense value.&lt;/p>
&lt;p>I&amp;rsquo;ve always been fascinated at the intersection of business and technology. I&amp;rsquo;d been coding for a long time before college, and while interesting it was also a means to an end. When you combine technology with business you can solve things in entirely new and valuable ways. My major was management information systems, and all folks in my program came out with a computer science minor in addition to their business degree–something pretty rare for more MIS majors in other programs and well generally for anyone coming out of a business school. Perhaps I&amp;rsquo;ll get into the value of CS training even if you aren&amp;rsquo;t looking for a CS job some other time.&lt;/p>
&lt;p>Within the program we would have a senior project that was actually a real world project for one of the large companies that sponsored part of the program. We&amp;rsquo;d have monthly reviews with the company stake holder. We&amp;rsquo;d also have weekly meetings, these were especially well run. There were really 3 items that made them especially efficient.&lt;/p>
&lt;h3 id="1-agendas-circulated-out-24-hours-ahead-of-time" >
&lt;div>
1. Agendas circulated out 24 hours ahead of time
&lt;/div>
&lt;/h3>
&lt;p>Before each meeting there was a very explicit agenda. This was circulated out 24 hrs in advance, at almost exactly the 24 hr mark the professors would inquire into the delay in the agenda. This early circulation allowed for:&lt;/p>
&lt;ol>
&lt;li>Time to review and prepare&lt;/li>
&lt;li>Ability to make modifications&lt;/li>
&lt;/ol>
&lt;p>A sample agenda may look something like:&lt;/p>
&lt;ul>
&lt;li>(5 minutes) - review last weeks action items&lt;/li>
&lt;li>(10 minutes) - review blockers
&lt;ul>
&lt;li>blocker 1 - foo&lt;/li>
&lt;li>blocker 2 - bar&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>(20 minutes) - feature design walk through of x&lt;/li>
&lt;li>(15 minutes) - toubleshooting of&lt;/li>
&lt;li>(10 minutes) - review action items and next steps&lt;/li>
&lt;/ul>
&lt;h3 id="2-explicit-roles-for-the-meeting" >
&lt;div>
2. Explicit roles for the meeting
&lt;/div>
&lt;/h3>
&lt;p>There were three roles explicitly set for each meeting:&lt;/p>
&lt;ul>
&lt;li>&lt;em>Manager&lt;/em> - This was essentially person responsible for setting up the agenda, ensuring the agenda was followed, and making sure everyone was involved and an active participant. I find that last piece is very key still today. Making sure folks that are remote have a chance to chime in, or ensuring very junior people are heard. Now days I often keep a small tally of how often various people within a meeting speak and make sure to give those that don&amp;rsquo;t a chance to.&lt;/li>
&lt;li>&lt;em>Timekeeper&lt;/em> - 75% of the meetings I&amp;rsquo;m in run long, and in the end there is a big scramble to figure out what the result of the meeting was and whats next. A timekeeper making sure that you spend the allocated amount of time is key. If you don&amp;rsquo;t do this that 10 mintues for reviewing action items and next steps gets squeezed and you lost a lot of the value of the meeting.&lt;/li>
&lt;li>&lt;em>Scribe&lt;/em> - A person whose sole job is to take notes ensured there were good quality notes. These would be kept within a sharepoint that was circulated around.&lt;/li>
&lt;/ul>
&lt;h3 id="3-after-the-meeting" >
&lt;div>
3. After the meeting
&lt;/div>
&lt;/h3>
&lt;p>While the scribe was the one to take the notes, the meeting wasn&amp;rsquo;t done when the meeting was over. The notes were then circulated around. Everyone on the team would review and make comments/notes on things they felt were different or missed details. At the end in the review action items there would be very clear owners assigned and next steps laid out.&lt;/p>
&lt;p>Within 24 hrs after the meeting while it was fresh everyone was required to review and acknowledge. This ensured there was a closed bookend and then this would be a clear transition for each of the roles to move on to the next meeting.&lt;/p>
&lt;h2 id="im-sorry-professors-you-were-right" >
&lt;div>
I&amp;rsquo;m sorry professors, you were right
&lt;/div>
&lt;/h2>
&lt;p>At the time, it was annoying. I could take my own notes. I remembered the things I needed to do. If we went over on time for one item it was because it was important. But now&amp;hellip; putting these things in place, any time I replicate this I get more time in my day and the team gets more done. Science/Math/History&amp;hellip; sure, but running efficient meetings I never would have expected how basic but also challenging and how valuable.&lt;/p></description></item><item><title>An interview on what makes Postgres unique (extensions)</title><link>/2019/11/13/postgres-interview-from-art-of-postgresql/</link><pubDate>Wed, 13 Nov 2019 12:55:56 -0800</pubDate><guid>/2019/11/13/postgres-interview-from-art-of-postgresql/</guid><description>&lt;p>I&amp;rsquo;ve been at dinners before with developers that admitted developers, themselves included, can be a bit opinionated. In one case one said for example, &amp;ldquo;I love Postgres, but I have no idea why.&amp;rdquo; They were sitting at the wrong table to use Postgres as an example&amp;hellip; But it is quite often that I am asked &lt;a href="/2017/04/30/why-postgres-five-years-later/">Why Postgres&lt;/a>.&lt;/p>
&lt;p>In fact a little over a year ago good friend Dimitri Fontaine asked if he could interview me for a book he&amp;rsquo;s working on &lt;a href="https://theartofpostgresql.com/?affiliate=cek">for Postgres&lt;/a>. I&amp;rsquo;ve long said their is a shortage of good books about Postgres and he&amp;rsquo;s done a great job with his in providing a guide targetted at developers, not just DBAs, that want to become better with their database. What follows is the excerpt of the interview from the book. And if you&amp;rsquo;re interested in picking up a copy he was friendly enough to share a discount code you can find below.&lt;/p>
&lt;p>&lt;strong>Intro&lt;/strong>&lt;/p>
&lt;p>Craig heads up the Cloud team &lt;a href="https://www.twitter.com/citusdata">@citusdata&lt;/a> &lt;strong>now running product for Azure Postgres since being acquired by Microsoft&lt;/strong>. Citus extends Postgres to be a horizontally scalable distributed database. If you have a database, especially Postgres, that needs to scale beyond a single node (typically at 100GB and up) Craig is always happy to chat and see if Citus can help.&lt;/p>
&lt;p>Previously Craig has spent a number of years @heroku, a platform-as-a-service, which takes much of the overhead out of IT and lets developers focus on building features and adding value. The bulk of Craig&amp;rsquo;s time at Heroku was spent running product and marketing for Heroku Data.&lt;/p>
&lt;p>&lt;strong>In your opinion, how important are extensions for the PostgreSQL open source project and ecosystem?&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>To me the extension APIs and growing ecosystem of extensions are the
biggest advancement to Postgres in probably the last 10 years. Extensions
have allowed Postgres to extend beyond a traditional relational database
to much more of a data platform. Whether it&amp;rsquo;s the initial NoSQL datatypes
(if we exclude XML that is) in hstore, to the rich feature set in
geospatial with GIS, or approximation algorithms such as HyperLogLog or
TopN you have extensions that now by themselves take Postgres into a new
frontier.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>Extensions allow the core to move at a slower pace, which makes sense.
Each new feature in core means it has to be thoroughly tested and safe.
That&amp;rsquo;s not to say that extensions don&amp;rsquo;t, but extensions that can exist
outside core, then become part of the contrib provide a great on ramp for
things to move much faster.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>What are your favorite PostgreSQL extensions, and why?&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>My favorite three extensions are:&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;ol>
&lt;li>&lt;em>pg_stat_statements&lt;/em>&lt;/li>
&lt;li>&lt;em>Citus&lt;/em>&lt;/li>
&lt;li>&lt;em>HyperLogLog&lt;/em>&lt;/li>
&lt;/ol>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>&lt;code>pg_stat_statements&lt;/code> is easily the most powerful extension for an
application developer without having to understand deep database internals
to get insights to optimize their database. For many application
developers the database is a black box, but &lt;code>pg_stat_statements&lt;/code> is a
great foundation for AI for your database that I only expect to be
improved upon in time.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>&lt;em>Citus&lt;/em>: I&amp;rsquo;m of course biased because I work there, but I followed Citus
and pg_shard for 3 years prior to joining. Citus turns Postgres into a
horizontally scalable database. Under the covers it&amp;rsquo;s sharded, but
application developers don&amp;rsquo;t have to think or know about that complexity.
With Citus Postgres is equipped to tackle larger workloads than ever
before as previously Postgres was constrained to a single box or overly
complicated architectures.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>&lt;em>HyperLogLog&lt;/em>: I have a confession to make. In part I just love saying
it, but it also makes you seem uber-intelligent when you read about the
algorithm itself. &amp;ldquo;K minimum value, bit observable patterns, stochastic
averaging, harmonic averaging.&amp;rdquo; I mean who doesn&amp;rsquo;t want to use something
with all those things in it? In simpler terms, it&amp;rsquo;s close enough
approximate uniques that are compose-able with a really small footprint on
storage. If you&amp;rsquo;re building something like a web analytics tool
HyperLogLog is an obvious go to.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>How do you typically find any extension you might need? Well, how do you
know you might need a PostgreSQL extension in the first place?&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&lt;a href="https://pgxn.org">pgxn.org&lt;/a> and github are my two go-tos. Though Google
also tends to work pretty well. And of course I stay up to date on new
ones via &lt;a href="https://postgresweekly.com">PostgresWeekly.com&lt;/a>.&lt;/em>&lt;/p>
&lt;p>&lt;em>Though in reality I often don&amp;rsquo;t always realize I need one. I search for
the problem I&amp;rsquo;m trying to solve and discover it. I would likely never
search for HyperLogLog, but a search for Postgres approximate count or
approximate distincts would yield it pretty quickly.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Is there any downside you could think of when your application code base
now relies on some PostgreSQL extension to run? I could think of extension&amp;rsquo;s
availability in cloud and SaaS offerings, for instance.&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>It really depends. There are extensions that are much more bleeding edge,
and ones that are more mature. Many of the major cloud providers support a
range of extensions, but they won&amp;rsquo;t support any extension. If they do
support it there isn&amp;rsquo;t a big downside to leveraging it. If they don&amp;rsquo;t you
need to weigh the cost of running and managing Postgres yourself vs. how
much value that particular extension would provide. As with all things
managed vs. not, there is a trade-off there and you need to decide which
one is right for you.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>Though if something is supported and easy to leverage wherever you run,
by all means, go for it.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Interesting Upcoming pgDays</title><link>/2019/10/29/Interesting-Upcoming-pgDays/</link><pubDate>Tue, 29 Oct 2019 12:55:56 -0800</pubDate><guid>/2019/10/29/Interesting-Upcoming-pgDays/</guid><description>&lt;p>I&amp;rsquo;ve been to a lot of conferences over the years. &lt;a href="https://2019.pgconf.eu/">PgConf EU&lt;/a>, &lt;a href="https://postgresopen.org">PostgresOpen&lt;/a>, too many pgDays to count, and even more none Postgres conferences (OSCON, Strangeloop, Railsconf, PyCon, LessConf, and many more). I&amp;rsquo;ve always found Postgres conferences one of the best places to get training and learn about what&amp;rsquo;s new with Postgres (in addition to Dimitri&amp;rsquo;s recent book, more on that below). They&amp;rsquo;re my regular stop to catch up on all the new features of a release before it comes out, and often there is a talk highlighting what is new with a simple easy to understand summary once released.&lt;/p>
&lt;p>I just got back from PGConf EU a little over a week ago and it was a great time. I&amp;rsquo;m sure we&amp;rsquo;ll see some rundowns of it start appearing on Postgres planet. But, as far as I&amp;rsquo;m concerned PGConf EU is in the past (unless your counting next year which is in Berlin-in which case I&amp;rsquo;ll see you there). For me it&amp;rsquo;s time to look to the future and there are a number of upcoming pgDays I&amp;rsquo;m looking forward to.&lt;/p>
&lt;p>The first two I want to highlight are separate events, but you&amp;rsquo;ll notice they&amp;rsquo;re scheduled nicely for you to easily attend both. With a day in between for travel you&amp;rsquo;ll find that many speakers and attendees depart one and head straight to the other. It makes for an easy opportunity to visit two cities, see two different communities, and yet not have to spend too much time traveling. The first is &lt;a href="https://2020.nordicpgday.org/">Nordic pgDay&lt;/a> in Helsinki. It&amp;rsquo;s coming up on March 24. The second is &lt;a href="https://2020.pgday.paris/">pgDay Paris&lt;/a> on March 26. Both of these are great single track conferences. If you&amp;rsquo;re in Europe of fancy a trip to Europe I recommend giving them a look, and even better the CFPs are open so consider submitting.&lt;/p>
&lt;p>Another pgDay I have to mention is right in my backyard. &lt;a href="https://2020.pgdaysf.org">pgDay SF&lt;/a> I&amp;rsquo;m particularly excited for a few reasons:&lt;/p>
&lt;ul>
&lt;li>San Francisco is very much a central tech hub, which means a great chance of learning from folks at many many interesting tech companies in attendance&lt;/li>
&lt;li>Just like Nordic and Paris this is a single track conference, which I&amp;rsquo;m a personal fan of because you can have continuity between talks and shared conversation with other attendees&lt;/li>
&lt;li>The venue! If you&amp;rsquo;re not from the bay area you may not be aware, but Swedish American Hall is well known music venue within SF. It&amp;rsquo;s had many famous artists &lt;a href="https://en.wikipedia.org/wiki/Cafe_Du_Nord">over the years&lt;/a> and now pgDay SF joins the ranks.&lt;/li>
&lt;/ul>
&lt;p>This isn&amp;rsquo;t an exhaustive list of course, just a few on my personal list that I hope to make it to. If you&amp;rsquo;re there and see me make sure to say hi!&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Guidance for conducting offsites</title><link>/2019/10/10/Guidance-for-conducting-offsites/</link><pubDate>Thu, 10 Oct 2019 12:55:56 -0800</pubDate><guid>/2019/10/10/Guidance-for-conducting-offsites/</guid><description>&lt;p>Offsites an invaluable tool in getting a team aligned. I&amp;rsquo;ve been a part of organizations where offsites never happened, and then when they happened at a regular interval. Just because offsites happened it didn&amp;rsquo;t mean they had the same significant impact to alignment and ability to execute moving forward. What follows is a few key principles around conducting an impactful offsite.&lt;/p>
&lt;h3 id="get-out-of-the-office" >
&lt;div>
Get out of the office
&lt;/div>
&lt;/h3>
&lt;p>An offsite isn&amp;rsquo;t reserving a conference room for a full day and just sitting there meeting on special topics. A change of scenery is important, and nice scenery will impact your abiltiy to collaborate. &lt;em>One long time friend and colleague communicated to me about 10 years into his working career, that the thing he most values in a workplace is natural light. He remarked younger him wanted free food and drinks, now he finds him much happier and more productive with natural light above all other amenities.&lt;/em> A similar environment for an offsite is very helpful.&lt;/p>
&lt;p>The best option isn&amp;rsquo;t a hotel with a rented conference room, but rather an AirBnB with each person their own room, a large kitchen, and large living room. More on the why for each of those later.&lt;/p>
&lt;p>From working with some teams that are often local and a portion of them remote, hosting the offsite within a 2 hr drive of your primary office can be good. You don&amp;rsquo;t waste the full day traveling, for remote team members they can also budget 1-2 days in the office to see other team members in addition to the time spent at the offsite.&lt;/p>
&lt;h3 id="collaboration-is-key" >
&lt;div>
Collaboration is key
&lt;/div>
&lt;/h3>
&lt;p>Get rid of powerpoint presentations and someone presenting on a screen. That isn&amp;rsquo;t collaboration, that is a presentation. If you have a team of 8 and each person presents for an hour you haven&amp;rsquo;t collaborated for 8 hrs, you&amp;rsquo;ve been presented to for 7 and presented for 1. I personally don&amp;rsquo;t like team building exercises, but I&amp;rsquo;ll admit they can be useful here.&lt;/p>
&lt;p>A presentation by the leadership at the offsite for a few minutes to frame things can be helpful. It&amp;rsquo;s key to not have a projector and folks staring at a screen. Instead having a few prepared notes and ability interactively discuss is great. Collaborating on a large notepad, or using sticky notes for ideas and brainstorming is great. One of my favorite things to do at an offsite is a &lt;a href="/2013/08/13/rule-of-thirds/">gridding exercise&lt;/a>.&lt;/p>
&lt;h3 id="2-3-days-is-ideal" >
&lt;div>
2-3 days is ideal
&lt;/div>
&lt;/h3>
&lt;p>You don&amp;rsquo;t need a full week offsite, but a 1 day offsite doesn&amp;rsquo;t really provide ideas to evolve and change over time. The ideal to me is 3 days where you can make some statements about ideas on day 1, and then drill deeper into those on day 2 or 3. Having the ability to do research on data and evaluate any plans you make is helpful. You also then can have good collaborative time, but also set aside time for contentious topics. If you cover a contentious topic and then jump right into collaboration without time to change your mindset you&amp;rsquo;re going to get a very different outcome. Breaking things up across days makes this way easier.&lt;/p>
&lt;p>2-3 days also allows time for non work activities. Coming together as a team will let you work better in the future. Boardgames are a common favorite, video games are an occasional activity. Sometimes sitting by a fireplace and enjoying a nice glass of wine and just catching up.&lt;/p>
&lt;p>&lt;em>Those moments can live on for a very long time. Many colleagues from years ago will recall how when playing &amp;ldquo;We didn&amp;rsquo;t play test this at all&amp;rdquo;, we brought back online an archived server intentionally to cause a page so an engineer would pick up his phone, only for one of us to play a card causing him to lose the game due to holding his phone. Those stories create a foundation and shared experience to build on in the future for how you work together&lt;/em>&lt;/p>
&lt;p>This takes me onto the next point&amp;hellip;&lt;/p>
&lt;h3 id="food" >
&lt;div>
Food
&lt;/div>
&lt;/h3>
&lt;p>Too often offsites are a day of meetings in a conference room, followed by dinner out at a nice restaurant. The exact opposite works better. We&amp;rsquo;ve already talked about location. But food should be collaborative as well. Over 2-3 days you may do one dinner out, but even that isn&amp;rsquo;t the norm. Instead make a meal list ahead of time, and people spend time in the kitchen together. You&amp;rsquo;ll typically find you have 1-2 more cooks in the team than others, but then you have a lot of helpers.&lt;/p>
&lt;p>&lt;em>It actually reminds me a bit of my wedding reception back home. I smoked about 80 lbs of meat for the reception. As we were taking the meat off, I walked back in to 4 generations of in-laws, the older ones teaching the younger ones how to pull pork.&lt;/em>&lt;/p>
&lt;p>Cooking together is another form of collaborating. You can easily learn about cultures and backgrounds. I didn&amp;rsquo;t realize melon with proscuitto was always supposed to be server with port if you&amp;rsquo;re in France, but now I can eat it no other way. Splitting up the duties so that 2-3 help cook a meal means you don&amp;rsquo;t spend all your time cooking, but you get people working together.&lt;/p>
&lt;h3 id="dont-steal-a-weekend" >
&lt;div>
Don&amp;rsquo;t steal a weekend
&lt;/div>
&lt;/h3>
&lt;p>I mentioned 2-3 days is ideal. Please don&amp;rsquo;t use one of those days as a weekend. As the leader or coordinator of such you may not have weekend obligations and happy to give up a day of it. But many on your team may have other commitements and such, an offsite is valuable, but asking people to give up their weekend to essentially do more work isn&amp;rsquo;t a great look.&lt;/p>
&lt;h3 id="offsites-for-everyone" >
&lt;div>
Offsites for everyone
&lt;/div>
&lt;/h3>
&lt;p>Offsites aren&amp;rsquo;t just for management. The folks in boots on the ground doing the work has as much need and value as the leadership team sitting there determining the next 5 year strategy. Allowing engineers that are building things, supporting customers, answering pages to brainstorm and collaborate on how to more effectively design the systems and move more quickly will pay huge dividends. You&amp;rsquo;ll find experiments, and then new tools and systems that allow you to ship things faster with higher quality. Collaborating with the product team is key as well, an engineering offsite in isolation leaves out the voice of the customer. A product offsite without engineering leaves you daydreaming of solutions without being grounded in the reality of what is possible.&lt;/p></description></item><item><title>The Engineering Manager/Product Manager Marriage</title><link>/2019/06/30/The-Engineering-Manager/Product-Manager-Marriage/</link><pubDate>Sun, 30 Jun 2019 12:55:56 -0800</pubDate><guid>/2019/06/30/The-Engineering-Manager/Product-Manager-Marriage/</guid><description>&lt;p>I&amp;rsquo;ve worked as a PM at a number of size companies for a few years now. At a startup and then as a part of a larger company once startups were acquired. I&amp;rsquo;ve been the first PM for a team as well as first for a company. I&amp;rsquo;ve written at times about product management, and today I&amp;rsquo;d like to drill into one aspect that doesn&amp;rsquo;t seem to get talked about enough and that is the pairing of product manager and engineering manager.&lt;/p>
&lt;h2 id="mom-vs-dad" >
&lt;div>
Mom vs. Dad
&lt;/div>
&lt;/h2>
&lt;p>As parents my partner and I have learned very quickly that we need to have a consistent voice and unified view of things. I care that our son watches less power rangers otherwise he&amp;rsquo;s going to use his megazord powers on our TV and we&amp;rsquo;ll be watching a lot more of nothing. My partner cares that when we&amp;rsquo;re visiting family in the south they drink enough water so they don&amp;rsquo;t get dehydrated.&lt;/p>
&lt;p>Meanwhile my kids are experts at leveraging us to get what they want. My daughter came to me last night asking if she could play on her iPad some. Not knowing if she had or if she&amp;rsquo;d already given an answer my safest question was have you asked your mom? In the absense of knowing my default isn&amp;rsquo;t a yes or no, it&amp;rsquo;s a &amp;ldquo;let me learn more.&amp;rdquo; and then potentially discuss it.&lt;/p>
&lt;h2 id="em-vs-pm" >
&lt;div>
EM vs. PM
&lt;/div>
&lt;/h2>
&lt;p>As a PM I want us to build a rich and powerful product, but there is a strong balance to doing too little vs. too much. It isn&amp;rsquo;t always a question of doing more, we need to make sure the product is well built. In order to do that we need to say no at times. Saying no, as well as yes, needs to come from a unified front, both engineering and product. If one side is agreeing without being aligned with the other half you&amp;rsquo;re going to wind up with a confused and frustrated team.&lt;/p>
&lt;p>There are a number of ways engineering managers and product managers can stay aligned. The first starts with being explicit with each other, so if you&amp;rsquo;re struggling with one side communicating things the other don&amp;rsquo;t agree with&amp;hellip; sit down and have a conversation about it. From an ongoing perspective you can get to a better aligned position to not have to discuss every question before you give an answer. My partner knows to make sure we don&amp;rsquo;t watch more than 2 episodes of power rangers and when we&amp;rsquo;re too amped up on it we shorten that.&lt;/p>
&lt;ul>
&lt;li>Are you having regularly 1:1s with your counterpart?&lt;/li>
&lt;li>Do you review emails out to the team ahead of time to capture feedback?&lt;/li>
&lt;li>Do you have conversations where you&amp;rsquo;re not on the same page in an offline fashion as opposed to in team meetings?&lt;/li>
&lt;li>Are you treating your EM/PM just like your partner at home? &lt;em>(I guess that does assume you treat your partner well, but that&amp;rsquo;s a whole other blog post)&lt;/em>&lt;/li>
&lt;/ul></description></item><item><title>Come over for dinner</title><link>/2019/05/01/Come-over-for-dinner/</link><pubDate>Wed, 01 May 2019 12:55:56 -0800</pubDate><guid>/2019/05/01/Come-over-for-dinner/</guid><description>&lt;p>When I first moved to the Bay area I was fresh out of grad school. I was frequently heading out to dinner or to happy hour after work with colleagues. I was young and single, so why not of course. As time passed, marriage, kids, etc. the ability to go out for a quick drink or dinner was competing with various priorities. Dinner and drinks with co-workers was always a great time. It wasn&amp;rsquo;t just about hanging out, it built rapport and trust which I found made me a more effective teammate and product manager. It was about 8 years ago that I started to implement a variation of heading out for dinner and drinks.&lt;/p>
&lt;p>I started inviting people over for dinner.&lt;/p>
&lt;p>I still do this regularly. Roughly once a week we end up hosting someone for dinner. Sometimes it is a single person, sometimes it is a group of people. Sometimes it is co-workers, sometimes former colleagues, often friends that don&amp;rsquo;t work in tech. Growing up in the south it was common to have people over, I&amp;rsquo;d said we did that just as much as going out to dinner with folks. You&amp;rsquo;d get an invite to go to someone elses place and you&amp;rsquo;d show up with a bottle of wine or flowers in hand. Initially when I asked people in the Bay area over for dinner I&amp;rsquo;d get weird looks. Over? Like to your house?&lt;/p>
&lt;p>The reaction from folks at the end of the night was very often&amp;hellip; that was really fun. Thanks for the invite, I can&amp;rsquo;t remember the last time I just sat down at someones place, had a good meal, and conversation.&lt;/p>
&lt;p>Once I found early success with this I started implementing it pretty methodically. When remote workers were in town I&amp;rsquo;d make sure to place them at thet top of the list to come if the scheduling worked. Same when friends visit from out of town. I&amp;rsquo;d also try to regularly rotate through my teams and those that report to me. At one point when I had 22 engineers that I was leading product for I had to do a bit of juggling and stagger things a bit, groups of 4 folks or so at a time and each would be over about once every 6 months. &lt;em>I made life a bit easier on myself by grouping vegans together, and vegetarians, and meat eaters. When you&amp;rsquo;re cooking in the Bay area you probably don&amp;rsquo;t have a 500 sq. foot kitchen, so cooking 2-3 different meals adds complexity. Thus simplifying.&lt;/em>&lt;/p>
&lt;p>All of this was for selfish reasons. I could excuse myself for 15 minutes to give the kids a bath, to read them a story, to tuck them in. At the same time I was able to continue building a rapport with co-workers that allowed us both to work together better.&lt;/p></description></item><item><title>Talking on the phone: better communication</title><link>/2019/04/24/Talking-on-the-phone-better-communication/</link><pubDate>Wed, 24 Apr 2019 12:55:56 -0800</pubDate><guid>/2019/04/24/Talking-on-the-phone-better-communication/</guid><description>&lt;p>I interact with a lot of people in a given week, a few in person and far more on video and conference calls. I don&amp;rsquo;t claim to be a perfect person to talk to on the phone, but over the past several years I&amp;rsquo;ve noticed how painful some conference call experiences can be. As more and more work is conducted virtually and not face to face an ability to do communicate well on conference/voice calls is tied to what success you can deliver. &lt;em>It isn&amp;rsquo;t about having a fancy phone or high bandwidth video call–though that can at times be useful&lt;/em>&lt;/p>
&lt;h3 id="lets-start-with-localremote-teams" >
&lt;div>
Let&amp;rsquo;s start with local/remote teams
&lt;/div>
&lt;/h3>
&lt;p>This one is a huge problem as companies go from 100% local to partially remote. When you start a meeting take note of how many folks are local vs. remote. If you have the majority of attendees on a video or conference call you&amp;rsquo;re likely fine. If however the majority is local you need to make a concerted effort to pause and ask for input from the phone. This is doubley true on large conference calls&amp;hellip; in those cases it can be best to explicitly call out remote folks to chime in.&lt;/p>
&lt;h3 id="talk-to-the-phone" >
&lt;div>
Talk to the phone
&lt;/div>
&lt;/h3>
&lt;p>When you&amp;rsquo;re in person folks can tend to wander, look away, work on a whiteboard. All of these things can be very collaborative when in person but are absolutely terrible on the phone. When you&amp;rsquo;re not speaking into where the microphone is you will immediately come across choppy. The subtle take away is you&amp;rsquo;re not a professional. That doesn&amp;rsquo;t mean you&amp;rsquo;re doing it intentionally, but when interacting via voice you have to be extra intentional to come across how you intend.&lt;/p>
&lt;h3 id="strong-short-words" >
&lt;div>
Strong, short words
&lt;/div>
&lt;/h3>
&lt;p>This applies when in person, but is especially true on the phone when you can&amp;rsquo;t read someone else. If you don&amp;rsquo;t have verbal cues to feed off from the other person then you need to listen to audible ones. If you&amp;rsquo;re talking for 5 minutes non-stop then you&amp;rsquo;ve learned nothing about how the other person is reacting. At times you may need to talk that long. I like to talk, but after 5 minutes talking non-stop on the phone I have to make sure I stop and say I&amp;rsquo;ve been talking too long. One it is only fair, and two it is a converation and you need to ensure that it&amp;rsquo;s flowing both ways.&lt;/p>
&lt;h3 id="gone-with-the-wind" >
&lt;div>
Gone with the wind
&lt;/div>
&lt;/h3>
&lt;p>Your environment and surroundings are absolutely terrible to a productive conversation. If you&amp;rsquo;re walking and there is any sense of wind, if the room is echo-ey, fix it. I&amp;rsquo;ve seen this both with people taking calls in transit, but also with conference rooms that weren&amp;rsquo;t well designed. For in transit invest in a great headset if you&amp;rsquo;ll be taking calls. Test several, read some reviews. If it is a conference actively ask others on calls with you. To just assume it&amp;rsquo;s fine will lead to people silently dismissing you&amp;rsquo;re not serious because calls with others are smoother.&lt;/p>
&lt;h3 id="overcommunicate" >
&lt;div>
Overcommunicate
&lt;/div>
&lt;/h3>
&lt;p>Speed up, slow down, raise your voice, lower your voice. On the phone you only have one form of expression: your voice. Use it. For some this takes practice. Whenever I&amp;rsquo;m talking to press or analysts I make sure I&amp;rsquo;m standing. I make sure to not have coffee 3-4 hrs before because otherwise I&amp;rsquo;m overly animated. Make sure to take pauses. An explicit pause can give others a chance to chime in and ask questions. When you hear someone on the phone asking a question and you already started talking because of latency finish, then apologize, and ask for them to go ahead.&lt;/p>
&lt;h3 id="be-intentional" >
&lt;div>
Be intentional
&lt;/div>
&lt;/h3>
&lt;p>No matter who you are or what you do you&amp;rsquo;re on the phone plenty. Whether a 1:1 call or a conference call. Most of use don&amp;rsquo;t like these calls and feel drained or frustrated by them. I don&amp;rsquo;t claim that most of my calls feel like a friday night our at a baseball game, but by being explicit in how we communicate I do feel that you can make calls not feel like busy work. Instead they can be a productive way to communicate if you make sure you&amp;rsquo;re communicating clearly and explicitly, but also listening and engaging equally with the other side of the line.&lt;/p></description></item><item><title>Using email as an effective tool</title><link>/2019/04/16/Using-email-as-an-effective-tool/</link><pubDate>Tue, 16 Apr 2019 12:55:56 -0800</pubDate><guid>/2019/04/16/Using-email-as-an-effective-tool/</guid><description>&lt;p>I send way too many emails in a day. My inbox is very intermingled with my to do list and often represents some form of it. More relevant though is that email is a primary means of how I accomplish work. Being a PM I work cross functionally with other teams (from marketing, to engineering, to sales, to BD, to other product teams) and of course customers. Having to work so cross functionality I&amp;rsquo;ve found a lot of hacks I use to be able to better accomplish your goals with email, here is a collection of some of those.&lt;/p>
&lt;p>&lt;em>Let me be clear, this is not another post about inbox 0, how I swapped to slack. This instead is how I use email to more effectively communicate and get people to engage. In other words it is about making emails more useful, not just getting through them faster. And onto those tips.&lt;/em>&lt;/p>
&lt;h3 id="dont-leave-a-document-in-a-document" >
&lt;div>
Don&amp;rsquo;t leave a document in a document
&lt;/div>
&lt;/h3>
&lt;p>Often times I&amp;rsquo;ve found folks will collaborate in a document during a meeting or take notes there. After the meeting folks will email the document around, but few seldom actually open. Reasons may be they&amp;rsquo;re not logged in on their phone or it may be they just don&amp;rsquo;t care that much, I&amp;rsquo;m not really sure. What I do know is that by taking the notes and action items from the doc and including them in the email you will get more people paying attention to them. If you really want to get good at this when there is significant revisions of a work in progress document, re-circulate the updated version via email. Again not just a link to it, but the document itself.&lt;/p>
&lt;h3 id="mail-merge-isnt-just-for-marketing" >
&lt;div>
Mail merge isn&amp;rsquo;t just for marketing
&lt;/div>
&lt;/h3>
&lt;p>Years ago I sent a company wide request for feedback (to about 120 people). I got less than 3 responses. I ran an experiment the next time I needed the same thing using a mail merge so my same email seemed personal and was from me to them instead of some large alias. I got a response rate of over 45%. Use this wisely&amp;hellip; not every email you send needs a response. A broad update can absolutely be to team@, but when you need to get actual feedback and people don&amp;rsquo;t seem to chime in this approach works great.&lt;/p>
&lt;h3 id="conversation-begets-conversation" >
&lt;div>
Conversation begets conversation
&lt;/div>
&lt;/h3>
&lt;p>Often times when there is an email to team@ folks just simply click archive. A great tip for managers and leadership is to chime in on these emails right away. It can help promote some positive discussion and cause folks to actually take notice of updates that might otherwise end up archived. Be careful of the inverse of this though, replying to all mass emails can create a culture where everyone thinks it&amp;rsquo;s their job to +1 and thumbs up things. There is a balance to this one between team productivity and team morale.&lt;/p>
&lt;h3 id="text-is-boring" >
&lt;div>
Text is boring
&lt;/div>
&lt;/h3>
&lt;p>Email is not like reading a novel &lt;em>(except when my colleague Daniel Farina writes them)&lt;/em>, if I wanted to read a novel I&amp;rsquo;d actually go read a novel. For email I want the clear concise points broken out. You should think about how easy it is to read on a phone. If a single paragraph consumes my entire screen you&amp;rsquo;ve lost your readers attention and that content goes else where. A number of things can help for readability:&lt;/p>
&lt;ul>
&lt;li>Short paragraphs and usage of line breaks&lt;/li>
&lt;li>Bullets are your friend (aren&amp;rsquo;t you enjoying this list already?)&lt;/li>
&lt;li>Numbers are also great as they call attention to themselves&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Bold/italics can also be useful, but assume many people use text only clients so you need to be careful. Also really don&amp;rsquo;t over-use these&lt;/em>&lt;/p>
&lt;h3 id="add-extra-tooling" >
&lt;div>
Add extra tooling
&lt;/div>
&lt;/h3>
&lt;p>Gmail and Outlook are both continuing to improve over time. With the demise of Inbox Gmail itself is seeing some more of those features. Reminders about old un-responded to emails are great. But you can do much more by adding in a third party tool. &lt;a href="http://www.boomeranggmail.com/referral_download.html?ref=vsz82">Boomerang&lt;/a> and yesware are two popular ones. These can help with things like returning an email to your inbox in a couple weeks so it can be out of sight for now but come back later. You can also schedule emails to be sent later at a time that may be more ideal for someone to read it, instead of sending it at midnight what about 9am so it appears more top of their inbox?&lt;/p>
&lt;h3 id="do-you-know-about-muting" >
&lt;div>
Do you know about muting?
&lt;/div>
&lt;/h3>
&lt;p>Muting is the single greatest feature within gmail. Email is a great place for an archive and history, it is a great place to clearly communicate things, it can be a horrible place when it comes to generating a bunch of noise.&lt;/p>
&lt;p>Personally I subscribe to lots of lists. I have filters for many of those, but many I actually want to see. That doesn&amp;rsquo;t mean I care about every response to every thread on those lists. When engineering is discussing whether to use CircleCI vs. Travis I see that the discussion is happening but don&amp;rsquo;t care too much on the outcome. Mute will silence that entire thread and move it to archived for me. It will only re-appear if I am explicitly added to the To:&lt;/p>
&lt;p>The fact that it persists in my archive is key for me. If I want to go back later and search to see the outcome I can, but I don&amp;rsquo;t have to create a new rule, or archive each reply to the thread.&lt;/p>
&lt;h3 id="these-are-just-a-few" >
&lt;div>
These are just a few
&lt;/div>
&lt;/h3>
&lt;p>These are only a few tips, but ones I&amp;rsquo;ve found extremely useful on two sides. The first is being more control of my inbox so it doesn&amp;rsquo;t control me. A workflow that works for me which includes mute, filtering lists, scheduling emails for later helps with that. The second is to me email isn&amp;rsquo;t something I have to do, it is a tool to work more effectively. Being intentional on how I construct messages, when I send them, and what is clearly communicated is key for my job.&lt;/p>
&lt;p>I&amp;rsquo;m curious, what are some of your favorite email tips &lt;a href="https://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>.&lt;/p></description></item><item><title>OKRs aren't going to fix your communication issues</title><link>/2019/03/30/OKRs-arent-going-to-fix-your-communication-issues/</link><pubDate>Sat, 30 Mar 2019 12:55:56 -0800</pubDate><guid>/2019/03/30/OKRs-arent-going-to-fix-your-communication-issues/</guid><description>&lt;p>Talking with a startup a few days ago they asked for my opinions on OKRs. I have slightly mixed opinions on them overall and started to disclose some of those. Though in sharing some of this I had a few immediate realizations that might be broadly applicable. The crux of his question was, at what stage should we put them in place. I&amp;rsquo;ve seen a few companies try to put in some form of OKR, and most were met with pretty mixed results. The reason is that OKRs need to change something about your behavior otherwise why put them in place&amp;hellip; either change something about the goals you would otherwise have or the methods at which you went about achieving them.&lt;/p>
&lt;p>Stepping back a bit, my first question and a very focusing question on almost any situation to ask is &amp;ldquo;What problem are we trying to solve?&amp;rdquo; In our conversation he actually paused a bit. As he paused a bit longer it was clear that question had not been fully asked or answered.&lt;/p>
&lt;p>The first and most common case I see with startups trying to put in place OKRs, v2moms, management by objectives is that the team is not aligned and focused on the same goals. But my follow-on question is consistently, have you communicated what you decided you goals were.&lt;/p>
&lt;p>Startups tend to go through some distinct growing phases. The early stages all the founders are in a room together building out the product. When you get the first few engineers you expand out a little, but still in a single co-working conference room easily. Eventually you need a real office. At the real office stage you start to have an all hands where, this is probably gathered around a large lunch table at first. At all hands no one takes meeting minutes and sends out a recap, instead people take some notes and you assume everyone was present.&lt;/p>
&lt;p>But, at about 20 people you have at least one person that misses the weekly team meeting and misses something key. In a 1:1 you catch it that it was talked about as a priority&amp;hellip; but they weren&amp;rsquo;t there. This very subtle change I&amp;rsquo;ve seen linger all the way up to a 70/80 person org. I&amp;rsquo;ve observed management meetings where someone missed and a key member was entirely mis-aligned on what the goals were for months following.&lt;/p>
&lt;p>That was a long detour, but the point is that explicit formal communication is a big change for early stage companies. Distributed teams tend to do this better than in person teams, but it is also not guaranteed.&lt;/p>
&lt;p>OKRs present a heavy-weight answer to the problem. OKRs tend to require hours and maybe even days to determine what are the right goals and metrics. Even if they are quick, does the process of OKRs change how you structure your team and work significantly for the next few weeks/months. If not, could you much more easily get away with&amp;hellip; wait for it&amp;hellip; emailing out what the company says priorities are. Email out the meeting notes from your all hands meeting. Email out (gasp) a recap of what you discussed and are thinking about as a management team. Sure every manager could go and have a 1:1 and recap the points for 30 minutes with each of their employees. Or you could use this thing that we&amp;rsquo;ve had for a little while&amp;hellip; email.&lt;/p></description></item><item><title>Tips for your first tech conference</title><link>/2019/03/18/Tips-for-your-first-tech-conference/</link><pubDate>Mon, 18 Mar 2019 12:55:56 -0800</pubDate><guid>/2019/03/18/Tips-for-your-first-tech-conference/</guid><description>&lt;p>I make it to a lot of conferences these days. I often see colleagues, former colleagues, and friends at these conferences. Sometimes it is friends I haven&amp;rsquo;t seen in a few years, sometimes I just saw the same person in a different country the week before. Conferences now are much easier for me, in fact it is a bit hard to recall what the experience was like when I first started attending, but I&amp;rsquo;m at least going to try to give some input so others can have a smoother first experience.&lt;/p>
&lt;h3 id="most-people-know-no-one" >
&lt;div>
Most people know no one
&lt;/div>
&lt;/h3>
&lt;p>There is a very strong chance you&amp;rsquo;re attending your first conference by yourself or just with a single colleague you know. Being suddenly surrounded by thousands of people you don&amp;rsquo;t know can be intimidating. The reality though is most folks there are just like you and know very few other people. Most people don&amp;rsquo;t go to multiple conferences in a year, they go to 1. There are often a lot of opportunities to get to know folks. Some of the best times are during breaks between the talk track, and whenever there is food/beverages. If there is breakfast served at the conference as much as you&amp;rsquo;d like to sleep in wake up and go have breakfast and chat with someone. At lunch if there is a half full table, go ask if a seat is taken and join the table vs. sitting at a completely open one. During the breaks don&amp;rsquo;t rush to get to the talk 10 minutes before it begins, stay and mingle with folks.&lt;/p>
&lt;p>If you&amp;rsquo;re really feeling shy wonder the booth floor. Those folks are paid to be there to talk to you. Let them tell you about their product or service, it&amp;rsquo;ll at least be a start to some flowing conversation.&lt;/p>
&lt;h3 id="speakers-can-be-your-friends-too" >
&lt;div>
Speakers can be your friends too
&lt;/div>
&lt;/h3>
&lt;p>If you&amp;rsquo;re new often the speakers can seem extra intimidating to get to know. Don&amp;rsquo;t let that be the case. If one is talking about a topic you&amp;rsquo;re excited about hang around after the talk and discuss it with them. Speakers aren&amp;rsquo;t necessarily any more technically advanced than you are they just happened to get a talk accepted.&lt;/p>
&lt;h3 id="study-the-agenda" >
&lt;div>
Study the agenda
&lt;/div>
&lt;/h3>
&lt;p>The default is to look at the list of talks being presented and pick out which ones you want to attend. But pay closer attention at so many conferences there are a bunch of other great activities to participate in. PyCon is a model example of this. In addition to all the talks there is:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://us.pycon.org/2019/events/auction/">PyLadies Auction&lt;/a> - Which is a great night of dinner, drinks, and an auction of fun Python focused or other items which benefits PyLadies.&lt;/li>
&lt;li>[5k run] - You wake up early in the morning and run (it should be noted that 5:30 am does not sound fun to me, but to each his own)&lt;/li>
&lt;li>&lt;a href="https://us.pycon.org/2019/events/dinners/">Evening dinners&lt;/a> - If you&amp;rsquo;re worried about having dinner plans then this is a great option at a fun venue already coordinated.&lt;/li>
&lt;/ul>
&lt;p>If you&amp;rsquo;re not at something as structured as PyCon then there are a few places you can find what is happening. These days conferences often have a slack channel. Join it, find out when people get into town. Find out if people like to hike or visit breweries, join in with others. There is also twitter. Twitter things don&amp;rsquo;t get planned far in advance, but often you can find last minute folks that are coordinating things.&lt;/p>
&lt;h3 id="stay-at-the-conference-hotel" >
&lt;div>
Stay at the conference hotel
&lt;/div>
&lt;/h3>
&lt;p>If there is an official conference hotel or hotels, stay there. This opinion may be a little more controversial, but stay with me. First you&amp;rsquo;ll find folks hanging around the hotel bar after or just sitting around mingling. It&amp;rsquo;s a just one more way to not feel isolated. Second, it often helps the conference. Conferences can take on big risks with minimum rooms filled at a hotel. They do this to get good rates, but it also presents risk. Staying at the hotel both keeps you around others that are there for the conference, but also helps the conference itself.&lt;/p>
&lt;h3 id="you-dont-have-to-attend-all-the-talks" >
&lt;div>
You don&amp;rsquo;t have to attend all the talks
&lt;/div>
&lt;/h3>
&lt;p>Talks are super helpful. You can learn a lot in a compressed period of time and then often get where to go next to learn further. Great ones teach you something but are also entertaining presentations as well. But, you don&amp;rsquo;t have to attend all the talks. Many conferences record the talks and make them available later. Personally I make a note of ones I wanted to see, as well as ones that others said were especially great. Then I go to youtube and watch them at 1.5 or 2x speed to get through more of them in less time.&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>Going to a conference may absolutely feel intimidating if it is your first. There will be a little of that first day of school jitters. What do you wear, who will you talk to, what if no one sits with you at lunch. Just know that for most people there it really is like the first day of school for them too. Even though it may be intimidating hopefully the above helps you jump in with a little less apprehension.&lt;/p></description></item><item><title>Give me back my monolith</title><link>/2019/03/13/Give-me-back-my-monolith/</link><pubDate>Wed, 13 Mar 2019 12:55:56 -0800</pubDate><guid>/2019/03/13/Give-me-back-my-monolith/</guid><description>&lt;p>It feels like we&amp;rsquo;re starting to pass the peak of the hype cycle of microservices. It&amp;rsquo;s no longer multiple times a week we now see a blog post of &amp;ldquo;How I migrated my monolith to 150 services&amp;rdquo;. Now I often hear a bit more of the counter: &amp;ldquo;I don&amp;rsquo;t hate my monolith, I just care that things stay performant&amp;rdquo;. We’ve actually seen some migrations from &lt;a href="https://segment.com/blog/goodbye-microservices/">micro-services back to a monolith&lt;/a>. When you go from one large application to multiple smaller services there are a number of new things you have to tackle, here is a rundown of all the things that were simple that you now get to re-visit:&lt;/p>
&lt;h3 id="setup-went-from-intro-chem-to-quantum-mechanics" >
&lt;div>
Setup went from intro chem to quantum mechanics
&lt;/div>
&lt;/h3>
&lt;p>Setting up a basic database and my application with a background process was a pretty defined process. I&amp;rsquo;d have the readme on Github, and often in an hour or maybe a few I&amp;rsquo;d be up and running when I started on a new project. Onboarding a new engineering, at least for an initial environment would be done in the first day. As we ventured into micro-services onboarding time skyrocketed. Yes, we have docker and orchestration such as K8s these days to help, but the time from start to up and running a K8s cluster just to onboard a new engineer is orders of magnitude larger than we saw a few years ago. For many junior engineers this is a burden that really is unnecessary complexity.&lt;/p>
&lt;h3 id="so-long-for-understanding-our-systems" >
&lt;div>
So long for understanding our systems
&lt;/div>
&lt;/h3>
&lt;p>Lets stay on the junior engineer perspective for just a moment. Back when we had monolithic apps if you had an error you had a clear stacktrace to see where it originated from and could jump right in and debug. Now we have a service that talks to another service, that queues something on a message bus, that another service processes, and then we have an error. We have to piece together all of these pieces to eventually learn that service a was on version 11 and service q was expecting vesion 12 already. This in contrast to my standard consolidated log, and lets not forget my interactive terminal/debugger for when I wanted to go step by step through the process. Debugging and understanding is now inherintly more complicated.&lt;/p>
&lt;h3 id="if-we-cant-debug-them-maybe-we-can-test-them" >
&lt;div>
If we can&amp;rsquo;t debug them, maybe we can test them
&lt;/div>
&lt;/h3>
&lt;p>Continuous integration and continuous development is now starting to become common place. Most new apps I see now days automatically build and run their tests with a new PR and require tests to pass and review before check-in. These are great processes to have in place and have been a big shift for a lot of companies. But now to really test my service I have to bring up a complete working version of my application. Remember back to onboarding that new engineer with their 150 service K8s cluster? Well now we get to teach our CI system how to bring up all those systems to actually test that things are working. That is probably a bit too much effort so we&amp;rsquo;re just going to test each piece in isolation, I&amp;rsquo;m sure our specs were good enough that APIs are clean and service failure is isolated and won&amp;rsquo;t impact others.&lt;/p>
&lt;h3 id="all-the-trade-offs-are-for-a-good-reason-right" >
&lt;div>
All the trade-offs are for a good reason. Right?
&lt;/div>
&lt;/h3>
&lt;p>There are a lot of reasons to migrate to micro-services. I&amp;rsquo;ve heard cases for more agility, for scaling your teams, for performance, to give you a more resilient service. The reality we&amp;rsquo;ve invested decades into development practices and tooling around monoliths that are still maturing. In my &lt;a href="https://www.citusdata.com/product/cloud">day to day&lt;/a> I work with a lot of folks from all different stacks. Usually we&amp;rsquo;re talking about scaling because they&amp;rsquo;re running into limits of a single node Postgres database. Most of our conversation focuses on &lt;a href="https://www.citusdata.com/blog/2018/06/28/scaling-from-one-to-one-hundred-thousand-tenants/">scaling the database&lt;/a>.&lt;/p>
&lt;p>But in all the conversations I&amp;rsquo;m fascinated to learn about their architecture. Where are they in their journey to micro-services. It has been an interesting trend to see more and more reactions &amp;ldquo;We&amp;rsquo;re happy with our monolithic app.&amp;rdquo; The road to micro-services may work fine for lots, and the benefits may outweigh the bumpy road to get there, but personally give me my monolithic app and a beach somewhere and I&amp;rsquo;ll be happy.&lt;/p></description></item><item><title>Why I love building developer products</title><link>/2019/03/12/why-i-love-building-developer-tools/</link><pubDate>Tue, 12 Mar 2019 12:55:56 -0800</pubDate><guid>/2019/03/12/why-i-love-building-developer-tools/</guid><description>&lt;p>For much of my career I&amp;rsquo;ve been focused on building out developer or data focused products with the customer in some form or fashion being a developer on the other end. I fully realize now that I&amp;rsquo;m destined to spend the rest of my career in that space, either that or trying my hand at wine making. There are a few things that I personally find rewarding about the space that I&amp;rsquo;ve shared with a number of people individually lately and thought I would share more broadly.&lt;/p>
&lt;p>First, software really is eating the world. Often developers and entrepeurs ask about what they could build that would be a good business. The reality is about anything that has not been modernized to as a service and improved with software could be. We have far less developers in the world than we need to execute on all the ways we could improve products and life. To me what is interesting is the last part of that last sentence. It is not that the market for developers is huge, which I do believe it is. It more that when we automate with systems we can get amazing economies of scale. I know folks that reminisce and talk about how we&amp;rsquo;re more stressed being always connected and such and that in the old days people got out and worked the fields and enjoyed the sun. They also absolutely physically exhausted their bodies in the process. The ability to make life better at scale is an interesting one and often done through systems we develop.&lt;/p>
&lt;p>The second reason is the challenge and the reward. Developers are notoriously tough critics. If it feels/smells like marketing then they have an allergic reaction, and that is probably because much of it is done poorly. If they experience really positive/great marketing they latch on more than the average person. Most developers are by nature a bit skeptical&amp;hellip; for some reason this resonates with me. But, I&amp;rsquo;ve found they are the largest/biggest supporters once they&amp;rsquo;re excited about something. Personally I&amp;rsquo;d rather folks more critical and then have a few diehard fans than a whole bunch of people I can try to some site with ads and convert them, but then never actually connect with my product/brand.&lt;/p>
&lt;p>The third and final reason is, I can understand it. Having worked at small startups, side projects, and at large enterprise I can understand the challenges as each different level. Building a product that I can directly relate to and connect with is some how easier to stay motivated. I&amp;rsquo;m sure instagram has a lot of interesting technical challenges, or that scaling an ad network is extremely challenging. But building a product that I could see myself directly benefiting from makes everyone&amp;rsquo;s input on the team valuable and key. This changes the entire dynamic from product team to engineering to marketing.&lt;/p>
&lt;p>Now days I dont get much chance to ship code to production, usually that is what I threaten when things are running behind, but at heart I&amp;rsquo;m still very much an engineer. Building products that make developers lives better and more productive may not change the world, but hopefully it better enables other developers to.&lt;/p></description></item><item><title>How can I help? East coast vs. West coast mentalities</title><link>/2019/03/03/how-can-i-help-east-vs-west/</link><pubDate>Sun, 03 Mar 2019 12:55:56 -0800</pubDate><guid>/2019/03/03/how-can-i-help-east-vs-west/</guid><description>&lt;p>Often times when I&amp;rsquo;m traveling on the east coast, whether it is NYC area or back home down south I try to spend some time to catch up with various people. In catching up we&amp;rsquo;ll spend some time talking about what we&amp;rsquo;re both up to, thoughts on tech or in general, and at the end I typically ask &amp;ldquo;Is there anything in particular I can help with?&amp;rdquo; More often than not the answer to this question isn&amp;rsquo;t super substantial, which is fine. But what is surprising is the stark contrast on reactions to this question and how it differs from west coast vs. east coast.&lt;/p>
&lt;p>On the east coast when I ask &amp;ldquo;How can I help?&amp;rdquo; I get a look of:&lt;/p>
&lt;ul>
&lt;li>What&amp;rsquo;s the catch?&lt;/li>
&lt;li>Okay, what is it you want me to do for you?&lt;/li>
&lt;li>There is no way you actually intend to help&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>Meanwhile on the west coast the mentality is generally quite different. I often have people showing their own willingness to help. It may be someone you know personally that is offering help, but have also seen where someone gets asked for input or help, refers someone else and now you have two people that have known each other for under 5 minutes and one willing to dispense helpful advice or assistance.&lt;/p>
&lt;p>The how I can help mentality of the west coast seems to follow that offering assistance is not a zero sum game, and by extending some effort now it hopefully comes back around when they need it themselves.&lt;/p></description></item><item><title>SQL: One of the most valuable skills</title><link>/2019/02/12/SQL-One-of-the-most-valuable-skills/</link><pubDate>Tue, 12 Feb 2019 12:55:56 -0800</pubDate><guid>/2019/02/12/SQL-One-of-the-most-valuable-skills/</guid><description>&lt;p>I&amp;rsquo;ve learned a lot of skills over the course of my career, but no technical skill more useful than SQL. SQL stands out to me as the most valuable skill for a few reasons:&lt;/p>
&lt;ol>
&lt;li>It is valuable across different roles and disciplines&lt;/li>
&lt;li>Learning it once doesn&amp;rsquo;t really require re-learning&lt;/li>
&lt;li>You seem like a superhero. &lt;em>You seem extra powerful when you know it because of the amount of people that aren&amp;rsquo;t fluent&lt;/em>&lt;/li>
&lt;/ol>
&lt;p>Let me drill into each of these a bit further.&lt;/p>
&lt;h2 id="sql-a-tool-you-can-use-everywhere" >
&lt;div>
SQL a tool you can use everywhere
&lt;/div>
&lt;/h2>
&lt;p>Regardless of what role you are in SQL will find a way to make your life easier. Today as a product manager it&amp;rsquo;s key for me to look at data, analyze how effective we&amp;rsquo;re being on the product front, and shape the product roadmap. If we just shipped a new feature, the data on whether someone has viewed that feature is likely somewhere sitting in a relational database. If I&amp;rsquo;m working on tracking key business metrics such as &lt;a href="/2014/02/26/Tracking-MoM-growth-in-SQL/">month over month growth&lt;/a>, that is likely somewhere sitting in a relational database. At the other end of almost anything we do there is likely a system of record that speaks SQL. Knowing how to access it most natively saves me a significant amount of effort without having to go ask someone else the numbers.&lt;/p>
&lt;p>But even before becoming a product manager I would use SQL to inform me about what was happening within systems. As an engineer it could often allow me to pull information I wanted faster than if I were to script it in say Ruby or Python. When things got slow in my webapp having an understanding of the SQL that was executed and &lt;a href="/2012/10/01/understanding-postgres-performance/">ways to optimize&lt;/a> it was indespensible. Yes, this was going a little beyond just a basic understanding of SQL&amp;hellip; but adding an &lt;a href="https://www.citusdata.com/blog/2017/10/11/index-all-the-things-in-postgres/">index to a query&lt;/a> instead of rolling my own homegrown caching well that was well worth the extra time learning.&lt;/p>
&lt;h2 id="sql-is-permanent" >
&lt;div>
SQL is permanent
&lt;/div>
&lt;/h2>
&lt;p>I recall roughly 20 years ago creating my first webpage. It was magical, and then I introduced some Javascript to make it even more impressive prompting users to click Yes/No or give me some input. Then about 10 years later jQuery came along and while it was a little more verbose at times and something new to learn it made things prettier overall so I committed to re-learning the jQuery approach to JS. Then it just picked up pace with Angular -&amp;gt; React/Ember, and now I have an entire pipeline to introduce basic Javascript into my website and the reality is I&amp;rsquo;m still trying to accomplish the same thing I was 20 years ago by having someone click Yes/No.&lt;/p>
&lt;p>SQL in contrast doesn&amp;rsquo;t really change. &lt;em>Caveat: It has changed–there is &lt;a href="https://modern-sql.com/">modern sql&lt;/a>, but I&amp;rsquo;d still argue less dramatically than other language landscapes&lt;/em>. Yes we get a new standard every few years and occasionally something new comes along like support for window functions or CTEs, but the basics of SQL are pretty permanent. Learning SQL once will allow you to re-use it heavily across your career span without having to re-learn. Don&amp;rsquo;t get me wrong I love learning new things, but I&amp;rsquo;d rather learn something truly new than just yet another way to accomplish the same task.&lt;/p>
&lt;h2 id="sql-seem-better-than-you-are" >
&lt;div>
SQL: Seem better than you are
&lt;/div>
&lt;/h2>
&lt;p>SQL is an underlearned skill, the majority of application developers just skip over it. Because so few actually know SQL well you can seem more elite than you actually are. In past companies with hundreds of engineers I&amp;rsquo;d get a question several times a week from junior to principal engineers of: &amp;ldquo;hey can you help me figure out how to write a query for this?&amp;rdquo; Because you&amp;rsquo;re skilled at something so few others are you can help them out which always makes life a little easier when you have a question for them.&lt;/p>
&lt;p>So if you&amp;rsquo;re not already proficient what are you waiting for, do you want to seem like a SQL badass yet?&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>The biggest mistake Postgres ever made</title><link>/2018/10/30/postgres-biggest-mistake/</link><pubDate>Tue, 30 Oct 2018 12:55:56 -0800</pubDate><guid>/2018/10/30/postgres-biggest-mistake/</guid><description>&lt;p>Postgres has experienced a long and great run. It is over 20 years old and has a track record of being safe and reliable (which is the top thing I care about in a database). In recent years it has become more cool with things like &lt;a href="https://www.citusdata.com/blog/2016/07/14/choosing-nosql-hstore-json-jsonb/">JSONB&lt;/a>, &lt;a href="https://www.citusdata.com/blog/2018/09/11/postgresql-11-just-in-time/">JIT support&lt;/a>, and a powerful &lt;a href="https://www.citusdata.com/blog/2017/10/25/what-it-means-to-be-a-postgresql-extension/">extension&lt;/a> ecosystem. But, Postgres has made some mistakes along the way, the most notable being the name.&lt;/p>
&lt;p>Postgres gets its name from &lt;a href="https://en.wikipedia.org/wiki/Ingres_(database)">Ingress&lt;/a>. Ingress was one of the first databases and was lead by Michael Stonebreaker who won a Turing award for Postgres and other works. Ingress began in the early 70s at UC Berkeley, which is still to this day known as a top university when it comes to databases. Out of Ingress came a number of databases you&amp;rsquo;ll still know today such as SQL Server and Sybase. It also as you may have guessed by now spawned Postgres which means Post-Ingress.&lt;/p>
&lt;p>In the early days of Postgres there was no SQL. No not NoSQL, there was not SQL. Postgres had its own query language. It wasn&amp;rsquo;t until 1995 that Postgres received SQL support, and with its addition of SQL support it updated its name to PostgreSQL.&lt;/p>
&lt;p>You see, with Postgres becoming PostgreSQL we began a journey of Postgres being mispronounced for its forseeable future and it is still currently the case. Is it really that big of an issue? Well it&amp;rsquo;s big enough that the PostgreSQL website has a FAQ including &lt;a href="https://www.postgresql.org/about/press/faq/">&amp;ldquo;How to pronounce PostgreSQL&amp;rdquo;&lt;/a>. As it stands today there are two generally accepted names:&lt;/p>
&lt;ul>
&lt;li>post-GRES-que-ell&lt;/li>
&lt;li>Postgres&lt;/li>
&lt;/ul>
&lt;p>With one of the above there is far less confusion. And in fact I&amp;rsquo;m not the only one to share this opinion. &lt;a href="https://en.wikipedia.org/wiki/Tom_Lane_(computer_scientist)">Tom Lane&lt;/a> is a major contributor to every Postgres release for more than the last decade. He&amp;rsquo;s one of the top 10 contributors to open source in general having worked on the JPEG/PNG/TIFF image formats before coming over to database land. Tom has this &lt;a href="https://www.postgresql.org/message-id/2693.1152762174@sss.pgh.pa.us">classic email&lt;/a> in the PostgreSQL mailing list:&lt;/p>
&lt;pre tabindex="0">&lt;code> [&amp;gt;&amp;gt; Can i get data in postgre from non-postgre db?
&amp;gt; The name is PostgreSQL or Postgres, not postgre.
It might help to explain that the pronunciation is &amp;#34;post-gres&amp;#34; or
&amp;#34;post-gres-cue-ell&amp;#34;, not &amp;#34;post-gray-something&amp;#34;.
I heard people making this same mistake in presentations at this
past weekend&amp;#39;s Postgres Anniversary Conference :-( Arguably,
the 1996 decision to call it PostgreSQL instead of reverting to
plain Postgres was the single worst mistake this project ever made.
It seems far too late to change now, though.
regards, tom lane
&lt;/code>&lt;/pre>&lt;p>The best part is this was mail was 2006, when it was arguably too late to change the name, and here we are in 2018 with the same issue.&lt;/p>
&lt;p>Personally I may start calling it Postgre just to emphasize a point, but for the rest of you just going with Postgres is probably a safe choice.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Postgres 11 - A First Look</title><link>/2018/09/20/postgresql-11-a-first-look/</link><pubDate>Thu, 20 Sep 2018 12:55:56 -0800</pubDate><guid>/2018/09/20/postgresql-11-a-first-look/</guid><description>&lt;p>Postgres 11 is almost here, in fact the latest beta shipped today, and it features a lot of exciting improvements. If you want to get the full list of features it is definitely worth checking out the &lt;a href="https://www.postgresql.org/docs/11/static/release-11.html">release notes&lt;/a>, but for those who don&amp;rsquo;t read the release notes I put together a run down of some what I consider the highlight features.&lt;/p>
&lt;h2 id="quitting-postgres" >
&lt;div>
Quitting Postgres
&lt;/div>
&lt;/h2>
&lt;p>This is a small usability feature, but so long over due. Now you can quit Postgres by simply typing &lt;code>quit&lt;/code> or &lt;code>exit&lt;/code>. Previously you had to use Ctrl + D or &lt;code>\q&lt;/code>. As a begginer it&amp;rsquo;s one thing to jump into a psql terminal, but once in if you can&amp;rsquo;t figure out how to quit it&amp;rsquo;s a frustrating experience. Small usability features, such as this and &lt;code>watch&lt;/code> in an earlier release, are often lost in the highlighted features which talk about performance or new data types. Improvements like this really go a long way for making Postgres a better database for everyone.&lt;/p>
&lt;h2 id="fear-column-addition-no-more" >
&lt;div>
Fear column addition no more
&lt;/div>
&lt;/h2>
&lt;p>&lt;a href="https://brandur.org/postgres-default">Brandur&lt;/a> had a great in depth write-up on this feature already, but it falls somewhere into the category of the above as well as a performance improvement. Previously when you added a new column that was &lt;code>NOT NULL&lt;/code> with a default value Postgres would have to take a lock and re-write the entire table. In a production environment on any sizable table for all practical purposes the result was an outage. The work around was to break your migrations apart to be a several &lt;a href="https://blog.codeship.com/rails-migrations-zero-downtime/">step process&lt;/a>.&lt;/p>
&lt;p>With Postgres 11 you can add a new column to a table that is not null with a default value. The new row will get materialized on your database without requiring a full re-write. Here is to having to think less about your migrations.&lt;/p>
&lt;h2 id="of-course-performance-is-a-highlight" >
&lt;div>
Of course performance is a highlight
&lt;/div>
&lt;/h2>
&lt;p>No Postgres release would be complete without some performance improvements. This release there are really two areas that feature key improvements around performance.&lt;/p>
&lt;h3 id="parallelism-continuing-to-mature" >
&lt;div>
Parallelism continuing to mature
&lt;/div>
&lt;/h3>
&lt;p>We first saw parallelism support back in PostgreSQL 9.6. At the time it was primarily for sequential scans, which if you used parallelism for your sequential scans was great, but overall that was a narrow focus. PostgreSQL 10 parallelism because much more useful, and with PostgreSQL 11 it just keeps getting better. Some of the highlights for parallelism include:&lt;/p>
&lt;ul>
&lt;li>Parallel hash joins&lt;/li>
&lt;li>Parallel append&lt;/li>
&lt;li>Parallel index creation - &lt;em>We&amp;rsquo;ve talked about how great this can be over on the &lt;a href="https://www.citusdata.com/blog/2017/01/17/parallel-indexing-with-citus/">Citus blog&lt;/a>. With it natively in Postgres it makes it even easier for people to leverage.&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>If you want to dig deeper into all the parallelism support in Postgres &lt;a href="https://speakerdeck.com/macdice/parallelism-in-postgresql-11">this presentation&lt;/a> by PostgreSQL committer Thomas Munro at &lt;a href="https://2018.postgresopen.org/">PostgresOpen Silicon Valley&lt;/a> from a few weeks ago is a great resource.&lt;/p>
&lt;h3 id="postgres-gets-a-jit" >
&lt;div>
Postgres gets a JIT
&lt;/div>
&lt;/h3>
&lt;p>Just in time compilation is going to be a big deal for Postgres for the coming years. We have the initial support for it now in PostgreSQL 11. Even in this initial implementation of JIT support you can see a nearly 30% speedup on certain queries, such as highlighted here by the &lt;a href="https://www.citusdata.com/blog/2018/09/11/postgresql-11-just-in-time/">TPC-H benchmark&lt;/a>&lt;/p>
&lt;p>It is still early days for the just in time query compilation support, so expect the improvements here to be even better in PostgreSQL 12 and 13.&lt;/p>
&lt;h2 id="statistics-keep-getting-better" >
&lt;div>
Statistics keep getting better
&lt;/div>
&lt;/h2>
&lt;p>In Postgres 10 we saw a feature that few have probably used &lt;a href="https://www.citusdata.com/blog/2018/03/06/postgres-planner-and-its-usage-of-statistics/">&lt;code>CREATE STATISTICS&lt;/code>&lt;/a>. You see under the covers Postgres keeps a lot of information about your database which it uses to determine the query plan it will use when executing a query. Most statistics were single column ones previously, now with &lt;code>CREATE STATISTICS&lt;/code> you could define a correlation between two separate columns. With Postgres 11 now you can create statistics based on expression indexes giving you even more cases where they can help the performance of your app.&lt;/p>
&lt;h2 id="keeping-standbys-warm" >
&lt;div>
Keeping standbys warm
&lt;/div>
&lt;/h2>
&lt;p>&lt;code>pg_prewarm&lt;/code> has been great for warming up a replica&amp;rsquo;s cache so that should you have a failover you&amp;rsquo;re not failing over to a cold cache. However up until PostgreSQL 11 you&amp;rsquo;d have to manually run it yourself or setup some scheduler such as &lt;a href="https://www.citusdata.com/blog/2016/09/09/pgcron-run-periodic-jobs-in-postgres/">pg_cron&lt;/a>, now you can configure &lt;code>pg_prewarm&lt;/code> to run all on it&amp;rsquo;s own at a regular interval.&lt;/p>
&lt;h2 id="and-more" >
&lt;div>
And more
&lt;/div>
&lt;/h2>
&lt;p>PostgreSQL 11 is packed with more features than I&amp;rsquo;ve seen in a release before, though I think I&amp;rsquo;ve also said that before. It will be exciting to see several of these features such as the JIT support, statistics, and others as it is still in the early days for them. Meanwhile we have a great set of new features to improve user experience as well as help performance with parallelism. If you&amp;rsquo;re curious to get your hands on these give the &lt;a href="https://www.postgresql.org/about/news/1890/">beta&lt;/a> a try and send your feedback to the PostgreSQL community.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>PostgresOpen 2018 - First look at talks</title><link>/2018/06/27/postgresopen-talk-list/</link><pubDate>Wed, 27 Jun 2018 12:55:56 -0800</pubDate><guid>/2018/06/27/postgresopen-talk-list/</guid><description>&lt;p>&lt;a href="https://2018.postgresopen.org/">PostgresOpen&lt;/a> is just a few months away and our &lt;a href="https://postgresql.us/events/pgopen2018/sessions/">list of talks&lt;/a> is now live and available on the PostgresOpen website. This year selecting the talks was the hardest yet not only due to the number of talk submissions, but also the across the board high quality of submissions. There is hopefully something for everyone among the talks, at least if you like Postgres that is.&lt;/p>
&lt;p>If you&amp;rsquo;re thinking about joining us I&amp;rsquo;d love to see you there and buy you a beer or coffee. The conference is September 5-7 in downtown San Francisco, and early bird tickets are open for just another few weeks. If you want to save some money on &lt;a href="https://2018.postgresopen.org/tickets/">tickets grab it&lt;/a> and the &lt;a href="https://2018.postgresopen.org/venue/">room&lt;/a> now before things jump.&lt;/p>
&lt;p>But, if you&amp;rsquo;re curious for a sampling of a few of the talks I thought I&amp;rsquo;d break down my top five I&amp;rsquo;m personally most excited about:&lt;/p>
&lt;h3 id="debugging-the-postgres-plannerhttpspostgresqluseventspgopen2018sessionssession551-debugging-the-postgres-planner" >
&lt;div>
&lt;a href="https://postgresql.us/events/pgopen2018/sessions/session/551-debugging-the-postgres-planner/">Debugging the Postgres planner&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Okay, this one immediately caught my atttention. Melanie will start with the basics of an explain plan to progress down into an actual bug within the Postgres planner, how to can debug it in Postgres, and then write a patch for a fix herself. This talk is well beyond my depth as I&amp;rsquo;ll likely never contribute code to the Postgres planner, but seems extremely entertaining and likely to highlight both performance profiling as well as useful debugging tips.&lt;/p>
&lt;h3 id="cleaning-out-crocodiles-teeth-with-postgresql-indexeshttpspostgresqluseventspgopen2018sessionssession506-cleaning-out-crocodiles-teeth-with-postgresql-indexes-a-story-on-all-the-index-types-in-pg" >
&lt;div>
&lt;a href="https://postgresql.us/events/pgopen2018/sessions/session/506-cleaning-out-crocodiles-teeth-with-postgresql-indexes-a-story-on-all-the-index-types-in-pg/">Cleaning out Crocodiles teeth with PostgreSQL indexes&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>I saw Louise give a super practical talk on undertanding explain this year in PgDay Paris. It was both valuable for application developers that aren&amp;rsquo;t Postgres experts as well as surfaced knowledge for those that thought they already understood explain. I&amp;rsquo;m excited to hear her take on indexes, but maybe even more excited for the storytelling that will come along with this talk. A talk that can be put to a story always becomes a bit easier to follow the journey than simply the technical facts.&lt;/p>
&lt;h3 id="how-postgresql-extension-apis-are-changing-the-face-of-relational-databaseshttpspostgresqluseventspgopen2018sessionssession491-how-postgresql-extension-apis-are-changing-the-face-of-relational-databases" >
&lt;div>
&lt;a href="https://postgresql.us/events/pgopen2018/sessions/session/491-how-postgresql-extension-apis-are-changing-the-face-of-relational-databases/">How PostgreSQL extension APIs are changing the face of relational databases&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;ve said it before personally that Postgres is becoming more of a data platform than simply a relational database. Part of that is flexibility towards datatypes and the broad use cases Postgres can support from OLTP, to OLAP, to &lt;a href="https://www.citusdata.com/blog/2018/06/07/what-is-citus-good-for/">HTAP&lt;/a>. The other big part is extensions! Extensions allow Postgres to continue to advance outside of the standard Postgres core codebase and release cycle. The list of extensions (&lt;a href="https://postgis.net/">PostGIS&lt;/a>, &lt;a href="https://www.citusdata.com/blog/2017/04/04/distributed_count_distinct_with_postgresql/">HyperLogLog&lt;/a>, &lt;a href="https://github.com/pgpartman/pg_partman">pg_partman&lt;/a>, &lt;a href="https://www.citusdata.com">Citus&lt;/a>) in this talk is pretty great, and curious to hear more on the APIs themselves.&lt;/p>
&lt;h3 id="connection-pooling-101httpspostgresqluseventspgopen2018sessionssession570-connection-pooling-101" >
&lt;div>
&lt;a href="https://postgresql.us/events/pgopen2018/sessions/session/570-connection-pooling-101/">Connection Pooling 101&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Okay, connection pooling has been talked about before. Yet, still SO MANY people don&amp;rsquo;t use it in production. Connection pooling can have as large of an impact as understanding explain. In this talk Samantha looks at the pros/cons of connection pooling itself with Postgres, and should provide some good guidance for getting things setup.&lt;/p>
&lt;h3 id="hot---understaning-this-important-optimization-updatehttpspostgresqluseventspgopen2018sessionssession517-hot-understanding-this-important-update-optimization" >
&lt;div>
&lt;a href="https://postgresql.us/events/pgopen2018/sessions/session/517-hot-understanding-this-important-update-optimization/">HOT - Understaning this important optimization update&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Grant&amp;rsquo;s talk last year on tuning Postgres for &lt;a href="https://www.youtube.com/watch?v=xrMbzHdPLKM">high write workloads&lt;/a> was a great one that covered not only practical tips but some of the details of how things work under the covers. This looks like a great follow-on focusing on heap only tuples and how they can greatly improve things like bloat and overal write throughput.&lt;/p>
&lt;h2 id="see-you-there" >
&lt;div>
See you there
&lt;/div>
&lt;/h2>
&lt;p>If you have any questions about the conference I&amp;rsquo;d be happy to answer them, though hopefully based on the short sampling of talks you have all the reason you need to join us in September.&lt;/p></description></item><item><title>Same great Postgres with a new player in town</title><link>/2018/03/20/same-great-postgres-new-player-in-town/</link><pubDate>Tue, 20 Mar 2018 12:55:56 -0800</pubDate><guid>/2018/03/20/same-great-postgres-new-player-in-town/</guid><description>&lt;p>Many of us have known how great &lt;a href="http://www.craigkerstiens.com/2012/04/30/why-postgres/">Postgres&lt;/a> was for &lt;a href="http://www.craigkerstiens.com/2017/04/30/why-postgres-five-years-later/">years&lt;/a>.&lt;/p>
&lt;p>&lt;em>In fact I recall a conversation with some sales engineers about 6 years ago that previously worked for a large database vendor that really no one likes down in Redwood City. They were remarking how the biggest threat to them was Postgres. At first they were able to just brush it off saying it was open source and no real database could be open source. Then as they dug in they realized there was more there than most knew about and they would have to continually be finding ways to discredit it in sales conversations. Well it doesn&amp;rsquo;t look like those SEs or the rest of that company was too successful.&lt;/em>&lt;/p>
&lt;p>Postgres is certainly &lt;a href="https://www.infoworld.com/article/3261571/database/how-postgresql-just-might-replace-your-oracle-database.html">having it&amp;rsquo;s moment&lt;/a>, and I personally don&amp;rsquo;t expect it to fade soon.&lt;/p>
&lt;p>An equally interesting shift I&amp;rsquo;ve watched from the outside has been Microsoft&amp;rsquo;s shift to support and engage with the &lt;a href="http://redmonk.com/sogrady/2017/09/28/microsoft-hiring/">open source movement&lt;/a>. Personally that shift is extremely exciting to see, especially today as they announce their general availability of their &lt;a href="https://azure.microsoft.com/en-us/blog/announcing-general-availability-of-azure-database-services-for-mysql-and-postgresql/">Postgres&lt;/a> offering. And with their announcement it looks they&amp;rsquo;re not just dabbling but shipping a very compelling offering, notably high availability is built-in which means they&amp;rsquo;re very much targetting production workloads. With their GA release there are a number of interesting boxes checked:&lt;/p>
&lt;ul>
&lt;li>HIPPA, SOC, ISO compliances&lt;/li>
&lt;li>99.99% uptime SLA&lt;/li>
&lt;li>Available in 22 regions&lt;/li>
&lt;/ul>
&lt;p>Personally I&amp;rsquo;m looking forward to the new competition for Postgres users as it&amp;rsquo;ll make Postgres better and better for all. When I was at Heroku and was running product for Heroku Postgres 7 years ago we were the only large major provider. Today that landscape looks a lot different and it just means more choice and more quality if you want to run Postgres. So welcome Microsoft, I look forward to giving Azure Postgres a try.&lt;/p></description></item><item><title>Postgres hidden gems</title><link>/2018/01/31/Postgres-hidden-gems/</link><pubDate>Wed, 31 Jan 2018 12:55:56 -0800</pubDate><guid>/2018/01/31/Postgres-hidden-gems/</guid><description>&lt;p>Postgres has a rich set of features, even when working everyday with it you may not discover all it has to offer. In hopes of learning some new features that I didn&amp;rsquo;t know about myself as well as seeing what small gems people found joy in I tweeted out to see what people came back from. The response was impressive, and rather than have it lost into ether of twitter I&amp;rsquo;m capturing some of the responses here along with some resources many of the features.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;ul>
&lt;li>&lt;a href="https://www.twitter.com/listrophy">@listrophy&lt;/a> - &lt;code>$ brew postgresql-update database&lt;/code>
&lt;ul>
&lt;li>&lt;em>Though personally I prefer Postgres.app ;)&lt;/em>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/pat_shaugnessy">@pat_shaugnessy&lt;/a> - ltree
&lt;ul>
&lt;li>Pat has a great post that walks through &lt;a href="http://patshaughnessy.net/2017/12/13/saving-a-tree-in-postgres-using-ltree">ltree&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/billyfung">@billyfung&lt;/a> - citext
&lt;ul>
&lt;li>A really handy datatype for case insensitive text&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/eeeebbbbrrrr">@eeeebbbbrrrr&lt;/a> - date math with intervals
&lt;ul>
&lt;li>I couldn&amp;rsquo;t agree more on this one, &lt;a href="/2017/06/08/working-with-time-in-postgres/">working with time in Postgres&lt;/a> is the easiest time I&amp;rsquo;ve every had&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/DataMiller">@DataMiller&lt;/a> - The jsonb datatype and lateral joins
&lt;ul>
&lt;li>I&amp;rsquo;d argue it&amp;rsquo;s hard to claim now JSONB is a hidden gem, but &lt;a href="https://blog.heapanalytics.com/postgresqls-powerful-new-join-type-lateral/">lateral joins&lt;/a> are certain a great one&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/ideasasylum">@ideasasylum&lt;/a> - row_number() over(partition &lt;a href="http://orders.site">http://orders.site&lt;/a>_id order by orders.created_at)
&lt;ul>
&lt;li>&lt;a href="https://robots.thoughtbot.com/postgres-window-functions">Window functions&lt;/a> are definitely a handy feature
was my hidden (to me) discovery this week&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/franckverrot">@franckverrot&lt;/a> - Index access method, and custom FDWs&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/jonjensen0">@jonjensen0&lt;/a> - &lt;a href="https://www.postgresql.org/docs/9.5/static/functions-srf.html">Set-returning functions&lt;/a> and custom aggregate functions can be very helpful.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/ascherbaum">@ascherbaum&lt;/a> - psql -x
&lt;ul>
&lt;li>Psql is indeed awesome and can be &lt;a href="http://www.craigkerstiens.com/2013/02/13/How-I-Work-With-Postgres/">well tuned&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/Abstr_ct">@Abstr_ct&lt;/a> - The fact that the docs are fantastic and all hidden gems are actually readily available. Oh, and pl/brainfuck obviously&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/Halpin_IO">@Halpin_IO&lt;/a> - Subnetting and network operations&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/jkatz05">@jkatz05&lt;/a> - Replication slots, both physical and logical. They&amp;rsquo;ve made setting up replication infinitely easier. And range types. Because they&amp;rsquo;re awesome.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/petereisentraut">@petereisentraut&lt;/a> - Unicode table borders&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/_avichalp">@_avichalp&lt;/a> Notify/listen&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/simonw">@simonw&lt;/a> - The fact that &lt;a href="https://www.citusdata.com/blog/2017/10/17/tour-of-postgres-index-types/">GIN indices&lt;/a> can make LIKE queries run fast even if the % isn&amp;rsquo;t just at the end of the string&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/javisantana">@javisantana&lt;/a> - it has a statistics system to plan queries that can be used by the user when accuracy does not matter, for example, use &amp;ldquo;explain select * from table&amp;rdquo; to replace count() or use &amp;ldquo;_postgis_selectivity&amp;rdquo; to know how many points fall into a bbox.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/l_avrot">@l_avrot&lt;/a> - The fact that we can use vim editor in psql&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/mashd">@mashd&lt;/a> - Logical decoding for change data capture.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/4thdoctor_scarf">@4thdoctor_scarf&lt;/a> - the MVCC. If I had a penny per each time I&amp;rsquo;ve explained how really works, I&amp;rsquo;ll be a millionaire now :)&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/docteur_klein">@docteur_klein&lt;/a> - \timing in psql&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/thibaut_barrere">@thibaut_barrere&lt;/a> - From times to times I find foreign data wrapper with CSV files very helpful (&amp;amp; easy to setup with Ruby&amp;rsquo;s Sequel library) &lt;a href="https://gist.github.com/thbar/0093ee54c5a61aa5a0c5a4737fc3bd45">https://gist.github.com/thbar/0093ee54c5a61aa5a0c5a4737fc3bd45&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/steve_touw">@steve_touw&lt;/a> - &lt;a href="http://www.craigkerstiens.com/2016/09/11/a-tour-of-fdws/">Foreign data wrappers&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/roimartinez_gis">@roimartinez_gis&lt;/a> - Clearly aggregate functions make live very simple :) .&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/whalesalad">@whalesalad&lt;/a> - select where datetime &amp;gt; yesterday and other natural language time queries.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/pwramsey">@pwramsey&lt;/a> - At the hacker level: hooks. So many cool hooks, and finding them, a bit of an easter egg hunt.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/pwramsey">@pwramsey&lt;/a> - At the user level: the quality and breadth of tsearch still feels radically under appreciated; same for ranges.&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/TomCiopp">@TomCiopp&lt;/a> - PostGIS / PgRouting&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/peterbe">@peterbe&lt;/a> - psql -l&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/jbrancha">@jbrancha&lt;/a> - In psql, setting ‘\x auto’ so that wide table results get displayed vertically!&lt;/li>
&lt;li>&lt;a href="https://www.twitter.com/westermanndanie">@westermanndanie&lt;/a> - &lt;code>\watch&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Well that was quite the list. And I&amp;rsquo;m sure we&amp;rsquo;ve only scratched the surface. Have something not on the list that you feel like classifies as a hidden gem? &lt;a href="https://www.twitter.com/craigkerstiens">Lets hear about it&lt;/a>&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Sourcing developer marketing content</title><link>/2017/12/28/Sourcing-developer-marketing-content/</link><pubDate>Thu, 28 Dec 2017 12:55:56 -0800</pubDate><guid>/2017/12/28/Sourcing-developer-marketing-content/</guid><description>&lt;p>I spend a lot of time with dev tool and data companies. I think I&amp;rsquo;ve more or less banished myself to a life of working in the space, no consumer products for me. In that world a common topic that comes up amongst marketing teams is how do I get my team to contribute to content? Sometimes the person already has an idea of how they want the team to jump onto the bandwagon of their plan, sometimes they&amp;rsquo;re entirely open minded. I won&amp;rsquo;t get into pros and cons of various approaches here, rather after sharing some of my approaches in one on one settings I thought it could be useful to share more broadly here.&lt;/p>
&lt;h3 id="turn-emails-into-blogs" >
&lt;div>
Turn emails into blogs
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m a big fan of high quality content when it comes to developer focused products. Yes, you can publish x vs. y with FUD and get some traction with it. You can publish high level customer stories that don&amp;rsquo;t get down into the details. But publishing high quality deep technical content that other engineers appreciate gives you a huge head start in getting buy in from your customers. The best thing about much of this type of content is you likely already have it sitting within your organization.&lt;/p>
&lt;p>Engineers spend a lot of time being thorough and articulate in their emails to their peers. If you see a well written email from one engineer to the engineers@ list and then others chime in either with questions, follow-up, or praise then it&amp;rsquo;s likely a great candidate for a blog post. We recently had one of these at Citus where another engineer replied with &amp;ldquo;Nice blog post :)&amp;rdquo;, a few weeks later we had &lt;a href="https://www.citusdata.com/blog/2017/12/22/distributed-count-vs-hyperloglog/">a post&lt;/a> for the rest of the world to read.&lt;/p>
&lt;p>The thing about emails though is the engineers won&amp;rsquo;t usually take and turn them into a blog post. Get a technically minded person that likes to write and put some framing around it, pull out relevant details, and collaborate with the engineer. I&amp;rsquo;ve often found going from one of these emails to a fully published blog post can be anywhere from 2-8 hrs (including reviews and edits).&lt;/p>
&lt;h3 id="beginner-mindset-with-tickets" >
&lt;div>
Beginner mindset with tickets
&lt;/div>
&lt;/h3>
&lt;p>As your product people and engineers spend more and more time with the product they become numb to the cool feature from 2 years ago. That initial awe is just expected. Yes there are new advanced features and tech that is being built&amp;hellip; but most of your users aren&amp;rsquo;t the advanced power users. You still need to speak to the people just now onboarding and discovering you.&lt;/p>
&lt;p>The best way to maintain this beginner mindset is to capture the interactions with those that are newer to your product. Over the years I&amp;rsquo;ve made the practice of cataloging support tickets and the type of issue encountered. Any time the same issue is seen several times it becomes a candidate for a blog post or at the very least being clearly documented.&lt;/p>
&lt;h3 id="make-sales-engineering-obsolete" >
&lt;div>
Make sales engineering obsolete
&lt;/div>
&lt;/h3>
&lt;p>Your sales engineers spend weeks with customers helping them implement complex solutions with your product. In a lot of cases they get really good at helping re-implement a similar solution over and over. Similar to your process with support tickets they&amp;rsquo;re a great source to take what they&amp;rsquo;ve done a few times over and turn it into a blog post.&lt;/p>
&lt;p>Usually after the first time implementing they have some ideas but there are rough edges. The second or third time they&amp;rsquo;ve helped a customer implement a particular approach it becomes a candidate for a post.&lt;/p>
&lt;h3 id="training-and-documentation-dont-have-to-be-siloed" >
&lt;div>
Training and Documentation don&amp;rsquo;t have to be siloed
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m a big fan of not doing anything for one reason. You should absolutely document your product, and if you need to do training to support customers go for it. But that doesn&amp;rsquo;t mean those bits of content can&amp;rsquo;t be re-used. Documentation is a great place to take the factual how something works and then give it some narration of the end to end experience in a blog post.&lt;/p>
&lt;h2 id="the-process" >
&lt;div>
The process
&lt;/div>
&lt;/h2>
&lt;p>If you&amp;rsquo;re asking the question how do I get more good content out there, then you&amp;rsquo;re not leveraging the content you&amp;rsquo;re already sitting on top of. Though perhaps equal is getting a process in place. A few tips for that:&lt;/p>
&lt;ul>
&lt;li>Don&amp;rsquo;t blanket ask to a list for volunteers, ask individuals and about specific posts. &lt;em>If you see a great email, respond and ask if you can work with them to get it turned into a blog post&lt;/em>&lt;/li>
&lt;li>You&amp;rsquo;ll need to navigate the process, and make sure to have a process&lt;/li>
&lt;li>Separate messaging/flow from grammar&lt;/li>
&lt;li>My typical process is: outline -&amp;gt; draft -&amp;gt; feedback from 2-3 on draft -&amp;gt; finalize draft -&amp;gt; feedback from 4-5 (often some external parties) -&amp;gt; publish&lt;/li>
&lt;/ul>
&lt;h2 id="whatd-i-miss" >
&lt;div>
What&amp;rsquo;d I miss?
&lt;/div>
&lt;/h2>
&lt;p>Have other tips that are key to the process? Know of other places where content may already exist but isn&amp;rsquo;t being leveraged? Would love to &lt;a href="https://www.twitter.com/craigkerstiens">hear your thoughts&lt;/a>.&lt;/p></description></item><item><title>Guidance on performing retrospectives</title><link>/2017/12/26/Guidance-on-performing-retrospectives/</link><pubDate>Tue, 26 Dec 2017 12:55:56 -0800</pubDate><guid>/2017/12/26/Guidance-on-performing-retrospectives/</guid><description>&lt;p>In my career I&amp;rsquo;ve had to conduct a number of retrospectives. Ahead of them it already sucked, there was an outage at some point, customers were impacted, and it was our fault. Never was it solely on our underlying infrastructure provider (AWS or Heroku), nope the blame was on us and we&amp;rsquo;d failed in some way. And as soon as the incident was resolved, it wasn&amp;rsquo;t time to go home and decompress with a beer, it was time start the process of a retrospective.&lt;/p>
&lt;p>Finding the motivation to get right back to work is tough, but not losing time is important. There is probably a lot out there on retrospectives, and in general I was well rehearsed at them. But since I&amp;rsquo;d not performed a large scale one in a few years I found myself rusty and thought it&amp;rsquo;d be good to share some of our process.&lt;/p>
&lt;h3 id="capture-details-immediately" >
&lt;div>
Capture details immediately
&lt;/div>
&lt;/h3>
&lt;p>It may not be clear if you&amp;rsquo;ve not been involved in many, but a retrospective is more than just a meeting to discuss what happened and how to fix it. It&amp;rsquo;s an overall process, it begins with capturing thorough details of what happened. The start is a timeline. The best thing to do is capture the details while they&amp;rsquo;re fresh. Start with a google doc and simply document the timeline of everything. Capture chat logs that are relevant while they&amp;rsquo;re fresh in history and easy to find.&lt;/p>
&lt;p>The start of an outage likely wasn&amp;rsquo;t the start of the timeline, there may have been something that happened days, weeks, or even years ago. Don&amp;rsquo;t just start from the time things went offline, go back to the causes as much as possible. If code was committed a year ago that was the offender make sure to note that.&lt;/p>
&lt;h3 id="running-the-retrospective-the-meeting-part" >
&lt;div>
Running the retrospective (the meeting part)
&lt;/div>
&lt;/h3>
&lt;p>There are a number of various good practices for running the retrospective itself. There are also a lot of different formats, all valid each with their own pros and cons. You can do with a basic timeline, what went well/didn&amp;rsquo;t, do a &lt;a href="https://en.wikipedia.org/wiki/5_Whys">five whys&lt;/a> analysis. I tend to prefer a clean and dry analysis of timeline, what went well and what didn&amp;rsquo;t and what we&amp;rsquo;re doing about it.&lt;/p>
&lt;p>Some key tips to help a retrospective meeting be productive:&lt;/p>
&lt;ul>
&lt;li>Explicitly set time bounds for each activity ahead of time, more so than maybe any other meeting it&amp;rsquo;s important to get through all your agenda. Hard time limits on the planned items is how you accomplish this.&lt;/li>
&lt;li>Spend at least some time on what went well, retrospectives aren&amp;rsquo;t fun. Spending some time on the good parts of your process and response isn&amp;rsquo;t wasted, just don&amp;rsquo;t be overly self-back-patting (that&amp;rsquo;s not a word but you get it).&lt;/li>
&lt;li>Don&amp;rsquo;t discuss people, or rather don&amp;rsquo;t point fingers. Yes, people will come up, but it&amp;rsquo;s about the technical and process errors not the person that performed them.&lt;/li>
&lt;/ul>
&lt;h3 id="the-important-part" >
&lt;div>
The important part
&lt;/div>
&lt;/h3>
&lt;p>Every step in the retrospective is important, but the goal of them all is to get to how you can improve. With any retrospective there are likely two categories of improvements that will surface. The first is bugs that caused the issue or engineering that could go in place to help with the specific issue. The second are process improvements. If you don&amp;rsquo;t have improvements in both areas then spend more time thinking on the one you&amp;rsquo;re missing.&lt;/p>
&lt;p>Improvements shouldn&amp;rsquo;t be isolated to the exact issue you saw. Yes you may see the exact same issue again, but there is also a lot more you can draw out that helps improve overall quality. It&amp;rsquo;s inevitable you&amp;rsquo;ll see different issues in the future, thinking of how you can improve your systems and processes to catch those future issues is time well spent.&lt;/p>
&lt;h3 id="sharing-the-details" >
&lt;div>
Sharing the details
&lt;/div>
&lt;/h3>
&lt;p>You&amp;rsquo;ve done the hard work in the above, but it&amp;rsquo;s still good to share publicly and transparently. Within your public retrospective I tend to follow:&lt;/p>
&lt;ol>
&lt;li>Apologize, &lt;strong>and mean it&lt;/strong>&lt;/li>
&lt;li>Show a firm understanding of your systems, and communicate the problem. Don&amp;rsquo;t try to be fancy technically, but don&amp;rsquo;t be too highlevel. Think goldilocks.&lt;/li>
&lt;li>Share what you&amp;rsquo;re doing to improve&lt;/li>
&lt;/ol>
&lt;p>&lt;em>Credit to Mark for being the first person I&amp;rsquo;m aware of to lay it out like the above&lt;/em>&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&lt;em>Thanks to &lt;a href="https://www.twitter.com/markimbriaco">Mark Imbriaco&lt;/a>, &lt;a href="https://www.twitter.com/blakegentry">Blake Gentry&lt;/a>, &lt;a href="https://www.twitter.com/danfarina">Daniel Farina&lt;/a>, &lt;a href="https://www.twitter.com/lukasfittl">Lukas Fittl&lt;/a>, &lt;a href="https://www.twitter.com/leinweber">Will Leinweber&lt;/a> for input and feedback along the way.&lt;/em>&lt;/p>
&lt;p>Looking for more resources on the topic? Make sure to check out these two talks:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://www.heavybit.com/library/video/every-minute-counts-coordinating-herokus-incident-response/">Every Minute Counts: Coordinating Heroku&amp;rsquo;s Incident Response&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://vimeo.com/67178303">Monitorama 2013 - Mark Imbriaco&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>Postgres - the non-code bits</title><link>/2017/10/31/Postgres-the-non-code-bits/</link><pubDate>Tue, 31 Oct 2017 12:55:56 -0800</pubDate><guid>/2017/10/31/Postgres-the-non-code-bits/</guid><description>&lt;p>Postgres is an interesting open source project. It&amp;rsquo;s truly one of a kind, it has its own license to prove it as opposed to falling under something like Apache or GPL. The Postgres community structure is something that is pretty well defined if you&amp;rsquo;re involved in the community, but to those outside it&amp;rsquo;s likely a little less clear. In case you&amp;rsquo;re curious to learn more about the community here&amp;rsquo;s a rundown of a few various aspects of it:&lt;/p>
&lt;h3 id="postgresql-license" >
&lt;div>
PostgreSQL License
&lt;/div>
&lt;/h3>
&lt;p>Let&amp;rsquo;s start with the legal part first. &lt;em>First IANAL&lt;/em>. PostgreSQL is under its own license. For those who don&amp;rsquo;t regularly follow software licensing it&amp;rsquo;s extremely liberal and flexible. You can take Postgres, fork it, change it, package it up, and resell it. This is actually one of the reasons you see Postgres at the core of so many other databases like Par Accel, Asterdata, etc. That and that it&amp;rsquo;s such a solid code base that is capable of being extended. &lt;em>I once heard someone describe how they don&amp;rsquo;t really like writing C, but they enjoy writing Postgres C ;)&lt;/em>&lt;/p>
&lt;p>&lt;em>A thing you can&amp;rsquo;t do is profit off the PostgreSQL logo without any approval from the core team.&lt;/em>&lt;/p>
&lt;h3 id="the-people" >
&lt;div>
The people
&lt;/div>
&lt;/h3>
&lt;p>Within the Postgres community there are 2 major sets of people.&lt;/p>
&lt;h3 id="the-core-team" >
&lt;div>
The core team
&lt;/div>
&lt;/h3>
&lt;p>The core team is a smaller team within the Postgres community. The core team is effectively a &lt;a href="https://www.postgresql.org/developer/core/">steering committee&lt;/a> for Postgres. They&amp;rsquo;re responsible for coordinating releases, handling confidential issues (read: security issues), managing permissions around PostgreSQL code and infrastructure, defining policy.&lt;/p>
&lt;p>The core team is a very small list of people, at the moment 5 individuals.&lt;/p>
&lt;h3 id="contributors" >
&lt;div>
Contributors
&lt;/div>
&lt;/h3>
&lt;p>Yes, anyone can contribute to Postgres, and with each release there are a laundry of people that write some code that goes into Postgres. If fact Postgres 10 had &lt;a href="https://www.postgresql.org/docs/current/static/release-10.html#idm46046833759776">325 people&lt;/a> that contributed in some form. That said there is a hierarchy that exists. The two biggest ones are committers and major contributors.&lt;/p>
&lt;p>&lt;strong>Committers&lt;/strong> gain access after years of contributing to Postgres showing sustained commitment to the project. New committers are voted on each year at PgCon which happens in March/April in Ottawa. If you&amp;rsquo;re ever curious for a conference of what&amp;rsquo;s coming and being deep in the internals of Postgres it&amp;rsquo;s one to check out. Once you do gain your commit bit you&amp;rsquo;re expected to contribute every couple of years to the project. And of course there are a &lt;a href="https://wiki.postgresql.org/wiki/Committers">number of qualifications&lt;/a> such as contributing high quality code and perhaps most key is helping review others contributions.&lt;/p>
&lt;p>&lt;strong>Major contributors&lt;/strong> are another notable group. Major contributors don&amp;rsquo;t have full sole commit access, but are held in a higher regard from consistently contributing major features as well as providing review for others.&lt;/p>
&lt;p>&lt;strong>Contributors&lt;/strong> in general are another area worth calling out. While they may not have a flagship feature to their name like the major contributors, Postgres is what it is because of the contributions of everyone.&lt;/p>
&lt;h3 id="postgresql-the-company" >
&lt;div>
PostgreSQL the company
&lt;/div>
&lt;/h3>
&lt;p>Well, it turns out there isn&amp;rsquo;t a company behind Postgres, it&amp;rsquo;s one thing that makes it unique–no one can ever &amp;ldquo;own it&amp;rdquo;. There are some official PostgreSQL non-profits though in particular the US non-profit and the EU non-profit. These non-profits ensure that the core guidelines are enforced and also give coverage for the community to help put on official community conferences. A few of these happen each year which include:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.pgcon.org/2018/">PGCon&lt;/a> - The hackers conference&lt;/li>
&lt;li>&lt;a href="https://2017.postgresopen.org/">PostgresOpen SV&lt;/a> - A consolidation of PostgresOpen and PGConf Silicon Valley&lt;/li>
&lt;li>&lt;a href="https://postgresopen.org/">PGConf EU&lt;/a> - The largest PG European Conference which moves around each year&lt;/li>
&lt;/ul>
&lt;p>If you&amp;rsquo;re looking for a way to support the PostgreSQL non-profit organization I&amp;rsquo;d encourage you to consider joining &lt;a href="https://postgresql.us/">PostgreSQL.us&lt;/a>.&lt;/p>
&lt;h3 id="engaging" >
&lt;div>
Engaging
&lt;/div>
&lt;/h3>
&lt;p>So you want to jump into the community, where do you even start? The first place I&amp;rsquo;d encourage is to subscribe to the &lt;a href="https://www.postgresql.org/list/">mailing list&lt;/a> or check out the &lt;a href="http://postgres-slack.herokuapp.com/">slack channel&lt;/a>. The users mailing is a great one to just jump in and help answer questions and see what people need help with. The hackers list is where you go to get a peek at all the fun debates/discussions/development.&lt;/p>
&lt;p>If you&amp;rsquo;re thinking about contributing it&amp;rsquo;s a good idea to lurk on the hackers list for a bit first. Then when the commitfest comes chip in and help review some patches and do some testing. Oh and of course, you can always blog about what you&amp;rsquo;re doing with Postgres and will aim to get it included into &lt;a href="https://www.postgresweekly.com">Postgres Weekly&lt;/a>.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Dear Postgres</title><link>/2017/10/12/Dear-Postgres/</link><pubDate>Thu, 12 Oct 2017 12:55:56 -0800</pubDate><guid>/2017/10/12/Dear-Postgres/</guid><description>&lt;!-- raw HTML omitted -->
&lt;p>Dear Postgres,&lt;/p>
&lt;p>I&amp;rsquo;ve always felt an affinity for you in my 9 years of working with you. I know others have known you longer, but that doesn&amp;rsquo;t mean they love you more. Years ago when others complained about your rigidness or that you weren&amp;rsquo;t as accommodating as others I found solace in your steadfast values:&lt;/p>
&lt;ol>
&lt;li>Don&amp;rsquo;t lose data&lt;/li>
&lt;li>Adhere to standards&lt;/li>
&lt;li>Move forward with a balancing act between new fads of the day while still continuously improving&lt;/li>
&lt;/ol>
&lt;p>You&amp;rsquo;ve been there and seen it all. Years ago you were being disrupted by XML databases. As companies made heavy investment into what such a document database would do for their organization you proceeded to &amp;ldquo;simply&amp;rdquo; add a datatype that accomplished the same and brought your years of progress along with it.&lt;/p>
&lt;p>In the early years you had the standard format of index &lt;em>b-tree&lt;/em> that most database engines leveraged. Then quietly but confidently you started adding more. Then came K-nearest neighbor, generalized inverted indexes (GIN), and generalized search-tree (GiST), only to be followed by space partitioned GiST and block range indexes (BRIN). Now the only question is which do I use?&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>All the while there was this other camp using for something that felt cool but outside my world: GIS. GIS, geographical information systems, I thought was something only civil engineers used. Then GPS came along, then the iPhone and location based devices came along and suddenly I wanted to find out the nearest path to my Peets, or manage geographical region for my grocery delivery service. PostGIS had been there all along building up this powerful feature set, sadly to this day I still mostly marvel from the sideline at this whole other feature set I long to take advantage of&amp;hellip; &lt;em>one day&amp;hellip; one day&lt;/em>.&lt;/p>
&lt;p>A little over 5 years ago I fell in love with your fastly improving analytical capabilities. No you weren&amp;rsquo;t an MPP system yet, but here came window functions and CTEs, then I almost understood recursive CTEs &lt;em>(still working on that one)&lt;/em>. I can iterate over data in a recursive fashion without PL/PgSQL? Yes please! I only want to use it more.&lt;/p>
&lt;p>And then five years ago, document stores start taking over the world. I feel like I&amp;rsquo;ve seen this story before, wasn&amp;rsquo;t XML going to change the internet? Enter JSON, the JSON datatype, and JSONB. Wow, this is really nice to mix relational, document storage, join against things. I suddenly don&amp;rsquo;t get why more don&amp;rsquo;t take this flexible approach to building on a good foundation and layering on the refinements.&lt;/p>
&lt;p>Extensions! Where have you been all my life? There’s &lt;a href="https://www.citusdata.com">Citus&lt;/a>, and &lt;a href="https://github.com/aggregateknowledge/postgresql-hll">HyperLogLog&lt;/a>, and &lt;a href="https://www.zombodb.com/">ZomboDB&lt;/a>, with each I can add functionality to Postgres without it being limited to the standard release, they can be in C or not. Wait, all along so much has been built on this foundation? PostGIS, full-text search, hstore? I like all those things, why didn&amp;rsquo;t you tell me all along about this foundation? Postgres, I like what I&amp;rsquo;m seeing how you&amp;rsquo;re allowing others to do more without having it be in the core of Postgres. This extension stuff is really kinda cool that it&amp;rsquo;s Postgres and then some, kinda like C and then ++, wait nevermind scratch that analogy.&lt;/p>
&lt;p>Sorry, I&amp;rsquo;ve rambled a bit. You&amp;rsquo;re a little over twenty years old now. I&amp;rsquo;ve known you for nearly ten of those years so I know there&amp;rsquo;s so much about your background I don&amp;rsquo;t know, I hope we get to spend the time together to share it all. This 10 release is really an exciting one to me. We&amp;rsquo;ve spent all this time together and I feel like each passing year the bond grows fonder.&lt;/p>
&lt;p>Now you&amp;rsquo;ve brought me better parallelism so I can further utilize my system resources. I now have partitioning. Thank you! I don&amp;rsquo;t have to roll my own hacks to help age out old data for my time series database. Logical replication will make so many other things possible, such as more online upgrades and integration with other systems.&lt;/p>
&lt;p>Postgres, I just want to say thank you for the past ten years together. Thank you for all you’ve done and for all you’ll continue to do in the future.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Tracking and managing your Postgres connections</title><link>/2017/09/18/postgres-connection-management/</link><pubDate>Mon, 18 Sep 2017 12:55:56 -0800</pubDate><guid>/2017/09/18/postgres-connection-management/</guid><description>&lt;p>Managing connections in Postgres is a topic that seems to come up several times a week in conversations. I&amp;rsquo;ve written some about scaling your connections and the right approach when you truly need a high level of connections, which is to use a connection pooler like pgBouncer. But what do you do before that point and how can you better track what is going on with your connections in Postgres?&lt;/p>
&lt;p>Postgres under the covers has a lot of metadata about both historical and current activity against a system. Within Postgres you can run the following query which will give you a few results:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> &lt;span style="color:#66d9ef">count&lt;/span>(&lt;span style="color:#f92672">*&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> pg_stat_activity
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">GROUP&lt;/span> &lt;span style="color:#66d9ef">BY&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">count&lt;/span> &lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#66d9ef">state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-------+-------------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span> &lt;span style="color:#f92672">|&lt;/span> active
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">69&lt;/span> &lt;span style="color:#f92672">|&lt;/span> idle
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">26&lt;/span> &lt;span style="color:#f92672">|&lt;/span> idle &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#66d9ef">transaction&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">11&lt;/span> &lt;span style="color:#f92672">|&lt;/span> idle &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#66d9ef">transaction&lt;/span> (aborted)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(&lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#66d9ef">rows&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Time: &lt;span style="color:#ae81ff">30&lt;/span>.&lt;span style="color:#ae81ff">337&lt;/span> ms
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Each of these is useful in determining what you should do to better manage your connection count. All of these numbers can be useful to record every say 30 seconds and chart on your own internal monitoring. Lets break down each:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>active&lt;/strong> - This is currently running queries, in a sense this is truly how many connections you may require at a time&lt;/li>
&lt;li>&lt;strong>idle&lt;/strong> - This is where you have opened a connection to the DB (most frameworks do this and maintain a pool of them), but nothing is happening. This is the one area that a connection pooler like pgBouncer can most help.&lt;/li>
&lt;li>&lt;strong>idle in transaction&lt;/strong> - This is where your app has run a &lt;code>BEGIN&lt;/code> but it&amp;rsquo;s now waiting somewhere in a transaction and not doing work.&lt;/li>
&lt;/ul>
&lt;p>For &lt;strong>idle&lt;/strong> as mentioned above it&amp;rsquo;s one that you do want to monitor and if you see a high number here it&amp;rsquo;s worth investing in setting up a pgBouncer.&lt;/p>
&lt;p>For &lt;strong>idle in transaction&lt;/strong> this one is a bit more interesting. Here what you likely want to do when first investigating is get an idea of how old those are. You can do this by querying pg_stat_activity and filtering for where the state is &lt;code>idle in transaction&lt;/code> and checking how old those queries are. For ones that have been running too long you may want to manually kill them.&lt;/p>
&lt;p>If you find that you have some stale transactions hanging around this could be for days, hours, or even just a few minutes you may want to set a default to kill those transactions.&lt;/p>
&lt;p>To help with this Postgres has a nice feature of a &lt;code>statement_timeout&lt;/code>. A statement timeout will automatically kill queries that run longer than the allotted time. You can set this at both a global level and for a specific session. To do this at the database level you&amp;rsquo;d run this with an &lt;code>alter database dbnamehere set statement_timeout = 60000;&lt;/code> which is 60 seconds. To do so during a given session simply run &lt;code>set statment_timeout = 6000000;&lt;/code>.&lt;/p>
&lt;p>For &lt;em>idle in transaction&lt;/em> that have been running too long there is its own setting setting that you can set in a similar fashion &lt;code>idle_in_transaction_session_timeout&lt;/code> (on Postgres 9.6 and up). Setting both &lt;code>statement_timeout&lt;/code> and &lt;code>idle_in_transaction_session_timeout&lt;/code> will help with cancelling long running queries and transactions.&lt;/p>
&lt;p>Keeping your connection limits in check should lead to a much healthier performing database and thus app.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Better database migrations in Postgres</title><link>/2017/09/10/better-postgres-migrations/</link><pubDate>Sun, 10 Sep 2017 12:55:56 -0800</pubDate><guid>/2017/09/10/better-postgres-migrations/</guid><description>&lt;p>As your database grows and scales there are some operations that you need to take more care of than you did when you were just starting. When working with your application in your dev environment you may not be fully aware of the cost of some operations until you run them against production. And at some point most of us have been guilty of it, running some migration that starts at 5 minutes, then 15 minutes in it&amp;rsquo;s still running, and suddenly production traffic is impacted.&lt;/p>
&lt;p>There are two operations that tend to happen quite frequently, each with some straightforward approaches to mitigate having any noticable amount of downtime. Let&amp;rsquo;s look at each of the operations, how they work and then how you can approach them in a safer way.&lt;/p>
&lt;h3 id="adding-new-columns" >
&lt;div>
Adding new columns
&lt;/div>
&lt;/h3>
&lt;p>Adding a new column is actually quite cheap in Postgres. When you do this it updates its underlying tracking of the columns that exist–which is almost instant. The part that becomes expensive is when you have some constraint against the column. A constraint could be a primary or foreign key, or some uniqueness constraint. Here Postgres has to scan through all the records in the table to ensure that it&amp;rsquo;s not being violated. Adding some constraint such as &lt;code>not null&lt;/code> does happen some, but is not the most common cause.&lt;/p>
&lt;p>The most common reason for slowness of adding a new column is that most frameworks make it very simple for you to set a default value for the new column. It&amp;rsquo;s one thing to do this for all new records, but when you do this when an existing table it means the database has to read all the records and re-write them with the new default value attached. This isn&amp;rsquo;t so bad for a table with a few hundred records, but for a few hundred million run it then go get yourself coffee, or lunch, or a 5 course meal because you&amp;rsquo;ll be waiting for a while.&lt;/p>
&lt;p>In short, &lt;code>not null&lt;/code> and setting a default value (on creation) of your new column will cause you pain. The solution is to not do those things. But, what if you want to have a default value and don&amp;rsquo;t want to allow &lt;code>nulls&lt;/code>. There&amp;rsquo;s a few simple steps you can take, by essentially splitting your migration up from 1 step to 4 migrations:&lt;/p>
&lt;ol>
&lt;li>Add your new column &lt;em>that allows nulls&lt;/em>&lt;/li>
&lt;li>Start writing your default value on all new records and updates&lt;/li>
&lt;li>Gradually backfill the default value&lt;/li>
&lt;li>Apply your constraint&lt;/li>
&lt;/ol>
&lt;p>Yes, this is a little more work, but it doesn&amp;rsquo;t impact production in nearly the same magnitude.&lt;/p>
&lt;h3 id="indexes" >
&lt;div>
Indexes
&lt;/div>
&lt;/h3>
&lt;p>Index creation like most DDL operations holds a lock while it&amp;rsquo;s occurring, this means any new data has to wait for the index to be created and then the new writes flow through. Again when firsting creating the table or on a small table this time is not very noticable. On a large database though, you can again wait minutes to possibly even hours. &lt;em>It&amp;rsquo;s a bit ironic when you think about it that adding an index to speed things up can slow things down while it&amp;rsquo;s happening.&lt;/em>&lt;/p>
&lt;p>Postgres of course has the answer for this with &lt;code>CONCURRENT&lt;/code> index creation. What this does is gradually build up the index in the background. You can create your index concurrently with: &lt;code>CREATE INDEX CONCURRENTLY&lt;/code>. As soon as the index is created and available as long as you did what you were hoping to Postgres will swap over to using it on queries.&lt;/p>
&lt;h3 id="a-tool-to-help" >
&lt;div>
A tool to help
&lt;/div>
&lt;/h3>
&lt;p>It&amp;rsquo;s a good practice to understand what is happening when you run a migration and its performance impact. That said you don&amp;rsquo;t have to manage this all on your own. At least for Rails there&amp;rsquo;s a tool to help enforce more of these as you&amp;rsquo;re developing to catch it earlier. &lt;a href="https://github.com/ankane/strong_migrations">Strong migrations&lt;/a> aims to catch many of these expensive operations for you to have your back, if you&amp;rsquo;re on Rails consider giving it a look.&lt;/p>
&lt;p>Have other tools or tips that can help with database migrations in Postgres? &lt;a href="https://www.twitter.com/craigkerstiens">Drop me a note&lt;/a> and I&amp;rsquo;ll work to add them to the list.&lt;/p></description></item><item><title>Postgres backups: Logical vs. Physical an overview</title><link>/2017/09/03/postgres-backups-physical-vs-logical/</link><pubDate>Sun, 03 Sep 2017 12:55:56 -0800</pubDate><guid>/2017/09/03/postgres-backups-physical-vs-logical/</guid><description>&lt;p>It&amp;rsquo;s not a very disputed topic that you should backup your database, and further test your backups. What is a little less discussed, at least for Postgres, is the types of backups that exist. Within Postgres there are two forms of backups and understanding them is a useful foundation for anyone working with Postgres. The two backup types are&lt;/p>
&lt;ol>
&lt;li>Physical: which consist of the actual bytes on disk,&lt;/li>
&lt;li>Logical: which is a more portable format.&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s dig into each a bit more so you can better assess which makes sense for you.&lt;/p>
&lt;h3 id="logical-backups" >
&lt;div>
Logical backups
&lt;/div>
&lt;/h3>
&lt;p>Logical backups are the most well known type within Postgres. This is what you get when you run &lt;code>pg_dump&lt;/code> against a database. There are a number of different formats you can get from &lt;a href="http://postgresguide.com/utilities/backup-restore.html">logical backups&lt;/a> and Postgres does a good job of making it easy to compress and configure this backup how you see fit.&lt;/p>
&lt;p>When a logical backup is run against a database it is not throttled, this introduces a noticable load on your database.&lt;/p>
&lt;p>As it&amp;rsquo;s reading the data from disk and generating (in layman terms) a bunch of SQL &lt;code>INSERT&lt;/code> statements, it has to actually see the data. It&amp;rsquo;s of note that older Postgres databases (read: prior to 9.3) there were no checksums against your database. Checksums are just one tool for you to help check against data corruption. Because a logical dump has to actually read and generate the data to insert it will discover any corruption that exists for you.&lt;/p>
&lt;p>This portable format is also very useful to pull down copies from production to different environments. I.e. if you need a copy of production data down on your local laptop &lt;code>pg_dump&lt;/code> is the way to do it. Logical backups are also database specific, but then allow you to dump only certain tables.&lt;/p>
&lt;p>All in all logical backups bring some good features, but come at two cost:&lt;/p>
&lt;ul>
&lt;li>Load on your system&lt;/li>
&lt;li>The backup contains data as of the time when it ran&lt;/li>
&lt;/ul>
&lt;h3 id="physical-backups" >
&lt;div>
Physical backups
&lt;/div>
&lt;/h3>
&lt;p>Physical backups are another option when it comes to backing up your database. As we mentioned earlier it is the physical bytes on disk. To understand physical backups we need to know a bit more under the covers about how Postgres works.&lt;/p>
&lt;p>Postgres, under the covers, is essentially one giant append only log. When you insert data it gets written to the log known as the write-ahead log (commonly called WAL). When you update data a new record gets written to the WAL. When you delete data a new record gets written to the WAL. Nearly all changes in Postgres including to indexes and otherwise cause an update to the WAL.&lt;/p>
&lt;p>With physical backups what you require to be able to create a restore of your database is two things:&lt;/p>
&lt;ol>
&lt;li>A &lt;code>base backup&lt;/code>, which is a copy of the bytes on disk as of that point and time&lt;/li>
&lt;li>Additional segments of the WAL to put the database in some consistent state.&lt;/li>
&lt;/ol>
&lt;p>A physical backup only requires a small amount of WAL to restore the database to some valid state, &lt;em>but&lt;/em> this also gives you some new flexibility. With a base backup plus WAL you can start to replay transactions up to a specific point in time. This is often how point-in-time recovery is performed within Postgres. If you accidentally drop a table, yes&amp;hellip; it happens, you can:&lt;/p>
&lt;ol>
&lt;li>Find a base backup before you dropped the table&lt;/li>
&lt;li>Restore that base backup&lt;/li>
&lt;li>Replay wal segments up to roughly that time just before you dropped the table.&lt;/li>
&lt;/ol>
&lt;p>&lt;em>If you&amp;rsquo;re considering setting up physical backups, consider using a tool like &lt;a href="https://www.citusdata.com/blog/2017/08/18/introducing-wal-g-faster-restores-for-postgres/">WAL-G&lt;/a> to help.&lt;/em>&lt;/p>
&lt;h3 id="logical-vs-physical-which-to-choose" >
&lt;div>
Logical vs. Physical which to choose
&lt;/div>
&lt;/h3>
&lt;p>Both are useful and provide different benefits. At smaller scale, say under 100 GB of data logical backups via &lt;code>pg_dump&lt;/code> are something you should absolutely be doing. Because backups happen quickly on smaller databases you may be able to get out without functionality like point-in-time recovery. At larger scale, as you approach 1 TB physical backups start to become your only option. Because of the load introduced by logical backups and the time lapse between capturing them they become less suitable for production.&lt;/p>
&lt;p>Hopefully this primer helps provide a high level overview of the two primary types of backups that exist as options for Postgres. Of course there is much deeper you can go on each, but consider ensuring you have at least one of the two if not both in place. Oh and make sure to test them, an un-tested backup isn&amp;rsquo;t a backup at all.&lt;/p></description></item><item><title>Postgres Open Silicon Valley line-up: First take</title><link>/2017/07/01/postgresopen-sv-line-up/</link><pubDate>Sat, 01 Jul 2017 12:55:56 -0800</pubDate><guid>/2017/07/01/postgresopen-sv-line-up/</guid><description>&lt;p>This year Postgres open and PGConf SV have combined to great a bigger and better conference right in downtown San Francisco. &lt;em>I&amp;rsquo;m obviously biased as I&amp;rsquo;m one of the co-chairs, and I know every conference organizer says picking the talks was hard, but I&amp;rsquo;m especially excited for the line-up this year&lt;/em>. The hard part for me is going to be which talks do I miss out on because I&amp;rsquo;m sitting in the other session that&amp;rsquo;s ongoing. You can see the full list of &lt;a href="https://postgresql.us/events/sessions/pgopen2017/">talk and tutorial sessions&lt;/a>, but I thought it&amp;rsquo;d be fun to do a rundown of some of my favorites.&lt;/p>
&lt;h3 id="how-postgres-could-index-itselfhttpspostgresqluseventssessionspgopen2017session399-how-postgres-could-index-itself" >
&lt;div>
&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/399-how-postgres-could-index-itself/">How Postgres could index itself&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/399-how-postgres-could-index-itself/">Postgres indexing itself&lt;/a> has long been on my wishlist. &lt;a href="https://www.twitter.com/akane">Andrew Kane&lt;/a> from Instacart, and creator of &lt;a href="https://github.com/ankane/pghero/">PgHero&lt;/a> has bottled up many learnings into a new tool: &lt;a href="https://medium.com/@ankane/introducing-dexter-the-automatic-indexer-for-postgres-5f8fa8b28f27">Dexter&lt;/a>. I suspect we&amp;rsquo;ll get a look at all that went into this, how it works, and how you can leverage it to have a more automatically tuned database.&lt;/p>
&lt;h3 id="scaling-a-saas-application-beyond-a-single-postgres-with-citushttpspostgresqluseventssessionspgopen2017session376-scaling-a-saas-application-beyond-a-single-postgres-with-citus" >
&lt;div>
&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/376-scaling-a-saas-application-beyond-a-single-postgres-with-citus/">Scaling a SaaS Application Beyond a Single Postgres with Citus&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Migration talks are all to common, from Postgres to MySQL from MySQL to Postgres, or from &lt;a href="https://containership.engineering/dynamodb-to-postgres-why-and-how-aa891681af4d">Dynamo to Postgres&lt;/a>. But this one is a little different flavor from Postgres to sharded Postgres with &lt;a href="https://www.citusdata.com">Citus&lt;/a>. Sharding into a distributed system of course brings new things to consider and think about, and &lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/376-scaling-a-saas-application-beyond-a-single-postgres-with-citus/">here you&amp;rsquo;ll learn about them&lt;/a> from first hand experience so hopefully you can avoid mistakes yourself.&lt;/p>
&lt;h3 id="concurrency-deep-divehttpspostgresqluseventssessionspgopen2017session374-concurrency-deep-dive" >
&lt;div>
&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/374-concurrency-deep-dive/">Concurrency Deep Dive&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/374-concurrency-deep-dive/">This one&lt;/a> looks to be a great under the hood look as well as likely very practical. It&amp;rsquo;ll cover MVCC which is really at so much of the core of how Postgres works, but then bring it up to what it means for things like locks. Best of all, this one like so many others comes with lots of real world experience from Segment.&lt;/p>
&lt;h3 id="postgres-window-magichttpspostgresqluseventssessionspgopen2017session364-postgres-window-magic" >
&lt;div>
&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/364-postgres-window-magic/">Postgres window magic&lt;/a>
&lt;/div>
&lt;/h3>
&lt;!-- raw HTML omitted -->
&lt;h3 id="running-postgresql--instagramhttpspostgresqluseventssessionspgopen2017session371-running-postgresql-instagram" >
&lt;div>
&lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/371-running-postgresql-instagram/">Running PostgreSQL @ Instagram&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Instagram is well known as one of the largest apps in the world. They optimized and changed their setup multiple times and probably scaled in about every way possible. &lt;a href="https://postgresql.us/events/sessions/pgopen2017/session/371-running-postgresql-instagram/">Here we get to learn&lt;/a> about all the various things you need in running at a truly astonishing scale.&lt;/p>
&lt;h3 id="many-many-morehttpspostgresqluseventssessionspgopen2017" >
&lt;div>
&lt;a href="https://postgresql.us/events/sessions/pgopen2017/">Many many more&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Of course there&amp;rsquo;s many more. Talks range from looks at new features, to how certain companies are using Postgres. We&amp;rsquo;ve got companies like Instacart and Instagram as mentioned giving talks, to Postgres core committers. Whether you want to learn about the inner workings of Postgres (which often hurts my brain) to how you can simply speed up your app you should find something you like, as long as you like Postgres that is. Take a look at the &lt;a href="https://postgresql.us/events/sessions/pgopen2017/">full list of sessions&lt;/a> and we hope to see you there.&lt;/p></description></item><item><title>Working with time in Postgres</title><link>/2017/06/08/working-with-time-in-postgres/</link><pubDate>Thu, 08 Jun 2017 12:55:56 -0800</pubDate><guid>/2017/06/08/working-with-time-in-postgres/</guid><description>&lt;p>A massive amount of reporting queries, whether really intensive data analysis, or just basic insights into your business involving looking at data over a certain time period. Postgres has really rich support for dealing with time out of the box, something that&amp;rsquo;s often very underweighted when dealing with a database. Sure, if you have a time-series database it&amp;rsquo;s implied, but even then how flexible and friendly is it from a query perspective? With Postgres there&amp;rsquo;s a lot of key items available to you, let&amp;rsquo;s dig in at the things that make your life easier when querying.&lt;/p>
&lt;h3 id="date-math" >
&lt;div>
Date math
&lt;/div>
&lt;/h3>
&lt;p>The most common thing I find myself doing is looking at users that have done something within some specific time window. If I&amp;rsquo;m executing this all from my app I can easily inject specific dates, but Postgres makes this really easy for you. Within Postgres you have a type called an interval that is some window of time. And fortunately Postgres takes care of the heavy lifting of how might something translate to or from hours/seconds/milliseconds/etc. Here&amp;rsquo;s just a few examples of things you could do with interals:&lt;/p>
&lt;ul>
&lt;li>&amp;lsquo;1 day&amp;rsquo;::interval&lt;/li>
&lt;li>&amp;lsquo;5 days&amp;rsquo;::interval&lt;/li>
&lt;li>&amp;lsquo;1 week&amp;rsquo;::interval&lt;/li>
&lt;li>&amp;lsquo;30 days&amp;rsquo;::interval&lt;/li>
&lt;li>&amp;lsquo;1 month&amp;rsquo;::interval&lt;/li>
&lt;/ul>
&lt;p>&lt;em>A note that if you&amp;rsquo;re looking to remove something like a full month, you actually want to use 1 month instead of trying to calculate yourself.&lt;/em>&lt;/p>
&lt;p>With a given interval you can easily shift some window of time, such as finding all users that have signed up for your service within the past week:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> &lt;span style="color:#f92672">*&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> users
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">WHERE&lt;/span> created_at &lt;span style="color:#f92672">&amp;gt;=&lt;/span> now() &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#e6db74">&amp;#39;1 week&amp;#39;&lt;/span>::interval
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="date-functions" >
&lt;div>
Date functions
&lt;/div>
&lt;/h3>
&lt;p>Date math makes it pretty easy for you to go and find some specific set of data that applies, but what do you do when you want a broader report around time? There&amp;rsquo;s a few options here. One is to leverage the built-in Postgres functions that help you work with dates and times. &lt;code>date_trunc&lt;/code> is one of the most used ones that will truncate a date down to some interval level. Here you can use the same general values as the above, but simply pass in the type of interval it will be. So if we wanted to find the count of users that signed up per week:&lt;/p>
&lt;pre tabindex="0">&lt;code>SELECT date_trunc(&amp;#39;week&amp;#39;, created_at),
count(*)
FROM users
GROUP BY 1
ORDER BY 1 DESC;
&lt;/code>&lt;/pre>&lt;p>This gives us a nice roll-up of how many users signed up each week. What&amp;rsquo;s missing here though is if you have a week that has no users. In that case because no users signed up there is no count of 0, it just simply doesn&amp;rsquo;t exist. If you did want something like this you could generate some range of time and then do a cross join with it against users to see which week they fell into. To do this first you&amp;rsquo;d generate a series of dates:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> generate_series(&lt;span style="color:#e6db74">&amp;#39;2017-01-01&amp;#39;&lt;/span>::date, now()::date, &lt;span style="color:#e6db74">&amp;#39;1 week&amp;#39;&lt;/span>::interval) weeks
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then we&amp;rsquo;re going to join this against the actual users table and check that the &lt;code>created_at&lt;/code> falls within the right range.&lt;/p>
&lt;pre tabindex="0">&lt;code>with weeks as (
select week
from generate_series(&amp;#39;2017-01-01&amp;#39;::date, now()::date, &amp;#39;1 week&amp;#39;::interval) week
)
SELECT weeks.week,
count(*)
FROM weeks,
users
WHERE users.created_at &amp;gt; weeks.week
AND users.created_at &amp;lt;= (weeks.week - &amp;#39;1 week&amp;#39;::interval)
GROUP BY 1
ORDER BY 1 DESC;
&lt;/code>&lt;/pre>&lt;h3 id="timestamp-vs-timestamptz" >
&lt;div>
Timestamp vs. Timestamptz
&lt;/div>
&lt;/h3>
&lt;p>What about storing the times themselves? Postgres has two types of timestamps. It has a generic timestamp and one with timezone embedded in it. In most cases you should generally opt for timestamptz. Why not timestamp? What happens if you move a server, or your server somehow swaps its configuration. Or perhaps more practically what about daylight savings time? In general you might think that you can simply just put in the time as you see it, but when different countries around the world observe things like daylight savings time differently it introduces complexities into your application.&lt;/p>
&lt;p>With timestamptz it&amp;rsquo;ll be aware of the extra parts of your timezone as it comes in. Then when you query from one timezone that accounts for daylights savings you&amp;rsquo;re all covered. There&amp;rsquo;s a &lt;a href="http://phili.pe/posts/timestamps-and-time-zones-in-postgresql/">number of articles&lt;/a> that cover a bit more in depth on the logic between timestamp and timestamp with timezone, so if you&amp;rsquo;re curious I encourage you to check them out, but by default you mostly just need to use timestamptz.&lt;/p>
&lt;h3 id="more" >
&lt;div>
More
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s a number of other functions and capabilities when it comes to dealing with time in Postrges. You can &lt;code>extract&lt;/code> various parts of a timesetamp or interval such as hour of the day or the month. You can grab the day of the week with &lt;code>dow&lt;/code>. And one of my favorites which is when we celebrate happy hour at Citus, there&amp;rsquo;s a literal for UTC 00:00:00 00:00:00 which is &lt;a href="https://www.postgresql.org/message-id/20050124200645.GA6126%40winnie.fuhr.org">&lt;code>allballs()&lt;/code>&lt;/a>. If you need to work with dates and times in Postgres I encourage you to check out the &lt;a href="https://www.postgresql.org/docs/current/static/functions-datetime.html">docs&lt;/a> before you try to re-write something of your own, chances are what you need may already be there.&lt;/p></description></item><item><title>Why use Postgres (Updated for last 5 years)</title><link>/2017/04/30/why-postgres-five-years-later/</link><pubDate>Sun, 30 Apr 2017 12:55:56 -0800</pubDate><guid>/2017/04/30/why-postgres-five-years-later/</guid><description>&lt;p>Five years ago &lt;a href="http://www.craigkerstiens.com/2012/04/30/why-postgres/">I wrote a post&lt;/a> that got some good attention on why you should use Postgres. Almost a year later I &lt;a href="http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2/">added a bunch of things&lt;/a> I missed. Many of those items bear repeating, and I&amp;rsquo;ll recap a few of those in the latter half of this post. But in the last 4-5 years there&amp;rsquo;s been a lot of improvements and more reasons added to the list of why you should use Postgres. Here&amp;rsquo;s the rundown of the things that make Postgres a great database you should consider using.&lt;/p>
&lt;h3 id="datatypes-including-jsonb-and-range-types" >
&lt;div>
Datatypes, including JSONB and range types
&lt;/div>
&lt;/h3>
&lt;p>Postgres has long had an open and friendly attitude for adding datatypes. It&amp;rsquo;s had arrays, geospatical and more for some time. A few years ago it got two datatypes worth thinking about using:&lt;/p>
&lt;h4 id="jsonb" >
&lt;div>
JSONB
&lt;/div>
&lt;/h4>
&lt;p>JSONB is a binary representation of JSON. It&amp;rsquo;s capable of being indexed on with &lt;code>GIN&lt;/code> and &lt;code>GIST&lt;/code> index types. You can also query into your full JSON document for quick lookups.&lt;/p>
&lt;h4 id="range-types" >
&lt;div>
Range types
&lt;/div>
&lt;/h4>
&lt;p>While it didn&amp;rsquo;t arrive to the same fame as JSONB, &lt;a href="https://wiki.postgresql.org/images/7/73/Range-types-pgopen-2012.pdf">range types&lt;/a> can be especially handy if they&amp;rsquo;re what you need. Within a single column you can have a range from one value to another–this is especially helpful for time ranges. If you&amp;rsquo;re building a calendaring application or often have a from and to of timestamps then range types can let you put that in a single column. The real benefit is that you can then have constraints that certain time stamps can&amp;rsquo;t overlap or other constraints that may make sense for your application.&lt;/p>
&lt;h3 id="extensions" >
&lt;div>
Extensions
&lt;/div>
&lt;/h3>
&lt;p>It&amp;rsquo;d be hard to talk about Postgres without all the ecosystem around it. Extensions are increasingly quite key when it comes to the community and growth of Postgres. Extensions allow you to hook into Postgres very natively without requiring them to be committed back to the core of Postgres. This means they can add rich functionality without being tied to a Postgres release and review cycle. Some great examples of this are:&lt;/p>
&lt;h4 id="citus" >
&lt;div>
Citus
&lt;/div>
&lt;/h4>
&lt;p>&lt;a href="https://www.citusdata.com">Citus&lt;/a> (who I work for) turns Postgres into a distributed database allowing you to easily shard your database across multiple nodes. To your application it still looks like a single database, but then under the covers it&amp;rsquo;s spread across multiple physical machines and Postgres instances.&lt;/p>
&lt;h4 id="hyperloglog" >
&lt;div>
HyperLogLog
&lt;/div>
&lt;/h4>
&lt;p>This is a personal favorite of mine that allows you to easily have close-enough distinct counts pre-aggregated, but then also do various operations on them across days such as unions, intersections, and more. &lt;a href="https://www.citusdata.com/blog/2017/04/04/distributed_count_distinct_with_postgresql/">HyperLogLog and other sketch algorithms&lt;/a> can be extremely common across large datasets and distributed systems, but it&amp;rsquo;s especially exciting to find them pretty close to out of the box in Postgres.&lt;/p>
&lt;h4 id="postgis" >
&lt;div>
PostGIS
&lt;/div>
&lt;/h4>
&lt;p>PostGIS isn&amp;rsquo;t new, but it&amp;rsquo;s worth highlighting again. It&amp;rsquo;s commonly regarded as the most advanced geospatial database. PostGIS adds new advanced geospatial datatypes, operators, and makes it easy to do many of the location based activities you need if you&amp;rsquo;re dealing with mapping or routing.&lt;/p>
&lt;h3 id="logical-replication" >
&lt;div>
Logical replication
&lt;/div>
&lt;/h3>
&lt;p>For many years the biggest knock against Postgres was the difficulty in setting up replication. Originally this was any form of replication, but then streaming replication came along (this is streaming of the binary WAL or write-ahead-log format). Tools like &lt;a href="https://github.com/wal-e/wal-e">wal-e&lt;/a> help leverage much of the Postgres mechanisms for things like disaster recovery.&lt;/p>
&lt;p>Then we had the foundation for logical replication in recent releases, though it still required an &lt;a href="https://github.com/2ndQuadrant/pglogical">extension&lt;/a> to Postgres so it wasn&amp;rsquo;t 100% out of the box. And, then finally we got full logical replication. Logical replication allows the sending of more or less actual commands, this means you could replicate only certain commands or certain tables.&lt;/p>
&lt;h3 id="scale" >
&lt;div>
Scale
&lt;/div>
&lt;/h3>
&lt;p>In addition to all of the usability featuers we&amp;rsquo;ve seen Postgres continue to get better and better at &lt;a href="https://www.slideshare.net/fuzzycz/postgresql-performance-improvements-in-95-and-96">performance&lt;/a>. In particular we now have the foundations for &lt;a href="https://www.postgresql.org/docs/current/static/parallel-query.html">parallelism&lt;/a> and on some queries you&amp;rsquo;ll see much better performance. Then if you need even greater scale than single node Postgres (such as 122 or 244 GB of RAM on RDS or Heroku) you have options like &lt;a href="https://www.citusdata.com">Citus&lt;/a> which was mentioned earlier that can help you scale out.&lt;/p>
&lt;h3 id="richer-indexing" >
&lt;div>
Richer indexing
&lt;/div>
&lt;/h3>
&lt;p>Postgres already had some pretty powerful indexing before with &lt;a href="https://www.postgresql.org/docs/9.5/static/textsearch-indexes.html">GIN and GiST&lt;/a>, those are now useful for JSONB. But we&amp;rsquo;ve also seen the arrival of KNN indexes and Sp-GiST and have even more on the way.&lt;/p>
&lt;h3 id="upsert" >
&lt;div>
Upsert
&lt;/div>
&lt;/h3>
&lt;p>Upsert was a work in progress for several years. It was one of those features that most people hacked around with &lt;a href="http://www.craigkerstiens.com/2013/11/18/best-postgres-feature-youre-not-using/">CTEs&lt;/a>, but that could create race conditions. It was also one of the few features MySQL had over Postgres. And just over a year ago we got &lt;a href="http://www.craigkerstiens.com/2015/05/08/upsert-lands-in-postgres-9.5/">official upsert&lt;/a> support.&lt;/p>
&lt;h3 id="foreign-data-wrappers" >
&lt;div>
Foreign Data Wrappers
&lt;/div>
&lt;/h3>
&lt;p>Okay, yes foreign data wrappers did exist many years ago. If you&amp;rsquo;re not familiar with foreign data wrappers, they allow you map an external data system to tables directly in Postgres. This means could could for example interact and query your &lt;a href="http://www.craigkerstiens.com/2012/10/18/connecting_to_redis_from_postgres/">Redis&lt;/a> database from directly in Postgres with SQL. They&amp;rsquo;ve continued to be improved more and more from what we had over 5 years ago. In particular we got support for write-able foreign data wrappers, meaning you can write data to other systems from directly in Postgres. There&amp;rsquo;s also now an official Postgres FDW which comes out of the box with Postgres and it by itself is quite useful when querying across various Postgres instances.&lt;/p>
&lt;h3 id="much-more" >
&lt;div>
Much more
&lt;/div>
&lt;/h3>
&lt;p>And if you missed the &lt;a href="http://www.craigkerstiens.com/2012/04/30/why-postgres/">earlier editions&lt;/a> of this, please feel free to &lt;a href="http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2/">check them out&lt;/a>. The cliff notes of them include:&lt;/p>
&lt;ul>
&lt;li>Window functions&lt;/li>
&lt;li>Functions&lt;/li>
&lt;li>Custom languages (PLV8 anyone?)&lt;/li>
&lt;li>NoSQL datatypes&lt;/li>
&lt;li>Custom functions&lt;/li>
&lt;li>Common table expressions&lt;/li>
&lt;li>Concurrent index creation&lt;/li>
&lt;li>Transactional DDL&lt;/li>
&lt;li>Foreign Data Wrappers&lt;/li>
&lt;li>Conditional and functional indexes&lt;/li>
&lt;li>Listen/Notify&lt;/li>
&lt;li>Table inheritance&lt;/li>
&lt;li>Per transaction synchronous replication&lt;/li>
&lt;/ul>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Getting started with JSONB in Postgres</title><link>/2017/03/12/getting-started-with-jsonb-in-postgres/</link><pubDate>Sun, 12 Mar 2017 12:55:56 -0800</pubDate><guid>/2017/03/12/getting-started-with-jsonb-in-postgres/</guid><description>&lt;p>JSONB is an awesome datatype in Postgres. I find myself using it on a weekly basis these days. Often in using some API (such as &lt;a href="https://www.clearbit.com">clearbit&lt;/a>) I&amp;rsquo;ll get a JSON response back, instead of parsing that out into a table structure it&amp;rsquo;s really easy to throw it into a JSONB then query for various parts of it.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re not familiar with JSONB, it&amp;rsquo;s a binary representation of JSON in your database. You can read a bit more about it vs. JSON &lt;a href="https://www.citusdata.com/blog/2016/07/14/choosing-nosql-hstore-json-jsonb/">here&lt;/a>.&lt;/em>&lt;/p>
&lt;p>In working with JSONB here&amp;rsquo;s a few quick tips to get up and running with it even faster:&lt;/p>
&lt;h3 id="indexing" >
&lt;div>
Indexing
&lt;/div>
&lt;/h3>
&lt;p>For the most part you don&amp;rsquo;t have to think to much about this. With Postgres powerful indexing types you can add one index and have everything within the JSON document, all the keys and all the values, automatically indexed. The key here is to add a &lt;code>GIN&lt;/code> index. Once this is done queries should be much faster where you&amp;rsquo;re searching for some value:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">INDEX&lt;/span> idx_data &lt;span style="color:#66d9ef">ON&lt;/span> companies &lt;span style="color:#66d9ef">USING&lt;/span> GIN (&lt;span style="color:#66d9ef">data&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="querying" >
&lt;div>
Querying
&lt;/div>
&lt;/h3>
&lt;p>Querying is a little bit more work, but once you get the basics it can be pretty straight forward. There&amp;rsquo;s a few new operators you&amp;rsquo;ll want to quickly ramp up on and from there querying becomes easy.&lt;/p>
&lt;p>For the most basic part you now have an operator so traverse down the various keys. First let&amp;rsquo;s get some idea of what the JSON looks like so we can have something to work with. Here&amp;rsquo;s a sample set of data that we get back from Clearbit:&lt;/p>
&lt;pre tabindex="0">&lt;code>{
&amp;#34;domain&amp;#34;: &amp;#34;citusdata.com&amp;#34;,
&amp;#34;company&amp;#34;: {
&amp;#34;id&amp;#34;: &amp;#34;b1ff2bdf-0d8d-4d6d-8bcc-313f6d45996a&amp;#34;,
&amp;#34;url&amp;#34;: &amp;#34;http:\/\/citusdata.com&amp;#34;,
&amp;#34;logo&amp;#34;: &amp;#34;https:\/\/logo.clearbit.com\/citusdata.com&amp;#34;,
&amp;#34;name&amp;#34;: &amp;#34;Citus Data&amp;#34;,
&amp;#34;site&amp;#34;: {
&amp;#34;h1&amp;#34;: null,
&amp;#34;url&amp;#34;: &amp;#34;http:\/\/citusdata.com&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Citus Data&amp;#34;,
},
&amp;#34;tags&amp;#34;: [
&amp;#34;SAAS&amp;#34;,
&amp;#34;Enterprise&amp;#34;,
&amp;#34;B2B&amp;#34;,
&amp;#34;Information Technology &amp;amp; Services&amp;#34;,
&amp;#34;Technology&amp;#34;,
&amp;#34;Software&amp;#34;
],
&amp;#34;domain&amp;#34;: &amp;#34;citusdata.com&amp;#34;,
&amp;#34;twitter&amp;#34;: {
&amp;#34;id&amp;#34;: &amp;#34;304455171&amp;#34;,
&amp;#34;bio&amp;#34;: &amp;#34;Builders of Citus, the extremely scalable PostgreSQL database.&amp;#34;,
&amp;#34;site&amp;#34;: &amp;#34;https:\/\/t.co\/hKpZjIy7Ej&amp;#34;,
&amp;#34;avatar&amp;#34;: &amp;#34;https:\/\/pbs.twimg.com\/profile_images\/630900468995108865\/GJFCCXrv_normal.png&amp;#34;,
&amp;#34;handle&amp;#34;: &amp;#34;citusdata&amp;#34;,
&amp;#34;location&amp;#34;: &amp;#34;San Francisco, CA&amp;#34;,
&amp;#34;followers&amp;#34;: 3770,
&amp;#34;following&amp;#34;: 570
},
&amp;#34;category&amp;#34;: {
&amp;#34;sector&amp;#34;: &amp;#34;Information Technology&amp;#34;,
&amp;#34;industry&amp;#34;: &amp;#34;Internet Software &amp;amp; Services&amp;#34;,
&amp;#34;subIndustry&amp;#34;: &amp;#34;Internet Software &amp;amp; Services&amp;#34;,
&amp;#34;industryGroup&amp;#34;: &amp;#34;Software &amp;amp; Services&amp;#34;
},
&amp;#34;emailProvider&amp;#34;: false
}
}
&lt;/code>&lt;/pre>&lt;p>Sorry it&amp;rsquo;s a bit long, but it gives us a good example to work with.&lt;/p>
&lt;h3 id="basic-lookups" >
&lt;div>
Basic lookups
&lt;/div>
&lt;/h3>
&lt;p>Now let&amp;rsquo;s query something fairly basic, the domain:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">#&lt;/span> &lt;span style="color:#66d9ef">SELECT&lt;/span> &lt;span style="color:#66d9ef">data&lt;/span>&lt;span style="color:#f92672">-&amp;gt;&lt;/span>&lt;span style="color:#e6db74">&amp;#39;domain&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> companies
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">WHERE&lt;/span> &lt;span style="color:#66d9ef">domain&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;citusdata.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">LIMIT&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">?&lt;/span>&lt;span style="color:#66d9ef">column&lt;/span>&lt;span style="color:#f92672">?&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-----------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#e6db74">&amp;#34;citusdata.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>-&amp;gt;&lt;/code> is likely the first operator you&amp;rsquo;ll use in JSONB. It&amp;rsquo;s helpful to traverse the JSON. Though of you&amp;rsquo;re looking to get the value as text you&amp;rsquo;ll actually want to use &lt;code>-&amp;gt;&amp;gt;&lt;/code>. Instead of giving you some quoted response back or JSON object you&amp;rsquo;re going to get it as text which will be a bit cleaner:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">#&lt;/span> &lt;span style="color:#66d9ef">SELECT&lt;/span> &lt;span style="color:#66d9ef">data&lt;/span>&lt;span style="color:#f92672">-&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#e6db74">&amp;#39;domain&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> companies
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">WHERE&lt;/span> &lt;span style="color:#66d9ef">domain&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;citusdata.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">LIMIT&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">?&lt;/span>&lt;span style="color:#66d9ef">column&lt;/span>&lt;span style="color:#f92672">?&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-----------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> citusdata.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="filtering-for-values" >
&lt;div>
Filtering for values
&lt;/div>
&lt;/h3>
&lt;p>Now with something like clearbit you may want to filter out for only certain type of companies. We can see in the example data that there&amp;rsquo;s a bunch of tags. If we wanted to find only companies that had the tag B2B we could use the &lt;code>?&lt;/code> operator once we&amp;rsquo;ve targetted down to that part of the JSON. The &lt;code>?&lt;/code> operator will tell us if some part of JSON has a top level key:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> &lt;span style="color:#f92672">*&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> companies
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">WHERE&lt;/span> &lt;span style="color:#66d9ef">data&lt;/span>&lt;span style="color:#f92672">-&amp;gt;&lt;/span>&lt;span style="color:#e6db74">&amp;#39;company&amp;#39;&lt;/span>&lt;span style="color:#f92672">-&amp;gt;&lt;/span>&lt;span style="color:#e6db74">&amp;#39;tags&amp;#39;&lt;/span> &lt;span style="color:#f92672">?&lt;/span> &lt;span style="color:#e6db74">&amp;#39;B2B&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="jsonb-but-pretty" >
&lt;div>
JSONB but pretty
&lt;/div>
&lt;/h3>
&lt;p>In querying JSONB you&amp;rsquo;ll typically get a nice compressed set of JSON back. While this is all fine if you&amp;rsquo;re putting it into your application, if you&amp;rsquo;re manually debugging and testing things you probably want something a bit more readable. Of course Postgres has your back here and you can wrap your JSONB with a pretty print function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> jsonb_pretty(&lt;span style="color:#66d9ef">data&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> companies;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="much-more" >
&lt;div>
Much more
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s a lot more in the &lt;a href="https://www.postgresql.org/docs/9.5/static/functions-json.html">docs&lt;/a> that you can find handy for the specialized cases when you need them. &lt;code>jsonb_each&lt;/code> will expand a JSONB document into individual rows. So if you wanted to count the number of occurences of every tag for a company, this would help. Want to parse out a JSONB to a row/record in Postgres there&amp;rsquo;s &lt;code>jsonb_to_record&lt;/code>. The docs are your friends for about everything you want to do but hopefully these few steps help kick start things if you want to get started with &lt;code>JSONB&lt;/code>.&lt;/p></description></item><item><title>Simple but handy Postgres features</title><link>/2017/01/08/simple-but-handy-postgresql-features/</link><pubDate>Sun, 08 Jan 2017 12:55:56 -0800</pubDate><guid>/2017/01/08/simple-but-handy-postgresql-features/</guid><description>&lt;p>It seems each week when I&amp;rsquo;m reviewing data with someone a feature comes up that they had no idea existed within Postgres. In an effort to continue documenting many of the features and functionality that are useful, here&amp;rsquo;s a list of just a few that you may find handy the next time your working with your data.&lt;/p>
&lt;h3 id="psql-and-e" >
&lt;div>
Psql, and \e
&lt;/div>
&lt;/h3>
&lt;p>This one I&amp;rsquo;ve &lt;a href="http://www.craigkerstiens.com/2013/02/13/How-I-Work-With-Postgres/">covered before&lt;/a>, but it&amp;rsquo;s worth restating. Psql is a great editor that already comes with Postgres. If you&amp;rsquo;re comfortable on the CLI you should consider giving it a try. You can even setup you&amp;rsquo;re own &lt;code>.psqlrc&lt;/code> for it so that it&amp;rsquo;s well customized to your liking. In particular turning &lt;code>\timing&lt;/code> on is especially useful. But even with all sorts of customization if you&amp;rsquo;re not aware that you can use your preferred editor by using &lt;code>\e&lt;/code> then you&amp;rsquo;re missing out. This will allow you to open up the last run query, edit it, save–and then it&amp;rsquo;ll run for you. Vim, Emacs, even Sublime text works just take your pick by setting your &lt;code>$EDITOR&lt;/code> variable.&lt;/p>
&lt;h3 id="watch" >
&lt;div>
Watch
&lt;/div>
&lt;/h3>
&lt;p>Ever sit at a terminal running a query over and over to see if something on your system changed? If you&amp;rsquo;re debugging something whether locally or even live in production, watching data change can be key to figuring out. Instead of re-running your query you could simply use the &lt;code>\watch&lt;/code> command in Postgres, this will re-run your query automatically every few seconds.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> now() &lt;span style="color:#f92672">-&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> query_start,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">state&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> query
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> pg_stat_activity
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>watch
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="jsonb-pretty-print" >
&lt;div>
JSONB pretty print
&lt;/div>
&lt;/h3>
&lt;p>I love &lt;a href="https://www.citusdata.com/blog/2016/07/14/choosing-nosql-hstore-json-jsonb/">JSONB&lt;/a> as a datatype. Yes, in cases it won&amp;rsquo;t be the &lt;a href="http://blog.heapanalytics.com/when-to-avoid-jsonb-in-a-postgresql-schema/">optimal&lt;/a> for performance (though at times it can be perfectly fine). If I&amp;rsquo;m hitting some API that returns a ton of data, I&amp;rsquo;m usually not using all of it right away. But, you never know when you&amp;rsquo;ll want to use the rest of it. I use &lt;a href="https://www.clearbit.com">Clearbit&lt;/a> this way today, and for safety sake I save all the JSON result instead of de-normalizing it. Unfortunately, when you query this in Postgres you get one giant compressed text of JSON. Yes, you could pipe out to something like jq, or you could simply use Postgres built in function to make it legible:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SELECT&lt;/span> jsonb_pretty(clearbit_response)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">FROM&lt;/span> lookup_data;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jsonb_pretty
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-------------------------------------------------------------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;person&amp;#34;&lt;/span>: &lt;span style="color:#960050;background-color:#1e0010">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;063f6192-935b-4f31-af6b-b24f63287a60&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;bio&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">null&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;geo&amp;#34;&lt;/span>: &lt;span style="color:#960050;background-color:#1e0010">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;lat&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">37&lt;/span>.&lt;span style="color:#ae81ff">7749295&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;lng&amp;#34;&lt;/span>: &lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">122&lt;/span>.&lt;span style="color:#ae81ff">4194155&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;city&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;San Francisco&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;state&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;California&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;country&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;United States&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;stateCode&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;CA&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;countryCode&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;US&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#960050;background-color:#1e0010">}&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#960050;background-color:#1e0010">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="importing-my-data-into-google" >
&lt;div>
Importing my data into Google
&lt;/div>
&lt;/h3>
&lt;p>This one isn&amp;rsquo;t Postgres specific, but I use it on a weekly basis and it&amp;rsquo;s key for us at &lt;a href="https://www.citusdata.com">Citus&lt;/a>. If you use something like Heroku Postgres, dataclips is an extremely handy feature that lets you have a real-time view of a query and the results of it, including an anonymous URL you can it for it. At Citus much like we did at Heroku Postgres we have a dashboard in google sheets which pulls in this data in real-time. To do this simple select a cell then put in: &lt;code>=importdata(&amp;quot;pathtoyourdataclip.csv&amp;quot;)&lt;/code>. Google will import any data using this as long as it&amp;rsquo;s in CSV form. It&amp;rsquo;s a great lightweight way to build out a dashboard for your business without rolling your own complicated dashboarding or building out a complex ETL pipeline.&lt;/p>
&lt;p>I&amp;rsquo;m sure I&amp;rsquo;m missing a ton of the smaller features that you use on a daily basis. Let me know &lt;a href="https://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a> the ones I forgot that you feel should be listed.&lt;/p></description></item><item><title>Syncing from Postgres to Salesforce - Data Mappings</title><link>/2016/11/23/syncing-from-postgres-to-salesforce-part-1/</link><pubDate>Wed, 23 Nov 2016 12:55:56 -0800</pubDate><guid>/2016/11/23/syncing-from-postgres-to-salesforce-part-1/</guid><description>&lt;p>For the second time now I&amp;rsquo;ve had to implement a system that syncs from my system of record into Salesforce.com, the first at Heroku and now at &lt;a href="https://www.citusdata.com">Citus Data&lt;/a>. The case here is pretty simple, I have a software-as-a-service, B2B product. It&amp;rsquo;s a homegrown application in these cases in Ruby, but could be Python, .Net, any language of your choosing. The problem is I don&amp;rsquo;t want to have to be rebuilding my own CRM, reporting, etc. on top of all of my internal database. And as soon as you&amp;rsquo;re at some reasonable size (sales guy of 1 or more) you need to be able to provide insights on what&amp;rsquo;s in that system of record database to others.&lt;/p>
&lt;p>While my tooling isn&amp;rsquo;t a full fledged product by any means, here&amp;rsquo;s a bit of how I&amp;rsquo;ve developed this process a few times over and some of the annoying bits of code to help get you started. In this post I&amp;rsquo;ll walk through some of the basic datatypes, then we&amp;rsquo;ll follow-up with the overall architecture and tweaks you need to make to Salesforce, and finally we&amp;rsquo;ll provide some example code to help you create this setup yourself.&lt;/p>
&lt;h3 id="leads-contacts-accounts-oh-my" >
&lt;div>
Leads, Contacts, Accounts oh my
&lt;/div>
&lt;/h3>
&lt;p>Despite being some of the largest as-a-service vendors in the world, Salesforce is still primarily setup for traditional high touch sales. What this means is some of the data you&amp;rsquo;ll commonly have, or in this case not have, can make it difficult to figure out what maps from your internal system to Salesforce. Within Salesforce there&amp;rsquo;s really 4 key data models you&amp;rsquo;re going to care about.&lt;/p>
&lt;h3 id="lead-vs-contact" >
&lt;div>
Lead vs. Contact
&lt;/div>
&lt;/h3>
&lt;p>In every as a service product you&amp;rsquo;ll have some user that creates and account which usually has an email address tied to it. This seems simple enough to load up to Salesforce as there is a clear email field. Within Salesforce there are two key data types which have a default field for this lead and contact, in Salesforce terms a lead is someone &lt;a href="https://success.salesforce.com/answers?id=90630000000gvTiAAI">considering doing business with you&lt;/a>, a contact someone who more so is doing business with you. If you have a freemium or timed trial model you might think to start classifying everyone that they&amp;rsquo;re a lead. Then, when they convert to a paying customer you turn them into a contact.&lt;/p>
&lt;p>If you&amp;rsquo;re anything like me, in running your SaaS business, you want a sign-up process that&amp;rsquo;s frictionless. This means give me an email address, password, and you&amp;rsquo;re off and running. Salesforce immediately starts to breakdown a bit in this regard. First you&amp;rsquo;re required for both lead and contact to provide a first and last name. In my case I do ask for name, and do a little bit of work on the code side to get values into both. You&amp;rsquo;ll see later that our process does result in some regular cleanup work needing to happen, but in our case we&amp;rsquo;re optimizing to get them signed up more than capturing every detail perfectly about them from the start.&lt;/p>
&lt;p>Leads are even more broken than contacts though. Leads require you to enter a company. While you may be able to just drop a company form field onto your sign-up page you&amp;rsquo;re likely to end up with junk data at least, if not actually driving some sign-ups away. Some of my favorite pieces of junk data I&amp;rsquo;ve seen users enter for company name: &amp;ldquo;pissed off developer&amp;rdquo;, &amp;ldquo;Acme Inc.&amp;rdquo;, and the all too common &amp;ldquo;Test Co.&amp;rdquo;. In reality these are often real developers, with real problems, and real budget, they just don&amp;rsquo;t want to share details before they&amp;rsquo;re ready.&lt;/p>
&lt;p>So in this case the TLDR; is that leads require:&lt;/p>
&lt;ul>
&lt;li>First name&lt;/li>
&lt;li>Last name&lt;/li>
&lt;li>Email&lt;/li>
&lt;li>Company name&lt;/li>
&lt;/ul>
&lt;p>This results in contacts being a more favorable datatype because it only requires:&lt;/p>
&lt;ul>
&lt;li>First name&lt;/li>
&lt;li>Last name&lt;/li>
&lt;li>Email&lt;/li>
&lt;/ul>
&lt;h3 id="accounts-vs-opportunities" >
&lt;div>
Accounts vs. Opportunities
&lt;/div>
&lt;/h3>
&lt;p>We have in some ways a similar but different dichotomy with Accounts and Opportunities as we did Leads and Contacts. Though this one can often map a bit more cleanly than we saw with leads. From a &lt;a href="https://success.salesforce.com/answers?id=90630000000gnvcAAA">pretty straight forward definition&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>Account - A business entity. Contacts work for Accounts.&lt;/li>
&lt;li>Opportunities - Sales events related to an Account and one or more Contacts.&lt;/li>
&lt;/ul>
&lt;p>This again can become problematic if you have no notion of Accounts at all in your system of record. Though if you are building a B2B application there is a good chance you may have something that makes sense. If you let uses free-form enter this instead of AT&amp;amp;T they may put &amp;ldquo;interactive team&amp;rdquo;, but you at least have some logical team that in their mind they roll up to.&lt;/p>
&lt;p>Opportunities is a much harder one in the SaaS world. In traditional marketing you have your standard stages of MQL (Marketing Qualified Lead), progressing to SQL (Sales Qualified Lead), etc. that you expect these potential customers to flow through. In the as-a-service world you may have people look from afar for weeks, then suddenly sign-up and give you a credit card and start paying within minutes. While there is still steps the customer may go through before buying you often have less insight into these. How you decide to structure your opportunities flow is entirely up to you. In my case I tend to opt to still have htem, but they&amp;rsquo;re an exception basis where a salesperson is actively engaged vs. the other 90%+ of fully self-service customers.&lt;/p>
&lt;p>Shifting back a little bit on accounts. The key with accounts is that if you have some notion of an team or org within your system of record then it makes sense to have that same structure setup in Salesforce. The most basic of this might be an idea of &amp;ldquo;Account owner&amp;rdquo; and &amp;ldquo;Team members&amp;rdquo;. You may have a person in there just for billing, an admin, and then users. Even if you don&amp;rsquo;t want to recreate the entire structure at least having all the contacts tied to the account is critical. I can&amp;rsquo;t count the number of times I&amp;rsquo;ve seen teams setup a &amp;ldquo;&lt;a href="mailto:billing@mycompany.com">billing@mycompany.com&lt;/a>&amp;rdquo; email, seen people try to interact with that email when in reality they wanted to be talking to &amp;ldquo;&lt;a href="mailto:jane@mycompany.com">jane@mycompany.com&lt;/a>&amp;rdquo; who logged in yesterday.&lt;/p>
&lt;h3 id="in-summary" >
&lt;div>
In summary
&lt;/div>
&lt;/h3>
&lt;p>For the most part Salesforce doesn&amp;rsquo;t quite let you map to what many of you&amp;rsquo;ll want to do in terms of mapping your data from your system of record to Salesforce. Expect to have to contort a bit and likely pump Salesforce with some garbage data. In general you&amp;rsquo;ll want to skip leads and go straight for contacts as contacts don&amp;rsquo;t require the same restrictions. Tying contacts to an account is the right level anyway, and from there up to you on how you&amp;rsquo;ll more manage the opportunities.&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>Open DNS for when DNS outages occur</title><link>/2016/10/21/opendns/</link><pubDate>Fri, 21 Oct 2016 12:55:56 -0800</pubDate><guid>/2016/10/21/opendns/</guid><description>&lt;p>Open DNS is a DNS resolver that caches records beyond their TTL if the upstream DNS server cannot be found. In cases like today&amp;rsquo;s major outage it can be handy to swap your DNS settings out for this, or it may be worth using as a standard default. Resolution may be a bit slow as it will try to see if the upstream server cannot be found, but it at least can get you back to a working state.&lt;/p>
&lt;p>If you know what you&amp;rsquo;re doing then all you need to do is configure your DNS settings to: &lt;code>208.67.220.220&lt;/code> and &lt;code>208.67.222.222&lt;/code>.&lt;/p>
&lt;p>If you need a little more guidance you can go into your System Preferences on Mac, select Network, then Advanced and finally the DNS tab. You should set it up to look as follows:&lt;/p>
&lt;p>&lt;img src="https://d3vv6lp55qjaqc.cloudfront.net/items/0c2T1M251T0D3r1D2Q3x/Network.png?X-CloudApp-Visitor-Id=e4475d145dcf11ebcffabf840edcc11f&amp;amp;v=cd767ce0" alt="DNS Configuration">&lt;/p></description></item><item><title>A tour of Postgres' Foreign Data Wrappers</title><link>/2016/09/11/a-tour-of-fdws/</link><pubDate>Sun, 11 Sep 2016 12:55:56 -0800</pubDate><guid>/2016/09/11/a-tour-of-fdws/</guid><description>&lt;p>SQL can be a powerful language for reporting. Whether you&amp;rsquo;re just exploring some data, or generating reports that show &lt;a href="/2014/02/26/Tracking-MoM-growth-in-SQL/">month over month revenue growth&lt;/a> it&amp;rsquo;s the &lt;a href="https://www.amazon.com/SQL-Relational-Theory-Write-Accurate/dp/1491941170/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1473612603&amp;amp;sr=1-1&amp;amp;keywords=sql+relational&amp;amp;tag=mypred-20">lingua franca&lt;/a> for data analysis. But, your data isn&amp;rsquo;t always in a SQL database, even then if you&amp;rsquo;re using Postgres you can still likely use SQL to analyze, query, even joing with that data. Foreign data wrappers have been around for years in Postgres, but are continuing to mature and be a great option for joining disparate systems.&lt;/p>
&lt;h3 id="overview-of-foreign-data-wrappers" >
&lt;div>
Overview of foreign data wrappers
&lt;/div>
&lt;/h3>
&lt;p>If you&amp;rsquo;re unfamiliar, foreign data wrappers, or FDW, allow you to connect from within Postgres to a remote system. Then you can query them from directly within Postgres. While there is an official Postgres FDW that ships with Postgres itself, that allows you to connect from one Postgres DB to another, there&amp;rsquo;s also a broad community of others.&lt;/p>
&lt;p>At the core of it Postgres provides certain APIs under the covers which each FDW extension can implement. This can include the ability to map SQL to whatever makes sense for a given system, push down various operators like where clauses, and as of Postgres 9.3 can even write data.&lt;/p>
&lt;p>To setup a FDW you first would install the extension, then provide the connection to the remote system, setup your schema/tables, and then you&amp;rsquo;re off to the races–or well ready to query. If you&amp;rsquo;ve got more than 2-3 databases or systems in your infrastructure, you&amp;rsquo;ll often benefit from FDWs as opposed to introducing a heavyweight ETL pipeline. Don&amp;rsquo;t mistake FDWs as the most performant method for joining data, but they are often the developer time efficient means of joining these data sets.&lt;/p>
&lt;p>Let&amp;rsquo;s look at just a few of the more popular and interesting ones.&lt;/p>
&lt;h3 id="postgres-fdw" >
&lt;div>
Postgres FDW
&lt;/div>
&lt;/h3>
&lt;p>The Postgres one is the easiest to get started with. First you&amp;rsquo;ll just enable it with &lt;code>CREATE EXTENSION&lt;/code>, then you&amp;rsquo;ll setup your remote server:&lt;/p>
&lt;pre>&lt;code>CREATE EXTENSION postgres_fdw;
CREATE SERVER core_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'foo', dbname 'core_db', port '5432');
&lt;/code>&lt;/pre>
&lt;p>Then you&amp;rsquo;ll create the user that has access to that database:&lt;/p>
&lt;pre>&lt;code>CREATE USER MAPPING FOR bi SERVER core OPTIONS (user 'bi', password 'secret');
&lt;/code>&lt;/pre>
&lt;p>Finally, create your foreign table:&lt;/p>
&lt;pre>&lt;code>CREATE FOREIGN TABLE core_users (
id integer NOT NULL,
username varchar(255),
password varchar(255),
last_login timestamptz
)
SERVER core;
&lt;/code>&lt;/pre>
&lt;p>Now you&amp;rsquo;ll see a new table in the database you created this in called &lt;code>core_users&lt;/code>. You can query this table just like you&amp;rsquo;d expect:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM core_users
WHERE last_login &amp;gt;= now() - '1 day'::interval;
&lt;/code>&lt;/pre>
&lt;p>You can also join against local tables, such as getting all the invoices for users that have logged in within the last month:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM invoices, core_users
WHERE core_users.last_login &amp;gt;= now() - '1 month::interval'
AND invoices.user_id = core_users.id
&lt;/code>&lt;/pre>
&lt;p>Hopefully this is all straight forward enough, but let&amp;rsquo;s also take a quick look at some of the other interesting ones:&lt;/p>
&lt;h3 id="mysql-fdw" >
&lt;div>
MySQL FDW
&lt;/div>
&lt;/h3>
&lt;p>For MySQL you&amp;rsquo;ll also have to &lt;a href="https://github.com/EnterpriseDB/mysql_fdw">download it&lt;/a> and install it as well since it doesn&amp;rsquo;t ship directly with Postgres. This should be fairly straight forward:&lt;/p>
&lt;pre>&lt;code>$ export PATH=/usr/local/pgsql/bin/:$PATH
$ export PATH=/usr/local/mysql/bin/:$PATH
$ make USE_PGXS=1
$ make USE_PGXS=1 install
&lt;/code>&lt;/pre>
&lt;p>Now that you&amp;rsquo;ve built it you&amp;rsquo;d follow a very similar path to setting it up as we did for Postgres:&lt;/p>
&lt;pre>&lt;code>CREATE EXTENSION mysql_fdw;
CREATE SERVER mysql_server
FOREIGN DATA WRAPPER mysql_fdw
OPTIONS (host '127.0.0.1', port '3306');
CREATE USER MAPPING FOR postgres
SERVER mysql_server
OPTIONS (username 'foo', password 'bar');
CREATE FOREIGN TABLE core_users (
id integer NOT NULL,
username varchar(255),
password varchar(255),
last_login timestamptz
)
SERVER mysql_server;
&lt;/code>&lt;/pre>
&lt;p>But MySQL while different than Postgres is also more similar in SQL support than say a more exotic NoSQL store. How well do they work as a foreign data wrapper? Let&amp;rsquo;s look at our next one:&lt;/p>
&lt;h3 id="mongodb" >
&lt;div>
MongoDB
&lt;/div>
&lt;/h3>
&lt;p>First you&amp;rsquo;ll go through much of the &lt;a href="https://github.com/EnterpriseDB/mongo_fdw">same setup&lt;/a> as you did for MySQL. The one major difference though is in the final step to setup the &lt;code>table&lt;/code>. Since a table doesn&amp;rsquo;t quite map in the same way with Mongo you have the ability to set two items: 1. the database and 2. the collection name.&lt;/p>
&lt;pre>&lt;code>CREATE FOREIGN TABLE core_users(
_id NAME,
user_id int,
user_username text,
user_last_login timestamptz)
SERVER mongo_server
OPTIONS (database 'db', collection 'users');
&lt;/code>&lt;/pre>
&lt;p>With this you can do some basic level of filtering as well:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM core_users
WHERE user_last_login &amp;gt;= now() - '1 day'::interval;
&lt;/code>&lt;/pre>
&lt;p>You can also write and delete data as well now just using SQL:&lt;/p>
&lt;pre>&lt;code>DELETE FROM core_users
WHERE user_id = 100;
&lt;/code>&lt;/pre>
&lt;p>Of course just putting SQL on top of Mongo doesn&amp;rsquo;t mean you get all the flexibility of analysis that you&amp;rsquo;d have directly within Postgres, this does go a long way towards allowing you to analyze data that lives across two different systems.&lt;/p>
&lt;h3 id="many-more" >
&lt;div>
Many more
&lt;/div>
&lt;/h3>
&lt;p>A few years ago there were some key ones which already made FDWs useful. Now there&amp;rsquo;s a rich list covering probably every system you could want. Whether it&amp;rsquo;s &lt;a href="http://www.craigkerstiens.com/2012/10/18/connecting_to_redis_from_postgres/">Redis&lt;/a>, a simple &lt;a href="https://www.postgresql.org/docs/9.5/static/file-fdw.html">CSV&lt;/a> one, or something newer like &lt;a href="https://github.com/snaga/monetdb_fdw">MonetDB&lt;/a> chances are you can find an &lt;a href="https://wiki.postgresql.org/wiki/Foreign_data_wrappers#NoSQL_Database_Wrappers">FDW&lt;/a> for the system you need that makes your life easier.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Five mistakes beginners make when working with databases</title><link>/2016/06/07/five-mistakes-databases/</link><pubDate>Tue, 07 Jun 2016 12:55:56 -0800</pubDate><guid>/2016/06/07/five-mistakes-databases/</guid><description>&lt;p>When you start out as a developer there&amp;rsquo;s an overwhelming amount of things to grasp. First there&amp;rsquo;s the language itself, then all the quirks of the specific framework you&amp;rsquo;re using,and after that (or maybe before) we&amp;rsquo;ll throw front-end development into the mix, and somewhere along the line you have to decide to store your data somewhere.&lt;/p>
&lt;p>Early on, with so many things to quickly master, the database tends to be an after-though in application design (perhaps because it doesn&amp;rsquo;t make an impact to end user experience). As a result there&amp;rsquo;s a number of bad practices that tend to get picked up when working with databases, here&amp;rsquo;s a rundown of just a few.&lt;/p>
&lt;h3 id="1-storing-images" >
&lt;div>
1. Storing images
&lt;/div>
&lt;/h3>
&lt;p>Images don&amp;rsquo;t belong in your database. Just because you can do something, it doesn&amp;rsquo;t mean you should.Images take up a massive amount of space in databases, and slow applications down by unnecessarily eating your database&amp;rsquo;s IO resources. The most common way this mistake occurs is when new developers base64 encode an image and store it in a database large text/blob field.&lt;/p>
&lt;p>The better approach is to upload your images directly to a service like Amazon S3, then store the image URL (hosted by Amazon) in your database as a text field. This way, each time you need to load an image, you need to simply output the image URL into a valid &lt;code>&amp;lt;img&amp;gt;&lt;/code> tag. This will greatly improve website responsiveness, and generally help scale web applications.&lt;/p>
&lt;h3 id="2-limitoffset" >
&lt;div>
2. Limit/Offset
&lt;/div>
&lt;/h3>
&lt;p>Pagination is extremely common in a number of applications.As soon as you start to learn SQL, the most straight-forward way to handle pagination is to &lt;code>ORDER BY&lt;/code> some column then &lt;code>LIMIT&lt;/code> the number of results returned, and for each extra page you&amp;rsquo;ll &lt;code>OFFSET&lt;/code> by so many records. This all seems entirely logical, until you realize at any moderate scale:&lt;/p>
&lt;ol>
&lt;li>The load this exerts on your database will be painful.&lt;/li>
&lt;li>It isn&amp;rsquo;t deterministic, should records change as the user flips between pages.&lt;/li>
&lt;/ol>
&lt;p>The unfortunate part is: pagination is quite complex, and there isn&amp;rsquo;t a one-size-fits-all solution. For more information on solving pagination problems, you can check &lt;a href="https://www.citusdata.com/blog/1872-joe-nelson/409-five-ways-paginate-postgres-basic-exotic">out numerous options&lt;/a>&lt;/p>
&lt;h3 id="3-integer-primary-keys" >
&lt;div>
3. Integer primary keys
&lt;/div>
&lt;/h3>
&lt;p>The default for almost all ORMs when creating a primary key is to create a serial field. This is a sequence that auto-increments and then you use that number as your primary key. This seems straight forward as an admin, because you can browse from /users/1 to /users/2, etc. And for most applications this can often be fine. And for most applications, this is fine. But, you&amp;rsquo;ll soon realize as you start to scale that integers primary keys can be exhausted, and are not ideal for large-scale systems. Further you&amp;rsquo;re reliant on that single system generating your keys. If a time comes when you have to scale the pain here will be huge. The better approach is to start &lt;a href="https://til.hashrocket.com/posts/31a5135e19-generate-a-uuid-in-postgresql">taking advantage of UUIDs&lt;/a> from the start.&lt;/p>
&lt;p>&lt;em>There&amp;rsquo;s also the bonus advantage of not secretly showcasing how many users/listings/whatever the key references directly to users on accident.&lt;/em>&lt;/p>
&lt;h3 id="4-default-values-on-new-columns" >
&lt;div>
4. Default values on new columns
&lt;/div>
&lt;/h3>
&lt;p>No matter how long you&amp;rsquo;ve been at it you won&amp;rsquo;t get the perfect schema on day 1. It&amp;rsquo;s better to think of database schemas as continuously evolving documents. Fortunately, it&amp;rsquo;s easy to add a column to your database, but: it&amp;rsquo;s also easy to do this in a horrific way. By default, if you just add a column it&amp;rsquo;ll generally allow NULL values. This operation is fast, but most applications don&amp;rsquo;t truly want null values in their data, instead they want to set the default value.&lt;/p>
&lt;p>If you do add a column with a default value on the table, this will trigger a full re-write of your table. &lt;em>Note: this is very bad for any sizable table on an application.&lt;/em> Instead, it&amp;rsquo;s far better to allow null values at first so the operation is instant, then set your default, and then, with a background process go and retroactively update the data.&lt;/p>
&lt;p>This is more complicated than it should be, but fortunately there are some &lt;a href="http://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/">handy guides&lt;/a> to help.&lt;/p>
&lt;h3 id="5-over-normalization" >
&lt;div>
5. Over normalization
&lt;/div>
&lt;/h3>
&lt;p>As you start to learn about normalization it feels like the right thing to do. You create a &lt;code>posts&lt;/code> table, which contains &lt;code>authors&lt;/code>, and each post belongs in a category. So you create a &lt;code>categories&lt;/code> table, and then you create a join table &lt;code>post_categories&lt;/code>. At the real root of it there&amp;rsquo;s not anything fundamentally wrong with normalizing your data, but at a certain point there are diminishing returns.&lt;/p>
&lt;p>In the above case categories could very easily just be an array of varchar fields on a post. Normalization makes plenty of sense, but thinking through it a bit more every time you have a many to many table and wondering if you really need a full table on both sides is worth giving a second thought.&lt;/p>
&lt;p>&lt;em>Edit: It&amp;rsquo;s probably worth saying that under-normalization is also a problem as well. There isn&amp;rsquo;t a one size fits all here. In general there are times where it does make sense to have a completely de-normalized and a completely normalized approach. As &lt;a href="https://twitter.com/fuzzychef/status/740248400243785728">@fuzzychef&lt;/a> described: &amp;ldquo;use an appropriate amount of normalization i.e. The goldilocks principle&amp;rdquo;&lt;/em>&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>When I asked about this on twitter I got a pretty great responses, but they were all over the map. From the basics of never looking at the queries the ORM is generating, to much more advanced topics such as isolation levels. The one I didn&amp;rsquo;t hit on that does seem to be a worthwhile one for anyone building a real world app is indexing. Knowing how &lt;a href="http://www.craigkerstiens.com/2012/10/01/understanding-postgres-performance/">indexing works&lt;/a>, and understanding &lt;a href="http://www.craigkerstiens.com/2013/05/30/a-collection-of-indexing-tips/">what indexes&lt;/a> you need to create is a critical part of getting good database performance. There&amp;rsquo;s a number of posts on indexing that teach the basics, as well as &lt;a href="http://www.craigkerstiens.com/2013/01/10/more-on-postgres-performance/">practical steps&lt;/a> for analyzing performance with Postgres.&lt;/p>
&lt;p>In general, I encourage you to treat the database as another tool in your chest as opposed to a necessary evil, but hopefully, the above tips will at least prevent you from making some initial mistakes as you dig in as a beginner.&lt;/p>
&lt;p>&lt;em>Special thanks to &lt;a href="https://twitter.com/mdeggies">@mdeggies&lt;/a> and &lt;a href="https://twitter.com/rdegges">@rdegges&lt;/a> for the initial conversation to spark the post at PyCon.&lt;/em>&lt;/p></description></item><item><title/><link>/2016/02/28/</link><pubDate>Sun, 28 Feb 2016 12:55:56 -0800</pubDate><guid>/2016/02/28/</guid><description>&lt;p>&lt;em>&lt;strong>Notice&lt;/strong>: Much of this post still applies, but now applies more directly to Citus. Since this post originally published, pg_shard is now deprecated. You can find some further guidance for sharding on the Citus blog and docs&lt;/em>&lt;/p>
&lt;p>Back in 2012 I wrote an overview of database sharding. Since then I&amp;rsquo;ve had a few questions about it, which have really increased in frequency over the last two months. As a result I thought I&amp;rsquo;d do a deeper dive with some actual hands on for sharding. Though for this hands on, because I do value my time I&amp;rsquo;m going to take advantage of &lt;code>pg_shard&lt;/code> rather than creating mechanisms from scratch.&lt;/p>
&lt;p>For those unfamiliar &lt;a href="https://github.com/citusdata/pg_shard/">pg_shard&lt;/a> is an open source extension from &lt;a href="http://citusdata.com">Citus data&lt;/a> who has a commerical product that you can think of is pg_shard++ (and probably much more). Pg_shard adds a little extra to let data automatically distribute to other Postgres tables (logical shards) and Postgres databases/instances (physical shards) thus letting you outgrow a single Postgres node pretty simply.&lt;/p>
&lt;p>Alright, enough talk about it, let&amp;rsquo;s get things up and running.&lt;/p>
&lt;h3 id="build-install" >
&lt;div>
Build, install
&lt;/div>
&lt;/h3>
&lt;p>&lt;em>The rest assume you have Postgres.app, version 9.5 setup and are on a Mac, much of these steps could be easily adapted for other Postgres installs or OSes.&lt;/em>&lt;/p>
&lt;p>PATH=/Applications/Postgres.app/Contents/Versions/latest/bin/:$PATH make&lt;/p>
&lt;p>sudo PATH=/Applications/Postgres.app/Contents/Versions/latest/bin/:$PATH make install&lt;/p>
&lt;p>cp /Applications/Postgres.app/Contents/Versions/9.5/share/postgresql/postgresql.conf.sample /Applications/Postgres.app/Contents/Versions/9.5/share/postgresql/postgresql.conf.sample&lt;/p>
&lt;p>Edit your &lt;code>postgresql.conf&lt;/code>:&lt;/p>
&lt;pre>&lt;code>#shared_preload_libraries = ''
&lt;/code>&lt;/pre>
&lt;p>TO:&lt;/p>
&lt;pre>&lt;code>shared_preload_libraries = 'pg_shard'
&lt;/code>&lt;/pre>
&lt;p>Then create a file in &lt;code>/Users/craig/Library/Application\ Support/Postgres/var-9.5/pg_worker_list.conf&lt;/code> where &lt;code>craig&lt;/code> is your username:&lt;/p>
&lt;pre>&lt;code># hostname port-number
localhost 5432
localhost 5433
&lt;/code>&lt;/pre>
&lt;p>You&amp;rsquo;ll also need to create a new Postgres instance:&lt;/p>
&lt;pre>&lt;code>initdb -D /Users/craig/Library/Application\ Support/Postgres/var-9.5-2
&lt;/code>&lt;/pre>
&lt;p>Then edit that &lt;code>postgresql.conf&lt;/code> inside that newly created folder with two main edits:&lt;/p>
&lt;pre>&lt;code>port = 5432
&lt;/code>&lt;/pre>
&lt;p>To&lt;/p>
&lt;pre>&lt;code>port = 5433
&lt;/code>&lt;/pre>
&lt;p>Finally setup our database then start it up:&lt;/p>
&lt;pre>&lt;code>createdb instagram
postgres -D /Users/craig/Library/Application\ Support/Postgres/var-9.5-2
&lt;/code>&lt;/pre>
&lt;h3 id="setup" >
&lt;div>
Setup
&lt;/div>
&lt;/h3>
&lt;p>Now you should have two running instances of Postgres, now let&amp;rsquo;s finally turn on the pg_shard extension, create some tables and see what we have. First connect to your main running Postgres instance, so in this case the the instagram database we first created &lt;code>psql instagram&lt;/code>, then let&amp;rsquo;s set things up:&lt;/p>
&lt;pre>&lt;code>CREATE EXTENSION pg_shard;
CREATE TABLE customer_reviews (customer_id TEXT NOT NULL, review_date DATE, review_rating INTEGER, product_id CHAR(10));
CREATE TABLE
Time: 4.734 ms
SELECT master_create_distributed_table(table_name := 'customer_reviews', partition_column := 'customer_id');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards(table_name := 'customer_reviews', shard_count := 16, replication_factor := 2);
master_create_worker_shards
-----------------------------
(1 row)
&lt;/code>&lt;/pre>
&lt;h3 id="understanding-and-using" >
&lt;div>
Understanding and using
&lt;/div>
&lt;/h3>
&lt;p>So that was a lot of initial setup. But now we have an application that could in theory scale to a shared application across 16 instances. If you want a refresher, there&amp;rsquo;s a difference between physical and logical shards. In this case above we have 16 logical ones and it&amp;rsquo;s replicated across 2 physical Postgres instances albeit on the same instance.&lt;/p>
&lt;p>Alright so a little more poking under the covers to see what happened before we actually start doing something with our data. If you&amp;rsquo;re still connected go ahead and run &lt;code>\d&lt;/code>, and you should see:&lt;/p>
&lt;pre>&lt;code> List of relations
Schema | Name | Type | Owner
--------+------------------------+-------+-------
public | customer_reviews | table | craig
public | customer_reviews_10000 | table | craig
public | customer_reviews_10001 | table | craig
public | customer_reviews_10002 | table | craig
public | customer_reviews_10003 | table | craig
public | customer_reviews_10004 | table | craig
public | customer_reviews_10005 | table | craig
public | customer_reviews_10006 | table | craig
public | customer_reviews_10007 | table | craig
public | customer_reviews_10008 | table | craig
public | customer_reviews_10009 | table | craig
public | customer_reviews_10010 | table | craig
public | customer_reviews_10011 | table | craig
public | customer_reviews_10012 | table | craig
public | customer_reviews_10013 | table | craig
public | customer_reviews_10014 | table | craig
public | customer_reviews_10015 | table | craig
(17 rows)
&lt;/code>&lt;/pre>
&lt;p>You can see that under the cover there&amp;rsquo;s a lot more &lt;code>customer_reviews&lt;/code> tables, in reality you don&amp;rsquo;t have to think about these or do anything with them. But just for reference they&amp;rsquo;re just plain ole Postgres tables under the cover. You can query them and poke at the data. The now mystical &lt;code>customer_reviews&lt;/code> will actually roll up the data across all your logical shards (tables) and physical shards (spanning across machines).&lt;/p>
&lt;p>&lt;em>It&amp;rsquo;s also of note that in production you might not actually use your primary DB as a worker, we did this more for expediency in setting it up on a local Mac. More typically you&amp;rsquo;d have 2 or more workers which are not the same a the primary, these were the ports we setup in our &lt;code>pg_worker_list.conf&lt;/code>.&lt;/em> A common setup would look something more like:&lt;/p>
&lt;p>&lt;img src="https://s3.amazonaws.com/f.cl.ly/items/3T2N2Q1K041g0a0L0j03/Untitled.png?v=7df00f6b" alt="">&lt;/p>
&lt;p>So now start inserting away:&lt;/p>
&lt;pre>&lt;code>INSERT INTO customer_reviews (customer_id, review_rating) VALUES ('HN802', 5);
INSERT INTO customer_reviews (customer_id, review_rating) VALUES ('FA2K1', 10);
&lt;/code>&lt;/pre>
&lt;p>For extra homework on your own you can now go and poke at where the underlying data actually surfaced.&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>Yes, there&amp;rsquo;s a number of limitations that you can learn a bit more about over on the &lt;a href="https://github.com/citusdata/pg_shard#limitations">github repo for pg_shard&lt;/a>. Though even with those it&amp;rsquo;s very usable as is, and let&amp;rsquo;s you get quite far in prepping an app for sharding. While I will say that all apps think they&amp;rsquo;ll need sharding and few actually do, given &lt;code>pg_shard&lt;/code> it&amp;rsquo;s minimal extra effort now to plan for such scaling should you need it.&lt;/p>
&lt;p>Up next we&amp;rsquo;ll look at how it&amp;rsquo;d work with a few languages, so you can get an idea of the end to end experience.&lt;/p></description></item><item><title>What being a PM is really like - Software is easy, People are hard</title><link>/2016/01/28/What-being-a-PM-is-really-like-Software-is-easy-People-are-hard/</link><pubDate>Thu, 28 Jan 2016 12:55:56 -0800</pubDate><guid>/2016/01/28/What-being-a-PM-is-really-like-Software-is-easy-People-are-hard/</guid><description>&lt;p>In recent months I&amp;rsquo;ve had the question nearly once a week about advice/tips for becoming a Product Manager or more commonly referred to as PM. These are generally coming from people that are either currently engineers, or previously were and are in some engineer/customer role such as a sales engineer or solution architect. There&amp;rsquo;s a number of &lt;a href="http://www.amazon.com/Inspired-Create-Products-Customers-Love/dp/0981690408?tag=mypred-20">high level&lt;/a> pieces talking about PM and it often feels glorious, I mean you get to make product decisions right? You get to call some shots. Well that sometimes may be true, but don&amp;rsquo;t assume it&amp;rsquo;s all rainbows and sparkles.&lt;/p>
&lt;p>Especially as a first time PM what your day to day will look like won&amp;rsquo;t be debating strategy all day long. Here&amp;rsquo;s a few of the good and the bad sides of being a PM.&lt;/p>
&lt;h3 id="plenty-of-grunt-work" >
&lt;div>
Plenty of grunt work
&lt;/div>
&lt;/h3>
&lt;p>While you may get to make a decision or two, the bulk of your time will not be thinking about grandiose visions, instead you&amp;rsquo;ll be doing a lot to gather data. There&amp;rsquo;s a lot of means for gathering data across lots of sources, the more you use the better you&amp;rsquo;ll be. Knowing the ones you steer towards, as well as ones you steer away from is useful so you can balance a bias more fairly. For myself SQL is a go-to, then customer interactions both qualitative and quantitative such as surveys, following what media is saying about your space is important as well. And while user studies are often relegated to design and UX, as a PM you need to make sure it at least happens (&lt;a href="http://www.invisionapp.com/">Invision App&lt;/a> is a favorite for lightweight tests).&lt;/p>
&lt;p>In a given week I probably spend 10 hrs interacting with customers, looking at data, and sadly that&amp;rsquo;s probably not enough.&lt;/p>
&lt;p>&lt;em>A few practical examples of this&lt;/em>&lt;/p>
&lt;p>Each morning I send emails to 10-20 users who used the product for the first time, yes this is automated but carving out 30 minutes of my day to actually follow-up with each of them is less automated.&lt;/p>
&lt;p>Another example is keeping a health of business dashboard up to date. Personally I use google sheets for this. Within one spreadsheet I have monthly and weekly targets as well as how we’re tracking against them. These are all updated on actual real time data, powered by Heroku’s dataclips with a simple &lt;code>=importCSV(‘http://dataclips.heroku.com/abcdefghij….csv’)&lt;/code>. In total my google spreadsheets has 1 high level overview, with about 20 underlying sheets that do all of the computations. In any given month 1 of my key 4-5 goals may be missed, which then spawns digging in deeper to figure out why and what we can do about it.&lt;/p>
&lt;h3 id="dictating-vs-consensus" >
&lt;div>
Dictating vs. consensus
&lt;/div>
&lt;/h3>
&lt;p>From a product decision making perspective you can force alignment by explicitly making every decision, or you can allow decisions to be made as a group voting if needed. Expect to use some balance of both of these among the team, and neither is never perfect. When it comes to outside the team you may still use both, but steer more strongly one way or the other. For example with the executive team it may be more consensus, with marketing it may be dictating your product roadmap which they can help support.&lt;/p>
&lt;p>Even within the team there will be times a decision must be made and there will be some people that don&amp;rsquo;t align. It&amp;rsquo;s key that you make the decision clearly and explicitly. Even though some individuals don&amp;rsquo;t like it, they won&amp;rsquo;t fight against it&amp;hellip; unless you make a habit of taking the input, then discarding it and going along your &amp;lsquo;intuition&amp;rsquo;. Even when there&amp;rsquo;s a strong case based on the data it may not be as clear as you think.&lt;/p>
&lt;p>In contrast, decision making by consensus most people will feel happier that they provided input into the product. If you take everyone&amp;rsquo;s input expect to end up with a product that feels like 10 people designed it, needless to say incoherent.&lt;/p>
&lt;p>As a PM expect to do a lot of listening, a good bit of convincing, and some occasional big decision making.&lt;/p>
&lt;h3 id="the-pain-you-feel-inside-the-building-doesnt-matter" >
&lt;div>
The pain you feel inside the building doesn&amp;rsquo;t matter
&lt;/div>
&lt;/h3>
&lt;p>You may think you&amp;rsquo;re solving a problem that exists for users, when in reality there was no problem at all. This is just a reminder that you need to keep empathy in mind above so much else.&lt;/p>
&lt;p>As an example, once a data team put in place a tool, supposedly for me. I looked at the tool and more or less didn&amp;rsquo;t understand why it was in place. They proceeded to explain that my problem was it took me too long to write SQL, so this tool will help me get the reports I need without SQL. At that point I proceeded to actually list off all the issues I did have, none of which &lt;a href="http://www.craigkerstiens.com/categories/postgres/">were SQL&lt;/a>.&lt;/p>
&lt;p>Prescribing a solution without knowing clearly &lt;strong>from customers&lt;/strong> what the problem is will leave you in a bad spot. All this means you have to set aside building the tool you want to use, and make sure you know what the &lt;a href="http://headrush.typepad.com/creating_passionate_users/2005/01/keeping_users_e.html">customer wants&lt;/a>.&lt;/p>
&lt;h3 id="marketing-is-your-job" >
&lt;div>
Marketing is your job
&lt;/div>
&lt;/h3>
&lt;p>Not external marketing, though often that work may still fall to you, but rather internal marketing.&lt;/p>
&lt;p>It’s important that you internally market the wins for your &lt;em>team&lt;/em>. These wins should very much be for the team, and not for your own benefit. The best PMs seem to disappear into the background, this is because you’re more surfacing all the work your team is doing than any of the details you helped coordinate. This is often counter to our natural instinct to tout our own accomplishments. This is only exaggerated in PM role, one where things can still ship if you’re not there, so there can often be a tendency to try to highlight the roles value. Fight that urge to self market.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Rest assured though–getting the team focused on solving the right problems, and then surfacing their wins will only help you go faster.&lt;/p>
&lt;h3 id="on-leading" >
&lt;div>
On leading
&lt;/div>
&lt;/h3>
&lt;!-- raw HTML omitted -->
&lt;p>At the end of the day ensuring the product is advancing is your job, so be prepared to do what you need to whether it’s leading or not to accomplish that.&lt;/p>
&lt;h3 id="its-not-all-rainbows-but-it-is-fun" >
&lt;div>
It’s not all rainbows, but it is fun
&lt;/div>
&lt;/h3>
&lt;p>The range of things you’ll have to focus on can be diverse and complex. In the end if you get a rush out of shipping and launching products, then all the work that goes into it can make it all worthwhile. It’s as much about figuring out what customers want and then getting your team building the right thing. For a first time PM it can be summed up by the notion that software is easy, people are hard.&lt;/p>
&lt;p>&lt;em>Special thanks to &lt;a href="http://www.twitter.com/lukasfittl">Lukas Fittl&lt;/a> and &lt;a href="http://www.twitter.com/iamclovin">Arun Thampi&lt;/a> for reviews and feedback on this post.&lt;/em>&lt;/p></description></item><item><title>Marketing definitions for developers</title><link>/2016/01/17/Marketing-definitions-for-developers/</link><pubDate>Sun, 17 Jan 2016 12:55:56 -0800</pubDate><guid>/2016/01/17/Marketing-definitions-for-developers/</guid><description>&lt;p>Marketing often feels like a dirty-icky thing to many developers. Well until you feel like you have a great product, but no one using it then you have to get a crash course in all of that. And while I might cover some of the actual basics in the future, just knowing what marketing people actually mean when they’re talking can be a huge jump start. Here&amp;rsquo;s a guide that distills many of the acronyms and terms down to what they actually mean in reality.&lt;/p>
&lt;p>&lt;strong>SEO - Search engine optimization.&lt;/strong> There&amp;rsquo;s two sides to this, one where you&amp;rsquo;re attempting to game the system known known as black hat. The other is simply creating good content.&lt;/p>
&lt;p>Tip: Now, unlike several years ago social sharing helps impact this.&lt;/p>
&lt;p>&lt;strong>SEM - Search engine marketing.&lt;/strong> The short of this is adwords, but broadly it&amp;rsquo;s any search engine.&lt;/p>
&lt;p>Tip: Be wary here, you can spend a lot of money quickly. Properly managing it takes time and effort otherwise you&amp;rsquo;re wasting money.&lt;/p>
&lt;p>&lt;strong>Display ads&lt;/strong> - Banner ads on websites. There&amp;rsquo;s a few common form factors in this world, so you&amp;rsquo;ll create a few then reuse them across lots of properties.&lt;/p>
&lt;p>Tip: Results may vary here, there are some hidden gems when advertising on various long tail sites.&lt;/p>
&lt;p>&lt;strong>Retargeting&lt;/strong> - This is where you&amp;rsquo;re serving an ad (most commonly display) to someone that&amp;rsquo;s previously visited your site. The process happens due to you &amp;lsquo;pixeling&amp;rsquo; them, and a cookie being set so the ad server knows they&amp;rsquo;ve seen you.&lt;/p>
&lt;p>Tip: Generally good bang for the buck here, but you still need initial visitors to even retarget to.&lt;/p>
&lt;p>&lt;strong>Funnel&lt;/strong> - The process of someone going from finding you to paying to paying more. Generally a process will look something like: Anonymous visitor by referral, sign ups, low money bucket, big money bucket.&lt;/p>
&lt;p>&lt;strong>Top of the funnel&lt;/strong> - Hopefully clear from the previous one, top of the funnel would be the max of users you reach out to or get to your site, usually down to getting them to sign up.&lt;/p>
&lt;p>&lt;strong>Bottom of the funnel&lt;/strong> - This is usually going from time you have a user to customer and then growing that customer via cross-selling and upselling.&lt;/p>
&lt;p>&lt;strong>Drip marketing&lt;/strong> - This is the process of gradually sending emails/notifications to your customers to get them to engage and learn about the product. Think of it as a welcome email on day 1, an intro on day 3, and on day 5 a different email based on what they&amp;rsquo;ve done so far. Really good drip marketing will create a different email for the user based on what they have or haven&amp;rsquo;t done.&lt;/p>
&lt;p>&lt;strong>Attribution (last/first/multi)&lt;/strong> - Attribution relates to how you got the user or customer (via web referral). There&amp;rsquo;s a few different ways of looking at this, last touch is the last website they visited before signing up, first touch is the first referral they were sent from, and multi touch (often more complicated to put in place) attributes something to all referrals they&amp;rsquo;ve come from.&lt;/p>
&lt;p>&lt;strong>AR - Analyst relations&lt;/strong>. Analysts cover particular products or areas in an industry, write reports, and often consult with large enterprises when making buying decisions. Analyst relations or AR is the common term for interacting with them, you can &lt;a href="/2015/07/25/A-guide-to-analyst-relations-for-startups/">learn more here&lt;/a>&lt;/p>
&lt;p>&lt;strong>PR - Public relations&lt;/strong>. This is generally the press/media side. It often involves launches, press releases, pitching media etc. You can read more of a &lt;a href="/2015/07/21/An-intro-PR-guide-for-startups/">guide on it here&lt;/a>&lt;/p>
&lt;p>&lt;strong>Briefing&lt;/strong> - This is normally with an analyst or press, and is typically a quick 30 minute call occasionally a demo of an upcoming launch.Usually&lt;/p>
&lt;p>&lt;strong>Inquiry&lt;/strong> - This refers more to the analyst side. Where a briefing is often more one sided for you to pitch/update them on what you’ve been doing, an inquiry is more a back and forth where you can ask what they’re seeing in the market and for input on direction.&lt;/p>
&lt;p>&lt;strong>Campaign&lt;/strong> - A collection of activities that go on around a certain thing focused on specific keywords or theme. This can be as little as a search engine marketing campaign which is the most common, or much larger and coordinated with billboards, webinars, etc.&lt;/p>
&lt;p>&lt;strong>Lead Gen&lt;/strong> - The sales funnel usually goes from just getting an email, to talking to them, to getting them to try a demo or run a POC, to eventually buying. Lead gen is the activity of just getting that initial contact so you can then further engage with them. In practice this can often involve giving something away, like a t-shirt in exchange for an email.&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>While this doesn&amp;rsquo;t cover every marketing activity under the sun, hopefully it&amp;rsquo;s a good primer on things you may have heard but been confused by. If there&amp;rsquo;s important ones I&amp;rsquo;ve missed please feel free to let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>&lt;/p></description></item><item><title>Writing more legible SQL</title><link>/2016/01/08/Writing-more-legible-SQL/</link><pubDate>Fri, 08 Jan 2016 12:55:56 -0800</pubDate><guid>/2016/01/08/Writing-more-legible-SQL/</guid><description>&lt;p>A number of times in a crowd I&amp;rsquo;ve asked how many people enjoy writing SQL, and often there&amp;rsquo;s a person or two. The follow up is how many people enjoy reading other people&amp;rsquo;s SQL and that&amp;rsquo;s unanimously 0. The reason for this is that so many people write bad SQL. It&amp;rsquo;s not that it doesn&amp;rsquo;t do the job, it&amp;rsquo;s just that people don&amp;rsquo;t tend to treat SQL the same as other languages and don&amp;rsquo;t follow strong code formatting guidelines. So, of course here&amp;rsquo;s some of my own recommendations on how to make SQL more readable.&lt;/p>
&lt;h3 id="one-thing-per-line" >
&lt;div>
One thing per line
&lt;/div>
&lt;/h3>
&lt;p>Only put a single column/table/join per line. This is going to make for slightly more verbose SQL, but it will be easier to read and edit.. Here&amp;rsquo;s a basic example:&lt;/p>
&lt;pre>&lt;code>SELECT foo,
bar
FROM baz
&lt;/code>&lt;/pre>
&lt;h3 id="align-your-projections-and-conditions" >
&lt;div>
Align your projections and conditions
&lt;/div>
&lt;/h3>
&lt;p>You can somewhat see this in the above with &lt;code>foo&lt;/code> and &lt;code>bar&lt;/code> being on the same line. This is reasonably common for columns you&amp;rsquo;re selecting, but it&amp;rsquo;s not applied as often in &lt;code>AND&lt;/code> or &lt;code>GROUP BY&lt;/code> clauses. As you can see there is a difference though between:&lt;/p>
&lt;pre>&lt;code>SELECT foo,
bar
FROM baz
WHERE foo &amp;gt; 3
AND bar = 'craig.kerstiens@gmail.com'
&lt;/code>&lt;/pre>
&lt;p>And a cleaner version:&lt;/p>
&lt;pre>&lt;code>SELECT foo,
bar
FROM baz
WHERE foo &amp;gt; 3
AND bar = 'craig.kerstiens@gmail.com'
&lt;/code>&lt;/pre>
&lt;h3 id="use-column-names-when-groupingordering" >
&lt;div>
Use column names when grouping/ordering
&lt;/div>
&lt;/h3>
&lt;p>This is personally an awful habit of mine, but it is extremely convenient to just order by the column number. In the above query we could just &lt;code>ORDER BY 1&lt;/code>. This is especially easy when column 1 may be something like SUM(foo). However, ensuring you explicitly &lt;code>ORDER BY SUM(foo)&lt;/code> will help limit any misunderstanding of the data.&lt;/p>
&lt;h3 id="comments" >
&lt;div>
Comments
&lt;/div>
&lt;/h3>
&lt;p>You comment your code all the time, yet so few seem to comment their queries. A simple &lt;code>--&lt;/code> allows you to inline a comment, perhaps where there&amp;rsquo;s some oddities to what you&amp;rsquo;re joining or just anywhere it may need clarification. You can of course &lt;a href="/2013/07/29/documenting-your-postgres-database/">go much further&lt;/a>, but at least some basic level of commenting should be required.&lt;/p>
&lt;h3 id="casing" >
&lt;div>
Casing
&lt;/div>
&lt;/h3>
&lt;p>As highlighted in these examples, having a standard for how you case your queries is especially handy. Sticking with all SQL keywords in caps allows you to easily parse what is SQL and what are columns or literals that you&amp;rsquo;re using in queries.&lt;/p>
&lt;h3 id="ctes" >
&lt;div>
CTEs
&lt;/div>
&lt;/h3>
&lt;p>First, yes they can be an optimisation boundary. But they can also make your query much more read-able and prevent you from doing the wrong thing because you couldn&amp;rsquo;t reason about a query.&lt;/p>
&lt;p>For those unfamiliar CTEs are like a view that exist just for the duration of that query being executed. You can have them reference previous CTEs so you can gradually build on them, much like you would code blocks. I won&amp;rsquo;t repeat too much of what &lt;a href="/2013/11/18/best-postgres-feature-youre-not-using/">I&amp;rsquo;ve already written about them&lt;/a>, but if you&amp;rsquo;re unfamiliar with them or not using them &lt;a href="/2013/11/18/best-postgres-feature-youre-not-using/">they are a must&lt;/a>. CTEs are easily one of the few pieces of SQL that I use on a daily basis.&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>Of course this isn&amp;rsquo;t the only way to make your SQL more readable and this isn&amp;rsquo;t an exhaustive list. But hopefully you find these tips helpful, and for your favorite tip that I missed&amp;hellip; let me know about it &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>.&lt;/p>
&lt;p>&lt;em>A special thanks to &lt;a href="http://www.twitter.com/Case">@Case&lt;/a> for reviewing.&lt;/em>&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>My top 10 Postgres features and tips for 2016</title><link>/2015/12/29/My-top-10-Postgres-features-and-tips-for-2016/</link><pubDate>Tue, 29 Dec 2015 12:55:56 -0800</pubDate><guid>/2015/12/29/My-top-10-Postgres-features-and-tips-for-2016/</guid><description>&lt;p>I find during the holiday season many pick up &lt;a href="http://www.amazon.com/Hard-Thing-About-Things-Building/dp/0062273205/ref=sr_1_1?ie=UTF8&amp;amp;qid=1451407536&amp;amp;sr=8-1&amp;amp;keywords=hard+thing+about&amp;amp;tag=mypred-20">new books&lt;/a>, learn a &lt;a href="http://crystal-lang.org/">new language&lt;/a>, or brush up on some other skill in general. Here&amp;rsquo;s my contribution to hopefully giving you a few new things to learn about Postgres and ideally utilize in the new year. It&amp;rsquo;s not in a top 10 list as much as 10 tips and tricks you should be aware of as when you need them they become incredibly handy. But, first a shameless plug if you find any of the following helpful, consider subscribing to &lt;a href="http://www.postgresweekly.com">Postgres weekly&lt;/a> a weekly newsletter with interesting Postgres content.&lt;/p>
&lt;h3 id="1-ctes---common-table-expressions" >
&lt;div>
1. CTEs - Common Table Expressions
&lt;/div>
&lt;/h3>
&lt;p>CTEs allow you to do crazy awesome things like recursive queries but even the most simple form of them I don&amp;rsquo;t go a day without using. Think of a CTE or commonly known as with clause as a view inside the time that query is running. This lets you more easily create readable query. Any query that&amp;rsquo;s constructed that&amp;rsquo;s even &lt;a href="/2013/11/18/best-postgres-feature-youre-not-using/">100 lines long&lt;/a>, but with 4-5 CTEs is undoubtedly going to be easier for someone new to come in and understand than a 20 line query that does the same thing. A few people like writing SQL, but no one likes reading someone else&amp;rsquo;s so do them a favor and read up on CTEs.&lt;/p>
&lt;h3 id="2-setup-a-psqlrc" >
&lt;div>
2. Setup a .psqlrc
&lt;/div>
&lt;/h3>
&lt;p>You setup a bashrc, vimrc, etc. Why not do the same for Postgres. Some of the great things you can do:&lt;/p>
&lt;ul>
&lt;li>Setup pretty formatting by default with &lt;code>\x auto&lt;/code>&lt;/li>
&lt;li>Set nulls to actually look like something &lt;code>\pset null ¤&lt;/code>&lt;/li>
&lt;li>Turn timing on by default &lt;code>\timing on&lt;/code>&lt;/li>
&lt;li>Customize your prompt &lt;code>\set PROMPT1 '%[%033[33;1m%]%x%[%033[0m%]%[%033[1m%]%/%[%033[0m%]%R%# '&lt;/code>&lt;/li>
&lt;li>Save commonly run queries that you can run by name&lt;/li>
&lt;/ul>
&lt;p>Here&amp;rsquo;s an example of my own &lt;code>psqlrc&lt;/code>:&lt;/p>
&lt;pre>&lt;code>\set QUIET 1
\pset null '¤'
-- Customize prompts
\set PROMPT1 '%[%033[1m%][%/] # '
\set PROMPT2 '... # '
-- Show how long each query takes to execute
\timing
-- Use best available output format
\x auto
\set VERBOSITY verbose
\set HISTFILE ~/.psql_history- :DBNAME
\set HISTCONTROL ignoredups
\set COMP_KEYWORD_CASE upper
\unset QUIET
&lt;/code>&lt;/pre>
&lt;h3 id="3-pg_stat_statements-for-where-to-index" >
&lt;div>
3. pg_stat_statements for where to index
&lt;/div>
&lt;/h3>
&lt;p>&lt;code>pg_stat_statements&lt;/code> is probably the single most valuable tool for improving performance on your database. Once enabled (with &lt;code>create extension pg_stat_statements&lt;/code>) it automatically records all queries run against your database and records often and how long they took. This allows you to then go and find areas you can optimize to get overall time back with one simple query:&lt;/p>
&lt;pre>&lt;code>SELECT
(total_time / 1000 / 60) as total_minutes,
(total_time/calls) as average_time,
query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 100;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>Yes, there is some performance cost to leaving this always on, but it&amp;rsquo;s pretty small. I&amp;rsquo;ve found it&amp;rsquo;s far more useful to be on and get major performance wins vs. the small cost of it always recording.&lt;/em>&lt;/p>
&lt;p>You can read much more on Postgres performance on a &lt;a href="http://www.craigkerstiens.com/2013/01/10/more-on-postgres-performance/">previous post&lt;/a>&lt;/p>
&lt;h3 id="4-slow-down-with-etl-use-fdws" >
&lt;div>
4. Slow down with ETL, use FDWs
&lt;/div>
&lt;/h3>
&lt;p>If you have a lot of &lt;em>microservices&lt;/em> or different apps then you likely have a lot of different databases backing them. The default for about anything you want to do is do create some data warehouse and ETL it all together. This often goes a bit too far to the extreme of aggregating &lt;strong>everything&lt;/strong> together.&lt;/p>
&lt;p>For the times you just need to pull something together once or on rare occasion &lt;a href="http://www.craigkerstiens.com/2013/08/05/a-look-at-FDWs/">foreign data wrappers&lt;/a> will let you query from one Postgres database to another, or potentially from Postgres to anything else such as &lt;a href="https://github.com/citusdata/mongo_fdw">Mongo&lt;/a> or Redis.&lt;/p>
&lt;h3 id="5-array-and-array_agg" >
&lt;div>
5. array and array_agg
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s little chance if you&amp;rsquo;re building an app you&amp;rsquo;re not using arrays somewhere within it. There&amp;rsquo;s no reason you shouldn&amp;rsquo;t be doing the same within your database as well. Arrays can be just another datatype within Postgres and have some great use cases like tags for blog posts directly in a single column.&lt;/p>
&lt;p>But, even if you&amp;rsquo;re not using arrays as a datatype there&amp;rsquo;s often a time when you want to rollup something like an array in a query then comma separate it. Something similar to the following could allow you to easily roll up a comma separated list of projects per user:&lt;/p>
&lt;pre>&lt;code>SELECT
users.email,
array_to_string(array_agg(projects.name), ',')) as projects
FROM
projects,
tasks,
users
WHERE projects.id = tasks.project_id
AND tasks.due_at &amp;gt; tasks.completed_at
AND tasks.due_at &amp;gt; now()
AND users.id = projects.user_id
GROUP BY
users.email
&lt;/code>&lt;/pre>
&lt;h3 id="6-use-materialized-views-cautiously" >
&lt;div>
6. Use materialized views cautiously
&lt;/div>
&lt;/h3>
&lt;p>If you&amp;rsquo;re not familiar with materialized view they&amp;rsquo;re a query that has been actually created as a table. So it&amp;rsquo;s a materialized or basically snapshotted version of some query or &amp;ldquo;view&amp;rdquo;. In their initial version materialized versions, which were long requested in Postgres, were entirely unusuable because when you it was a locking transaction which could hold up other reads and acticities avainst that view.&lt;/p>
&lt;p>They&amp;rsquo;ve since gotten much better, but there&amp;rsquo;s no tooling for refreshing them out of the box. This means you have to setup some scheduler job or cron job to regularly refresh your materialized views. If you&amp;rsquo;re building some reporting or BI app you may undoubtedly need them, but their usability could still be advanced so that Postgres knew how to more automatically refresh them.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re on Postgres 9.3, the above caveats about preventing reads still does exist&lt;/em>&lt;/p>
&lt;h3 id="7-window-functions" >
&lt;div>
7. Window functions
&lt;/div>
&lt;/h3>
&lt;p>Window functions are perhaps still one of the more complex things of SQL to understand. In short they let you order the results of a query, then compute something from one row to the next, something generally hard to do without procedural SQL. You can do some very basic things with them such as rank where &lt;a href="http://postgresguide.com/sql/window.html">each result appears&lt;/a> ordered by some value, or something more complex like compute &lt;a href="http://www.craigkerstiens.com/2014/02/26/Tracking-MoM-growth-in-SQL/">MoM growth directly in SQL&lt;/a>.&lt;/p>
&lt;h3 id="8-a-simpler-method-for-pivot-tables" >
&lt;div>
8. A simpler method for pivot tables
&lt;/div>
&lt;/h3>
&lt;p>Table_func is often referenced as the way to compute a pivot table in Postgres. Sadly though it&amp;rsquo;s pretty difficult to use, and the more basic method would be to just do it with raw SQL. This will get much better with &lt;a href="http://www.craigkerstiens.com/2015/12/27/postgres-9-5-feature-rundown/">Postgres 9.5&lt;/a>, but until then something where you sum up each condition where it&amp;rsquo;s true or false and then totals is much simpler to reason about:&lt;/p>
&lt;pre>&lt;code>select date,
sum(case when type = 'OSX' then val end) as osx,
sum(case when type = 'Windows' then val end) as windows,
sum(case when type = 'Linux' then val end) as linux
from daily_visits_per_os
group by date
order by date
limit 4;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>Example query courtesy of &lt;a href="http://www.twitter.com/tapoueh">Dimitri Fontaine&lt;/a> and &lt;a href="http://tapoueh.org/blog/2013/07/04-Simple-case-for-pivoting">his blog&lt;/a>.&lt;/em>&lt;/p>
&lt;h3 id="9-postgis" >
&lt;div>
9. PostGIS
&lt;/div>
&lt;/h3>
&lt;p>Sadly on this one I&amp;rsquo;m far from an expert. PostGIS is arguably the best option of any GIS database options. The fact that you get all of the standard Postgres benefits with it makes it even more powerful–a great example of this is GiST indexes which came to Postgres in recent years and offers great performance gains for PostGIS.&lt;/p>
&lt;p>If you&amp;rsquo;re doing something with geospatial data and need something more than the easy to use &lt;code>earth_distance&lt;/code> extension then crack open PostGIS.&lt;/p>
&lt;h3 id="10-jsonb" >
&lt;div>
10. JSONB
&lt;/div>
&lt;/h3>
&lt;p>I almost debated leaving this one off the list, ever since Postgres 9.2 JSON has been at least one of the marquees in each Postgres release. JSON arrived with much hype, and JSONB fulfilled on the initial hype of Postgres starting to truly compete as a document database. JSONB only continues to become more powerful with &lt;a href="http://www.craigkerstiens.com/2015/12/08/massive-json/">better libraries&lt;/a> for taking advantage of it, and it&amp;rsquo;s &lt;a href="https://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.5#JSONB-modifying_operators_and_functions">functions improving&lt;/a> with each release.&lt;/p>
&lt;p>If you&amp;rsquo;re doing anything with JSON or playing with another document database and ignoring JSONB you&amp;rsquo;re missing out, of course don&amp;rsquo;t forget the GIN and GiST indexes to really get the benefits of it.&lt;/p>
&lt;h3 id="the-year-ahead" >
&lt;div>
The year ahead
&lt;/div>
&lt;/h3>
&lt;p>Postgres 9.5/9.6 should continue to improve and bring many new features in the years ahead, what&amp;rsquo;s your preference for something that doesn&amp;rsquo;t exist yet but you do want to see land in Postgres. Let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>&lt;/p></description></item><item><title>Postgres 9.5 - The feature rundown</title><link>/2015/12/27/Postgres-9.5-The-feature-rundown/</link><pubDate>Sun, 27 Dec 2015 12:55:56 -0800</pubDate><guid>/2015/12/27/Postgres-9.5-The-feature-rundown/</guid><description>&lt;p>The headline of Postgres 9.5 is undoubtedly: Insert&amp;hellip; on conflict do nothing/update or more commonly known as Upsert or Merge. This removes one of the last remaining features which other databases had over Postgres. Sure we&amp;rsquo;ll take a look at it, but first let&amp;rsquo;s browse through some of the other features you can look forward to when Postgres 9.5 lands:&lt;/p>
&lt;h3 id="grouping-sets-cube-rollup" >
&lt;div>
Grouping sets, cube, rollup
&lt;/div>
&lt;/h3>
&lt;p>Pivoting in Postgres has &lt;a href="http://www.craigkerstiens.com/2013/06/27/Pivoting-in-Postgres/">sort of been possible&lt;/a> as has rolling up data, but it required you to know what those values and what you were projecting to, to be known. With the new functionality to allow you to group various sets together rollups as you&amp;rsquo;d normally expect to do in something like Excel become trivial.&lt;/p>
&lt;p>So now instead you simply add the grouping type just as you would on a normal group by:&lt;/p>
&lt;pre>&lt;code>SELECT department, role, gender, count(*)
FROM employees
GROUP BY your_grouping_type_here;
&lt;/code>&lt;/pre>
&lt;p>By simply selecting the type of rollup you want to do Postgres will do the hard work for you. Let&amp;rsquo;s take a look at the given example of department, role, gender:&lt;/p>
&lt;ul>
&lt;li>&lt;code>grouping sets&lt;/code> will project out the count for each specific key. As a result you&amp;rsquo;d get each department key, with other keys as null, and the count for each that met that department.&lt;/li>
&lt;li>&lt;code>cube&lt;/code> will give you the same values as above, but also the rollups of every individual combination. So in addition to the total for each department, you&amp;rsquo;d get breakups by the department and gender, and department and role, and department and role and gender.&lt;/li>
&lt;li>&lt;code>rollup&lt;/code> will give you a slightly similar version to cube but only give you the detailed groupings in the order they&amp;rsquo;re presented. So if you specified &lt;code>roll (department, role, gender)&lt;/code> you&amp;rsquo;d have no rollup for department and gender alone.&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Check the what&amp;rsquo;s new wiki for a bit more clarity on &lt;a href="https://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.5#GROUPING_SETS.2C_CUBE_and_ROLLUP">examples and output&lt;/a>&lt;/em>&lt;/p>
&lt;h3 id="import-foreign--schemas" >
&lt;div>
Import foreign schemas
&lt;/div>
&lt;/h3>
&lt;p>I only use foreign tables about once a month, but when I do use them they&amp;rsquo;ve inevitably saved many hours of creating a one off ETL process. Even still the effort to setup new foreign tables has shown a bit of their infancy in Postgres. Now once you&amp;rsquo;ve setup your foreign database, you can import the schema, either all of it or specific tables you prefer.&lt;/p>
&lt;p>It&amp;rsquo;s as simple as:&lt;/p>
&lt;pre>&lt;code>IMPORT FOREIGN SCHEMA public
FROM SERVER some_other_db INTO reference_to_other_db;
&lt;/code>&lt;/pre>
&lt;h3 id="pg_rewind" >
&lt;div>
pg_rewind
&lt;/div>
&lt;/h3>
&lt;p>If you&amp;rsquo;re managing your own Postgres instance for some reason and running HA, pg_rewind could become especially handy. Typically to spin up replication you have to first download the physical, also known as base, backup. Then you have to replay the Write-Ahead-Log or WAL–so it&amp;rsquo;s up to date then you actually flip on replication.&lt;/p>
&lt;p>Typically with databases when you fail over you shoot the other node in the head or &lt;a href="https://en.wikipedia.org/wiki/STONITH">STONITH&lt;/a>. This means just get rid of it, completely throw it out. This is still a good practice, so bring it offline, make it inactive, but from there now you could then flip it into a mode and use pg_rewind. This could save you pulling down lots and lots of data to get a replica back up once you have failed over.&lt;/p>
&lt;h3 id="upsert" >
&lt;div>
Upsert
&lt;/div>
&lt;/h3>
&lt;p>Upsert of course will be the highlight of Postgres 9.5. I already talked about it some when &lt;a href="http://www.craigkerstiens.com/2015/05/08/upsert-lands-in-postgres-9.5/">it initially landed&lt;/a>. The short of it is, if you&amp;rsquo;re inserting a record and there&amp;rsquo;s a conflict, you can choose to:&lt;/p>
&lt;ul>
&lt;li>Do nothing&lt;/li>
&lt;li>Do some form of update&lt;/li>
&lt;/ul>
&lt;p>Essentially this will let you have the typically experience of create or update that most frameworks provide but without a potential race condition of incorrect data.&lt;/p>
&lt;h3 id="jsonb-pretty" >
&lt;div>
JSONB pretty
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s a few updates &lt;a href="https://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.5#JSONB-modifying_operators_and_functions">to JSONB&lt;/a>. The one I&amp;rsquo;m most excited about is making JSONB output in psql read much more legibly.&lt;/p>
&lt;p>If you&amp;rsquo;ve got a JSONB field just give it a try with:&lt;/p>
&lt;pre>&lt;code>SELECT jsonb_pretty(jsonb_column)
FROM foo;
&lt;/code>&lt;/pre>
&lt;h3 id="give-it-a-try" >
&lt;div>
Give it a try
&lt;/div>
&lt;/h3>
&lt;p>Just in time for the new year &lt;a href="http://www.postgresql.org/about/news/1631/">the RC is ready&lt;/a> and you can get hands on with it. Give it a try, and if there&amp;rsquo;s more you&amp;rsquo;d like to hear about Postgres please feel free to drop me a note &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Going from blog posts to full launches</title><link>/2015/12/26/Going-from-blog-posts-to-full-launches/</link><pubDate>Sat, 26 Dec 2015 12:55:56 -0800</pubDate><guid>/2015/12/26/Going-from-blog-posts-to-full-launches/</guid><description>&lt;p>I recall extremely early stage where you&amp;rsquo;d build a feature, realize it was awesome, then the next day write a blog post for it. At some point you start to move from that to more coordinated launches. A larger coordinated launch allows you to reach a bigger audience, can lead to bigger deals, and help expand your overall market. But perhaps more importantly by the time you hit full launch you&amp;rsquo;ve message tested and ensured it&amp;rsquo;s going to resonate in the way you expect.&lt;/p>
&lt;p>&lt;em>The process itself will both help amplify and validate/refine your message&lt;/em>&lt;/p>
&lt;p>This is often a more gradual process than a sudden single change, you&amp;rsquo;ll introduce new parts of this in time. And for many what an entire launch process looks like comes by trial an error, to help shorten that learning curve here&amp;rsquo;s key areas I pay attention for a launch and process followed by a rough timeline.&lt;/p>
&lt;h3 id="product-first" >
&lt;div>
Product first
&lt;/div>
&lt;/h3>
&lt;p>Making sure the product is in the right shape is key to any big launch. You don&amp;rsquo;t get a second shot and if the product isn&amp;rsquo;t in shape customers often won&amp;rsquo;t take a second look at it later. For this reason I strongly prefer to have your product locked and loaded before you even start talking launch times, or at least be in the bug clean up phase. This means you&amp;rsquo;ve built a feature, validated with alpha users or private beta, and are ready to open it up to the world.&lt;/p>
&lt;p>If you have to set a launch date without the product or feature being already done allow padding. Sometimes it&amp;rsquo;s good for the team to know the padding, sometimes it isn&amp;rsquo;t. When you have extra time it&amp;rsquo;s not uncommon for your development to magically consume exactly that amount of time and still result in a small scramble towards the end.&lt;/p>
&lt;p>A good driver I&amp;rsquo;ve found is needing to have it fully like to demo a few weeks out from the launch itself, such as during &lt;a href="">analyst pre-briefings&lt;/a>.&lt;/p>
&lt;h3 id="crafting-your-message" >
&lt;div>
Crafting your message
&lt;/div>
&lt;/h3>
&lt;p>Every launch is an opportunity to tell your core message and value prop. If you miss this opportunity for focusing on a single narrow feature you&amp;rsquo;ve missed the biggest opportunity you had in a launch. You can&amp;rsquo;t relaunch your full product every time though–you do need some big improvements or feature that you can highlight, but you should still hit your core message.&lt;/p>
&lt;p>First you should know that your feature solves some specific problem, you should know this from the alpha/beta testing and if it doesn&amp;rsquo;t solve this problem &lt;a href="/2014/08/13/when-to-ship-when-to-kill/">you&amp;rsquo;re not ready to launch&lt;/a>. Yes, some people will launch a product before the product is completely there–this is common in a marketing driven company as opposed to a product/engineering driven company.&lt;/p>
&lt;p>Your message should lead with the problem you&amp;rsquo;re solving, not the laundry list of features. The best launches lead with some broader thematic message, even better if it&amp;rsquo;s an altruistic world changing one. A rough example of this:&lt;/p>
&lt;p>To the point to the product, and probably over generalized as boring:&lt;/p>
&lt;ul>
&lt;li>Connectify brings a new way of taking your dumb devices at home and turning them into intelligent connected devices.&lt;/li>
&lt;/ul>
&lt;p>In contrast, broad thematic message, followed lightly by the product.&lt;/p>
&lt;ul>
&lt;li>We live in a connected world, and with new connected devices there&amp;rsquo;s the opportunity not just give you more data but help you improve how you live your life. Connectify helps you at bringing the devices that matter together with ease.&lt;/li>
&lt;/ul>
&lt;h3 id="testing-your-message" >
&lt;div>
Testing your message
&lt;/div>
&lt;/h3>
&lt;p>You should treat your message just like a product, testing it gradually along the way. Once you&amp;rsquo;ve got some initial framing of it, test it internally, then with friendly customers or community members. Leading up to the launch I usually have a timeline and get all the content and communication rolling about 3 weeks out. I&amp;rsquo;ll give a bit of a timeline below but first some more around message testing&lt;/p>
&lt;h4 id="analysts" >
&lt;div>
Analysts
&lt;/div>
&lt;/h4>
&lt;p>If you regularly use &lt;a href="/2015/07/25/A-guide-to-analyst-relations-for-startups/">any analysts&lt;/a> you should absolutely use them to help with a launch. Several weeks out is a great time to test key messages with them, get feedback, and if you&amp;rsquo;re lucky you may even get them to provide a quote for the launch.&lt;/p>
&lt;p>Keep in mind here a inquiry is an opportunity to test your message and get feedback. You should talk roughly half of the time here, they should be talking the other half. In contrast briefings before launch you should have your message fully baked and should simply be pitching your message and possibly demo-ing.&lt;/p>
&lt;h4 id="friendlies" >
&lt;div>
Friendlies
&lt;/div>
&lt;/h4>
&lt;p>This may be more contentious, but at least at early stage sharing drafts with friendly community members is a great way to get feedback and refine your message. Here you should be especially concious of the request of their time and expect to have some delay before they get back to you. Being top secret about your message ahead of time won&amp;rsquo;t add much value to it being a home run, where as better ensuring it resonates will help it to be more successful.&lt;/p>
&lt;h4 id="customers" >
&lt;div>
Customers
&lt;/div>
&lt;/h4>
&lt;p>Customers I call out as a separate bucket. Customers have less incentive to leak your news than friendlies, but also fall somewhere on the other spectrum of analysts. A key piece about customers is there is an opportunity for them to be a launch partner. And so on to that topic:&lt;/p>
&lt;h3 id="launch-partners" >
&lt;div>
Launch partners
&lt;/div>
&lt;/h3>
&lt;p>Press and others like seeing and knowing you have external validation. Similarly many see the benefit of being part of a launch, after all it&amp;rsquo;s more free press for them. For a launch partner there are various levels, though for most providing some quote is a pretty common level.&lt;/p>
&lt;p>The best way to do this is talk to them about what they like about the feature/product and take a first stab at the quote for them from their feedback. Some may very much want to wordsmith their own which is fine, but minimizing the work required of them while–trying to hit something they&amp;rsquo;d say as well–as a message that flows can best be done by you taking a first pass.&lt;/p>
&lt;p>Further there&amp;rsquo;s varying levels of value with quotes and references. In descending order:&lt;/p>
&lt;ol>
&lt;li>Customers&lt;/li>
&lt;li>Analysts&lt;/li>
&lt;li>Community Members&lt;/li>
&lt;/ol>
&lt;h3 id="the-other-details" >
&lt;div>
The other details
&lt;/div>
&lt;/h3>
&lt;p>During launch week I mostly want to be dotting i&amp;rsquo;s and crossing t&amp;rsquo;s, meaning: I want the product done. I want documentation done. I want the blog post finalized. I want to be in the mode of send internal announcements, prep internal teams, talk to media.&lt;/p>
&lt;h4 id="prepping-internal-teams" >
&lt;div>
Prepping internal teams
&lt;/div>
&lt;/h4>
&lt;p>Obviously the engineering and product people involved will be in the loop. But you need to notify many others some of which should have been in the loop already, some less so:&lt;/p>
&lt;ul>
&lt;li>Support - There&amp;rsquo;s a new product surface area, support should be top of your list so they can field the tickets and questions that come in&lt;/li>
&lt;li>Sales - Even if there is no price change or impact, new features allow sales to communicate value to customers&lt;/li>
&lt;/ul>
&lt;h3 id="timeline" >
&lt;div>
Timeline
&lt;/div>
&lt;/h3>
&lt;p>Finally what&amp;rsquo;s the end to end timeline look like with all the little details. Here&amp;rsquo;s a rough one that&amp;rsquo;s fully built out. IF you&amp;rsquo;re smaller and don&amp;rsquo;t have a regular cadence of analysts in hand then just expect that doesn&amp;rsquo;t apply. IF your support team is the product and engineers maybe that&amp;rsquo;s lighter weight. Basically feel free to take out parts, but expect your process to grow to something of this size.&lt;/p>
&lt;ul>
&lt;li>4 weeks out - Outline of blog post with key messages&lt;/li>
&lt;li>Test that outline internally&lt;/li>
&lt;li>3 weeks out - Start to get a rough draft in place&lt;/li>
&lt;li>3 weeks out - Share internally and with friendlies. At this point you&amp;rsquo;re explicitely looking for message feedback. Tell people to not waste time on nitpicks of words or grammar, it will be 98% re-written by the time you&amp;rsquo;re done&lt;/li>
&lt;li>2.5 weeks out - Analyst inquiries for message testing&lt;/li>
&lt;li>2.5 weeks out - Start putting together product demo&lt;/li>
&lt;li>2 weeks out - Start putting together documentation&lt;/li>
&lt;li>2 weeks out - Start nailing down blog post for final messages&lt;/li>
&lt;li>1 weeks out - Start to put final touches on blog post for grammar&lt;/li>
&lt;li>1 week out - Analyst briefings&lt;/li>
&lt;li>1 week out - Update support&lt;/li>
&lt;li>3-5 days out - Stage blog post&lt;/li>
&lt;li>3-5 days out - Stage new documentation&lt;/li>
&lt;li>2-4 days out - Make sure PRs are ready or feature flags, in short the switch is there or live but not public&lt;/li>
&lt;li>1-3 days out - Update sales&lt;/li>
&lt;li>1-3 days out - Interall communication to all@&lt;/li>
&lt;li>1-3 days out - Media briefings&lt;/li>
&lt;li>LAUNCH DAY - Sit in a room and watch all the things, engage with twitter/HN/etc.&lt;/li>
&lt;/ul></description></item><item><title>Postgres and Node - Hands on using Postgres as a Document Store with MassiveJS</title><link>/2015/12/08/Postgres-and-Node-Hands-on-using-Postgres-as-a-Document-Store-with-MassiveJS/</link><pubDate>Tue, 08 Dec 2015 12:55:56 -0800</pubDate><guid>/2015/12/08/Postgres-and-Node-Hands-on-using-Postgres-as-a-Document-Store-with-MassiveJS/</guid><description>&lt;p>JSONB in Postgres is absolutely awesome, but it&amp;rsquo;s taken a little while for libraries to come around to make it as useful as would be ideal. For those not following along with Postgres lately, here&amp;rsquo;s the quick catchup for it as a NoSQL database.&lt;/p>
&lt;ul>
&lt;li>In Postgres 8.3 over 5 years ago Postgres received &lt;a href="http://www.craigkerstiens.com/2013/07/03/hstore-vs-json/">hstore a key/value&lt;/a> store directly in Postgres. It&amp;rsquo;s big limitation was it was only for text&lt;/li>
&lt;li>In the years after it got GIN and GiST indexes to make queries over hstore extremely fast indexing the entire collection&lt;/li>
&lt;li>In Postgres 9.2 we got JSON&amp;hellip; sort of. Really this way only text validation, but allowed us to create some &lt;a href="http://www.craigkerstiens.com/2013/05/29/postgres-indexes-expression-or-functional-indexes/">functional indexes&lt;/a> which were still nice.&lt;/li>
&lt;li>In Postgres 9.4 we got JSONB - the B stands for Better according to &lt;a href="http://www.twitter.com/leinweber">@leinweber&lt;/a>. Essentially this is a full binary JSON on disk, which can perform as fast as other NoSQL databases using JSON.&lt;/li>
&lt;/ul>
&lt;p>This is all great, but when it comes to using JSON you need a library that plays well here. As you might have guessed it from &lt;a href="http://www.craigkerstiens.com/2015/11/30/massive-node-postgres-an-overview-and-intro/">my previous post this is where MassiveJS comes in&lt;/a>. Most ORMs take a more legacy approach to &lt;a href="http://www.craigkerstiens.com/2014/01/24/rethinking-limits-on-relational/">how they work with the database&lt;/a>, in contrast the other side of the world believes in document only storage way is the future. In contrast Postgres believes there is a time and place for everything, just like Massive, except it believes Postgres is the path &lt;a href="http://www.craigkerstiens.com/2012/04/30/why-postgres/">just as I do&lt;/a>.&lt;/p>
&lt;p>Alright, enough context, let&amp;rsquo;s take a look.&lt;/p>
&lt;h3 id="getting-all-setup" >
&lt;div>
Getting all setup
&lt;/div>
&lt;/h3>
&lt;p>First go ahead and create a database, let&amp;rsquo;s call it massive, and then let&amp;rsquo;s connect to it and create our example table:&lt;/p>
&lt;pre>&lt;code>$ createdb massive
$ psql massive
# create table posts (id serial primary key, body jsonb);
&lt;/code>&lt;/pre>
&lt;p>Now that we&amp;rsquo;ve got our database setup let&amp;rsquo;s seed it with some data. If you want you can simple hop over to the github repo and pull it down then run &lt;code>node load_json.js&lt;/code> to load the example data. A quick look at it, given an &lt;code>example.json&lt;/code> file we&amp;rsquo;re going to iterate over it. For each record in there, we&amp;rsquo;re going to call saveDoc. Based on our table which has a unique id key and a body jsonb field it&amp;rsquo;ll simply save our JSON document into that table:&lt;/p>
&lt;pre>&lt;code>var parsedJSON = require('./example.json');
for(i = 0; i &amp;lt; parsedJSON.posts.length; i++) {
db.saveDoc(&amp;quot;posts&amp;quot;, parsedJSON.posts[1], function(err,res){});
};
&lt;/code>&lt;/pre>
&lt;p>&lt;em>If you want to just take a look at this &lt;a href="https://github.com/craigkerstiens/json_node_example">github repo&lt;/a>, once you create a database you can run &lt;code>node load_json.js&lt;/code> to seed it.&lt;/em>&lt;/p>
&lt;h3 id="why-json-at-all" >
&lt;div>
Why JSON at all?
&lt;/div>
&lt;/h3>
&lt;p>JSON data is all over the place, in many cases it&amp;rsquo;s fast and flexible and allows you to move more quickly. Yes, much of the time normalizing your data can be useful, but there is something to be said for expediency saving some data and querying across it. Querying across some giant document also used to be much more expensive, but now with JSONB and it&amp;rsquo;s indexes that can be extremely fast.&lt;/p>
&lt;h3 id="querying" >
&lt;div>
Querying
&lt;/div>
&lt;/h3>
&lt;p>So how do we go about querying? Well it&amp;rsquo;s pretty simple with Massive, they provide a nice &lt;code>findDoc&lt;/code> function to let you just search for contents of a specific key within the document. Let&amp;rsquo;s say I wanted to pull back all posts that are in the Postgres category, well it&amp;rsquo;s as simple as:&lt;/p>
&lt;pre>&lt;code>db.posts.findDoc({title : 'Postgres'}, function(err,docs){
console.log(docs);
});
&lt;/code>&lt;/pre>
&lt;p>The real beauty of this is if you added a GIN index (which will index the entire document) this query will be &lt;a href="http://obartunov.livejournal.com/175235.html">quite performant&lt;/a>.&lt;/p>
&lt;p>&lt;em>Just make sure to add your GIN index&lt;/em>:&lt;/p>
&lt;pre>&lt;code>CREATE INDEX idx_posts ON posts USING GIN(body jsonb_path_ops);
CREATE INDEX idx_posts_search ON posts USING GIN(search);
&lt;/code>&lt;/pre>
&lt;p>But even better, with Massive it&amp;rsquo;ll automatically add these for you if you just start saving docs. It will automatically create the table and appropriate indexes, just doing the correct thing out of the box.&lt;/p>
&lt;h3 id="full-text-and-json" >
&lt;div>
Full text and JSON
&lt;/div>
&lt;/h3>
&lt;p>Cool, so you can do an exact look up. Which is great when you&amp;rsquo;re matching a category&amp;hellip; which could be easily normalized. It&amp;rsquo;s great when you&amp;rsquo;re matching numbers, which also could likely reside in their own column. But what about when you&amp;rsquo;re searching over a large document, or a set of keys within some document which may require several joins, or indeterminate data structure, well you may want to search for the presence of that string at all. As you may have guessed this is quite trivial.&lt;/p>
&lt;pre>&lt;code>db.posts.searchDoc({
keys : [&amp;quot;title&amp;quot;, &amp;quot;category&amp;quot;],
term : [&amp;quot;Postgres&amp;quot;]
}, function(err,docs){
console.log(docs);
})
&lt;/code>&lt;/pre>
&lt;p>Hopefully it&amp;rsquo;s pretty straight forward, but to be very clear. Call out the document table you want to search, then the keys you&amp;rsquo;ll want to include in the search, then the term. This will search for any place the contents that string are found in matching values for those keys.&lt;/p>
&lt;p>Which will nicely yield the expected documents:&lt;/p>
&lt;pre>&lt;code>[ { link: 'http://www.craigkerstiens.com/2015/05/08/upsert-lands-in-postgres-9.5/',
title: 'Upsert Lands in PostgreSQL 9.5 – a First Look',
category: 'Postgres',
comments: [ [Object] ],
id: 2 },
{ link: 'http://www.craigkerstiens.com/2015/11/30/massive-node-postgres-an-overview-and-intro/',
title: 'Node, Postgres, MassiveJS - a Better Database Experience',
id: 3 } ]
&lt;/code>&lt;/pre>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>While Massive isn&amp;rsquo;t perfect, its approach to storing queries in files, using the schema vs. having to define your models in code and the database, and it&amp;rsquo;s smooth document integration makes it a real contender as a better database library when working with Node. Give it a try and let me know your thoughts.&lt;/p></description></item><item><title>Node, Postgres, MassiveJS - A better database experience</title><link>/2015/11/30/Node-Postgres-MassiveJS-A-better-database-experience/</link><pubDate>Mon, 30 Nov 2015 12:55:56 -0800</pubDate><guid>/2015/11/30/Node-Postgres-MassiveJS-A-better-database-experience/</guid><description>&lt;p>First some background–I&amp;rsquo;ve always had a bit of a love hate relationship with ORMs. ORMs are great for basic crud applications, which inevitably happens at some point for an app. The main two problems I have with ORMs is:&lt;/p>
&lt;ol>
&lt;li>They treat all databases as equal (yes, this is a little overgeneralized but typically true). They claim to do this for database portability, but in reality an app still can&amp;rsquo;t just up and move from one to another.&lt;/li>
&lt;li>They don&amp;rsquo;t handle complex queries well at all. As someone that sees SQL as a very powerful language, taking away all the power just leaves me with pain.&lt;/li>
&lt;/ol>
&lt;p>&lt;em>Of course these aren&amp;rsquo;t the &lt;a href="https://kev.inburke.com/kevin/faster-correct-database-queries/">only issues&lt;/a> with them, just the two ones I personally run into over and over.&lt;/em>&lt;/p>
&lt;p>In some playing with Node I was optimistic to explore &lt;a href="http://massive-js.readthedocs.org">Massive.JS&lt;/a> as it seems to buck the trend of just imitating all other ORMs. My initial results–it makes me want to do more with Node just for this library. After all the power of a language is the ecosystem of libraries around it, not just the core language. So let&amp;rsquo;s take a quick tour through with a few highlights of what makes it really great.&lt;/p>
&lt;h3 id="getting-setup" >
&lt;div>
Getting setup
&lt;/div>
&lt;/h3>
&lt;p>Without further adieu here&amp;rsquo;s a quick tour around it.&lt;/p>
&lt;p>First let&amp;rsquo;s pull down the example database from &lt;a href="http://postgresguide.com/setup/example.html">PostgresGuide&lt;/a>&lt;/p>
&lt;p>Then let&amp;rsquo;s setup out Node app:&lt;/p>
&lt;pre>&lt;code>$ npm init
$ npm install massive --save
&lt;/code>&lt;/pre>
&lt;h3 id="connecting-and-querying" >
&lt;div>
Connecting and querying
&lt;/div>
&lt;/h3>
&lt;p>Now let&amp;rsquo;s try to connect and say query a user from within our database. Create the following as an &lt;code>index.js&lt;/code> file, then run with &lt;code>node index.js&lt;/code>:&lt;/p>
&lt;pre>&lt;code>var massive = require(&amp;quot;massive&amp;quot;);
var connectionString = &amp;quot;postgres://ckerstiens:@localhost/example&amp;quot;;
var db = massive.connectSync({connectionString : connectionString});
db.users.find(1, function(err,res){
console.log(res);
});
&lt;/code>&lt;/pre>
&lt;p>Upon first run if you&amp;rsquo;re like me and use the &lt;a href="http://postgresguide.com/setup/example.html">PostgresGuide example database&lt;/a> (which I now need to go back and tidy up), you&amp;rsquo;ll get the following:&lt;/p>
&lt;pre>&lt;code>db.users.find(1, function(err,res){
^
TypeError: Cannot read property 'find' of undefined
&lt;/code>&lt;/pre>
&lt;p>I can&amp;rsquo;t describe how awesome it is to see this. What&amp;rsquo;s happening is when Massive loads up it&amp;rsquo;s connecting to your database, checking what tables you have. In this case though because we don&amp;rsquo;t have a proper primary key defined it doesn&amp;rsquo;t load them. It could treat id as some magical field of course like Rails used to and ignore the need for an index, but instead it not only encourages a good database design but requires it.&lt;/p>
&lt;p>So let&amp;rsquo;s go back and create our index in our database:&lt;/p>
&lt;pre>&lt;code>$ psql example
$ alter table users add primary key (id);
&lt;/code>&lt;/pre>
&lt;p>Alright now let&amp;rsquo;s run our script again with &lt;code>node index.js&lt;/code> and see what we have:&lt;/p>
&lt;pre>&lt;code>{ id: 1,
email: 'john.doe@gmail.com',
created_at: Thu Sep 24 2015 03:42:52 GMT-0700 (PDT),
deleted_at: null }
&lt;/code>&lt;/pre>
&lt;p>Perfect! Now we&amp;rsquo;re all connected and it even queried our database for us. Now let&amp;rsquo;s take a few more look at some of the operators.&lt;/p>
&lt;h3 id="running-an-arbitrary-query" >
&lt;div>
Running an arbitrary query
&lt;/div>
&lt;/h3>
&lt;p>&lt;code>db.run&lt;/code> will let me run any arbritrary SQL. An example such as &lt;code>db.run(&amp;quot;select 'hello'&amp;quot;)&lt;/code> will produce [ { &amp;lsquo;?column?&amp;rsquo;: &amp;lsquo;hello&amp;rsquo; } ].&lt;/p>
&lt;p>This makes it nice and easier for us to break out of the standard ORM model and just run SQL.&lt;/p>
&lt;h3 id="find-for-quick-look-ups" >
&lt;div>
Find for quick look ups
&lt;/div>
&lt;/h3>
&lt;p>Similar to so many other database tools &lt;code>find&lt;/code> will offer you the most common quick look ups:&lt;/p>
&lt;pre>&lt;code>$ db.users.find({email: 'jane.doe@gmail.com'}, function(err, res){console.log(res)});
$ db.users.find({'created_at &amp;gt;': '2015-09-24'}, function(err, res){console.log(res)});
&lt;/code>&lt;/pre>
&lt;p>And of course there&amp;rsquo;s a where operator for multiple conditions.&lt;/p>
&lt;h3 id="structuring-queries-in-your-application" >
&lt;div>
Structuring queries in your application
&lt;/div>
&lt;/h3>
&lt;p>While in the next post I&amp;rsquo;ll dig in deep to JSON, this is perhaps my favorite feature of Massive&amp;hellip; It&amp;rsquo;s design for pulling out queries into individudal SQL files. Simply create a &lt;code>db&lt;/code> folder and put your SQL in there. Let&amp;rsquo;s take the most basic example of our user email lookup and put it in &lt;code>user_lookup.sql&lt;/code>&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM users
WHERE email = $1
&lt;/code>&lt;/pre>
&lt;p>Now back in our application we can run this and pass in a parameter to it:&lt;/p>
&lt;pre>&lt;code>db.user_lookup(['jane.doe@gmail.com'], function(err,res){
console.log(res);
});
&lt;/code>&lt;/pre>
&lt;p>This separation of our queries from our code makes it easier to track them, view diffs, and even more so &lt;a href="http://www.craigkerstiens.com/2012/11/17/how-i-write-sql/">create very readable SQL&lt;/a>.&lt;/p>
&lt;h3 id="up-next" >
&lt;div>
Up next
&lt;/div>
&lt;/h3>
&lt;p>So sure, you can connect to a database, you can query some things. There were a couple of small but more novel things that we blew through in here. First is the fact I didn&amp;rsquo;t have to define all my schema, it just knew it as &lt;a href="http://www.craigkerstiens.com/2014/01/24/rethinking-limits-on-relational/">it really should&lt;/a>. The separation of SQL queries you&amp;rsquo;ll custom write into files is simple, but will make for much more maintainable applications over the long term. And best of all is the JSON support, which I&amp;rsquo;ll get to soon&amp;hellip;&lt;/p></description></item><item><title>Seeding a sharing-economy or platform company</title><link>/2015/10/02/Seeding-a-sharing-economy-or-platform-company/</link><pubDate>Fri, 02 Oct 2015 12:55:56 -0800</pubDate><guid>/2015/10/02/Seeding-a-sharing-economy-or-platform-company/</guid><description>&lt;p>These days if you&amp;rsquo;re creating a company you likely hope to accomplish more with less people, two ways of doing this fall to: The sharing economy and creating a platform. It&amp;rsquo;s easy to see the case for this when you have such &lt;a href="http://graphics.wsj.com/billion-dollar-club/">unicorns&lt;/a> like AirBnB or Uber. The opportunity for each of those to compete against hotel chains or taxi services which each need to manage their own inventory is incredibly exciting and revolutionary. In a similar fashion platforms can offer much the same, Heroku&amp;rsquo;s platform and marketplace made it easier than ever for developers to click a button and get everything they needed years ago. It&amp;rsquo;s not just their code, it&amp;rsquo;s everything from &lt;a href="https://www.heroku.com/postgres">Postgres&lt;/a> to Mongo to &lt;a href="https://elements.heroku.com/addons#logging">Logging&lt;/a>. Or take the app store as example. Smart phones weren&amp;rsquo;t a new thing when the iPhone came out, but it was only the saviest of users that had apps installed on their windows smartphone or blackberry. The app store made the iPhone different than any other phone by allowing others to build and improve it, turning the iPhone not into a phone but a platform.&lt;/p>
&lt;p>Platforms and the sharing economy both let you get further than having to take on the costs of offering the equivilent all on your own. And while a great idea to venture into one of these two areas, starting them isn&amp;rsquo;t as trivial as simply deciding to. For both of these you have issues with having a two sided market, first you have to convince the providers to come along, then the customers or vice versa. As a result of this two sided market issue the easiest way to actually start is by bootstrapping it yourself – or faking it til you make it.&lt;/p>
&lt;p>What are some good examples of faking this? I&amp;rsquo;m sure you can probably find some good stories going back about AirBnB or Uber, but let&amp;rsquo;s assume times were different then. Let&amp;rsquo;s take a look at a very recent example: &lt;a href="http://techcrunch.com/2015/08/26/lugg-an-app-for-on-demand-short-distance-moves-raises-3-8-million/">Lugg&lt;/a> which just launched in the latest batch of YC. Lugg is Uber for moving essentially, allowing you to on-demand request furniture moved from one place to another. Early on Lugg built their app, then waited for requests to come in, then the founders got in a truck and moved the furniture themselves. As a customer the founders are likely providing a great experience, without ever having to tip their hat at the ways their hacking the impression of being a large well oiled machine.&lt;/p>
&lt;p>But what about a platform? Slack continues to grow like wildfire as the new medium for communication. These days there&amp;rsquo;s endless integrations for slack, and I expect they&amp;rsquo;ll continue to expand what a platform for communication looks like. But a year ago they were quite a ways from having people show up at their door to add an integration. Sure there were people using them, but to expect github/trello/asana to immediately build an integration for every new flavor of the week tool would be crazy. Yet, without these integrations slack wouldn&amp;rsquo;t be nearly as useful as it is today–and probably wouldn&amp;rsquo;t have seen the growth it&amp;rsquo;s seen. In the early days of a platform the easiest way to get these integrations and partners in place is to show up and build the work yourself. Slack carried the weight early of building these integrations, much as Heroku add-ons showed up at partners offices and help write the code to get them as a provider in the marketplace. And while both Slack and Heroku are larger companies now, it still holds true for smaller ones starting today. &lt;a href="https://www.blockspring.com/">Blockspring&lt;/a>, a company which aims to make web services available through spreadsheets, had to do very much the same thing building their initial integrations themselves. Now with their rapidly growing user base and already large collection of APIs they may be able to shift the model, but early on that wasn&amp;rsquo;t so much an option.&lt;/p>
&lt;p>If you want to build a platform, start by creating the impression of one while still carrying the load yourself. Yes, move to a true platform as soon as you can, but don&amp;rsquo;t wait for others to show up before you go that route.&lt;/p></description></item><item><title>A guide to analyst relations for startups</title><link>/2015/07/25/A-guide-to-analyst-relations-for-startups/</link><pubDate>Sat, 25 Jul 2015 12:55:56 -0800</pubDate><guid>/2015/07/25/A-guide-to-analyst-relations-for-startups/</guid><description>&lt;p>When it comes to go to market and marketing there&amp;rsquo;s lots of pieces in a toolchest that all work together. One that comes a bit later, but if used properly (much like a &lt;a href="/2015/07/21/An-intro-PR-guide-for-startups/">PR agency&lt;/a>) can be valuable is industry analysts. And while working with a PR agency can quickly start to become clear. How to work with analysts so it is productive on both sides can take a bit longer to figure out, or at least it did for me. Even before you do start working with them there&amp;rsquo;s the question of if or when should you. Here&amp;rsquo;s hoping this primer makes it a bit faster and easier for others.&lt;/p>
&lt;h3 id="what-is-an-analyst" >
&lt;div>
What is an analyst
&lt;/div>
&lt;/h3>
&lt;p>&lt;em>Apologies to all analysts, but of all parts of this post I might butcher this one&lt;/em>&lt;/p>
&lt;p>Analysts talk to a lot of companies, both the ones making products as well as the ones purchasing them. I&amp;rsquo;m not actually sure what the spread is I&amp;rsquo;d guess 80-20. A large output of this and other activities is creating various reports and rankings. Gartner&amp;rsquo;s Magic Quadrant is probably the most well known industry ranking. Much of what they create isn&amp;rsquo;t freely available for consumption so you likely don&amp;rsquo;t see the sheer volume of insights they put out.&lt;/p>
&lt;h3 id="why-would-you-engage-with-an-analyst" >
&lt;div>
Why would you engage with an analyst
&lt;/div>
&lt;/h3>
&lt;p>So what do they do for you? There’s really two major buckets:&lt;/p>
&lt;p>&lt;strong>Help with sales/marketing&lt;/strong> - Given they&amp;rsquo;re informing and influencing buying decisions of businesses they can be one more person on your side. If a launch in Techcrunch makes business foo aware of product bar, then an analyst report or ranking can help sway a decision on whether to try bar vs. baz.&lt;/p>
&lt;p>&lt;strong>Consulting&lt;/strong> - The other major opportunity is for the analyst to give some form of guidance. In a larger company when you already have an established product they should absolutely be part of your launch process (more on that in a future post). They&amp;rsquo;re actively following your market and space, hopefully just as you are to some extent. They can offer an outside perspective and help with broad areas of focus and messaging.&lt;/p>
&lt;p>&lt;em>More&lt;/em> - In reality it’s as clean cut as above. They may be able to introduce you to good candidates for hiring. They may be able to introduce you to a large company interested in acquiring some capability which you have. They may be able to connect you with investors. All of these things can and do happen, but the above buckets typically are the primary drivers.&lt;/p>
&lt;h3 id="when" >
&lt;div>
When?
&lt;/div>
&lt;/h3>
&lt;p>First, engaging with analysts should always come after you have some confidence in the product, after you&amp;rsquo;ve started some marketing drumbeat, and after sales. In short don&amp;rsquo;t be in a huge rush here, you&amp;rsquo;ll get there, but don&amp;rsquo;t be in too big of a rush. As you start to get some attention and momentum it&amp;rsquo;s just as likely they&amp;rsquo;ll engage with you first as you reaching out. Also, marketing != sales, more on that in a future post.&lt;/p>
&lt;p>But, let&amp;rsquo;s assume you&amp;rsquo;ve got a product &lt;strong>which targets business&lt;/strong> (&lt;em>Analysts aren&amp;rsquo;t just for tech companies, though you’ll see the benefit here sooner if you’re say a database company than a HR product&lt;/em>). Let’s also assume you&amp;rsquo;ve got some sales and have some &lt;a href="/2015/07/21/An-intro-PR-guide-for-startups/">good launches under your belt&lt;/a>. As it starts to come up in sales calls if you&amp;rsquo;re in any industry reports or rankings that may be an indicator, if you&amp;rsquo;re hearing about other competitors having more validation in such reports. As a general rule of thumb once you&amp;rsquo;ve got inhouse PR they should be able to help guide and steer to the right time.&lt;/p>
&lt;h3 id="so-how-do-you-engage-with-an-analyst" >
&lt;div>
So how do you engage with an analyst
&lt;/div>
&lt;/h3>
&lt;p>If you&amp;rsquo;re engaging in some form of report or article, that should start to be pretty self explanatory. They&amp;rsquo;ll send you a questionnaire, you fill it out. You go back and forth a little bit.&lt;/p>
&lt;p>However, the majority of my interactions aren&amp;rsquo;t on those articles and reports, for ever one time I fill out lots of questions to help some report or ranking I have 20 calls with an analyst.&lt;/p>
&lt;p>There are two primary calls you can have, an inquiry and a briefing.&lt;/p>
&lt;h4 id="inquiries" >
&lt;div>
Inquiries
&lt;/div>
&lt;/h4>
&lt;p>Inquiry is just a fancy word for consulting call. An inquiry you will always be paying for.&lt;/p>
&lt;p>&lt;em>A small detour here. The regularity and consistency in which you engage with an analyst makes a difference. They&amp;rsquo;re also people at the end of the day, so while firms have certain styles it&amp;rsquo;s even further multiplied by being very people driven. In your interactions you&amp;rsquo;ll have a different rapport with different people, it&amp;rsquo;s at a minimum important to be aware of this.&lt;/em>&lt;/p>
&lt;p>So back to an inquiry. Within an inquiry your goal is to pull back the curtain and give some backstage insights into what you&amp;rsquo;re doing and where you&amp;rsquo;re headed. This is typically under NDA and trust the NDA of an analyst. It&amp;rsquo;s worthwhile to be as candid as you can here, yes it feels weird, but you&amp;rsquo;ll get the most value. They&amp;rsquo;re not like that of a reporter looking for a scoop (not that you can&amp;rsquo;t trust reporters, just know if you say it, it&amp;rsquo;s on record). You don&amp;rsquo;t have to relish the entire call to one area, but areas of coverage are often:&lt;/p>
&lt;ul>
&lt;li>Upcoming products and major releases you’re working on&lt;/li>
&lt;li>Broader strategy and roadmap&lt;/li>
&lt;li>Get input on what they&amp;rsquo;re seeing and hearing from customers&lt;/li>
&lt;/ul>
&lt;h4 id="briefings" >
&lt;div>
Briefings
&lt;/div>
&lt;/h4>
&lt;p>The other type of call we have is a briefing. This is a little similar to that of a press briefing. You&amp;rsquo;ll get on the call, and walk through some upcoming launch or just give an update on your company and progress. The latter is more common if they&amp;rsquo;re unfamiliar with you or your product.&lt;/p>
&lt;p>Analyst briefings are good to do earlier than your press briefings, compared to press they&amp;rsquo;re like a bike with training wheels. It&amp;rsquo;s best if you still maintain your balance–the ride will be smoother, but there&amp;rsquo;s a little less risk of completely toppling over. One key difference is you often have a powerpoint deck you get to walk through during an analyst briefing. I&amp;rsquo;ve found this is helpful for pacing and key messages, I used to be skeptical, but now very much feel it&amp;rsquo;s always worth doing.&lt;/p>
&lt;p>&lt;em>Pro-tip: You can create a deck and use it for press too, no they won&amp;rsquo;t want to get on a gotomeeting, but you can send it over so they have more content later. BUT, more importantly you can also walk through it on your own screen if it helps with pacing.&lt;/em>&lt;/p>
&lt;p>Within a briefing you&amp;rsquo;ll have some ability to ask them questions at points. Does this resonate? Are you hearing similar? What are you seeing in the market? Don&amp;rsquo;t turn it into an inquiry, but knowing the parts that hit home for them allow you to refine your pitch for the next call.&lt;/p>
&lt;h4 id="engaging---the-tactical-parts" >
&lt;div>
Engaging - the tactical parts
&lt;/div>
&lt;/h4>
&lt;p>&amp;ldquo;Analysts are pretty much paid to talk and write&amp;rdquo; - &lt;a href="http://www.twitter.com/cote">@cote&lt;/a>. So expect that often when you occupy their time there&amp;rsquo;s a price to it. In terms of finding them it should be pretty easy, to know the list of ones in your space, you may see them quoted or reference in various media outlets. You may just naturally crop up in a report.&lt;/p>
&lt;p>If you create a regular relationship with them you&amp;rsquo;ll have some contract of hours over the course of a quarter or year. At an early stage company this is often owned and manage by whomever runs your PR from an internal perspective.&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>If you&amp;rsquo;re about to engage with analysts for the first time or haven’t figured out how to get the most out of your interactions I hope the broad overview is helpful. If there&amp;rsquo;s some glaring parts you feel I&amp;rsquo;ve missed let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>. And for further reading/watching I’d encourage checking out the great talk from &lt;a href="http://www.twitter.com/cote">@cote&lt;/a> in the &lt;a href="http://www.heavybit.com/library/video/2014-01-21-michael-cote">Heavybit library&lt;/a>.&lt;/p>
&lt;p>As far as take-aways and a recap:&lt;/p>
&lt;ol>
&lt;li>Don&amp;rsquo;t be too eager to jump in with analysts. They can absolutely provide value, but you have to put some time in before it really starts to pay off. It&amp;rsquo;s not an overnight change and takes building a rapport with them.&lt;/li>
&lt;li>At the same time, analysts can be useful in many B2B areas not just tech ones.&lt;/li>
&lt;li>When in an inquiry be open and as transparent as possible.&lt;/li>
&lt;li>Powerpoint/Keynote/Google presentations are useful in briefings, even if it&amp;rsquo;s just for you to follow along.&lt;/li>
&lt;/ol></description></item><item><title>A guide to PR for startups</title><link>/2015/07/21/An-intro-PR-guide-for-startups/</link><pubDate>Tue, 21 Jul 2015 12:55:56 -0800</pubDate><guid>/2015/07/21/An-intro-PR-guide-for-startups/</guid><description>&lt;p>You&amp;rsquo;ve built your product and you&amp;rsquo;re now ready for your first major launch. Or you&amp;rsquo;ve been through a launch or two, but are looking to scale the process as you&amp;rsquo;re doing more launches and announcements. You really have two options: do it &lt;a href="http://jasonlbaptiste.com/featured-articles/how-i-pitched-techcrunch-and-13-ways-to-get-press-when-you-launch-your-startup/">all on your own&lt;/a>, or work with a PR agency. One frequent crossroad is that you&amp;rsquo;re not at the point of a full time PR person, but unsure what a PR agency can offer you; and, further what&amp;rsquo;s the best way to work with them so you&amp;rsquo;re getting the maximum value.&lt;/p>
&lt;p>As I&amp;rsquo;ve talked to more startups lately, it&amp;rsquo;s become clear that effectively working with PR teams and the media is mostly learned by doing. Because there&amp;rsquo;s not much guidance out there, here&amp;rsquo;s an attempt at some basic guidelines.&lt;/p>
&lt;h3 id="on-pr" >
&lt;div>
On PR
&lt;/div>
&lt;/h3>
&lt;p>First there&amp;rsquo;s two types here and they&amp;rsquo;re not mutually exclusive. In-house PR is a full time person or team that works within your company, here you&amp;rsquo;ll often have a pretty different experience. From my experience, in-house PR people tend to understand a company message and vision because they are living and breathing your company values every day.&lt;/p>
&lt;p>The other alternative is hiring a PR agency. An agency will have several (sometimes hundreds!) of clients. The relationship that you’ll have with an agency is much different than in-house. You&amp;rsquo;ll use them just like you would a consultant or contractor. Most startups end up with the agency approach first, because of the perception of “more people working for a cheaper cost than hiring in-house.” However, it&amp;rsquo;s of note an agency doesn&amp;rsquo;t alleviate you of doing work, nor should you want them to handle all parts of it.&lt;/p>
&lt;h4 id="messaging" >
&lt;div>
Messaging
&lt;/div>
&lt;/h4>
&lt;p>An agency may offer to help with messaging, but take this somewhat lightly. I don&amp;rsquo;t doubt that some are very good at it, but in most cases I&amp;rsquo;ve found they don&amp;rsquo;t have the same amount of customer interaction as you as a founder or early employee would. Further, your vision of impact to the market and direction may be more distant than theirs. You should expect to own your messaging, just like you own your product.&lt;/p>
&lt;p>Where they can heavily help is providing a lot of structured frameworks for helping you get to your messaging. Some pretty basic templates of standard questions for customers and partners can go along way in helping you actually uncover what they feel your value is.&lt;/p>
&lt;p>&lt;em>On your key messaging/value prop, there&amp;rsquo;s two pieces I&amp;rsquo;ll drop in here. While I&amp;rsquo;d love to write another long post on it, I wonder when I&amp;rsquo;ll actually get it out. So the first is pitch the problem you&amp;rsquo;re trying to solve–&lt;a href="http://500hats.typepad.com/500blogs/2009/08/your-solution-is-not-my-problem.html">Dave McClure&lt;/a> talks about this as well as anyone. The second is don&amp;rsquo;t pitch features, pitch the use cases and solutions. Pitch what&amp;rsquo;s possible&lt;/em>&lt;/p>
&lt;h4 id="pitching" >
&lt;div>
Pitching
&lt;/div>
&lt;/h4>
&lt;p>This is the number one area I&amp;rsquo;ve found that having PR makes a huge difference. In the world of reporting, different reporters have different beats (areas of coverage), styles, outreach preferences, and most importantly, different relationships with companies and people. Knowing &lt;em>all&lt;/em> of this and how to pitch a story to them is key. Yes you can spend hours researching and creating a perfect story just for them, and do that again, and again and hopefully land some coverage. But I&amp;rsquo;d argue a bit: that&amp;rsquo;s not the best use of your time.&lt;/p>
&lt;p>With a good PR person or agency you&amp;rsquo;ll be able to strike a mix of:&lt;/p>
&lt;ul>
&lt;li>Here&amp;rsquo;s the outlets I want to be in and why (have a good reason for why).&lt;/li>
&lt;li>Understanding the audience and readership.&lt;/li>
&lt;li>What outlets you feel like your key customers are reading, and validate this with the agency.&lt;/li>
&lt;/ul>
&lt;p>From there, if you&amp;rsquo;ve found a good agency they already have relationships with your key journalists / publications. So if you have a compelling product, you just need to give them the right messaging of the particular launch or news.&lt;/p>
&lt;h4 id="what-else-to-expect-from-your-agency" >
&lt;div>
What else to expect from your agency
&lt;/div>
&lt;/h4>
&lt;p>A surprise for some is how the whole process works. The agency is going to be there on the phone with you. You&amp;rsquo;re not going to hang out over beers while pitching being chummy. The reporter is listening to multiple other pitches, it&amp;rsquo;s likely they had one right before you and right after. The agency is there listening, helping keep time and track of conversation for reporter fact-checking after the interview.&lt;/p>
&lt;p>Hopefully they&amp;rsquo;re also keeping notes. They should be able to provide you with some high level notes of what message resonated with each reporter and what didn&amp;rsquo;t, what you covered, and what they asked. This is especially useful for future interactions.&lt;/p>
&lt;p>Similarly you should get a briefing 1 pager ahead of time. You should be able to skim this, you don&amp;rsquo;t have to memorize. But it&amp;rsquo;ll include key things about recent articles written by the reporter, their beat, topics to dive into and ones to stay away from. If you can connect the dots, those notes from an initial call start to feed into the 1 pagers for future calls.&lt;/p>
&lt;h3 id="onto-the-briefing" >
&lt;div>
Onto the briefing
&lt;/div>
&lt;/h3>
&lt;p>Of course it&amp;rsquo;s important to land the briefing in the first place, but just as important is getting it right. Coming into it, the reporter will have already gotten the high level pitch&amp;hellip; It&amp;rsquo;s why they took the call. You&amp;rsquo;ll get a mixed bag of those that are open to teeing up the opportunity to those that want to get right to the news. Roll with what they prefer, but also don&amp;rsquo;t be afraid of trying to hit some of your key points.&lt;/p>
&lt;h4 id="have-your-key-messages-ready" >
&lt;div>
Have your key messages ready
&lt;/div>
&lt;/h4>
&lt;p>Sound bites help hugely here. Analogies, customer references, whatever you want to hit. Have it ready. Also if you&amp;rsquo;ve got a great sound bite that helps tell the story, it can make the reporter&amp;rsquo;s job easier. Just don&amp;rsquo;t swing too far into happy go lucky marketing land. It’s important to remember that you’re talking to a person. Have a conversation - don’t talk at them.&lt;/p>
&lt;h4 id="go-slow" >
&lt;div>
Go slow
&lt;/div>
&lt;/h4>
&lt;p>It may seem obvious when you think about it, but as you&amp;rsquo;re talking the reporter is writing. Or at least you hope they are. Some do it by hand and type up notes late, some type right then and there. When you hear a pause it doesn&amp;rsquo;t always mean to keep going and it seldom means hurry up. Become extra comfortable with pauses. Check in if you&amp;rsquo;re going to fast, if they&amp;rsquo;re following, if they have any questions. I&amp;rsquo;ve had people bring me in a beer before because I&amp;rsquo;d had multiple cups of coffee through a few pitches, and they were trying to slow me down a bit. Know your pace, and then slow it down.&lt;/p>
&lt;h4 id="questions" >
&lt;div>
Questions
&lt;/div>
&lt;/h4>
&lt;p>It&amp;rsquo;s okay if they don&amp;rsquo;t have a lot of questions, they may not. They may have none at all. Yes, pause, and give them a chance, or even ask if they have any. But don&amp;rsquo;t stress too much if they have no questions.&lt;/p>
&lt;p>On the flip side of that - you’re PR person should have prepared a list of questions for you beforehand that the reporter could possibly throw your way. Be sure you’ve thought through and practiced all the Q&amp;amp;A scenarios before the interview so you aren’t caught off-guard when you’re in front of the reporter.&lt;/p>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>If it&amp;rsquo;s your first go around, don&amp;rsquo;t stress too much. Have the headlines you want in your mind and key messages, or better yet write them out. &lt;em>Personally I write key things on a whiteboard nice and large before I&amp;rsquo;m on the call&lt;/em>. Finally once you&amp;rsquo;re all done, enjoy reading the coverage. &lt;strong>But you&amp;rsquo;re not all done&lt;/strong> after you get some coverage look back, run a retrospective just like you would for a software project. What worked well, why did or didn&amp;rsquo;t something work. What can you improve next time.&lt;/p>
&lt;p>*Full disclosure, this is based across interactions with a small sample size of different PR agencies and individuals. Mileage may differ heavily from PR firm to PR firm, but hopefully the above provides at least some roadmap for more clarity vs. flying blind. As always if you&amp;rsquo;ve got feedback/questions, feel free to let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>&lt;/p>
&lt;p>&lt;em>Finally a special thanks to &lt;a href="http://www.twitter.com/pavtalk">Paul Katsen&lt;/a> for much of the inspiration on creating this post and to he and &lt;a href="http://www.twitter.com">Katie Boysen&lt;/a> for review&lt;/em>&lt;/p></description></item><item><title>Moving past averages in SQL (Postgres) – Percentiles</title><link>/2015/06/07/Moving-past-averages-in-SQL-Postgres-Percentiles/</link><pubDate>Sun, 07 Jun 2015 12:55:56 -0800</pubDate><guid>/2015/06/07/Moving-past-averages-in-SQL-Postgres-Percentiles/</guid><description>&lt;p>Often when you&amp;rsquo;re tracking a metric for the first time you take a look at your average. For example what is your ARPU - Average Revenue Per User. In theory this tells you if you can acquire new user how much you&amp;rsquo;ll make off that user. Or maybe what&amp;rsquo;s your average life time value of a customer. Yet, many that are more familiar looking and extracting meaning from data median or a few different looks at &lt;a href="http://apmblog.dynatrace.com/2012/11/14/why-averages-suck-and-percentiles-are-great/">percentiles can be much more meaningful&lt;/a>.&lt;/p>
&lt;p>And while you can very easily get the &lt;code>AVG&lt;/code> in Postgres, with a small amount more effort you can report on percentiles as well. Window functions have been around for some time in Postgres. They allow you to order your result set over a certain group. The most basic example is if you want to order by date, but know which one falls at place 10 in order you can use a window function and project out the &lt;code>rank()&lt;/code>.&lt;/p>
&lt;p>Beyond outputting the rank yourself and doing extra manipulation Postgres has some great utilities to make the most common uses even easier. Being able to compute things such as the perc 95 directly on the data, or lay out for every record in the result where it falls within a percentile is hugely useful. Let&amp;rsquo;s take a look:&lt;/p>
&lt;p>Assuming you have a table called purchases, which has a total in it we could try:&lt;/p>
&lt;pre>&lt;code>SELECT id,
total,
ntile(100) OVER (ORDER BY total) AS perc_rank
FROM purchases
&lt;/code>&lt;/pre>
&lt;p>This would give us something like:&lt;/p>
&lt;pre>&lt;code> id | total | perc_rank
----------|---------|-----------
264 | 12034 | 100
643 | 11830 | 100
...
...
304 | 751 | 95
&lt;/code>&lt;/pre>
&lt;p>What this would tell us is we have less than 5% of our purchases that have a total over 751. From here you can start to dig in and extract all sorts of different meanings, and by doing directly in SQL you&amp;rsquo;re closer to the data and have one less processing step.&lt;/p>
&lt;p>Percentiles get even more fun with the ordered set functions that came out in &lt;a href="/2014/02/02/Examining-PostgreSQL-9.4/">Postgres 9.4&lt;/a>. They even allow you to project out hypothetical values in certain cases. For now I&amp;rsquo;d encourage adding ntile to your toolbox anytime you&amp;rsquo;re analyzing average or medians it will make your world a bit better, and then consider exploring further on the &lt;a href="http://www.postgresql.org/docs/9.4/static/functions-aggregate.html#FUNCTIONS-ORDEREDSET-TABLE">ordered set functions&lt;/a>&lt;/p></description></item><item><title>Upsert lands in PostgreSQL 9.5 – A first look</title><link>/2015/05/08/Upsert-lands-in-PostgreSQL-9.5-A-first-look/</link><pubDate>Fri, 08 May 2015 12:55:56 -0800</pubDate><guid>/2015/05/08/Upsert-lands-in-PostgreSQL-9.5-A-first-look/</guid><description>&lt;p>If you’ve followed anything I’ve &lt;a href="/2012/04/30/why-postgres/">written about Postgres&lt;/a>, you know that I’m a fan. At the same time you know that there’s been one feature that so many other databases have, which Postgres lacks and it &lt;a href="/2014/08/15/my-postgres-wishlist-for-9.5/">causes a huge amount of angst for not being in Postgres&lt;/a>… Upsert. Well the day has come, it’s finally committed and will be available &lt;a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=168d5805e4c08bed7b95d351bf097cff7c07dd65">in Postgres 9.5&lt;/a>.&lt;/p>
&lt;p>Sure we’re still several months away from Postgres 9.5 being released, anywhere from 3-6 months as a best guess. That doesn’t mean we can’t take a first look at this feature. Though before we get into it a few special call outs of thanks to Peter Geoghegan of the &lt;a href="http://www.heroku.com/postgres">Heroku Postgres&lt;/a> team for being the primary author on it, Andres Freund who recently just joined &lt;a href="https://www.citusdata.com">Citus Data&lt;/a> for his heavy contributions, and Heikki Linnakangas as well for his contributions.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>And now onto the exploration. Upsert is the common name, but if you’re unfamiliar upsert is essentially create or update – Create this new record, but if a conflict exists update it. Let’s take a practical example.&lt;/p>
&lt;p>Assume you have a web scraper that imports product information into a table. Each product has a UPC code, title, description, and link. There’s a unique constraint on the UPC code. Now, if your web scraper tries to insert a new product, and a product with the same UPC already exists, you’d usually get an error. But you don’t want the query to fail, you’d want to update the existing product instead. Maybe with a new image, maybe a new description, whatever have you, but I don’t want it to blow up… I simply want to capture the new data and save it.&lt;/p>
&lt;p>&lt;strong>So before&lt;/strong>: Insert a record… Exception this violates a unique constraint… Let your app figure out what to do. &lt;em>protip: often applications would try to work around this, but you can run a chance of a race condition and duplicate records if there’s a conflict. TLDR; it’s not a perfect solution.&lt;/em>&lt;/p>
&lt;p>&lt;strong>Now&lt;/strong>: Insert a record… There’s a unique constraint violation… Okay, let’s just update all the new record’s fields &lt;strong>inside a single transaction&lt;/strong>&lt;/p>
&lt;p>So enough explanation, here’s how it actually looks in the syntax:&lt;/p>
&lt;pre>&lt;code>INSERT INTO products (
upc,
title,
description,
link)
VALUES (
123456789,
‘Figment #1 of 5’,
‘THE NEXT DISNEY ADVENTURE IS HERE - STARRING ONE OF DISNEY'S MOST POPULAR CHARACTERS! ’,
‘http://www.amazon.com/dp/B00KGJVRNE?tag=mypred-20’
)
ON CONFLICT DO UPDATE SET description=excluded.description;
&lt;/code>&lt;/pre>
&lt;p>It’s been a long time coming for this, and it makes building applications that need this kind of behavior even easier. While it would have been great for this to be available years ago, kudos to Postgres and its community for taking the approach that is safe for your data. The result we have now both provides the desired behavior of create or update, &lt;strong>and&lt;/strong> is performant without the risk of race conditions for your data.&lt;/p></description></item><item><title>A product management blueprint</title><link>/2015/02/18/A-product-management-blueprint/</link><pubDate>Wed, 18 Feb 2015 12:55:56 -0800</pubDate><guid>/2015/02/18/A-product-management-blueprint/</guid><description>&lt;p>I find myself having more conversations with startups – both small and large – about product management. I&amp;rsquo;ve blogged about some of &lt;a href="http://www.craigkerstiens.com/2013/03/13/planning-and-prioritizing/">the tools&lt;/a> in my chest here but I haven&amp;rsquo;t talked much about my “blueprint” for product management, which I find myself laying out in many conversations over coffee. What follows is this process I’ve used a few times over with new teams to get product and engineering moving together, shipping in a predictable manner, and tackling bigger and more strategic projects.&lt;/p>
&lt;h3 id="trust" >
&lt;div>
Trust
&lt;/div>
&lt;/h3>
&lt;p>I need to know how to work with my team, what their working styles are, and how we interact. This starts by simply interacting – specifically, outside of the office. I heard a similar opinion recently from Chris Fry (who ran engineering at Salesforce and Twitter) when he remarked something to the effect of: “you can tell a good PM from a bad one based on if he goes to drinks with his team.” Without getting hung up on whether it’s beers or coffee, it’s more about socialization with your team and time outside the office. My personal approach: expect a dinner invite over to my place when I take on running product for a new team.&lt;/p>
&lt;h3 id="velocity" >
&lt;div>
Velocity
&lt;/div>
&lt;/h3>
&lt;p>Once you&amp;rsquo;ve started to build some rapport, it&amp;rsquo;s time to get down to business. If being able to quickly commit and ship something isn’t a problem for you, then it’s easy to just assume this is working. In reality most teams I encounter that need PM support don’t have shipping nailed down. You probably already know if you fall into that category of feeling like you can commit and ship vs. not, so if you’re not able to do that a few tips:&lt;/p>
&lt;ul>
&lt;li>There’s some projects that everyone wants to ship that’s been tried over and over, &lt;strong>don’t tackle that first&lt;/strong>.&lt;/li>
&lt;li>Shipping something is better than nothing. It doesn&amp;rsquo;t have to be the right thing.&lt;/li>
&lt;li>Sometimes you don&amp;rsquo;t have to ship something to get velocity, you can launch things you already have&lt;/li>
&lt;li>&lt;del>Kill scope&lt;/del> Test things earlier and more iteratively, the more you can validate or try something without requiring a large investment the more everyone feels better about the direction you’re heading.&lt;/li>
&lt;/ul>
&lt;p>The key here is to commit to projects, deliver, and move on. Your velocity depends solely on delivery, not tasks, not sprints, not projects, etc. If you haven’t shipped anything in a year, then your velocity for the year is zero. At a later point you should move from the focus on shipping anything to shipping the right things, it’s more important to ship 1 thing that moves the needle than 10 that don’t, but that’s a later concern.&lt;/p>
&lt;h3 id="killing-things" >
&lt;div>
Killing things
&lt;/div>
&lt;/h3>
&lt;p>On the note of killing scope&amp;hellip; I&amp;rsquo;ve heard it articulated at times, that some engineers are happy when certain PMs show up because it means less work for them. When you go over to an engineer’s desk are you creating more or less work? The answer should be less some large percentage of the time. If you can find a way to accomplish your goals with less effort, it&amp;rsquo;s always a win. Every project everywhere always needs more time or money, what’s more innovative is how you can help a project to ship without one of those two.&lt;/p>
&lt;p>At a broader perspective than just scope – one of the biggest ways product can help engineering is by pushing harder for killing off features and the scope of a product. There&amp;rsquo;s a good test on if something is ready to ship: if you &lt;a href="http://www.craigkerstiens.com/2014/08/13/when-to-ship-when-to-kill/">tell beta users you&amp;rsquo;re killing it&lt;/a> and they yell at you that you shouldn’t kill it, then it’s ready to ship.&lt;/p>
&lt;p>If you’ve already shipped things, but they’re not delivering value or not being used, kill them. It’s that simple, it may have been a great idea at the time, but either invest in making sure it’s used or kill it so you don’t have to maintain it.&lt;/p>
&lt;h3 id="roadmap-planning" >
&lt;div>
Roadmap planning
&lt;/div>
&lt;/h3>
&lt;p>Usually getting velocity and killing things takes 3-6 months to really take full effect. At this point a team feels like they&amp;rsquo;re not under a pile of technical debt, and they can commit to shipping projects. This is the point when product and engineering are melding and you can really start to have fun about where you&amp;rsquo;re headed. At this point I&amp;rsquo;ve seen a huge mix of where engineers are more actively or less actively engaged in this process. And the reality is this is everyone’s job to be thinking about where you&amp;rsquo;re headed as a company – at least that&amp;rsquo;s the case for any company that classifies itself as a startup.&lt;/p>
&lt;p>My favorite tool for this is a team gridding exercise, you can read more about this &lt;a href="http://www.craigkerstiens.com/2013/03/13/planning-and-prioritizing/">here&lt;/a> and &lt;a href="http://www.craigkerstiens.com/2013/08/13/rule-of-thirds/">here&lt;/a>. This is often best conducted at an off-site where you have an opportunity for casual conversation which can foster broader thinking beyond the obvious bug fixes or smaller product improvements.&lt;/p>
&lt;p>&lt;em>One item of note I&amp;rsquo;ve heard from teams that have done this or similar exercises is they still have trouble deciding what to do after the fact. The role of product is to get to that decision. The most important part is getting to a decision and not the perfect one, gather data, decide, revisit as you go along. All of this isn’t to say that it’s an arbitrary decision, customers, data all inform that as well as the effort to impact matrix exercise, but in the end a clear direction isn’t executed on consensus.&lt;/em>&lt;/p>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>There’s really no end or done when it comes to the role and the work.&lt;/p>
&lt;p>There’s always another milestone and the market is always moving around you. But once you’re able to execute predictably and think in an ordered sense about your roadmap, you’re in a position to be able to monitor and adapt to the market, and even more so experiment and shape the market yourself. At that point you have to keep doing it and then the hard part becomes finding ways of keeping a fresh perspective &lt;em>protip: customers are an important part of that equation&lt;/em>&lt;/p>
&lt;p>Have tips/tricks/practices that I completely missed here or that you disagree with? I’m always happy to talk with others so drop me a note &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>.&lt;/p></description></item><item><title>A simple guide for DB migrations</title><link>/2014/10/01/A-simple-guide-for-DB-migrations/</link><pubDate>Wed, 01 Oct 2014 12:55:56 -0800</pubDate><guid>/2014/10/01/A-simple-guide-for-DB-migrations/</guid><description>&lt;p>Most web applications will add/remove columns over time. This is extremely common early on and even mature applications will continue modifying their schemas with new columns. An all too common pitfall when adding new columns is setting a not null constraint in Postgres.&lt;/p>
&lt;h3 id="not-null-constraints" >
&lt;div>
Not null constraints
&lt;/div>
&lt;/h3>
&lt;p>What happens when you have a not null constraint on a table is it will re-write the entire table. Under the cover Postgres is really just an append only log. So when you update or delete data it&amp;rsquo;s really just writing new data. This means when you add a column with a new value it has to write a new record. If you do this requiring columns to not be null then you&amp;rsquo;re re-writing your entire table.&lt;/p>
&lt;p>Where this becomes problematic for larger applications is it will hold a lock preventing you from writing new data during this time.&lt;/p>
&lt;h3 id="a-better-way" >
&lt;div>
A better way
&lt;/div>
&lt;/h3>
&lt;p>Of course you may want to not allow nulls and you may want to set a default value, the problem simply comes when you try to do this all at once. The safest approach at least in terms of uptime for your table -&amp;gt; data -&amp;gt; application is to break apart these steps.&lt;/p>
&lt;ol>
&lt;li>Start by simply adding the column with allowing nulls but setting a default value&lt;/li>
&lt;li>Run a background job that will go and retroactively update the new column to your default value&lt;/li>
&lt;li>Add your not null constraint.&lt;/li>
&lt;/ol>
&lt;p>Yes it&amp;rsquo;s a few extra steps, but I can say from having walked through this with a number of developers and their apps it makes for a much smoother process for making changes to your apps.&lt;/p></description></item><item><title>My wishlist for Postgres 9.5</title><link>/2014/08/15/My-wishlist-for-Postgres-9.5/</link><pubDate>Fri, 15 Aug 2014 12:55:56 -0800</pubDate><guid>/2014/08/15/My-wishlist-for-Postgres-9.5/</guid><description>&lt;p>As I followed along with the &lt;a href="/2014/03/24/Postgres-9.4-Looking-up/">9.4 release&lt;/a> of Postgres I had a few posts of things that I was excited about, some things that missed, and a bit of a wrap-up. I thought this year (year in the sense of PG releases) I&amp;rsquo;d jump the gun and lay out areas I&amp;rsquo;d love to see addressed in PostgreSQL 9.5. And here it goes:&lt;/p>
&lt;h3 id="upsert" >
&lt;div>
Upsert
&lt;/div>
&lt;/h3>
&lt;p>Merge/Upsert/Insert or Update whatever you want to call it this is still a huge wart that it doesn&amp;rsquo;t exist. There&amp;rsquo;s been a few implementations show up on mailing lists, and to the best of my understanding there&amp;rsquo;s been debate on if it&amp;rsquo;s performant enough or that some people would prefer another implementation or I don&amp;rsquo;t know what other excuse. The short is this really needs to happen, until that time you can always &lt;a href="http://stackoverflow.com/questions/1109061/insert-on-duplicate-update-in-postgresql/8702291#8702291">implement it with a CTE&lt;/a> which can have a race condition.&lt;/p>
&lt;h3 id="foreign-data-wrappers" >
&lt;div>
Foreign Data Wrappers
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s so much opportunity here, and this has easily been my &lt;a href="/2013/08/05/a-look-at-FDWs/">favorite feature of the past 2-3 years in Postgres&lt;/a>. Really any improvement is good here, but a hit list of a few valuable things:&lt;/p>
&lt;ul>
&lt;li>Pushdown of conditions&lt;/li>
&lt;li>Ability to accept a DSN to a utility function to create foreign user and tables.&lt;/li>
&lt;li>Better security around creds of foreign tables&lt;/li>
&lt;li>More out of the box FDWs&lt;/li>
&lt;/ul>
&lt;h3 id="statsanalytics" >
&lt;div>
Stats/Analytics
&lt;/div>
&lt;/h3>
&lt;p>Today there&amp;rsquo;s &lt;a href="http://madlib.net/">madlib&lt;/a> for machine learning, and 9.4 got support for &lt;a href="http://www.depesz.com/2014/01/11/waiting-for-9-4-support-ordered-set-within-group-aggregates/">ordered set aggregates&lt;/a>, but even still Postgres needs to keep moving forward here. PL-R and PL-Python can help a good bit as well, but having more out of the &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-aggregate.html">box functions&lt;/a> for stats can continue to keep it at the front of the pack for a database that&amp;rsquo;s not only safe for your data, but powerful to do analysis with.&lt;/p>
&lt;h3 id="multi-master" >
&lt;div>
Multi-master
&lt;/div>
&lt;/h3>
&lt;p>This is definitely more of a dream than not. Full multi-master replication would be amazing, and it&amp;rsquo;s getting closer to possible. The sad truth is even once it lands it will probably require a year of maturing, so even more reason for it to hopefully hit in 9.5&lt;/p>
&lt;h3 id="logical-replication" >
&lt;div>
Logical Replication
&lt;/div>
&lt;/h3>
&lt;p>The foundation made it in for 9.4 which is huge. This means we&amp;rsquo;ll probably see a good working out of the box logical replication in 9.5. For those less familiar this means the replication is SQL based vs. the binary WAL stream. This means things like using replication to upgrade across versions is possible. So not quite 0 downtime, but ~ a minute or two to upgrade versions. Even of large DBs.&lt;/p>
&lt;h3 id="an-official-gui" >
&lt;div>
An official GUI
&lt;/div>
&lt;/h3>
&lt;p>Alright this one is probably a pipe dream. And to kick it off, no pgAdmin doesn&amp;rsquo;t cut it. A good end user tool for connecting/querying would be huge. Fortunately the ecosystem is improving here with &lt;a href="http://www.jackdb.com">JackDB&lt;/a> (web based) and &lt;a href="https://eggerapps.at/pgcommander/">PG Commander&lt;/a> (mac app), but these still aren&amp;rsquo;t discoverable enough for most users.&lt;/p>
&lt;h3 id="what-do-you-want" >
&lt;div>
What do you want?
&lt;/div>
&lt;/h3>
&lt;p>So there&amp;rsquo;s my wishlist, what&amp;rsquo;s yours for 9.5? Let me know - &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>.&lt;/p></description></item><item><title>When to ship it, when to kill it</title><link>/2014/08/13/When-to-ship-it-when-to-kill-it/</link><pubDate>Wed, 13 Aug 2014 12:55:56 -0800</pubDate><guid>/2014/08/13/When-to-ship-it-when-to-kill-it/</guid><description>&lt;p>A few weeks ago at lunch I had the opportunity to catch up with a company in the current YC batch, building something very similar to dataclips. While we talked about a lot of things from what we&amp;rsquo;ve learned from dataclips, marketing, and other areas. One area we talked about was product and when to ship vs. when to kill things and I realized I hadn&amp;rsquo;t talked on my fairly simple but clear view on this publicly, so here it is.&lt;/p>
&lt;p>&lt;em>A large credit to &lt;a href="http://www.twitter.com/hirodusk">Adam Wiggins&lt;/a> for giving this model early on in Heroku and his approach to shipping product.&lt;/em>&lt;/p>
&lt;h3 id="a-precursor-to-shipping" >
&lt;div>
A precursor to shipping
&lt;/div>
&lt;/h3>
&lt;p>First a little background on shipping, in shipping something I&amp;rsquo;m going to assume you have some process of alpha/beta testing with users. This is actually fairly key, if you&amp;rsquo;re not testing it with users then well the rest of this is all moot. Alpha and beta testing is pretty simple, you need some early users. These can be friends, people within a network, or random users you select from. There&amp;rsquo;s different value to how you select these but that&amp;rsquo;s a topic for another time and place.&lt;/p>
&lt;h3 id="on-to-shipping" >
&lt;div>
On to shipping
&lt;/div>
&lt;/h3>
&lt;p>So how do you know it&amp;rsquo;s ready. The basic idea is super simple. Give it to some users in alpha/beta testing. Or start to roll it out following a one -&amp;gt; some -&amp;gt; many all principle (maybe to 5% or 10% of your userbase). Then take that brand new feature away.&lt;/p>
&lt;p>There&amp;rsquo;s a couple of ways to do this as far as mechanics. If you&amp;rsquo;re in contact with users such as alpha/beta users that you were higher touch with just email them. Tell them you&amp;rsquo;re removing the feature, or if you want to approach it more softly ask them how much they&amp;rsquo;d miss it if it were gone tomorrow. If you&amp;rsquo;re rolling it out more broadly perhaps behind a feature flag, flip it off and watch for feedback.&lt;/p>
&lt;p>&lt;em>Once you take the feature away or threaten to if you don&amp;rsquo;t have users with pitchforks almost immediately then it&amp;rsquo;s not ready to ship&lt;/em>.&lt;/p>
&lt;p>Go back to the drawing board and work more on it or simply kill it. As &lt;!-- raw HTML omitted -->@james_heroku&lt;!-- raw HTML omitted --> would say: &amp;ldquo;So you&amp;rsquo;re saying the reason to ship the shitty thing now is becase you&amp;rsquo;ve spent a lot of time on it?&amp;rdquo;. Stepping back it&amp;rsquo;s all logical, but all too often it&amp;rsquo;s not put in practice when shipping it.&lt;/p>
&lt;h3 id="your-metrics-can-lie" >
&lt;div>
Your metrics can lie
&lt;/div>
&lt;/h3>
&lt;p>Relying on just seeing a user spend some time on the new feature can often be misleading vs. the above approach. There&amp;rsquo;s a great talk by Des Traynor over at &lt;!-- raw HTML omitted -->intercom.io&lt;!-- raw HTML omitted --> that hits on this in part, the basic premise in there is that users shifting time from feature X to Y doesn&amp;rsquo;t mean it was a success it just means they&amp;rsquo;re spending time on something different. In launching new things you want to increase the overall value of your product, not simply shift users focus to the new flavor of the week.&lt;/p></description></item><item><title>Scaling Organizations - Scribing</title><link>/2014/07/14/Scaling-Organizations-Scribing/</link><pubDate>Mon, 14 Jul 2014 12:55:56 -0800</pubDate><guid>/2014/07/14/Scaling-Organizations-Scribing/</guid><description>&lt;p>In the process of growing a company there&amp;rsquo;s several hurdles based on the size of the company. What worked at 5 doesn&amp;rsquo;t work at 20, what works at 20 doesn&amp;rsquo;t work at 50, and what worked at 50 doesn&amp;rsquo;t work at 150. There&amp;rsquo;s a lot of talk about &lt;a href="http://lifehacker.com/5965280/follow-jeff-bezos-two-pizza-rule-to-avoid-the-dangers-of-groupthink">two pizza teams&lt;/a> and &lt;a href="http://adam.herokuapp.com/past/2011/4/28/scaling_a_development_team/">scaling development teams&lt;/a> out there. One thing I haven&amp;rsquo;t seen quite enough of is details around scribing and documenting things.&lt;/p>
&lt;h3 id="planning" >
&lt;div>
Planning
&lt;/div>
&lt;/h3>
&lt;p>At teams of 2 and 3 you get everyone in a room. Perhaps 1 person says what you&amp;rsquo;re going to do and you all rally around it, or maybe it&amp;rsquo;s a day of debate and persuasion from all sides.&lt;/p>
&lt;p>In the end though you all leave, get heads down, but all know what goal you&amp;rsquo;re working towards. At a larger company planning doesn&amp;rsquo;t scale quite this way. I&amp;rsquo;ve seen roadmapping and planning done a variety of ways as companies scale, but most times the thing they miss for far too long is documenting what comes out of it. Many may produce some level of artifact, but a cohesive wrap-up is often missed. Such an artifact should be easily digestible within a couple minutes, but also deep enough to answer many of the initial questions raised by the high level pieces.&lt;/p>
&lt;h3 id="meetings" >
&lt;div>
Meetings
&lt;/div>
&lt;/h3>
&lt;p>Meetings are a smaller level item than broader planning, and tend to go without thorough note taking than higher level planning. With growth you&amp;rsquo;ll have more meetings, trust me you will. The more meetings you have the more likely you may miss one or two you&amp;rsquo;re interested in. Or perhaps its as simple as some team members being out. Summer is especially hard around this. For a team of 10 it&amp;rsquo;s not uncommon that you may go all summer with at least 1 person not in the meeting and often two.&lt;/p>
&lt;p>Keeping those that miss the meeting well informed of what happened at it is critical as you scale. This is slightly less important at an extremely large company, though still valuable, but critical &lt;em>as you scale to larger&lt;/em>. As you&amp;rsquo;re scaling things are changing faster, and context can more easily get lost.&lt;/p>
&lt;p>So how do you improve this?&lt;/p>
&lt;p>Some practical tips:&lt;/p>
&lt;ul>
&lt;li>Have a set of running notes with someone consistently scribing is a great standard to set. &lt;em>If you missed a meeting you know where to go for it.&lt;/em>&lt;/li>
&lt;li>Recording who was and was not at the meeting can be incredibly valuable. I&amp;rsquo;ve heard statements &amp;ldquo;I said X at Y meeting&amp;rdquo;, the only problem with that statement is I wasn&amp;rsquo;t at Y meeting.&lt;/li>
&lt;li>Not only recording the meeting notes, but explicitly calling out who&amp;rsquo;s not there can help to know if that information should be explicitly passed along vs. just missed.&lt;/li>
&lt;li>Within your long running document have a summary to wrap it up. While scribing is great it can lead to not seeing the forest for the trees at times.&lt;/li>
&lt;/ul>
&lt;p>And a few from others:&lt;/p>
&lt;ul>
&lt;li>Meetings need a &lt;strong>purpose&lt;/strong> and an &lt;strong>agenda&lt;/strong>. If I don&amp;rsquo;t know why I&amp;rsquo;m having a meeting, or what will be covered, I won&amp;rsquo;t go. If I&amp;rsquo;m organizing a meeting and can&amp;rsquo;t spare the time to produce an agenda and goal, I shouldn&amp;rsquo;t waste other people&amp;rsquo;s time with the meeting – &lt;a href="http://www.twitter.com/jacobian">@jacobian&lt;/a>&lt;/li>
&lt;li>Any meeting over about 15-20 isn&amp;rsquo;t a meeting, it&amp;rsquo;s a presentation (which is OK too but make it clear that it&amp;rsquo;s a download, not a discussion). – &lt;a href="http://www.twitter.com/jacobian">@jacobian&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="email" >
&lt;div>
Email
&lt;/div>
&lt;/h3>
&lt;p>If you aren&amp;rsquo;t aware I&amp;rsquo;m a &lt;a href="/2014/02/07/my-email-hacks/">big fan of email&lt;/a>. Email is almost guaranteed that someone will at least open it (at least if its to them or a clear enough list). If you have something you want someone to read – email it. You can have a canonical wiki, or Trello board, or a variety of tools, but email will get more eyeballs than any of these. At the same time don&amp;rsquo;t email things that are already documented elsewhere.&lt;/p>
&lt;p>Emails are great for highlighting the things people absolutely need to know about. Short and concise emails will also help to improve reach. Be careful to make these emails have a high ratio of information size to value. If you have a lot of extra follow on content send them somewhere else to read.&lt;/p>
&lt;p>Finally don’t overuse email. If you’re sending the same thing every week people will become numb to this. &lt;a href="http://www.yesware.com">Monitoring if your emails are being opened/responded&lt;/a> to can help to know if you&amp;rsquo;re over-broadcasting.&lt;/p></description></item><item><title>Postgres and Connection Pooling</title><link>/2014/05/22/Postgres-and-Connection-Pooling/</link><pubDate>Thu, 22 May 2014 12:55:56 -0800</pubDate><guid>/2014/05/22/Postgres-and-Connection-Pooling/</guid><description>&lt;p>Connection pooling is quickly becoming one of the more frequent questions I hear. So here&amp;rsquo;s a primer on it. If there&amp;rsquo;s enough demand I&amp;rsquo;ll follow up a bit further with some detail on specific Postgres connection poolers and setting them up.&lt;/p>
&lt;h3 id="the-basics" >
&lt;div>
The basics
&lt;/div>
&lt;/h3>
&lt;p>For those unfamiliar, a connection pool is a group of database connections sitting around that are waiting to be handed out and used. This means when a request comes in a connection is already there whether in your framework or some other pooling process, and then given to your application for that specific request or transaction. In contrast, without any connection pooling your application will have to reach out to your database to establish a connection. While in the most basic sense you may thinking connecting to a database is quick, often theres &lt;a href="/2013/03/07/Fixing-django-db-connections/">some overhead here&lt;/a>. An example is SSL negotiation that may have to occur which means you&amp;rsquo;re looking at not 1-2 ms but often closer to 30-50.&lt;/p>
&lt;h3 id="the-options" >
&lt;div>
The options
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s really two major options when it comes to connection pooling:&lt;/p>
&lt;ul>
&lt;li>Framework pooling&lt;/li>
&lt;li>Standalone pooler&lt;/li>
&lt;li>&lt;em>Persistent connections&lt;/em>&lt;/li>
&lt;/ul>
&lt;h4 id="framework-pooling" >
&lt;div>
Framework pooling
&lt;/div>
&lt;/h4>
&lt;p>Today many modern application frameworks have at least some basic level of connection pooling. This means as your application server starts up it will create a pool of connections to use. It&amp;rsquo;s worth noting that while most modern frameworks have pooling, not all do, and further it may not be enabled by default.&lt;/p>
&lt;p>If you&amp;rsquo;re using the Sequel ORM for Ruby or SQLAlchemy for Python you&amp;rsquo;re well covered here. Further &lt;a href="https://devcenter.heroku.com/articles/concurrency-and-database-connections">Rails&lt;/a> is in pretty good shape also, though you may want to configure the pool size. For Django it&amp;rsquo;s a bit of a mixed story. For some time &lt;a href="/2013/03/07/Fixing-django-db-connections/">Django&lt;/a> did not have pooling at all. As of Django 1.6 you now have persistent connections by default and the ability to enable a pool.&lt;/p>
&lt;h4 id="persistent-connections" >
&lt;div>
Persistent connections
&lt;/div>
&lt;/h4>
&lt;p>Persistent connections don&amp;rsquo;t offer all of the benefits of pooling, but can often work well enough. Persistent connections is the act of maintaining a connection to your database once it&amp;rsquo;s connected. In the case where you have overhead of 30-50 ms each time you connect this can be quite helpful. At the same time you&amp;rsquo;re limited to the number of things that can be interacting with your databases as you&amp;rsquo;re limited to 1 connection per entry point to your webserver.&lt;/p>
&lt;h4 id="standalone-pooling" >
&lt;div>
Standalone pooling
&lt;/div>
&lt;/h4>
&lt;p>Postgres can be a bit of a sore spot when it comes to handling a ton of connections. For Postgres each connection you have to your database assumes some overhead of memory. Casual observations have seen it be between 5 and 10 MB assuming some basic query workload. And even if you have the memory overhead on your Postgres instance there becomes a point where management of connections becomes a limiting factor, we&amp;rsquo;ve seen this somewhere in the hundreds. While framework level connection poolers can give some better performance and lengthen the time before you have to deal with something more complex if you&amp;rsquo;re successful that time may come.&lt;/p>
&lt;p>&lt;em>A rule of thumb I&amp;rsquo;d use is if you have over 100 connections you want to look at something more robust&lt;/em>&lt;/p>
&lt;p>In this case that something more robust is a standalone pooler specifically for Postgres. A standalone pooler can be much more configurable overall letting you specify how it works for Postgres sessions, transactions, or statements. Further these are very specifically designed to work with Postgres handling a very large pool of connections without adding too much overhead. In contrast to the 5MB-ish standard connection to Postgres PG Bouncer has a 2kb per connection.&lt;/p>
&lt;p>So once you&amp;rsquo;re at the point of needing one there&amp;rsquo;s really two options.&lt;/p>
&lt;ol>
&lt;li>&lt;a href="http://pgfoundry.org/projects/pgbouncer">PG Bouncer&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.pgpool.net/mediawiki/index.php/Main_Page">PG Pool&lt;/a>&lt;/li>
&lt;/ol>
&lt;h3 id="pg-bouncer" >
&lt;div>
PG Bouncer
&lt;/div>
&lt;/h3>
&lt;p>My short and sweet recomendation is towards PG Bouncer. Contrary to how it&amp;rsquo;s named PG Pool is a multi purpose tool that does a lot of things (pooling, load balancing, replication, more). PG Bouncer takes the philosophy of doing one thing and doing it extremely well. I tend to favor these types of tools, which is the same reason I lean towards &lt;a href="https://github.com/wal-e/wal-e">WAL-E&lt;/a> to help with Postgres replication.&lt;/p>
&lt;h3 id="need-more" >
&lt;div>
Need more?
&lt;/div>
&lt;/h3>
&lt;p>Need more guidance with setting up and running PGBouncer? Give this &lt;a href="http://datachomp.com/archives/getting-started-with-pgbouncer/">guide&lt;/a> a look or try the &lt;a href="https://github.com/gregburek/heroku-buildpack-pgbouncer">pgbouncer buildpack&lt;/a> if running on Heroku. If you&amp;rsquo;re still interested in a deeper guide let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a> and I&amp;rsquo;ll work on getting it into the queue.&lt;/p>
&lt;p>Finally, make sure to sign-up below to get updates on Postgres content and first access to training.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Personas, data science, k-means</title><link>/2014/05/08/Personas-data-science-k-means/</link><pubDate>Thu, 08 May 2014 12:55:56 -0800</pubDate><guid>/2014/05/08/Personas-data-science-k-means/</guid><description>&lt;p>&lt;!-- raw HTML omitted --> If one of the industry lingo terms in title didn&amp;rsquo;t make your skin crawl a little then I need to try harder. At the same time you&amp;rsquo;ve probably heard someone use one of them in a non-trolling way in the last month. All three of these can often actually mean the same or similar things, it&amp;rsquo;s just people approach them differently from their world perspective.&lt;/p>
&lt;p>Personas don&amp;rsquo;t have to be marketing only speak, and data science doesn&amp;rsquo;t have to be only for stats people. My goal here is to simply set a context for the rest of the meat which talks about how you can simply look at your data and let it surface things you may not have known.&lt;/p>
&lt;h3 id="personas" >
&lt;div>
Personas
&lt;/div>
&lt;/h3>
&lt;p>I most commonly hear this term from &amp;ldquo;business people&amp;rdquo;. In fact not too long ago I recall interacting with someone that wanted to define personas for a company. They wanted to give them names, Joe and Mary. Joe is a father of 2, he works between 8 and 5, because he has to pick kids up from school, he&amp;rsquo;s always worked at fortune 100 companies. Mary is single, she&amp;rsquo;s a small business owner, she likes using tools instead of building things herself. If you think this is overly exaggerated on what you might expect that&amp;rsquo;s fair. Lets take a company I&amp;rsquo;m fond of &lt;a href="http://www.travisci.com">Travis CI&lt;/a>, if someone were to do this for them it might look like:&lt;/p>
&lt;ul>
&lt;li>Enterprise QA developer&lt;/li>
&lt;li>Startup full stack engineer&lt;/li>
&lt;li>Open source contributor&lt;/li>
&lt;/ul>
&lt;p>&lt;em>While this is all fine and good, a name and what they do doesn&amp;rsquo;t help in the substantial way I&amp;rsquo;d like.&lt;/em> Sure use personas if it helps you think about who you&amp;rsquo;re building the product for, but don&amp;rsquo;t expect customers to say yes I fit into only this bucket by trying to create classifications like this.&lt;/p>
&lt;p>&lt;strong>Let&amp;rsquo;s rephrase this to be super simple, groupings of people, no groupings of something that have a likely outcome based on some various inputs. Perhaps a better term for it is archtype&lt;/strong>&lt;/p>
&lt;h3 id="data-science" >
&lt;div>
Data science
&lt;/div>
&lt;/h3>
&lt;p>The application of math or statistics to learn something about your business. It doesn&amp;rsquo;t have to be big data, or NoSQL, simply the application of an algorithm to learn something. Extending it a bit, let&amp;rsquo;s assume it&amp;rsquo;s to do something actionable. This is a bit of a chicken and egg, because you can&amp;rsquo;t look at different data the same way everytime and have a valuable intrepretation. Sometimes it requires using several methods and examining the quality of the results. We can apply a little more clarity and judgement to ease this process though.&lt;/p>
&lt;h3 id="k-means" >
&lt;div>
k-means
&lt;/div>
&lt;/h3>
&lt;p>Alright onto the meat of what I was hoping to dig into here, well actually first a little more of a detour. Tracking key data for your business should be extremely clear. Hopefully you&amp;rsquo;re already doing this, if you&amp;rsquo;re not already tracking &lt;a href="/2014/02/26/Tracking-MoM-growth-in-SQL/">month over month growth&lt;/a> then go implement it today. If you don&amp;rsquo;t know your lifetime value or attrition rate then get on those too. But if you do have that and still are unclear how to move the needle on some goal, maybe that goal is increasing lifetime value then we&amp;rsquo;re at the right place.&lt;/p>
&lt;p>An extremely old algorithm for grouping things together and fairly commonly known in stats communities is &lt;a href="http://en.wikipedia.org/wiki/K-means_clustering">k-means&lt;/a>. It will group things together based on their likeness into some set, thats where the k comes from, of groups. It&amp;rsquo;s also known as an unsupervised clustering method, because you simply put the data in, and let it create these groupings for you. But why or how is it useful, you know you want to influence lifetime value so you should just find what makes people increase it and move that, well&amp;hellip; we may be able to get there with k-means.&lt;/p>
&lt;h3 id="practicality" >
&lt;div>
Practicality
&lt;/div>
&lt;/h3>
&lt;p>Most commonly when you search for k-means you&amp;rsquo;ll find some image similar to the one at the top of the post. This image graphically represents the clustering and the center of those clusters. And while visually interesting doesn&amp;rsquo;t actually tell you how to act upon it. A clearer way is actually often by examing the clusters and whats common, this tells you how to actually treat that archtype differently.&lt;/p>
&lt;p>In his book &lt;a href="http://www.amazon.com/dp/B00F0WRXI0?tag=mypred-20">Data Smart&lt;/a> John Foreman actually does a great job of laying this out in a pratical way. I&amp;rsquo;m particularly partial to his example also because it uses wine as an example. His example generates a variety of groupings, looking at the surrouding meta data its then possible to discover that:&lt;/p>
&lt;ul>
&lt;li>Grouping 1 likes Pinot&lt;/li>
&lt;li>Grouping 2 likes buying in bulk&lt;/li>
&lt;li>Grouping 3 likes buying small volume&lt;/li>
&lt;li>Grouping 4 likes bubbly&lt;/li>
&lt;/ul>
&lt;p>From here you can then start to get some idea of what you&amp;rsquo;d do with this. Perhaps you&amp;rsquo;d create a deal each month so that it appeals to all groups, or target them with different deals. Or maybe you&amp;rsquo;d simply not send an email to them if you didn&amp;rsquo;t have a deal that month. If course you could go more granular down into a recommendation engine to get a personalized recommendation for each customer, but for a lot of smaller apps/sites that&amp;rsquo;s simply not feasible.&lt;/p>
&lt;p>So in this case the output would look less like the image at the top and more like a set of 4 groups, then a CSV of every user and which grouping they fall in. Yes, its a less sexy graph, but a much more applicable CSV or excel output.&lt;/p>
&lt;p>In the end what we&amp;rsquo;ve really done is define personas or archtypes based on whats similar between customers vs. arbitrary perceptions we may come in with.&lt;/p>
&lt;h3 id="whats-next" >
&lt;div>
Whats next
&lt;/div>
&lt;/h3>
&lt;p>Up next I&amp;rsquo;ll actually dig in on a real world example here. &lt;a href="http://www.twitter.com/alexbaldwin">Alex&lt;/a> over at &lt;a href="https://hackdesign.org/">HackDesign&lt;/a> was kind enough to give me access to their data to create a more practical example of this. While I&amp;rsquo;m just now digging in, there should be a tangible example of this to follow.&lt;/p></description></item><item><title>Postgres Datatypes – The ones you're not using.</title><link>/2014/05/07/Postgres-Datatypes-The-ones-youre-not-using./</link><pubDate>Wed, 07 May 2014 12:55:56 -0800</pubDate><guid>/2014/05/07/Postgres-Datatypes-The-ones-youre-not-using./</guid><description>&lt;p>&lt;!-- raw HTML omitted -->Postgres has a variety of datatypes, in fact quite a few more than most other databases. Most commonly applications take advantage of the standard ones – integers, text, numeric, etc. Almost every application needs these basic types, the rarer ones may be needed less frequently. And while not needed on every application when you do need them they can be an extremely handy. So without further ado let&amp;rsquo;s look at some of these rarer but awesome types.&lt;/p>
&lt;h3 id="hstore" >
&lt;div>
hstore
&lt;/div>
&lt;/h3>
&lt;p>Yes, I&amp;rsquo;ve talked about &lt;a href="/2013/07/03/hstore-vs-json/">this one before&lt;/a>, yet still not enough people are using it. Of this list of datatypes this is one that could also have benefit for most if not all applications.&lt;/p>
&lt;p>Hstore is a key-value store directly within Postgres. This means you can easily add new keys and values &lt;em>(optionally)&lt;/em>, without haveing to run a migration to setup new columns. Further you can still get great performance by using Gin and GiST indexes with them, which automatically index all keys and values for hstore.&lt;/p>
&lt;p>&lt;em>It&amp;rsquo;s of note that hstore is an extension and not enabled by default. If you want the ins and outs of getting hands on with it, give the article on &lt;a href="http://postgresguide.com/sexy/hstore.html">Postgres Guide&lt;/a> a read.&lt;/em>&lt;/p>
&lt;h3 id="range-types" >
&lt;div>
Range types
&lt;/div>
&lt;/h3>
&lt;p>If there is ever a time where you have two columns in your database with one being a from, another being a to, you probably want to be using &lt;a href="http://www.postgresql.org/docs/9.2/static/rangetypes.html">range types&lt;/a>. Range types are just that a set of ranges. A super common use of them is when doing anything with calendaring. The place where they really become useful is in their ability to apply constraints on those ranges. This means you can make sure you don&amp;rsquo;t have overlapping time issues, and don&amp;rsquo;t have to rebuild heavy application logic to accomplish it.&lt;/p>
&lt;h3 id="timestamp-with-timezone" >
&lt;div>
Timestamp with Timezone
&lt;/div>
&lt;/h3>
&lt;p>Timestamps are annoying, plain and simple. If you&amp;rsquo;ve re-invented handling different timezones within your application you&amp;rsquo;ve wasted plenty of time and likely done it wrong. If you&amp;rsquo;re using plain timestamps within your application further there&amp;rsquo;s a good chance they dont even mean what you think they mean. Timestamps with timezone or timestamptz automatically includes the timezone with the timestamp. This makes it easy to convert between timezones, know exactly what you&amp;rsquo;re dealing with, and will in short save you a ton of time. There&amp;rsquo;s seldom a case you shouldn&amp;rsquo;t be using these.&lt;/p>
&lt;h3 id="uuid" >
&lt;div>
UUID
&lt;/div>
&lt;/h3>
&lt;p>Integers as primary keys aren&amp;rsquo;t great. Sure if you&amp;rsquo;re running a small blog they work fine, but if you&amp;rsquo;re application has to scale to a large size then integers can create problems. First you can run out of them, second it can make other details such as sharding a little more annoying. At the same time they are super readable. However, using the actual UUID datatype and extension to automatically generate them can be incredibly handy if you have to scale an application.&lt;/p>
&lt;p>&lt;em>Similar to hstore, there&amp;rsquo;s an &lt;a href="http://www.postgresql.org/docs/9.3/static/uuid-ossp.html">extension&lt;/a> that makes the UUID much more useful.&lt;/em>&lt;/p>
&lt;h3 id="binary-json" >
&lt;div>
Binary JSON
&lt;/div>
&lt;/h3>
&lt;p>This isn&amp;rsquo;t available yet, but will be in Postgres 9.4. &lt;a href="/2014/03/24/Postgres-9.4-Looking-up/">Binary JSON&lt;/a> is of course JSON directly within your database, but also lets you add Gin indexes directly onto JSON. This means a much simpler setup in not only inserting JSON, but having fast reads. If you want to learn a bit more about this, &lt;a href="/training/index.html">sign up&lt;/a> to &lt;a href="/training/index.html">get notified&lt;/a> of training regarding the upcoming PostgreSQL 9.4 release.&lt;/p>
&lt;h3 id="money" >
&lt;div>
Money
&lt;/div>
&lt;/h3>
&lt;p>Please don&amp;rsquo;t use this&amp;hellip; The money datatype assumes a single currency type, and generally brings with it more caveats than simply using a numeric type.&lt;/p>
&lt;h3 id="more" >
&lt;div>
More
&lt;/div>
&lt;/h3>
&lt;p>It&amp;rsquo;s already been pointed out on twitter that I missed a few. To give a quick highlight of some others:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.craigkerstiens.com/2012/08/20/arrays-in-postgres/">Arrays&lt;/a>&lt;/li>
&lt;li>Interval – time intervals, such as &amp;lsquo;1 hour&amp;rsquo;, &amp;lsquo;1 day&amp;rsquo;&lt;/li>
&lt;li>ISN - should help for anything with products&lt;/li>
&lt;li>Inet - Tracking IPs&lt;/li>
&lt;/ul>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>What&amp;rsquo;d I miss? What are you&amp;rsquo;re favorite types? Let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>, or sign-up below to updates on Postgres content and first access to training.&lt;/p></description></item><item><title>What you need to know about April 7 and your security on the web.</title><link>/2014/04/08/What-you-need-to-know-about-April-7-and-your-security-on-the-web./</link><pubDate>Tue, 08 Apr 2014 12:55:56 -0800</pubDate><guid>/2014/04/08/What-you-need-to-know-about-April-7-and-your-security-on-the-web./</guid><description>&lt;!-- raw HTML omitted -->
&lt;ul>
&lt;li>Yahoo&lt;/li>
&lt;li>Amazon.com&lt;/li>
&lt;li>Netflix&lt;/li>
&lt;li>Various banks&lt;/li>
&lt;li>Many more&lt;/li>
&lt;/ul>
&lt;p>If you&amp;rsquo;re interested in more technical details you can &lt;a href="http://www.heartbleed.com">follow along&lt;/a> or on the &lt;a href="https://blog.heroku.com/archives/2014/4/8/openssl_heartbleed_security_update">Heroku blog&lt;/a>.&lt;/p>
&lt;p>The short of it is you, yes you as in everyone, should rotate your passwords once all websites are safe. For further details please continue reading.&lt;/p>
&lt;h3 id="what-does-the-vulnerability-mean" >
&lt;div>
What does the vulnerability mean
&lt;/div>
&lt;/h3>
&lt;p>&lt;!-- raw HTML omitted --> In this case it allowed an external party to acquire a moderate amount of data from some computer running your website. Extremely clear examples (such as shown on the right) highlight an example of random third parties easily acquiring most recently logged in Yahoo mail usernames and passwords.&lt;/p>
&lt;h3 id="the-first-step" >
&lt;div>
The first step
&lt;/div>
&lt;/h3>
&lt;p>The first step in resolving this is actually not a step required by you at all, unless you&amp;rsquo;re running a production website online. The first step requires the developers running the site to update their site so they are no longer vulnerable. This as available to happen as early as April 7, and many major sites were fully updated and again safe as of April 8.&lt;/p>
&lt;h3 id="still-area-for-concern" >
&lt;div>
Still area for concern
&lt;/div>
&lt;/h3>
&lt;p>With security vulnerabilities there are two key things to consider. First is the vulnerability itself, second is whether its therotical or can be simply acted upon. Yes, there&amp;rsquo;s a range here. One of the most unfortunate pieces from talking to those that know about security is this was extremely trivial to act upon.&lt;/p>
&lt;p>&lt;em>This is made even worse in that this vulnerability has existed for 2 years without many knowing about it, meaning people have had an ability to snoop and collect parts of your data for two years&lt;/em>&lt;/p>
&lt;h3 id="what-to-do" >
&lt;div>
What to do?
&lt;/div>
&lt;/h3>
&lt;p>First things first, be extremely cautious with any major website you connect with anything important. Any account that you have a password and you care about the account you should cease logging into it &lt;strong>until you know its safe&lt;/strong>. As of the morning of April 8 here is a &lt;a href="https://gist.github.com/dberkholz/10169691">list of sites that were safe and ones that were vulnerable&lt;/a>. You can check any site today &lt;a href="http://filippo.io/Heartbleed/">here&lt;/a>.&lt;/p>
&lt;p>Once it&amp;rsquo;s clear that a site you know is now updated and safe either via that list of the latter tool you should change your password. For the time that this has existed and ease of comprimising its safe to assume all of your internet passwords and data within those accounts could have been comprimised. This means any website you have logged into within the last two years you should change the password for. Changing your passwords limits anyone being able to access that again.&lt;/p>
&lt;p>&lt;em>I am not a security expert or analyst, but have heavily interacted with many that are in dealing with this incident. This advice is high level intended at non technical experts, if you have any questions or feedback please let me know on twitter &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>&lt;/em>&lt;/p></description></item><item><title>Some non-traditional marketing tips</title><link>/2014/03/31/Some-non-traditional-marketing-tips/</link><pubDate>Mon, 31 Mar 2014 12:55:56 -0800</pubDate><guid>/2014/03/31/Some-non-traditional-marketing-tips/</guid><description>&lt;p>Marketing is generally unexciting to a ton of engineers, until it brings eyeballs which bring feedback and dollars. Marketing doesn&amp;rsquo;t have to always be cheesy campaigns or ads, it can often just be surfacing the things your customers actually do want to care about. My favorite type of marketing is when a service sells me on something at the exact time I want it. Here&amp;rsquo;s a few short tips on some non-traditional marketing that won&amp;rsquo;t seem sleezy but still can work quite well.&lt;/p>
&lt;h3 id="email-subscriptions-to-your-blog" >
&lt;div>
Email subscriptions to your blog
&lt;/div>
&lt;/h3>
&lt;p>RSS is pretty dead, google went and killed it with google reader. Sure there&amp;rsquo;s some decent replacements if you&amp;rsquo;re really tied to it. In particular &lt;a href="http://newsblur.com/">newsblur&lt;/a> by &lt;a href="http://www.twitter.com/samuelclay">@samuelclay&lt;/a> is a great reader. But now days content emerges on twitter, fb, and ranking services, then later is discovered via search. Both of these work pretty well, but twitter is ephemeral for so many. Email still converts incredibly well, if people are abandoning rss but still care about your content give them the ability for it to be put right in front of their face via email.&lt;/p>
&lt;h3 id="market-in-transactional-emails" >
&lt;div>
Market in transactional emails
&lt;/div>
&lt;/h3>
&lt;p>Have emails that include receipts? Account confirmations? General notices? No not a monthly newsletter! Transactional emails are obviously valuable to your users. Why not include a small call out to your latest announcement? Have a central hook that your emails can check from and simply include a small call to action within there.&lt;/p>
&lt;p>&lt;em>Credit to &lt;a href="http://www.twitter.com/stevenbristol">@stevenbristol&lt;/a> on &lt;a href="http://strongbusinessespodcast.com/16571/149964-episode-17-security-authy-and-disney">strong business podcast&lt;/a> for this one&lt;/em>&lt;/p>
&lt;h3 id="retarget-to-your-existing-users" >
&lt;div>
Retarget to your existing users
&lt;/div>
&lt;/h3>
&lt;p>In a similar vein of notifying your existing customers in transactional emails about news, you should be doing this all over the web. Retargeting is great to convert people once you&amp;rsquo;ve already got them on a landing page, but its also incredibly useful to get existing users to &lt;a href="http://insideintercom.io/talk-product-strategy-saying/">use a specific feature&lt;/a>. If you track if they&amp;rsquo;ve never used a feature retargeting is a great way to make them aware of it, and once they&amp;rsquo;ve used it just count it as a conversion.&lt;/p>
&lt;p>&lt;em>My favorite retargeting provider &lt;a href="http://www.perfectaudience.com/">perfect audience&lt;/a> makes this quite convenient as they allow a bit more control than most retargeting services&lt;/em>&lt;/p>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>Marketing doesn&amp;rsquo;t have to be throwing your product and messaging in someones face, but you should make your users aware of it. The more engaged they are they more they&amp;rsquo;ll stick around and be happy about using you&amp;rsquo;re product, assuming you&amp;rsquo;ve built a good one. What are some of your favorite tips?&lt;/p></description></item><item><title>A year's look at Postgres</title><link>/2014/03/26/A-years-look-at-Postgres/</link><pubDate>Wed, 26 Mar 2014 12:55:56 -0800</pubDate><guid>/2014/03/26/A-years-look-at-Postgres/</guid><description>&lt;p>A couple years back I started more regularly blogging, though I&amp;rsquo;ve done this off and on before, this time I kept some regularity. A common theme started to emerge with some content on Postgres about once a month because most of what was out there was much more reference oriented. A bit after that I connected with &lt;a href="http://www.twitter.com/peterc">petercooper&lt;/a>, who runs quite a few weekly email newsletters. As someone thats been interested helping give others a good reason to create content the obvious idea of &lt;a href="http://www.postgresweekly.com">Postgres Weekly&lt;/a> emerged.&lt;/p>
&lt;p>Since then we&amp;rsquo;ve now had the newsletter running for over a year, helped surface quite a bit of content, and grown to over 5,000 subscribers. First if you&amp;rsquo;re not subscribed, then go &lt;a href="http://www.postgresweekly.com">subscribe now&lt;/a>.&lt;/p>
&lt;p>And if you need some inspiration or just want to reminisce with me&amp;hellip; here&amp;rsquo;s a look back at a few highlights over the past year:&lt;/p>
&lt;h3 id="the-inagural-issue" >
&lt;div>
The inagural issue
&lt;/div>
&lt;/h3>
&lt;h4 id="postgres-the-bits-you-havent-foundhttppostgres-bitsherokuappcomutm_sourcecraigkerstiensutm_mediumblog" >
&lt;div>
&lt;a href="http://postgres-bits.herokuapp.com/?utm_source=craigkerstiens&amp;amp;utm_medium=blog">Postgres: The Bits You Haven&amp;rsquo;t Found&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>A slide-deck from a presentation at Heroku&amp;rsquo;s Waza conference that highlights many of the more unknown and rare features within Postgres, including &amp;lsquo;WITH&amp;rsquo;, arrays, pub/sub, and hstore.&lt;/p>
&lt;h4 id="open-source-releasepostgresql-hllhttpblogaggregateknowledgecom20130204open-source-release-postgresql-hllutm_sourcecraigkerstiensutm_mediumblog" >
&lt;div>
&lt;a href="http://blog.aggregateknowledge.com/2013/02/04/open-source-release-postgresql-hll/?utm_source=craigkerstiens&amp;amp;utm_medium=blog">Open Source Release:postgresql-hll&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>Aggregate Knowledge released Postgres HyperLogLog, which is a new Postgres datatype hll that strikes a balance between HyperLogLog and a simple set. This data type solves the problem of calculating uniques for a given data set efficiently both in performance and storage.&lt;/p>
&lt;p>&lt;em>The above is still one of my favorite extensions that most of the world doesn&amp;rsquo;t know about&lt;/em>&lt;/p>
&lt;h4 id="how-i-work-with-postgres---psql-my-postgresql-adminhttpwwwcraigkerstienscom20130213how-i-work-with-postgresutm_sourcecraigkerstiensutm_mediumbloga" >
&lt;div>
&lt;a href="http://www.craigkerstiens.com/2013/02/13/How-I-Work-With-Postgres/?utm_source=craigkerstiens&amp;amp;utm_medium=bloga">How I Work with Postgres - Psql, My PostgreSQL Admin&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>A common question for anyone new or even experienced with Postgres is whats the best editor out there? Most when they are asking this are asking for a GUI editor, this post highlights much of the power in the CLI &amp;lsquo;psql&amp;rsquo; editor.&lt;/p>
&lt;h3 id="a-mix-of-notable-entries" >
&lt;div>
A mix of notable entries
&lt;/div>
&lt;/h3>
&lt;h4 id="issue-6httppostgresweeklycomissues6-dissecting-postgresql-cve-2013-1899httpblogblackwinghqcom201304082utm_sourcecraigkerstiensutm_mediumblog" >
&lt;div>
&lt;a href="http://postgresweekly.com/issues/6">Issue 6&lt;/a> &lt;a href="http://blog.blackwinghq.com/2013/04/08/2/?utm_source=craigkerstiens&amp;amp;utm_medium=blog">Dissecting PostgreSQL CVE-2013-1899&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>After the heavily publicized and very serious security vulnerability was patched last week Blackwing intelligence took the chance to dig in. Read more on the details of the vulnerability such as what damage can be done and the basics of how its exploitable.&lt;/p>
&lt;h4 id="issue-16httppostgresweeklycomissues16-tom-lane-explains-query-planner-videohttpwwwjustintvsfpugb419326732utm_sourcecraigkerstiensutm_mediumblog" >
&lt;div>
&lt;a href="http://postgresweekly.com/issues/16">Issue 16&lt;/a> &lt;a href="http://www.justin.tv/sfpug/b/419326732?utm_source=craigkerstiens&amp;amp;utm_medium=blog">Tom Lane Explains Query Planner video&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>Tom Lane, one of the major contributors to Postgres and on the Postgres core team, was in San Francisco last week and gave a talk at the SF Postgres Users Group. Here&amp;rsquo;s the video from the talk where Tom explains the innards of the PostgreSQL query planner. Whether you&amp;rsquo;re a noob or a knowledgable Postgres user this is a must watch.&lt;/p>
&lt;h4 id="issue-35httppostgresweeklycomissues35-top-10-psql--commands-i-usehttpwwwchesnokcomdaily20131106top-10-psql-commands-i-use" >
&lt;div>
&lt;a href="http://postgresweekly.com/issues/35">Issue 35&lt;/a> &lt;a href="http://www.chesnok.com/daily/2013/11/06/top-10-psql-commands-i-use/">Top 10 psql ‘\’ commands I use&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>Psql is incredibly powerful, but the list of options within it can be overwhelming. Heres a straight forward list of @selenamarie’s top 10 commands.&lt;/p>
&lt;h4 id="issue-38httppostgresweeklycomissues38-everyday-postgres-tuning-a-brand-new-server---the-10-minute-editionhttpwwwchesnokcomdaily20131113everyday-postgres-tuning-a-brand-new-server-the-10-minute-editionutm_sourcecraigkerstiensutm_mediumblog" >
&lt;div>
&lt;a href="http://postgresweekly.com/issues/38">Issue 38&lt;/a> &lt;a href="http://www.chesnok.com/daily/2013/11/13/everyday-postgres-tuning-a-brand-new-server-the-10-minute-edition/?utm_source=craigkerstiens&amp;amp;utm_medium=blog">Everyday Postgres: Tuning a brand-new server - the 10 minute edition&lt;/a>
&lt;/div>
&lt;/h4>
&lt;p>After a fresh install, there are probably a few knobs you want to tweak on Postgres. If you’re new to doing this, it can be a bit overwhelming. Here’s a quick primer on tuning a brand new server to be more properly configured.&lt;/p>
&lt;h3 id="and-the-latest-issuehttppostgresweeklycomissues51" >
&lt;div>
&lt;a href="http://postgresweekly.com/issues/51">And the latest issue&lt;/a>
&lt;/div>
&lt;/h3>
&lt;p>Which highlights a wealth of information on &lt;a href="http://postgresweekly.com/issues/51">jsonb&lt;/a>, and a bit of various knowledge touching on &lt;a href="http://hans.io/blog/2014/03/25/postgresql_cluster/index.html?utm_source=craigkerstiens&amp;amp;utm_medium=blog">cluster&lt;/a>, &lt;a href="http://practiceovertheory.com/blog/2013/07/12/recursive-query-is-recursive/?utm_source=craigkerstiens&amp;amp;utm_medium=blog">recursive queries with CTEs&lt;/a>, and &lt;a href="http://www.davidhampgonsalves.com/Postgres-ranges/?utm_source=craigkerstiens&amp;amp;utm_medium=blog">range types&lt;/a>.&lt;/p>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>What did you like? Any favorites I missed? What would you like to see more of? Let me know &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a> or at &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens at gmail.com&lt;/a>&lt;/p></description></item><item><title>PostgreSQL 9.4 - Looking up (with JSONB and logical decoding)</title><link>/2014/03/24/PostgreSQL-9.4-Looking-up-with-JSONB-and-logical-decoding/</link><pubDate>Mon, 24 Mar 2014 12:55:56 -0800</pubDate><guid>/2014/03/24/PostgreSQL-9.4-Looking-up-with-JSONB-and-logical-decoding/</guid><description>&lt;p>Just a few weeks back I wrote a article discussing many of the things that were likely to miss making the &lt;a href="http://www.craigkerstiens.com/2014/02/15/PostgreSQL-9.4-What-I-Wanted/">9.4 PostgreSQL release&lt;/a>. Since that post a few weeks ago the landscape has already changed, and much more for the positive.&lt;/p>
&lt;p>&lt;em>The lesson here, is never count Postgres out&lt;/em>. As &lt;a href="www.linuxinsider.com/story/Bruce-Momjian-PostrgreSQL-Prefers-the-Scenic-Route-80045.html">Bruce discussed in a recent interview&lt;/a>, Postgres is slow and steady, but much like the turtle can win the race.&lt;/p>
&lt;p>So onto the actual features:&lt;/p>
&lt;h3 id="jsonb" >
&lt;div>
JSONB
&lt;/div>
&lt;/h3>
&lt;p>JSON has existed for a while in Postgres. Though the JSON that exists today simply validates that your text is valid JSON, then goes on to store it in a text field. This is fine, but not overly performant. If you do need some flexibility of your schema and performance without much effort then hstore may already work for you today, you can of course read more on this in an old post comparing &lt;a href="http://www.craigkerstiens.com/2013/07/03/hstore-vs-json/">hstore to json&lt;/a>.&lt;/p>
&lt;p>But let&amp;rsquo;s assume you do want JSON and a full document store, which is perfectly reasonable. Your option today is still best with the JSON datatype. And if you&amp;rsquo;re retrieving full documents this is fine, however if you&amp;rsquo;re searching/filtering on values within those documents then you need to take advantage of some functional indexing. You can do this some of the &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-json.html">built-in operators&lt;/a> or with full &lt;a href="https://postgres.heroku.com/blog/past/2013/6/5/javascript_in_your_postgres/">JS in Postgres&lt;/a>. This is a little more work, but also very possible to get good performance.&lt;/p>
&lt;p>Finally, onto the perfect world, where JSON isn&amp;rsquo;t just text in your database. For some time there&amp;rsquo;s been a discussion around hstore and its future progress and of course the future of JSON in Postgres. These two worlds have finally heavily converged for PostgreSQL 9.4 giving you &lt;a href="http://www.postgresql.org/message-id/E1WRpmB-0002et-MT@gemulon.postgresql.org">the best of both worlds&lt;/a>. With what was known as hstore2, by &lt;a href="http://obartunov.livejournal.com/177247.html">The Russians&lt;/a> under the covers, and collective efforts on JSONB (Binary representation of JSON) which included all the JSON interfaces you&amp;rsquo;d expect. We now have full document storage and awesome performance with little effort.&lt;/p>
&lt;p>Digging in a little further, why does it matter that its a binary representation? Well under the covers building on the hstore functionality brings along some of the awesome index types in Postgres. Namely GIN and possibly in the future GIST. These indexes will automatically index all keys and values within a document, meaning you don&amp;rsquo;t have to manually create individual functional indexes. Oh and they&amp;rsquo;re &lt;a href="http://thebuild.com/presentations/pg-as-nosql-pgday-fosdem-2013.pdf">fast and often small&lt;/a> on disk as well.&lt;/p>
&lt;h3 id="logical-decoding" >
&lt;div>
Logical Decoding
&lt;/div>
&lt;/h3>
&lt;p>Logical replication was another feature that I talked about that was likely missing. Here there isn&amp;rsquo;t the same positive news as JSONB, as there&amp;rsquo;s not a 100% usable feature available. Yet there is a big silver lining in it. &lt;a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=b89e151054a05f0f6d356ca52e3b725dd0505e53">Committed just over a week ago&lt;/a> was logical decoding. This means that we can decode the WAL (Write-Ahead-Log) into logical changes. In layman&amp;rsquo;s terms this means something thats unreadable to anything but Postgres (and version dependent in cases) can be intrepretted to a series of &lt;code>INSERT&lt;/code>s, &lt;code>UPDATE&lt;/code>s, &lt;code>DELETE&lt;/code>s, etc. With logical commands you could then start to get closer to cross version upgrades and eventually multi-master.&lt;/p>
&lt;p>With this commit it doesn&amp;rsquo;t mean all the pieces are there in the core of Postgres today. What it does mean is the part thats required of the Postgres core is done. The rest of this, which includes sending the logical replication stream somewhere, and then having something apply it can be developed fully as an extension.&lt;/p>
&lt;h3 id="in-conclusion" >
&lt;div>
In Conclusion
&lt;/div>
&lt;/h3>
&lt;p>Postgres 9.4 isn&amp;rsquo;t 100% complete yet, as the commitfest is still going on. You can follow along on the &lt;a href="www.postgresql.org/list/pgsql-hackers/2014-03/">postgres hackers mailing list&lt;/a> or on the &lt;a href="https://commitfest.postgresql.org/">commitfest app&lt;/a> where you can follow specific patches or even chip in on reviewing. And of course I&amp;rsquo;ll do my best to continue to highlight useful features here and surface them on &lt;a href="http://www.postgresweekly.com">Postgres Weekly&lt;/a> as well.&lt;/p></description></item><item><title>Tracking Month over Month Growth in SQL</title><link>/2014/02/26/Tracking-Month-over-Month-Growth-in-SQL/</link><pubDate>Wed, 26 Feb 2014 12:55:56 -0800</pubDate><guid>/2014/02/26/Tracking-Month-over-Month-Growth-in-SQL/</guid><description>&lt;p>&lt;!-- raw HTML omitted --> In analyzing a business I commonly look at reports that have two lenses, one is by doing various cohort analysis. The other is that I look for Month over Month or Week over Week or some other X over X growth in terms of a percentage. This second form of looking at data is relevant when you&amp;rsquo;re in a SaaS business or essentially anythign that does recurring billing. In such a business focusing on your MRR and working on &lt;a href="http://www.amazon.com/dp/B003XVYKRW?tag=mypred-20">growing your MRR is how success can often be measured&lt;/a>.&lt;/p>
&lt;p>I&amp;rsquo;ll jump write in, first lets assume you have some method of querying your revenue. In this case you may have some basic query similar to:&lt;/p>
&lt;pre>&lt;code>SELECT date_trunc('month', mydate) as date,
sum(mymoney) as revenue
FROM foo
GROUP BY date
ORDER BY date ASC;
&lt;/code>&lt;/pre>
&lt;p>This should give you a nice clean result:&lt;/p>
&lt;pre>&lt;code> date | revenue
------------------------+----------
2013-10-01 00:00:00+00 | 10000
2013-11-01 00:00:00+00 | 11000
2013-12-01 00:00:00+00 | 11500
&lt;/code>&lt;/pre>
&lt;p>Now this is great, but the first thing I want to do is start to see what my percentage growth month over month is. Surprise, surprise, I can do this directly in SQL. To do so I&amp;rsquo;ll use a &lt;a href="http://postgresguide.com/tips/window.html">window function&lt;/a> and then use the &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-window.html">lag function&lt;/a>. According to the Postgres docs&lt;/p>
&lt;p>&lt;em>lag(value any [, offset integer [, default any ]]) same type as value returns value evaluated at the row that is offset rows before the current row within the partition; if there is no such row, instead return default. Both offset and default are evaluated with respect to the current row. If omitted, offset defaults to 1 and default to null&lt;/em>&lt;/p>
&lt;p>Essentially it orders it based on the &lt;a href="http://www.postgresql.org/docs/9.3/static/tutorial-window.html">window function&lt;/a> and then pulls in the value from the row before. So in action it looks something like:&lt;/p>
&lt;pre>&lt;code>SELECT date_trunc('month', mydate) as date,
sum(mymoney) as revenue,
lag(mymoney, 1) over w previous_month_revenue
FROM foo
WINDOW w as (order by date)
GROUP BY date
ORDER BY date ASC;
&lt;/code>&lt;/pre>
&lt;p>Combining to actually make it a bit more pretty (with some casting to a numeric and then formatting a bit) in terms of a percentage:&lt;/p>
&lt;pre>&lt;code>SELECT date_trunc('month', mydate) as date,
sum(mymoney) as revenue,
round((1.0 - (cast(mymoney as numeric) / lag(mymoney, 1) over w)) * 100, 1) myVal_growth
FROM foo
WINDOW w as (order by date)
GROUP BY date
ORDER BY date ASC;
&lt;/code>&lt;/pre>
&lt;p>And you finally get a nice clean output of your month over month growth directly &lt;a href="http://www.amazon.com/dp/B0043EWUQQ?tag=mypred-20">in SQL&lt;/a>:&lt;/p>
&lt;pre>&lt;code> date | revenue | growth
------------------------+----------+--------
2013-10-01 00:00:00+00 | 10000 | null
2013-11-01 00:00:00+00 | 11000 | 10.0
2013-12-01 00:00:00+00 | 11500 | 4.5
&lt;/code>&lt;/pre></description></item><item><title>PostgreSQL 9.4 - What I was hoping for</title><link>/2014/02/25/PostgreSQL-9.4-What-I-Wanted/</link><pubDate>Tue, 25 Feb 2014 12:55:56 -0800</pubDate><guid>/2014/02/25/PostgreSQL-9.4-What-I-Wanted/</guid><description>&lt;p>Theres no doubt that the &lt;a href="/2014/02/02/Examining-PostgreSQL-9.4/">9.4 release&lt;/a> of PostgreSQL will have some great improvements. However, for all of the improvements it delivering it had the promise of being perhaps the most impactful release of &lt;a href="http://www.amazon.com/dp/B008IGIKY6?tag=mypred-20">Postgres&lt;/a> yet. Several of the features that would have given it my stamp of best release in at least 5 years are now already not making it and a few others are still on the border. Here&amp;rsquo;s a look at few of the things that were hoped for and not to be at least until another 18 months.&lt;/p>
&lt;h3 id="upsert" >
&lt;div>
Upsert
&lt;/div>
&lt;/h3>
&lt;p>Upsert, merge, whatever you want to call it, this is been a sore hole for sometime now. Essentially this is insert based on this ID or if that key already exists update other values. This was something being worked on pretty early on in this release, and throughout the process continuing to make progress. Yet as progress was made so were exteneded discussions about syntax, approach, etc. In the end two differing views on how it should be implemented have the patch still sitting there with other thoughts on an implementation but not code ready to commit.&lt;/p>
&lt;p>At the same time I&amp;rsquo;ll acknowledge upsert as a hard problem to address. The locking and concurrency issues are non-trivial, but regardless of those having this in there mostly kills the final argument for anyone to chose MySQL.&lt;/p>
&lt;h3 id="better-json" >
&lt;div>
Better JSON
&lt;/div>
&lt;/h3>
&lt;p>JSON is Postgres is super flexible, powerful, and &lt;strong>generally slow&lt;/strong>. Postgres does validation and some parsing of JSON, but without something like &lt;a href="https://postgres.heroku.com/blog/past/2013/6/5/javascript_in_your_postgres/">PLV8&lt;/a>, or &lt;a href="http://www.craigkerstiens.com/2013/05/29/postgres-indexes-expression-or-functional-indexes/">functional indexes&lt;/a> you may not get great performance. This is because under the covers the JSON is represented as text and as a result many of the more powerful indexes that could lend benefit, such as GIN or GIST, simply don&amp;rsquo;t apply here.&lt;/p>
&lt;p>As a related effort to this &lt;a href="http://postgresguide.com/sexy/hstore.html">hstore&lt;/a>, the key/value store, is working on being updated. This new support will add types and nesting making it much more usable overall. However the syntax and matching of how JSON functions isn&amp;rsquo;t guranteed to be part of it. The proposal and actually work is still there and not rejected yet, but looks heavily at risk. Backing a new binary representation of JSON with hstore 2 would deliver so many benefits further building upon the foundation of hstore, JSON, PLV8 that exists today for Postgres.&lt;/p>
&lt;h3 id="apt-get-for-your-extensions" >
&lt;div>
apt-get for your extensions
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m almost not even sure where to start with this one. The notion within a Postgres community is that packaging for distros is super simple and extensions should just be packaged for them. Then there&amp;rsquo;s &lt;a href="http://pgxn.org/">PGXN&lt;/a> the Postgres extension network where you can download and compile and muck with annoying settings to get extensions to build. This proposal would have delivered a built in installer much like NPM or rubygems or PyPi and the ability for someone to simply say install extension from this centralized repository. No, it was setting out to solve the issue of having a single repository but would make it much easier for people to run one.&lt;/p>
&lt;p>For all the awesome-ness that exists in extensions such as &lt;a href="http://tapoueh.org/blog/2013/02/25-postgresql-hyperloglog">HyperLogLog&lt;/a>, &lt;a href="http://www.craigkerstiens.com/2012/10/18/connecting_to_redis_from_postgres/">foreign data wrappers&lt;/a>, &lt;a href="http://madlib.net/">madlib&lt;/a> theres hundreds of other extensions that could be written and be valuable. They don&amp;rsquo;t even all require C, they could fully exist in JavaScript with PLV8. Yet I&amp;rsquo;m on the fence encouraging people to write such because if no one uses it then much of the point in the reusability of an extension is lost. Here&amp;rsquo;s hoping that there&amp;rsquo;s a change of opinion in the future that packaging is a solved problem and that creating an ecosystem for others to contribute to the Postgres world without knowing C is a positive thing.&lt;/p>
&lt;h3 id="logical-replication" >
&lt;div>
Logical replication
&lt;/div>
&lt;/h3>
&lt;p>When I first heard this might have some shot at making it in 9.4 I was shocked. This is something that while some may not take notice of I&amp;rsquo;ve felt pain of for many years. Logical replication means in short enabling upgrades across PostgreSQL versions without a dump and restore, but even more so laying the ground work for more complicated architectures like perhaps multi-master. Yes, even with logical replication in theres still plenty of work to do, but having the groundwork laid goes a long way. There are options for it today with third party tools, but the management of these is painful at best.&lt;/p>
&lt;h3 id="in-conclusion" >
&lt;div>
In conclusion
&lt;/div>
&lt;/h3>
&lt;p>The positive of this one is that the building blocks are in and its continuing to make progress. Its just that we&amp;rsquo;ll have to wait about 18 months before the release of PostgreSQL 9.5 before its in our hands.&lt;/p></description></item><item><title>How I hack email</title><link>/2014/02/07/my-email-hacks/</link><pubDate>Fri, 07 Feb 2014 12:55:56 -0800</pubDate><guid>/2014/02/07/my-email-hacks/</guid><description>&lt;p>In a conversation with &lt;a href="http://www.twitter.com/alexbaldwin">@alexbaldwin&lt;/a> yesterday the topic of email came up, with each of us quickly diving into various observations, how its both awesome and a great form of communication/engagement, how most people still do it really bad. Alex has some good experience with it with hack design having over 100,000 subscribers. A tangent in an entirely unrelated meeting with &lt;a href="http://www.twitter.com/mschoening">@mschoening&lt;/a> and others it was suggested instead of emailing a list to send out a ton of individual emails instead. Both of these reminded me that email is incredibly powerful, but taking advantage of its power has to be intentional.&lt;/p>
&lt;p>This is not about ways to get to inbox 0 or better manage your inflow of emails. Rather its about how to get the maximum output out of emails that you send, or minimum output depending on what you prefer.&lt;/p>
&lt;h3 id="1-email-to-100-vs-100-emails-to-1" >
&lt;div>
1 email to 100 vs. 100 emails to 1
&lt;/div>
&lt;/h3>
&lt;p>This is perhaps my favorite approach to get more efficient feedback and also know how broad an impact something has. Most smaller companies or groups within a company have a mailing list thats &lt;a href="mailto:all@yourcompany.com">all@yourcompany.com&lt;/a> or &lt;a href="mailto:ourgroup@mycompany.com">ourgroup@mycompany.com&lt;/a>. When people want to communicate out to the entire list its a great mechanism, however when you want feedback from the entire company its not a great mechanism.&lt;/p>
&lt;p>The reason being is that most people will know how many are on that list and assume that someone else will pick it up. This concept is fairly common in physical settings known as the &lt;a href="http://en.wikipedia.org/wiki/Bystander_effect">bystander effect&lt;/a>, stating that individuals often do not offer up help to a victim when there are other bystanders preset.&lt;/p>
&lt;p>Finally in certain situations you&amp;rsquo;ll want to hear the same thing 100 times. Hearing something once doesn&amp;rsquo;t represent how much others echo that. You&amp;rsquo;ll only see so many +1s on a thread, getting 100 individual responses ensure you get not only the breadth of responses but amplitude of them.&lt;/p>
&lt;p>&lt;em>FWIW, I ran a test of this sending an email to essentially all@heroku, then an individualized email in a similar form. The one directly addressed to people received 5x response as well as more thorough responses in the same time frame&lt;/em>&lt;/p>
&lt;h3 id="scaling-requests-for-input" >
&lt;div>
Scaling requests for input
&lt;/div>
&lt;/h3>
&lt;p>The issue that typically exists with the above is that you don&amp;rsquo;t want 100 responses from 100 people most of the time. Most of the time you want feedback from 2 or 3, then feedback from 4 or 5, then smaller feedback or revision from the rest of that 100. This is actually how I craft blog posts, I start with broad messaging/theming. At that level there&amp;rsquo;s truly 100 different directions it could go, that kind of input it not helpful when I have to narrow it down to a single one. When collecting product/roadmap input it can be helpful. Knowing which of the two I&amp;rsquo;m aiming for is critical in deciding a method.&lt;/p>
&lt;h3 id="being-explicit-about-the-before-and-the-ask" >
&lt;div>
Being explicit about the before and the ask
&lt;/div>
&lt;/h3>
&lt;p>On the note of crafting a blog post I do usually start with a request from 2 or 3 to get general direction. This takes the effect of, is this interesting? From here though theres still further refinement. The next phase is, does this flow, does it make sense? Here having a broader list is helpful so usually it&amp;rsquo;ll hit around 4 to 5 people. Finally I&amp;rsquo;ll revert to the 1 email to 100 people on a mailing list asking for grammar input because mine is crap. Here I don&amp;rsquo;t mind the bystander effect because I want people to intentionally filter so it works well.&lt;/p>
&lt;p>The key at each step of the process is being extremely clear of whats already been done. With a blog post as an example&amp;hellip; If I don&amp;rsquo;t explain the process of people having reviewed and set the goals and some consensus that it meets them, that several have been over it for flow, and that what I&amp;rsquo;m looking for now which is grammar feedback.&lt;/p>
&lt;h3 id="circulating-through-people" >
&lt;div>
Circulating through people
&lt;/div>
&lt;/h3>
&lt;p>Email and requests are a time burden on people. I commonly diversify and circle through a set of people. Much in the same way I reach out to people to have drinks or coffee every so often I am to not do the same person every week and only that person with the exception of my wife.&lt;/p>
&lt;p>Having more of a rotating basis of getting through people increases their excited-ness to provide input. If I&amp;rsquo;m always going back to the same people they may feel slightly drained by my constant requests, and quite rightfully so. At the same time the input is good, but diversifying where you receive it gives a broader perspective.&lt;/p>
&lt;h3 id="delayed-sending" >
&lt;div>
Delayed sending
&lt;/div>
&lt;/h3>
&lt;p>This is one that may be a little more obvious to people. But sending an email to slow down a thread, not seem over eager, or for whatever other reason you may have is hugely useful. There&amp;rsquo;s really two tools I look to here: 1. &lt;a href="http://www.boomeranggmail.com/referral_download.html?ref=vsz82">Boomerang&lt;/a> and 2. &lt;a href="http://www.yesware.com">Yesware&lt;/a>. Both have slightly different benefits. Boomerang with a much simpler interface, Yesware better integration with Salesforce. Regardless of which you choose, if you ever want to type and email but send it at some point later one of these is critical.&lt;/p>
&lt;h3 id="fin" >
&lt;div>
Fin.
&lt;/div>
&lt;/h3>
&lt;p>While this list is less of a defined process and more of a collection of random processes, several of these I&amp;rsquo;d be much less effective without, and the collection of all makes getting appropriate reactions from email incredibly useful. I&amp;rsquo;d love to hear what hacks you use to elicit positive impact from the emails you receive, as always if you have feedback please drop me a note.&lt;/p></description></item><item><title>Examining Postgres 9.4 - A first look</title><link>/2014/02/02/Examining-PostgreSQL-9.4/</link><pubDate>Sun, 02 Feb 2014 12:55:56 -0800</pubDate><guid>/2014/02/02/Examining-PostgreSQL-9.4/</guid><description>&lt;p>&lt;a href="http://www.amazon.com/dp/B008IGIKY6?tag=mypred-20">PostgreSQL&lt;/a> is currently entering its final commit fest. While its still going, which means there could still be more great features to come, we can start to take a look at what you can expect from it now. This release seems to bring a lot of minor increments versus some bigger highlights of previous ones. At the same time there&amp;rsquo;s still a lot on the bubble that may or may not make it which could entirely change the shape of this one. For a peek back of some of the past ones:&lt;/p>
&lt;h3 id="highlights-of-92" >
&lt;div>
Highlights of 9.2
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="/2013/01/10/more-on-postgres-performance/">pg_stat_statements&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://wiki.postgresql.org/wiki/Index-only_scans">Index only scans&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://postgres.heroku.com/blog/past/2012/12/6/postgres_92_now_available/#json_support">JSON Support&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://postgres.heroku.com/blog/past/2012/12/6/postgres_92_now_available/#range_type_support">Range types&lt;/a>&lt;/li>
&lt;li>Huge performance improvements&lt;/li>
&lt;/ul>
&lt;h3 id="highlights-of-93" >
&lt;div>
Highlights of 9.3
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="/2013/08/05/a-look-at-FDWs/">Postgres foreign data wrapper&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://postgres.heroku.com/blog/past/2013/9/9/postgres_93_now_available/#materialized_views">Materialized views&lt;/a>&lt;/li>
&lt;li>Checksums&lt;/li>
&lt;/ul>
&lt;h2 id="on-to-94" >
&lt;div>
On to 9.4
&lt;/div>
&lt;/h2>
&lt;p>With 9.4 instead of a simply list lets dive into a little deeper to the more noticable one.&lt;/p>
&lt;h3 id="pg_prewarm" >
&lt;div>
pg_prewarm
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;ll lead with one that those who need it should see huge gains (read larger apps that have a read replica they eventually may fail over to). Pg_prewarm will pre-warm your cache by loading data into memory. You may be interested in running &lt;code>pg_prewarm&lt;/code> before bringing up a new Postgres DB or on a replica to keep it fresh.&lt;/p>
&lt;p>&lt;em>Why it matters&lt;/em> - If you have a read replica it won&amp;rsquo;t have the same cache as the leader. This can work great as you can send queries to it and it&amp;rsquo;ll optimize its own cache. However, if you&amp;rsquo;re using it as a failover when you do have to failover you&amp;rsquo;ll be running in a degraded mode while your cache warms up. Running &lt;code>pg_pregwarm&lt;/code> against it on a periodic basis will make the experience when you do failover a much better one.&lt;/p>
&lt;h3 id="refresh-materialized-view-concurrently" >
&lt;div>
Refresh materialized view concurrently
&lt;/div>
&lt;/h3>
&lt;p>Materialized views just came into Postgres in 9.3. The problem with them is they were largely unusable. This was because they 1. Didn&amp;rsquo;t auto-refresh and 2. When you did refresh them it would lock the table while it ran the refresh making it unreadable during that time.&lt;/p>
&lt;p>Materialized views are often most helpful on large reporting tables that can take some time to generate. Often such a query can take 10-30 minutes or even more to run. If you&amp;rsquo;re unable to access said view during that time it greatly dampens their usefulness. Now running &lt;code>REFRESH MATERIALIZED VIEW CONCURRENTLY foo&lt;/code> will regenerate it in the background so long as you have a unique index for the view.&lt;/p>
&lt;h3 id="ordered-set-aggregates" >
&lt;div>
Ordered Set Aggregates
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m almost not really sure where to begin with this, the name itself almost makes me not want to take advantage. That said what this enables is if a few really awesome things you could do before that would require a few extra steps.&lt;/p>
&lt;p>While there&amp;rsquo;s plenty of aggregate functions in postgres getting something like percentile 95 or percentile 99 takes a little more effort. First you must order the entire set, then re-iterate over it to find the position you want. This is something I&amp;rsquo;ve commonly done by using a window function coupled with a CTE. Now its much easier:&lt;/p>
&lt;pre>&lt;code>SELECT percentile_disc(0.95)
WITHIN GROUP (ORDER BY response_time)
FROM pageviews;
&lt;/code>&lt;/pre>
&lt;p>In addition to varying percentile functions you can get quite a few others including:&lt;/p>
&lt;ul>
&lt;li>Mode&lt;/li>
&lt;li>percentile_disc&lt;/li>
&lt;li>percentile_cont&lt;/li>
&lt;li>rank&lt;/li>
&lt;li>dense_rank&lt;/li>
&lt;/ul>
&lt;h3 id="more-to-come" >
&lt;div>
More to come
&lt;/div>
&lt;/h3>
&lt;p>As I mentiend earlier the commit fest is still ongoing this means some things are still in flight. Here&amp;rsquo;s a few that still offer some huge promise but haven&amp;rsquo;t been committed yet:&lt;/p>
&lt;ul>
&lt;li>Insert on duplicate key or better known as Upsert&lt;/li>
&lt;li>HStore 2 - various improvements to HStore&lt;/li>
&lt;li>JSONB - Binary format of JSON built on top of HStore&lt;/li>
&lt;li>Logical replication - this one looks like some pieces will make it, but not a wholey usable implementation.&lt;/li>
&lt;/ul></description></item><item><title>Where to go with developer content</title><link>/2014/01/28/where-to-go-developer-content/</link><pubDate>Tue, 28 Jan 2014 12:55:56 -0800</pubDate><guid>/2014/01/28/where-to-go-developer-content/</guid><description>&lt;p>Last week I wrote up some &lt;a href="/2014/01/16/developer-marketing-where-to-start-with-content/">initial steps for getting started with marketing a developer&lt;/a> focused product. The short of it was quite trying to do &amp;ldquo;marketing&amp;rdquo; and just start putting out interesting material. A big part of this is sourcing material from your company&amp;rsquo;s developers. From there you want to gradually shift it from simply interesting technical posts to things that align with your core beliefs and add value to your customers.&lt;/p>
&lt;p>Perhaps the easiest way to do this is by highlighting some examples of it.&lt;/p>
&lt;h3 id="teach-them-how-to" >
&lt;div>
Teach them how to
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="https://www.tindie.com/">Tindie&lt;/a> is a marketplace focused on makers. Browsing their site is simply awesome, there&amp;rsquo;s everything from fully &lt;a href="https://www.tindie.com/products/browse/home/">built things&lt;/a> to raw supplies to let me &lt;a href="https://www.tindie.com/supplies/">start hacking&lt;/a>. The biggest problem though is they don&amp;rsquo;t tell me how to take advantage of so much on their site. Posts similar to New Relic&amp;rsquo;s on how they made their &lt;a href="http://blog.newrelic.com/2013/11/18/making-futurestack-badge/">awesome conference badges&lt;/a> with a ready made shopping list of components would both get me excited and teach me something I didn&amp;rsquo;t know how to do prior.&lt;/p>
&lt;p>Now a lot of this may seem obvious, but its not just about giving a how to. This doesn&amp;rsquo;t belong in a readme or in product documentation. Instead the activity of regularly crafting relevant stories that stretch how people think about hardware hacking should be a top of mind focus. It also positions you as a thought leader within the space. Right now there is no thought leader for makers, and theres ample opportunity to be that.&lt;/p>
&lt;h3 id="timely-content" >
&lt;div>
Timely content
&lt;/div>
&lt;/h3>
&lt;p>Chipmaker &lt;a href="https://www.spark.io/">Spark.io&lt;/a> recently hugely capitalized on the &lt;a href="http://gizmodo.com/google-just-bought-nest-for-3-2-billion-1500503899">Nest acquisition&lt;/a> by writing a post only days after of how you can build an &lt;a href="http://blog.spark.io/2014/01/17/open-source-thermostat/">open source Nest for $70&lt;/a>. I suspect they didn&amp;rsquo;t have such a post just lying around waiting for the acquisition and instead scrambled to get it all together almost as soon as it occurred.&lt;/p>
&lt;p>Over time the opportunity will always present itself in some form to attach yourself to another story. Sometimes this can be related to a direct competitor, sometimes its simply tangential. Being willing to quickly invest time when an opportunity presents itself is key to taking advantage of those opportunities. But please don&amp;rsquo;t let such opportunities be your only way of capturing attention, there should still be a steady beat and focus.&lt;/p>
&lt;h3 id="let-your-beliefs-come-out" >
&lt;div>
Let your beliefs come out
&lt;/div>
&lt;/h3>
&lt;p>Nearly everytime I sit down with some founder or very early employee at a company the vibe and impression I get from them is an order of magnitude stronger than the company&amp;rsquo;s public persona. At the root of every company trying to do something big is an acute focus on a problem with strong opinions about how to solve them. You don&amp;rsquo;t win people over by giving middle of the road opinions.&lt;/p>
&lt;p>Heroku&amp;rsquo;s often been an example of being extremely opinionated. For a long time you found bits of this within our product such as with an ephermal filesystem – which in the long term enables scalability. Or with directing the separation of code and config – which helps reproducability for when things go wrong and spinning up new copies of your app.&lt;/p>
&lt;p>Again the biggest problem with this opinionation wasn&amp;rsquo;t that it existed, but that it wasn&amp;rsquo;t talked about clearly or loudly enough. Its now much clearer and broader in the form of &lt;a href="http://12factor.net/">12 Factor&lt;/a> which fully codifies those strong opinions which influence the product, but also has applicability outside of Heroku.&lt;/p>
&lt;h3 id="all-of-the-approaches" >
&lt;div>
All of the approaches
&lt;/div>
&lt;/h3>
&lt;p>Doing just one of the above really isn&amp;rsquo;t enough. Having multiple types of content such as the above three allow you to be much more effective. Of course the way you manage them and distribute them changes based on the type of content, but more on that later.&lt;/p></description></item><item><title>Rethinking the limits on relational databases</title><link>/2014/01/24/Rethinking-the-limits-on-relational-databases/</link><pubDate>Fri, 24 Jan 2014 12:55:56 -0800</pubDate><guid>/2014/01/24/Rethinking-the-limits-on-relational-databases/</guid><description>&lt;p>Theres a lot of back and forth on NoSQL databases. The unfortunate part with all the back and forth and unclear definitions of NoSQL is that many of the valuable learnings are lost. This post isn&amp;rsquo;t about the differences in NoSQL definitions, but rather some of the huge benefits that do exist in whats often grouped into the schema-less world that could easily be applied to the relational world.&lt;/p>
&lt;h3 id="forget-migrations" >
&lt;div>
Forget migrations
&lt;/div>
&lt;/h3>
&lt;p>Perhaps the best thing about the idea of a schemaless database is that you can just push code and it works. Almost exactly five years ago Heroku shipped &lt;code>git push heroku master&lt;/code> letting you simply push code from git and it just work. CouchDB and MongoDB have done similar for databases&amp;hellip; you don&amp;rsquo;t have to run &lt;code>CREATE TABLE&lt;/code> or &lt;code>ALTER TABLE&lt;/code> migrations before working with your database. There&amp;rsquo;s something wonderful about just building and shipping your application without worrying about migrations.&lt;/p>
&lt;p>This is often viewed as a limitation of relational databases. Yet it doesn&amp;rsquo;t really have to. You see even in schema-less database the relationships are still there, its just you&amp;rsquo;re managing it at the application level. There&amp;rsquo;s no reason higher level frameworks or ORMs couldn&amp;rsquo;t handle the migration process. As it is today the process of adding a column to a relational database is quite straightforward in a sense where it doesn&amp;rsquo;t introduce downtime and is capable of letting the developer still move quickly its just not automatically baked in.&lt;/p>
&lt;pre>&lt;code># Assuming a column thats referenced doesn't exist
# Automatically execute relevant bits in your ORM
# This isn't code meant for you to run
ALTER TABLE foo ADD COLUMN bar varchar(255); # This is near instant
# Set your default value in your ORM
UPDATE TABLE foo SET bar = 'DEFAULT VALUE' WHERE bar IS NULL;
ALTER TABLE foo ALTER COLUMN bar NOT NULL;
&lt;/code>&lt;/pre>
&lt;p>Having Rails/Django/(Framework of your choice) automatically notice the need for a column to exist and make appropriate modifications you could work with it the same way you would managing a document relation in your code. Sure this is a manual painful process today, but theres no reason this can&amp;rsquo;t be fully handled by PostgreSQL or directly within an ORM .&lt;/p>
&lt;h3 id="documents" >
&lt;div>
Documents
&lt;/div>
&lt;/h3>
&lt;p>The other really strong case for the MongoDB/CouchDB camp is document storage. In this case I&amp;rsquo;m going to equate a document directly to a JSON object. JSON itself is a wonderfully simply model that works so well for portability, and having to convert it within your application layer is well just painful. Yes Postgres has a JSON datatype, and the JSON datatype is continuing to be adopted now by many other relational databases. &lt;em>I was shocked to hear that DB2 is getting support for JSON myself, while I expect improvements to come to it JSON was not at the top of my list&lt;/em>.&lt;/p>
&lt;p>And JSON does absolutely make sense as a data type within a column. But thats still a bit limiting as a full document store, what you want in those cases is any query result as a full JSON object. This is heavily undersold within Postgres that you can simply convert a full row to JSON with a &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-json.html">single function&lt;/a> - &lt;code>row_to_json&lt;/code>.&lt;/p>
&lt;p>Again having higher level frameworks take full advantage so that under the covers you can have your strongly typed tables, but a flexibility to map them to flexible JSON objects makes a great deal of sense here.&lt;/p>
&lt;h3 id="out-of-the-box-interfaces" >
&lt;div>
Out of the box interfaces
&lt;/div>
&lt;/h3>
&lt;p>This isn&amp;rsquo;t a strict benefit of schema-less databases. Some schema-less databases have this more out of the box such as Couch where others less so. The concept of exposing a rest interface is not something new, and has been tried on top of relational databases a &lt;a href="http://htsql.org/">few times over&lt;/a>. This is clearly something that does need to be delivered. The case for it is pretty clear, it reduces the work of people having to recreate admin screens and gives an easy onboarding process for noobs.&lt;/p>
&lt;p>Unfortunately there&amp;rsquo;s not clear progress on this today for Postgres or other relational databases. In contrast other databases are delivering on this front often from day one :/&lt;/p>
&lt;h3 id="where-to" >
&lt;div>
Where to
&lt;/div>
&lt;/h3>
&lt;p>Some of the shifts in schema-less or really in other databases in general are not so large they cannot be subsummed into a broader option. At the same time there are some strong merits such as the ones above which do take an active effort to deliver on expanding what is a &amp;ldquo;relational database&amp;rdquo;.&lt;/p></description></item><item><title>Where to start with developer content</title><link>/2014/01/21/Where-to-start-with-developer-content/</link><pubDate>Tue, 21 Jan 2014 12:55:56 -0800</pubDate><guid>/2014/01/21/Where-to-start-with-developer-content/</guid><description>&lt;p>Getting the word out&lt;/p>
&lt;h3 id="hacker-news" >
&lt;div>
Hacker News
&lt;/div>
&lt;/h3>
&lt;p>When it comes to marketing, specifically to developers, the most common question is how do I get on Hacker News? The second most commong is, well in addition to there what matters. This fully depends on your audience, and if you really only care about the former versus the broader issue of creating a sustainable model for circulating your content then just read these links then move on. If you want a full model for getting your content out there then keep reading.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://nathanael.hevenet.com/the-best-time-to-post-on-hacker-news-a-comprehensive-answer/">The best time to post to hacker news&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://alexstechthoughts.com/post/29406022580/how-to-get-on-the-frontpage-of-hacker-news">How to get on the front page of hacker news&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="more-than-just-hacker-news" >
&lt;div>
More than just Hacker News
&lt;/div>
&lt;/h3>
&lt;p>First off don&amp;rsquo;t get me wrong, HN can provide a great surge of short term traffic. There&amp;rsquo;s a few problems I have with this though. To begin with it gives you one shot to get your message perfect, if you have the wrong message, miss your call to action, or forget an affiliate link then you get your 15k viewers well you get no second shot at it. Though more interestingly and a bit of gut feel, I&amp;rsquo;ve noticed that traffic contains more bounes and lower engagement. And then theres the issue that its definitely not a science to getting on there&amp;hellip;.&lt;/p>
&lt;h3 id="other-news-sites" >
&lt;div>
Other news sites
&lt;/div>
&lt;/h3>
&lt;p>Of course theres other news sites, ones of relevance include reddit, dzone, monacle. I&amp;rsquo;ve found each of these can be similar in some ways to hacker news. Yet, they have a bit longer of a shelf life, giving me a slightly higher propensity to give them some attention. At the same time they also have a smaller reach.&lt;/p>
&lt;h3 id="twitter" >
&lt;div>
Twitter
&lt;/div>
&lt;/h3>
&lt;p>Twitter is yet another method that can work quite well. Observations of it include lower traffic than something like a hacker news, and equal to better engagement overall. Perhaps the most interesting piece I find is that you&amp;rsquo;ll often get more intelligent and also positive discussion on twitter vs. HN. There is one huge fail I find with twitter that nearly every company commits. The author of the post or company twitter handle posts it, then 10 people proceed to retweet it within 10 minutes. The problem with this if you&amp;rsquo;re anything like places I&amp;rsquo;ve worked at is you have a strong overlap of followers, this combined with the empheral nature of twitter means you&amp;rsquo;re diminishing reach. Instead having a few people (dont make it a strict requirement) retweet later in the day can help broaden your reach.&lt;/p>
&lt;h3 id="google-plus" >
&lt;div>
Google Plus
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m slightly ashamed to be including this on here&amp;hellip; I don&amp;rsquo;t use it, I don&amp;rsquo;t care for it, etc. I have no hard evidence of this either, but publishing on Google Plus seems to speed up Google&amp;rsquo;s indexing of the article to be much closer to instant. Take it for what you will.&lt;/p>
&lt;h3 id="email" >
&lt;div>
Email
&lt;/div>
&lt;/h3>
&lt;p>That thing you still get too much of is a great way of getting content out.&lt;/p>
&lt;h3 id="long-tail" >
&lt;div>
Long tail
&lt;/div>
&lt;/h3>
&lt;p>Please please please do not underestimate the value in the long tail of your content. Google sends me between 200 and 500 new uniques a day due to various articles. Think about the areas you want to rank for and create your content for them, work on getting it out and syndicated, then&lt;/p></description></item><item><title>Where to start with developer content</title><link>/2014/01/16/Where-to-start-with-developer-content/</link><pubDate>Thu, 16 Jan 2014 12:55:56 -0800</pubDate><guid>/2014/01/16/Where-to-start-with-developer-content/</guid><description>&lt;p>Commonly at developer focused companies the question from a marketing team will come up of &amp;ldquo;How do we get content that developers find interesting&amp;rdquo;? Or how can I get our developers to blog more? Or some other similar question. I general the question of creating content and engaging with developers is a very common one, and often theres a mismatch between what marketing wants to do and what developers appreciate.&lt;/p>
&lt;h3 id="stop-marketing" >
&lt;div>
Stop marketing
&lt;/div>
&lt;/h3>
&lt;p>Forget trying to &amp;ldquo;market&amp;rdquo; to developers. Hopefully you at least have developers that believe in the product their building, if thats not the case then find a new product or a new team. If you&amp;rsquo;ve got a product targetted at developers and a team that believes in it then you&amp;rsquo;re already half way there to marketing it. Now back to the first point, forget trying to market it. Start with building some form of an audience, reputation, respect among other developers. This isn&amp;rsquo;t done through ads, email marketing, SEO or any of that. Its done by creating content that developers find interesting, as a first step forget your product entirely, but don&amp;rsquo;t worry we&amp;rsquo;ll get there soon enough.&lt;/p>
&lt;h3 id="sourcing-content" >
&lt;div>
Sourcing content
&lt;/div>
&lt;/h3>
&lt;p>The first piece of it on finding content should actually be extremely simple. Typically engineers love sharing knowledge and information. At least once a week there&amp;rsquo;s an email out to all the engineers of a truly interesting approach to something. This content is often not in a perfect form for external publication, but quite close. In particular Heroku has &lt;a href="https://twitter.com/mmcgrana">one employee&lt;/a>, an early employee and now architect, that every email he sends to such a group I pull down and save for future reading. Another example of this was one of the Heroku founder Adam Wiggins, you can find many similar emails slightly cleaned up as blog posts on his own &lt;a href="https://adam.heroku.com/">blog&lt;/a>.&lt;/p>
&lt;p>Take these emails, find someone technical enough to clean them up and ship them. Your goals here are to simply build some level of connection with other developers. Now a lot of time these may not be in the right &amp;ldquo;voice&amp;rdquo; for your company blog. Thats quite fine, I&amp;rsquo;m a strong proponent of letting developers create their own personalitiies. The place for the content then may not always be on the company blog. In general I find there&amp;rsquo;s three groupings:&lt;/p>
&lt;ul>
&lt;li>Content for the company blog by an employee&lt;/li>
&lt;li>Content for an individuals blog (the caveat here is they need to regularly create content - every 6 months doesnt cut it)&lt;/li>
&lt;li>Content for an &lt;a href="http://codeascraft.com/">engineering blog&lt;/a> (if you have enough of the above that blog infrequently this is a great home for it)&lt;/li>
&lt;/ul>
&lt;h3 id="dont-worry-about-the-product-yet" >
&lt;div>
Don&amp;rsquo;t worry about the product yet
&lt;/div>
&lt;/h3>
&lt;p>No really don&amp;rsquo;t worry about pitching your product. There was an awesome piece on the &lt;a href="http://insideintercom.io/new-features-usually-flop/">intercom blog talking about why most features fail&lt;/a> and how companies pitch the details versus the problem they solve. Though there was a hidden gem in there:&lt;/p>
&lt;p>{% blockquote [Des Traynor] [http://insideintercom.io/new-features-usually-flop/] [New Features Usually Flop] %}
Telling your customers something is a “ground up rewrite”, “HTML5 based”, “responsive” or anything like that will miss the mark unless you’re selling to developers.
{% endblockquote %}&lt;/p>
&lt;p>For companies targetting developers this actually works really well, as a developer I care about the how. Simply put its interesting. Another great example of this is &lt;a href="http://blog.priceonomics.com/">priceonomics&lt;/a>. To be honest I only checked what they actually do in writing this post, but their posts I regularly find interesting.&lt;/p>
&lt;h3 id="whats-next" >
&lt;div>
Whats next
&lt;/div>
&lt;/h3>
&lt;p>What do you want to know about? Creating a voice/brand, starting to pitch your product, content distribution? Let me know. A good about of my time is spent on these and happy to discuss further on whats valuable to others so we don&amp;rsquo;t have to suffer through painful marketing. Let me know &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a> or &lt;a href="http://www.twitter.com/craigkerstiens">@craigkerstiens&lt;/a>&lt;/p></description></item><item><title>Digging in with Foreign Tables</title><link>/2013/12/19/Digging-in-with-Foreign-Tables/</link><pubDate>Thu, 19 Dec 2013 12:55:56 -0800</pubDate><guid>/2013/12/19/Digging-in-with-Foreign-Tables/</guid><description>&lt;p>I wrote a couple months back about exploring FDWs. Its become quite clear to me, despite still having ample room for improvement, they&amp;rsquo;re not getting enough attention. Foreign data wrappers are perhaps better thought of as a foreign table, or even better yet as a view into some remote data source. They don&amp;rsquo;t take care of auto-updating or syncing data, thats all up to you, but it gives you a straight forward mapping to work with remote data easier.&lt;/p>
&lt;p>The first step in working with FDWs is getting them setup. I wrote an earlier post on how to do this manually. And if you&amp;rsquo;re on Heroku theres an even easier solution if you want to setup a mapping entirely from one DB to another. The &lt;a href="">pg-extras CLI plugin&lt;/a> has a command &lt;code>fdwsql&lt;/code> which will generate the SQL to map all the tables for you. To run it simply specify the prefix app and database:&lt;/p>
&lt;pre>&lt;code>heroku pg:fdwsql yourprefix APP::DATABASE_URL
&lt;/code>&lt;/pre>
&lt;p>This will generate a lot of SQL. From here you&amp;rsquo;ll want to connect to the database where you want those foreign tables to be visible. Then run all the SQL. This will create all the foreign tables, this will mostly look just like another view or table to you in &lt;code>\d&lt;/code>.&lt;/p>
&lt;h3 id="tips-on-working-with-them" >
&lt;div>
Tips on working with them
&lt;/div>
&lt;/h3>
&lt;p>For the most part you can work with your foreign tables just like any other view or table. You can insert into them, read from them, join against them. Though currently foreign tables have some performance limitations, such as when joining it may return a lot more data than you expect then join. To make your performance a bit more ideal you can follow a few basic principles.&lt;/p>
&lt;p>Lets look at some example tables to highlight this:&lt;/p>
&lt;pre>&lt;code>&amp;gt; \d
users
todos
&lt;/code>&lt;/pre>
&lt;p>In this case users is local and the todos are a foreign table. Looking at each of the schemas we have something like you might expect:&lt;/p>
&lt;pre>&lt;code>&amp;gt; \d users
Table &amp;quot;public.users&amp;quot;
Column | Type | Modifiers
-------------+-----------------------------+-----------
id | integer | not null
email | text |
created_at | timestamp without time zone |
Indexes:
&amp;quot;users_pkey&amp;quot; PRIMARY KEY, btree (id)
&amp;quot;users_created&amp;quot; btree (created_at)
&amp;gt; \d todo
Foreign Table &amp;quot;public.todo&amp;quot;
Column | Type | Modifiers
-------------+-----------------------------+-----------
id | integer | not null
user_id | integer |
desc | text |
created_at | timestamp without time zone |
status | boolean |
Indexes:
&amp;quot;users_pkey&amp;quot; PRIMARY KEY, btree (id)
&amp;quot;todo_created&amp;quot; btree (created_at)
&lt;/code>&lt;/pre></description></item><item><title>The best Postgres feature you're not using – CTEs aka WITH clauses</title><link>/2013/11/18/best-postgres-feature-youre-not-using/</link><pubDate>Mon, 18 Nov 2013 12:55:56 -0800</pubDate><guid>/2013/11/18/best-postgres-feature-youre-not-using/</guid><description>&lt;p>SQL by default isn&amp;rsquo;t typically friendly to dive into, and especially so if you&amp;rsquo;re reading someone else&amp;rsquo;s already created queries. For some reason most people throw out principles we follow in other languages &lt;a href="http://www.craigkerstiens.com/2013/07/29/documenting-your-postgres-database/">such as commenting&lt;/a> and composability just for SQL. I was recently reminded of a key feature in Postgres that most don&amp;rsquo;t use by &lt;a href="http://www.twitter.com/timonk">@timonk&lt;/a> highlighting it in his AWS Re:Invent Redshift talk. The simple feature actually makes SQL both readable and composable, and even for my own queries capable of coming back to them months later and understanding them, where previously they would not be.&lt;/p>
&lt;p>The feature itself is known as CTEs or common table expressions, you may also here it referred to as &lt;code>WITH&lt;/code> clauses. The general idea is that it allows you to create something somewhat equivilant to a view that only exists during that transaction. You can create multiple of these which then allow for clear building blocks and make it simple to follow what you&amp;rsquo;re doing.&lt;/p>
&lt;p>Lets take a look at a nice simple one:&lt;/p>
&lt;pre>&lt;code>WITH users_tasks AS (
SELECT
users.email,
array_agg(tasks.name) as task_list,
projects.title
FROM
users,
tasks,
project
WHERE
users.id = tasks.user_id
projects.title = tasks.project_id
GROUP BY
users.email,
projects.title
)
&lt;/code>&lt;/pre>
&lt;p>Using this I could now just append some basic other query on to the end that references this CTE &lt;code>users_tasks&lt;/code>. Something akin to:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM users_tasks;
&lt;/code>&lt;/pre>
&lt;p>But where it becomes more interesting is chaining these together. So while I have all tasks assigned to each user here, perhaps I want to then find which users are responsible for more than 50% of the tasks on a given project, thus being the bottleneck. To oversimplify this we could do it a couple of ways, total up the tasks for each project, and then total up the tasks for each user per project:&lt;/p>
&lt;pre>&lt;code>total_tasks_per_project AS (
SELECT
project_id,
count(*) as task_count
FROM tasks
GROUP BY project_id
),
tasks_per_project_per_user AS (
SELECT
user_id,
project_id,
count(*) as task_count
FROM tasks
GROUP BY user_id, project_id
),
&lt;/code>&lt;/pre>
&lt;p>Then we would want to combine and find the users that are now over that 50%:&lt;/p>
&lt;pre>&lt;code>overloaded_users AS (
SELECT tasks_per_project_per_user.user_id,
FROM tasks_per_project_per_user,
total_tasks_per_project
WHERE tasks_per_project_per_user.task_count &amp;gt; (total_tasks_per_project / 2)
)
&lt;/code>&lt;/pre>
&lt;p>Now as a final goal I&amp;rsquo;d want to get a comma separated list of tasks of the overloaded users. So we&amp;rsquo;re simply giong to join against that &lt;code>overloaded_users&lt;/code> and our initial list of &lt;code>users_tasks&lt;/code>. Putting it all together it looks somewhat long, but becomes much more readable. And as a bonus I layered in some comments.&lt;/p>
&lt;pre>&lt;code>--- Created by Craig Kerstiens 11/18/2013
--- Query highlights users that have over 50% of tasks on a given project
--- Gives comma separated list of their tasks and the project
--- Initial query to grab project title and tasks per user
WITH users_tasks AS (
SELECT
users.id as user_id,
users.email,
array_agg(tasks.name) as task_list,
projects.title
FROM
users,
tasks,
project
WHERE
users.id = tasks.user_id
projects.title = tasks.project_id
GROUP BY
users.email,
projects.title
),
--- Calculates the total tasks per each project
total_tasks_per_project AS (
SELECT
project_id,
count(*) as task_count
FROM tasks
GROUP BY project_id
),
--- Calculates the projects per each user
tasks_per_project_per_user AS (
SELECT
user_id,
project_id,
count(*) as task_count
FROM tasks
GROUP BY user_id, project_id
),
--- Gets user ids that have over 50% of tasks assigned
overloaded_users AS (
SELECT tasks_per_project_per_user.user_id,
FROM tasks_per_project_per_user,
total_tasks_per_project
WHERE tasks_per_project_per_user.task_count &amp;gt; (total_tasks_per_project / 2)
)
SELECT
email,
task_list,
title
FROM
users_tasks,
overloaded_users
WHERE
users_tasks.user_id = overloaded_users.user_id
&lt;/code>&lt;/pre>
&lt;p>CTEs won&amp;rsquo;t always be quite as performant as optimizing your SQL to be as concise as possible. In most cases I have seen performance differences smaller than a 2X difference, this tradeoff for readability is a nobrainer as far as I&amp;rsquo;m concerned. And with time the Postgres optimizer should continue to get better about such performance.&lt;/p>
&lt;p>As for the verbosity, yes I could have done this query in probably 10-15 lines of very concise SQL. Yet, most may not be able to understand it quickly if at all. Readability is huge when it comes to SQL to ensure its doing the right thing. SQL will almost always tell you an answer, it just may not be to the question you think you&amp;rsquo;re asking. Ensuring your queries can be reasoned about is critical to ensuring accuracy and CTEs are one great way of accomplishing that.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Tooling for Simple but Informative Emails</title><link>/2013/10/13/Tooling-for-Simple-but-Informative-Emails/</link><pubDate>Sun, 13 Oct 2013 12:55:56 -0800</pubDate><guid>/2013/10/13/Tooling-for-Simple-but-Informative-Emails/</guid><description>&lt;p>Emails are one of my favorite methods of communicating with users. Its works as a quick test for product validation. It works well at one-&amp;gt;some-&amp;gt;many-&amp;gt; all. Its still highly effective even as much noise as we receive in our inboxes. Over the years I&amp;rsquo;ve tried a lot of email tools from custom built solutions, to newer entrants that help around drip actions (&lt;a href="http://www.intercom.io">intercom.io&lt;/a> and &lt;a href="http://www.customer.io">customer.io&lt;/a>), to more &amp;ldquo;enterprise&amp;rdquo; tools such as Marketo. While I have varying opinions on all of those, I still find myself coming back to a simple one off script setup to deliver clear concise emails.&lt;/p>
&lt;h3 id="getting-the-data" >
&lt;div>
Getting the Data
&lt;/div>
&lt;/h3>
&lt;p>The first step of any email is deciding what you want to do, but hopefully you know that already. The part that is usually a bit more effort is actually getting the list to send it to and formatting it appropriately. I usually opt for SQL. While the specifics of the query of course always vary it common follows a general structure:&lt;/p>
&lt;pre>&lt;code>WITH initial_data AS (
SELECT
email,
app_name,
information_about_app
FROM
users,
apps
WHERE users.id = apps.user_id
AND some_filter_to_limit_data
),
candidates_for_email AS ... --- likely to have additional CTEs
--- Finally I build up the list
SELECT email,
array_to_string(array_agg(data_for_email), '
') --- an important note is to add a newline or not here depending on how you wish to format it
FROM candidates_for_email
GROUP BY email;
&lt;/code>&lt;/pre>
&lt;p>The query structure you&amp;rsquo;ll want is first column email, second column whatever data you want to include in your email.&lt;/p>
&lt;p>From here I usually create a dataclip of it. This makes it easy to allow my data to change over time. If I&amp;rsquo;m testing an email for data over the last 7 days I just come back in 7 days and I have new data. It also lets me easily share and iterate on the data. The nice part is there&amp;rsquo;s an easy way to click a button and get the data as a CSV which is what you want for sending.&lt;/p>
&lt;p>Once you download the CSV you&amp;rsquo;ll want to remove the header line as its not needed for the script.&lt;/p>
&lt;h3 id="sending-the-mail" >
&lt;div>
Sending the Mail
&lt;/div>
&lt;/h3>
&lt;p>To actually send the email you&amp;rsquo;ll need this script, which is largely credited to &lt;a href="http://www.twitter.com/leinweber">@leinweber&lt;/a>:&lt;/p>
&lt;pre>&lt;code>require 'mail'
require 'csv'
FILE = ARGV[0]
Mail.defaults do
delivery_method :smtp, {
address: 'smtp address',
port: 587,
domain: 'gmail.com',
user_name: 'craig.kerstiens@gmail.com',
password: ENV.fetch('EMAIL_PASSWORD'),
authentication: :plain,
enable_starttls_auto: true
}
end
def send_email(address, app)
mail = Mail.new do
to address
from 'Craig Kerstiens &amp;lt;craig.kerstiens@gmail.com&amp;gt;'
subject &amp;quot;Your email subject in here&amp;quot;
body generate_body(app)
end
end
def generate_body(app)
%Q(
Hi,
Your list of apps:
#{app}
Various email content in here...
)
end
CSV.parse(File.read(FILE)).each do |line|
address = line[0]
app = line[1]
m = send_email(address, app)
puts m.to_s
p m.deliver!
puts
puts
end
&lt;/code>&lt;/pre>
&lt;p>&lt;em>You&amp;rsquo;ll want to make sure to export the PW of your email provider with EXPORT EMAIL_PASSWORD=pw_here&lt;/em>&lt;/p>
&lt;p>You can easily download this script from off of &lt;a href="https://gist.github.com/craigkerstiens/6922897">Github&amp;rsquo;s Gist&lt;/a>. I&amp;rsquo;d recommend using an email service provider other than Gmail in sending your emails such as &lt;a href="http://www.mailgun.com">mailgun&lt;/a> as they&amp;rsquo;re built to handle sending a large amount of emails. Finally send your emails:&lt;/p>
&lt;pre>&lt;code>ruby email.rb nameofyourfile.csv
&lt;/code>&lt;/pre></description></item><item><title>Disabling muting while typing in Google hangouts</title><link>/2013/09/12/Disabling-muting-while-typing-in-Google-hangouts/</link><pubDate>Thu, 12 Sep 2013 12:55:56 -0800</pubDate><guid>/2013/09/12/Disabling-muting-while-typing-in-Google-hangouts/</guid><description>&lt;p>Google hangouts is awesome, its my preferred method for most audio/video calls these days. When running a group call I often dial into a separate phone if I have a better phone available for the group. It also got around the annoyance that when you are typing google automatically mutes you. This for most people is pretty subpar. While dialing in to the hangout can still be nice, you don&amp;rsquo;t have to do so to get rid of the annoying muting while typing. To fix such simply open up your terminal and run:&lt;/p>
&lt;pre>&lt;code> defaults write com.google.googletalkplugind exps -string [\&amp;quot;-tm\&amp;quot;]
&lt;/code>&lt;/pre>
&lt;p>&lt;em>This clever hack discovered courtesy of &lt;a href="http://www.twitter.com/timtyrrell">@timtyrrell&lt;/a> passed along to me by &lt;a href="http://www.twitter.com/mattmanning">@mattmanning&lt;/a> and &lt;a href="http://www.twitter.com/blakegentry">@blakegentry&lt;/a>&lt;/em>&lt;/p></description></item><item><title>Diving into Postgres JSON operators and functions</title><link>/2013/09/11/Diving-into-Postgres-JSON-operators-and-functions/</link><pubDate>Wed, 11 Sep 2013 12:55:56 -0800</pubDate><guid>/2013/09/11/Diving-into-Postgres-JSON-operators-and-functions/</guid><description>&lt;p>Just as &lt;a href="https://postgres.heroku.com/blog/past/2013/9/9/postgres_93_now_available/">PostgreSQL 9.3&lt;/a> was coming out I had a need to take advantage of the JSON datatype and some of the &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-json.html">operators and functions&lt;/a> within it. The use case was pretty simple, run a query across a variety of databases, then take the results and store them. We explored doing something more elaborate with the columns/values, but in the end just opted to save the entire result set as JSON then I could use the operators to explore it as desired.&lt;/p>
&lt;p>Here&amp;rsquo;s the general idea in code (using sequel):&lt;/p>
&lt;pre>&lt;code>result = r.connection { |c| c.fetch(self.query).all }
mymodel.results = result.to_json
&lt;/code>&lt;/pre>
&lt;p>As the entire dataset was stored as some compressed JSON I needed to do a bit of manipulation to get it back into a form that was workable. Fortunately all the steps were fairly straightforward.&lt;/p>
&lt;p>First you want to unnest each result from the json array, in my case this looked like:&lt;/p>
&lt;pre>&lt;code>SELECT json_array_elements(result)
&lt;/code>&lt;/pre>
&lt;p>The above will unnest all of the array elements so I have an individual result as JSON. A real world example would look something similar to:&lt;/p>
&lt;pre>&lt;code>SELECT json_array_elements(result)
FROM query_results
LIMIT 2;
json_array_elements
&lt;/code>&lt;/pre>
&lt;hr>
&lt;p>{&amp;ldquo;column_name&amp;rdquo;:&amp;ldquo;data_in_here&amp;rdquo;}
{&amp;ldquo;column_name_2&amp;rdquo;:&amp;ldquo;other_data_in_here&amp;rdquo;}
(2 rows)&lt;/p>
&lt;p>From here based on the query I would want to get some specific value. In this case I&amp;rsquo;m going to search for the text key column_name_2:&lt;/p>
&lt;pre>&lt;code>SELECT json_array_elements(result)-&amp;gt;'column_name_2'
FROM query_results
LIMIT 1;
json_array_elements
-----------------------
&amp;quot;other_data_in_here&amp;quot;
(1 rows)
&lt;/code>&lt;/pre>
&lt;p>&lt;em>One gotcha I encountered was when I wanted to search for some value or exclude some value&amp;hellip; Expecting I could just compare the result of the above in a where statement I was sadly mistaken because the equals operator didn&amp;rsquo;t translate.&lt;/em> My first attempt at fixing this was to cast in this form:&lt;/p>
&lt;pre>&lt;code>SELECT json_array_elements(result)-&amp;gt;'column_name_2'::text
&lt;/code>&lt;/pre>
&lt;p>The sad part is because of the operator the cast doesn&amp;rsquo;t get applied as I&amp;rsquo;d expect. Instead you&amp;rsquo;ll want to do:&lt;/p>
&lt;pre>&lt;code>SELECT (json_array_elements(result)-&amp;gt;'column_name_2')::text
&lt;/code>&lt;/pre>
&lt;p>Of course theres plenty more you can do with the &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-json.html">JSON operators in the new Postgres 9.3&lt;/a>. If you&amp;rsquo;ve already got JSON in your application give them a look today. And while slightly worse, if you&amp;rsquo;ve got JSON stored in a text field simply cast it with &lt;code>::json&lt;/code> to begin using the operators.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>The Rule of Thirds - followup</title><link>/2013/08/13/The-Rule-of-Thirds-followup/</link><pubDate>Tue, 13 Aug 2013 12:55:56 -0800</pubDate><guid>/2013/08/13/The-Rule-of-Thirds-followup/</guid><description>&lt;p>Several months back I wrote about how we do &lt;a href="http://www.craigkerstiens.com/2013/03/13/planning-and-prioritizing/">higher level, long term planning within the Heroku Postgres team&lt;/a>. If you haven&amp;rsquo;t read the previous article please start there.&lt;/p>
&lt;p>The exercise or rule of thirds is intended to be approximate prioritization and not a perfect science. Since that time I&amp;rsquo;m familiar with some teams both in and out of Heroku who have attempted this exercise with varying levels of success. We&amp;rsquo;ve now done this process 4 times within the team and after the most recent exercise attempted to take some time to internalize why its worked well, creating some more specifics about the process. Heres an attempt to provide even more clarity:&lt;/p>
&lt;h2 id="gather-data-ahead-of-time" >
&lt;div>
Gather data ahead of time
&lt;/div>
&lt;/h2>
&lt;p>Its really common to have a list things to work on, but knowing the impact of those is commonly pure speculation. There may be some people that talk to customers, but even then its a subset of your actual customer base. Going into the exercise as much data you can have ahead of time on impact of features and specific problems helps. In our case we do this by:&lt;/p>
&lt;ol>
&lt;li>Surveying current customers and users&lt;/li>
&lt;li>Surveying attriters&lt;/li>
&lt;li>Engaging with customer facing teams to hear trends&lt;/li>
&lt;li>Input from external parties such as analysts on trends&lt;/li>
&lt;/ol>
&lt;h2 id="allow-for-casual-discussion" >
&lt;div>
Allow for casual discussion
&lt;/div>
&lt;/h2>
&lt;p>We typically conduct our planning exercise at an offsite, this is a multi-day time of team bonding, planning, hacking. We intentionally schedule our planning excercise towards the end of the offsite. This allows us to have updates/presentations frmo the data we&amp;rsquo;ve gathered and from those that are customer facing. Presentations are meant to be short and direct, discussion can flow casually after. This gets a lot of people on the same page at a smaller level and reduces the problem of too many cooks in the kitchen come time for the actual exercise.&lt;/p>
&lt;h2 id="the-rule-of-thirds" >
&lt;div>
The rule of thirds
&lt;/div>
&lt;/h2>
&lt;h3 id="creating-the-list" >
&lt;div>
Creating the list
&lt;/div>
&lt;/h3>
&lt;p>Coming to the exercise itself&amp;hellip; We begin by everyone writing a list of their ideas individually, this is meant to be a list of the features we want to place on the grid. At this point theres no prioritizing of difficulty or impact. In addition each list while individually created does not have to contain items that only pertain to you, its more a comprehensive list of all the things you can think of that may be important to do.&lt;/p>
&lt;h3 id="bucketing-part-1" >
&lt;div>
Bucketing part 1
&lt;/div>
&lt;/h3>
&lt;p>Once individual lists are created you can then collectively or designate one or two people to clean it up. We do this in two forms:&lt;/p>
&lt;ol>
&lt;li>Removing duplicate items, which there should be several of.&lt;/li>
&lt;li>Bucketing my a common/theme idea, this simply makes things more digestable&lt;/li>
&lt;/ol>
&lt;p>If you&amp;rsquo;re a big group of greater than 7 then it may be advisable to designate two people to do this exercise together. If a smaller group it can be manageable to coordinate collectively.&lt;/p>
&lt;h3 id="bucketing-part-2" >
&lt;div>
Bucketing part 2
&lt;/div>
&lt;/h3>
&lt;p>Once you&amp;rsquo;ve removed dupes, identified themes, and removed excess items (depending on your team size you&amp;rsquo;ll find how many feels right - we aim an average of 5-6 per square for a team of 10) its then on to actually putting them on the grid. In the past we&amp;rsquo;ve done this a variety of ways but our most recent process seemed to be quiet efficient. We gave each item 60 seconds, at the end of that minute wherever the item was it was left there. This forced some quick discussion on impact and difficulty but in the end left us at a very good hit rate without taking multiple hours to complete the exercise.&lt;/p>
&lt;h3 id="final-pass" >
&lt;div>
Final pass
&lt;/div>
&lt;/h3>
&lt;p>We intentionally design it so that low effort and high impact is on the top right corner. Finally once everything is on there we allocate names to the tasks, and put boxes around items we&amp;rsquo;re planning to do in the coming months. With boxes make it very clear of what we are doing as well as explicitly things we are not. The initials or names make it clear of how loaded down people are. If your name is on 3 tasks that are high difficulty, then you&amp;rsquo;re likely over allocated.&lt;/p>
&lt;p>At this point things usually fall out pretty quickly and we emerge with some rough roadmap that in retrospect we&amp;rsquo;ve followed pretty accuately.&lt;/p></description></item><item><title>The missing PostgreSQL documentation</title><link>/2013/08/07/The-missing-PostgreSQL-documentation/</link><pubDate>Wed, 07 Aug 2013 12:55:56 -0800</pubDate><guid>/2013/08/07/The-missing-PostgreSQL-documentation/</guid><description>&lt;p>For a couple of years I&amp;rsquo;ve complained about the Postgres documentation and at the same time paraded it as one of the best sets of documentation I&amp;rsquo;ve encountered. In many ways the reason I veer towards &lt;a href="http://www.postgresql.org">Postgres&lt;/a> as well as &lt;a href="http://www.python.org">Python&lt;/a> and &lt;a href="http://www.djangoproject.com">Django&lt;/a> is the quality of their documentation. If you need to find details about something its documented, and more importantly well and thoroughly documented.&lt;/p>
&lt;p>In large part I came to Python by happenstance through &lt;a href="http://www.djangoproject.com">Django&lt;/a>, and Postgres through happenstance of an employer. Yet, Django was very little of an accident. The Django Tutorial got me a large part of what I needed to know and more excited about development than I had been in some time. Python has done some work at adding docs to make this even better, sadly its still very much needed for PostgreSQL.&lt;/p>
&lt;h3 id="whats-missing-in-the-postgres-docs" >
&lt;div>
Whats Missing in the Postgres Docs
&lt;/div>
&lt;/h3>
&lt;p>Theres a huge variety of types of documentation, off the top of my head theres:&lt;/p>
&lt;ul>
&lt;li>Reference docs (Postgres excels at this)&lt;/li>
&lt;li>Onboarding (Postgres tutorial huh?)&lt;/li>
&lt;li>Tailored guides (Postgres? I can haz? Nope&amp;hellip; We don&amp;rsquo;t understand&amp;hellip;.)&lt;/li>
&lt;/ul>
&lt;p>Postgres is great if you know the name of what you&amp;rsquo;re looking for, but if you don&amp;rsquo;t you&amp;rsquo;re entirely left in the dark.&lt;/p>
&lt;h3 id="understanding-the-power-of-postgres" >
&lt;div>
Understanding the power of Postgres
&lt;/div>
&lt;/h3>
&lt;p>Postgres is good enough at performance, good enough at usability, and awesome at how powerful and flexible it can be. But all of this is entirely lost if you have to know the esoteric name of what you&amp;rsquo;re looking for.&lt;/p>
&lt;p>&lt;em>What the hell is an hstore&amp;hellip; In so many ways KVstore makes infintely more sense. In the same sense PLV8, I have to know not only what PL stands for but V8 as well, versus the JavaScript extension for Postgres.&lt;/em>&lt;/p>
&lt;p>I understand there are plenty of reasons why some of these things are the way they are, but its also limiting how great the broader perception is. Postgres externally is this hard to use DB, that well is just a database, versus giving developers a set of powerful and useful functions to make their lives better.&lt;/p>
&lt;h3 id="the-solution" >
&lt;div>
The Solution
&lt;/div>
&lt;/h3>
&lt;p>Lets fix things, there are a ton of people that would love to know more about all things Postgres. This ranges from a good set of onboarding docs, to specific blog posts on topics that people are curious about. Just last week I got an email about improving &lt;strong>the&lt;/strong> Postgres tutorial&amp;hellip; Yes theres a tutorial hidden in the &lt;a href="http://www.postgresql.org/docs/9.2/static/tutorial.html">2000 page set of documentation for Postgres&lt;/a>. Its simply old, mostly uninteresting, and well just needs to be completely recreated. A great alternative would be a few tutorials/guides for:&lt;/p>
&lt;ul>
&lt;li>Noobs to databases in general (Total 101 guide)&lt;/li>
&lt;li>Building and architecting your application with Postgres (App Devs)&lt;/li>
&lt;li>Administering and maintaining Postgres (DBAs)&lt;/li>
&lt;li>SQL and reporting in Postgres (consumers of data, analysts, product people, marketing, etc.)&lt;/li>
&lt;/ul>
&lt;p>If jumping in and contributing to fixing the core tutorial isn&amp;rsquo;t your cup of tea because you don&amp;rsquo;t want to learn and write in &lt;a href="http://www-sul.stanford.edu/tools/tutorials/html2.0/gentle.html">SGML&lt;/a>, send a pull request to &lt;a href="http://postgresguide.com">postgresguide.com&lt;/a> or do a [guest post on my blog](mailto:craig.kerstiens@gmail.com]. If thats too much effort please just let us know, what do you want to see - &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens at gmail.com&lt;/a>&lt;/p></description></item><item><title>A look at Foreign Data Wrappers</title><link>/2013/08/05/A-look-at-Foreign-Data-Wrappers/</link><pubDate>Mon, 05 Aug 2013 12:55:56 -0800</pubDate><guid>/2013/08/05/A-look-at-Foreign-Data-Wrappers/</guid><description>&lt;p>There are two particular sets of features that continue to keep me very excited about the momentum of Postgres. And while PostgreSQL has had some great momentum in the past few years these features may give it an entirely new pace all together. One is extensions, which is really its own category. Dimitri Fontaine was talking about doing a full series just on extensions, so here&amp;rsquo;s hoping he does so I dont have to :)&lt;/p>
&lt;p>One subset of extensions which I consider entirely separate is the other thing, which is foreign data wrappers or FDWs. FDWs allow you to connect to other data sources from within Postgres. From there you can query them with SQL, join across disparate data sets, or join across different systems. Recently I had a good excuse to give the &lt;code>postgres_fdw&lt;/code> a try. And while I&amp;rsquo;ve blogged about the Redis FDW previously, the Postgres one is particularly exciting because with PostgreSQL 9.3 it will ship as a contrib module, which means all Postgres installers should have it&amp;hellip; you just have to turn it on.&lt;/p>
&lt;p>Let&amp;rsquo;s take a look at getting it setup and then dig into it a bit. First, because I don&amp;rsquo;t have Postgres 9.3 sitting around on my system I&amp;rsquo;m going to provision one from Heroku Postgres:&lt;/p>
&lt;pre>&lt;code>$ heroku addons:add heroku-postgresql:crane --version 9.3
&lt;/code>&lt;/pre>
&lt;p>Once it becomes available I&amp;rsquo;m going to connect to it then enable the extension:&lt;/p>
&lt;pre>&lt;code>$ heroku pg:psql BLACK -acraig
# CREATE EXTENSION postgres_fdw;
&lt;/code>&lt;/pre>
&lt;p>Now its there, so we can actually start using it. To use the FDW there&amp;rsquo;s four basic things you&amp;rsquo;ll want to do:&lt;/p>
&lt;ol>
&lt;li>Create the remote server&lt;/li>
&lt;li>Create a user mapping for the remote server&lt;/li>
&lt;li>Create your foreign tables&lt;/li>
&lt;li>Start querying some things&lt;/li>
&lt;/ol>
&lt;h3 id="the-setup" >
&lt;div>
The setup
&lt;/div>
&lt;/h3>
&lt;p>You&amp;rsquo;ll only need to do each of the following once, once you&amp;rsquo;re server, user and foreign table are all setup you can simply query away. This is a nice advantage over db_link which only exists for the set session. &lt;em>One downside I did find was that you can&amp;rsquo;t use a full Postgres connection string, which would make setting it up much simpler&lt;/em>. So onto setting up our server:&lt;/p>
&lt;pre>&lt;code># CREATE SERVER app_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (dbname 'dbnamehere', host 'hostname-here);
&lt;/code>&lt;/pre>
&lt;p>Next we&amp;rsquo;ll actually create our user mapping. In this case we&amp;rsquo;ll take the remote username and password and map it to our current user we&amp;rsquo;re already connected with.&lt;/p>
&lt;pre>&lt;code># CREATE USER MAPPING for user_current
SERVER app_db
OPTIONS (user 'remote_user', password 'remote_password');
&lt;/code>&lt;/pre>
&lt;p>And finally we&amp;rsquo;re going to configure our tables. &lt;em>There were some additional pains here as there wasn&amp;rsquo;t a perfectly clean way to generate the &lt;code>CREATE TABLE&lt;/code>. Sure you could pg_dump just that table, but overall it felt a bit cludgey.&lt;/em>&lt;/p>
&lt;pre>&lt;code># CREATE FOREIGN TABLE users
(
id integer,
email text,
created_at timestamp,
first_name text,
last_name text
)
SERVER app_db OPTIONS (table_name 'users')
&lt;/code>&lt;/pre>
&lt;p>Now we&amp;rsquo;ve got all of our local data, as well as remote data. For that report against two databases where you previously wrote a ruby or python script, ran a query, constructed another query, then executed it you can directly do in your database. We can simply query our new table - &lt;code>SELECT * FROM users LIMIT 5;&lt;/code>&lt;/p>
&lt;p>But the real power of foreign data wrappers goes well beyond just Postgres to Postgres. Having a defined contract in translating from one system to another, will really allow reinventing the way we work with data. This is especially true in large datasets where doing ETL on terrabytes of data takes longer than asking the questions of it.&lt;/p>
&lt;p>While we&amp;rsquo;re waiting for more FDWs to be ready to use in production situations the Postgres FDW is a great start, &lt;em>though the Redis one is on its way&lt;/em>. Even better is that it ships with standard installs of Postgres, meaning it will see more usage and help push them to advance further.&lt;/p>
&lt;p>&lt;em>One final nicety, you&amp;rsquo;re not required to have ALL Postgres 9.3 DBs, just one that can then connect to the others, so go ahead and give it try :)&lt;/em>&lt;/p></description></item><item><title>Postgres Dollar Quoting</title><link>/2013/08/02/Postgres-Dollar-Quoting/</link><pubDate>Fri, 02 Aug 2013 12:55:56 -0800</pubDate><guid>/2013/08/02/Postgres-Dollar-Quoting/</guid><description>&lt;p>After my most recent post on &lt;a href="/2013/07/29/documenting-your-postgres-database/">documenting your database&lt;/a> I had a colleague and friend chime in:&lt;/p>
&lt;p>{% blockquote @danfarina &lt;a href="https://twitter.com/danfarina/status/362007008079126528">https://twitter.com/danfarina/status/362007008079126528&lt;/a> %}
@craigkerstiens You may want to mention for another post the generality of dollar quoting: it&amp;rsquo;s not just for CREATE FUNCTION.
{% endblockquote %}&lt;/p>
&lt;p>Luckily I was able to convince him to create the post. You can read a bit more on him below, but without further adieu here&amp;rsquo;s a bit on dollar quoting within Postgres:&lt;/p>
&lt;p>Postgres supports two forms of entry of data literals into the system.
One is the familiar single-quote:&lt;/p>
&lt;pre>&lt;code>=&amp;gt; SELECT 'hello';
?column?
----------
hello
(1 row)
&lt;/code>&lt;/pre>
&lt;p>This format is problematic when one might be using single quotes in
the textual string.&lt;/p>
&lt;p>Postgres also supports another way to enter data
literals, most often seen in &lt;code>CREATE FUNCTION&lt;/code>, but can be profitably
used anywhere. This is called &amp;ldquo;dollar quoting,&amp;rdquo; and it looks like
this:&lt;/p>
&lt;pre>&lt;code>=&amp;gt; SELECT $$hello's the name of the game$$;
?column?
------------------------------
hello's the name of the game
(1 row)
&lt;/code>&lt;/pre>
&lt;p>If one needs nested dollar quoting, one can specify a string, much
like the &amp;lsquo;heredoc&amp;rsquo; feature seen in some programming languages:&lt;/p>
&lt;pre>&lt;code>=&amp;gt; SELECT $goodbye$hello's the name of the $$ game$goodbye$;
?column?
---------------------------------
hello's the name of the $$ game
(1 row)
&lt;/code>&lt;/pre>
&lt;p>This can appear anywhere where single quotes would otherwise be,
simplifying tasks like using contractions in database object comments,
for example:&lt;/p>
&lt;pre>&lt;code>=&amp;gt; CREATE TABLE described(a int);
=&amp;gt; COMMENT ON TABLE described IS $$I'm describing this,
including newlines and an apostrophe in the contraction &amp;quot;I'm.&amp;quot;$$;
&lt;/code>&lt;/pre>
&lt;p>Or, alternatively, entry of literals for types that may include
apostrophes in their serialization, such as &amp;rsquo;text&amp;rsquo; or &amp;lsquo;json&amp;rsquo;:&lt;/p>
&lt;pre>&lt;code>=&amp;gt; CREATE TABLE json(data json);
=&amp;gt; INSERT INTO json(data) VALUES
($${&amp;quot;quotation&amp;quot;: &amp;quot;'there is no time like the present'&amp;quot;}$$);
&lt;/code>&lt;/pre>
&lt;h3 id="security" >
&lt;div>
Security
&lt;/div>
&lt;/h3>
&lt;p>Even though dollar quotes can be used to reduce the pain of many
quoting problems, don&amp;rsquo;t be tempted to use them to avoid SQL injection:
an adversary that knows one is using dollar quoting can still mount
exactly the same kind of attacks as if one were using single quotes.&lt;/p>
&lt;p>There is also no need, because any place a data literal can appear can
also be used with parameter binding (e.g. &lt;code>$1&lt;/code>, &lt;code>$2&lt;/code>, &lt;code>$3&lt;/code>&amp;hellip;), which one&amp;rsquo;s
Postgres driver should support. Nevertheless, for data or scripts one
is working with by hand, dollar quoting can make things much easier to
read.&lt;/p>
&lt;h3 id="about-the-author" >
&lt;div>
About the Author
&lt;/div>
&lt;/h3>
&lt;p>Daniel Farina is a long time colleague and friend, having worked together at 5 different companies. He&amp;rsquo;s part of the &lt;a href="https://twitter.com/danfarina/status/362007008079126528">Heroku Postgres&lt;/a> team as the resident tuple groomer, and the creator of &lt;a href="https://github.com/wal-e/wal-e">WAL-E&lt;/a>.&lt;/p>
&lt;p>&lt;em>As is always the case if you have articles you&amp;rsquo;d like to see created or if you&amp;rsquo;re interested in doing a guest post please feel free to drop me a line &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens at gmail.com&lt;/a>. And if you have articles you feel are helpful to others in the Postgres world drop me a note as well for including them in &lt;a href="http://www.postgresweekly.com">Postgres Weekly&lt;/a>.&lt;/em>&lt;/p></description></item><item><title>Documenting your PostgreSQL database</title><link>/2013/07/29/Documenting-your-PostgreSQL-database/</link><pubDate>Mon, 29 Jul 2013 12:55:56 -0800</pubDate><guid>/2013/07/29/Documenting-your-PostgreSQL-database/</guid><description>&lt;p>Just a few days ago I was surprised by what someone was doing with their database, and not in the typical horrifying travesty against mankind. Rather, it was a feature that while familiar with I&amp;rsquo;d never seen anyone fully take proper advantage of - &lt;code>COMMENT&lt;/code> or describing tables. Postgres has a nice facility for you to provide a description for just about anything:&lt;/p>
&lt;ul>
&lt;li>Table&lt;/li>
&lt;li>Column&lt;/li>
&lt;li>Function&lt;/li>
&lt;li>Schema&lt;/li>
&lt;li>View&lt;/li>
&lt;li>Index&lt;/li>
&lt;li>Etc.&lt;/li>
&lt;/ul>
&lt;p>The specific use case was a database acting as a datamart pulling in data from multiple sources to be able to report against disparate data. Over the years I&amp;rsquo;ve seen this occur really one three ways, the first is that a limited set of people, typically one person, have knowledge over all the datasources and thus far the sole individual responsible for creating reports and answering questions of the data. The second, is wide open access to anyone that wishes for it. In this case you often have people asking questions of the data, and because they don&amp;rsquo;t understand the relationships coming up to entirely wrong conclusions. The final approach is to create some external documentation, entity relationship diagrams, data dictionaries, etc. This last one often works okay enough, but often suffers from lack of updates and being too heavyweight.&lt;/p>
&lt;p>A better solution, and all around good process is simply documenting clearly within the database itself. Simply comment each table and column, just as you would outside of your DB then it can be quite clear when inside the database working interactivly:&lt;/p>
&lt;pre>&lt;code>COMMENT ON TABLE products IS 'Products catalog';
COMMENT ON COLUMN products.price is 'Current price of a single item purchased';
&lt;/code>&lt;/pre>
&lt;p>While an obvious example above naming even the most mundance columns can help create more accurate reports. Then of course when you want to inspect your DB its quite clear:&lt;/p>
&lt;pre>&lt;code>\d+ users
# \d+ users
Table &amp;quot;public.users&amp;quot;
Column | Type | ... | Description
------------+-----------------------------+-...-+-----------------------------------------
id | integer | ... | auto serial pk
first_name | character varying(50) | ... | required first name of user
last_name | character varying(50) | ... | required first name of user
email | character varying(255) | ... | email address of account
data | hstore | ... | mix of data, city, state, gender
created_at | timestamp without time zone | ... | when account was created, not confirmed
updated_at | timestamp without time zone | ... | time any details were last updated
Indexes:
&amp;quot;idx_user_created&amp;quot; btree (date_trunc('day'::text, created_at))
Has OIDs: no
&lt;/code>&lt;/pre>
&lt;p>But it doesn&amp;rsquo;t necessarily have to stop there. Which actually brings me to one other item, you should be commenting your SQL just the same. SQL comments can be done easily by just starting a line with &lt;code>--&lt;/code>, or you can have it at the end of the line with further info. Here&amp;rsquo;s a nice example:&lt;/p>
&lt;pre>&lt;code>-- Query aggregates all project names that have open past due tasks grouped by email
SELECT
users.email,
array_to_string(array_agg(projects.name), ',')) as projects # Aggregate all projects and separate by comma
FROM
projects,
tasks,
users
-- A user has a project, which has tasks
WHERE projects.id = tasks.project_id
-- Check for tasks that are due before now and not done yet
AND tasks.due_at &amp;gt; tasks.completed_at
AND tasks.due_at &amp;lt; now()
AND users.id = projects.user_id
GROUP BY
users.email
&lt;/code>&lt;/pre>
&lt;p>You comment your code, why shouldn&amp;rsquo;t you comment your database?&lt;/p></description></item><item><title>hstore vs. JSON - Which to use in Postgres</title><link>/2013/07/03/hstore-vs.-JSON-Which-to-use-in-Postgres/</link><pubDate>Wed, 03 Jul 2013 12:55:56 -0800</pubDate><guid>/2013/07/03/hstore-vs.-JSON-Which-to-use-in-Postgres/</guid><description>&lt;p>If you&amp;rsquo;re deciding what to put in &lt;a href="http://www.amazon.com/Seven-Databases-Weeks-Modern-Movement/dp/1934356921?tag=mypred-20">Postgres and what not to&lt;/a>, consider that Postgres can be a &lt;a href="/2012/06/11/schemaless-django/">perfectly good schema-less database&lt;/a>. Of course as soon as people realized this then the common comes a question, is hstore or JSON better. Which do I use and in what cases. Well first, if you&amp;rsquo;re not familiar check out some previous material on them:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.postgresql.org/docs/9.2/static/hstore.html">hstore on PostgresGuide&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.postgresql.org/docs/9.2/static/hstore.html">hstore in Postgres docs&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.craigkerstiens.com/2012/06/11/schemaless-django/">hstore with Django&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.2#JSON_datatype">JSON datatype&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://postgres.heroku.com/blog/past/2013/6/5/javascript_in_your_postgres/">JavaScript support in Postgres&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>If you&amp;rsquo;re already up to date with both of them, but still wondering which to use lets dig in.&lt;/p>
&lt;h3 id="hstore" >
&lt;div>
hstore
&lt;/div>
&lt;/h3>
&lt;p>hstore is a key value store directly within your database. Its been a common favorite of mine and has been for some time. hstore gives you flexibility when working with your schema, as you don&amp;rsquo;t have to define models ahead of time. Though its two big limitations are that 1. it only deals with text and 2. its not a full document store meaning you can&amp;rsquo;t nest objects.&lt;/p>
&lt;p>Though major benefits of hstore include the ability to index on it, robust support for various operators, and of course the obvious of flexibility with your data. Some of the basic operators available include:&lt;/p>
&lt;p>Return the value from column&lt;code>foo&lt;/code> for key &lt;code>bar&lt;/code>:&lt;/p>
&lt;pre>&lt;code>foo-&amp;gt;'bar'
&lt;/code>&lt;/pre>
&lt;p>Does the specified column &lt;code>foo&lt;/code> contain a key &lt;code>bar&lt;/code>:&lt;/p>
&lt;pre>&lt;code>foo?'bar'
&lt;/code>&lt;/pre>
&lt;p>Does the specified column &lt;code>foo&lt;/code> contain a value of &lt;code>baz&lt;/code> for key &lt;code>bar&lt;/code>:&lt;/p>
&lt;pre>&lt;code>foo@&amp;gt;'bar-&amp;gt;baz'
&lt;/code>&lt;/pre>
&lt;p>Perhaps one of the best parts of hstore is that you can index on it. In particular Postgres &lt;code>gin&lt;/code> and &lt;code>gist&lt;/code> indexes allow you to index all keys and values within an hstore. A talk by &lt;a href="http://www.twitter.com/XoF">Christophe Pettus&lt;/a> of PgExperts actually highlights some &lt;a href="http://thebuild.com/presentations/pg-as-nosql-pgday-fosdem-2013.pdf">performance details of hstore with indexes&lt;/a>. To give away the big punchline in several cases hstore with gin/gist beats mongodb in performance.&lt;/p>
&lt;h3 id="json" >
&lt;div>
json
&lt;/div>
&lt;/h3>
&lt;p>JSON in contrast to hstore is a full document datatype. In addition to nesting objects you have support for more than just text (read numbers). As you insert JSON into Postgres it will automatically ensure its valid JSON and error if its well not. JSON gets a lot better come Postgres 9.3 as well with &lt;a href="http://www.postgresql.org/docs/devel/static/functions-json.html">some built in operators&lt;/a>. Though if you need more functionality in it today you should look at &lt;a href="https://code.google.com/p/plv8js/wiki/PLV8">PLV8&lt;/a>.&lt;/p>
&lt;h3 id="which-to-use" >
&lt;div>
Which to Use
&lt;/div>
&lt;/h3>
&lt;p>So which do you actually want to use in your application? If you&amp;rsquo;re already using JSON and simply want to store it in your database then the JSON datatype is often the correct pick. However, if you&amp;rsquo;re just looking for flexibility with your data model then hstore is likely the path you want to take. hstore will give you much of the flexibility you want as well as a good ability to query your data in a performant manner. Of course much of this starts to change in Postgres 9.3.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Pivoting in Postgres</title><link>/2013/06/27/Pivoting-in-Postgres/</link><pubDate>Thu, 27 Jun 2013 12:55:56 -0800</pubDate><guid>/2013/06/27/Pivoting-in-Postgres/</guid><description>&lt;p>Earlier today on an internal Heroku group alias there was a &lt;a href="https://postgres.heroku.com/dataclips">dataclip&lt;/a> shared. The dataclip listed off some data grouped by a category, there was a reply a few minutes later with a modification to the query that used the &lt;code>crosstab&lt;/code> function to pivot directly in SQL. There were immediately several reactions on the list that went something like this:&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/1b0G101r0B2W243b2933/Image%202013.06.27%202%3A06%3A23%20PM.gif" alt="mindblown">&lt;/p>
&lt;p>While a mostly simple function in Postgres (there are a few rough edges), it really is all too handy. So here it is in action. Taking some data that looks like&lt;/p>
&lt;ul>
&lt;li>row identifier, in this case date&lt;/li>
&lt;li>category grouping, in this case OS&lt;/li>
&lt;li>value&lt;/li>
&lt;/ul>
&lt;p>Given a really basic query that generates some sample data it may look something like this:&lt;/p>
&lt;pre>&lt;code>SELECT generate_series AS date,
b.desc AS TYPE,
(random() * 10000 + 1)::int AS val
FROM generate_series((now() - '100 days'::interval)::date, now()::date, '1 day'::interval),
(SELECT unnest(ARRAY['OSX', 'Windows', 'Linux']) AS DESC) b;
&lt;/code>&lt;/pre>
&lt;p>You get results that look like:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>But of course this isn&amp;rsquo;t overly helpful in comparing day to day overall. You can do so on a OS by OS basis, but its annoying enough as is. The easy solution is to simply use a pivot table on your data. Most people at this point would pull it up into Excel or Google Docs, or you can do it directly in Postgres. To do so you&amp;rsquo;ll first enable the extension &lt;code>tablefunc&lt;/code>:&lt;/p>
&lt;pre>&lt;code>CREATE EXTENSION tablefunc
&lt;/code>&lt;/pre>
&lt;p>Then you&amp;rsquo;ll use the crosstab function. The function looks something like:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM crosstab(
'SELECT row_name, category_grouping, value FROM foo',
'SELECT category_names FROM bar')
AS
ct_result (category_name text, category1 text, category2 text, etc.)
&lt;/code>&lt;/pre>
&lt;p>Lets see it an actual action. Given the same query we used to generate fake data we can actually pivot on it now directly in PostgreSQL:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM crosstab(
'SELECT
a date,
b.desc AS os,
(random() * 10000 + 1)::int AS value
FROM generate_series((now() - ''100 days''::interval)::date, now()::date, ''1 DAY''::interval) a,
(SELECT unnest(ARRAY[''OSX'', ''Windows'', ''Linux'']) AS DESC) b ORDER BY 1,2
','SELECT unnest(ARRAY[''OSX'', ''Windows'', ''Linux''])'
)
AS ct(date date, OSX int, Windows int, Linux int);
&lt;/code>&lt;/pre>
&lt;p>And see some results:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Have fun analyzing your data directly in your DB now. And as always if you have feedback/questions/requests please feel free to drop me a line &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>&lt;/p></description></item><item><title>Javascript Functions for PostgreSQL</title><link>/2013/06/25/Javascript-Functions-for-PostgreSQL/</link><pubDate>Tue, 25 Jun 2013 12:55:56 -0800</pubDate><guid>/2013/06/25/Javascript-Functions-for-PostgreSQL/</guid><description>&lt;p>Javascript in Postgres has gotten a good bit of love lately, part of that is from &lt;a href="http://postgres.herpku.com">Heroku Postgres&lt;/a> recently &lt;a href="https://postgres.heroku.com/blog/past/2013/6/5/javascript_in_your_postgres/">adding support for Javascript&lt;/a> and part from a variety of people championing the power of it such as &lt;a href="http://twitter.com/leinweber">@leinweber&lt;/a> (&lt;a href="http://www.youtube.com/watch?v=fRupMAVdmWA">Embracing the web with JSON and PLV8&lt;/a>) and &lt;a href="http://twitter.com/selenamarie">@selenamarie&lt;/a> (&lt;a href="https://speakerdeck.com/selenamarie/schema-liberation-with-json-and-plv8-and-postgres">schema liberation with JSON and PLV8&lt;/a>). In a recent conversation it was pointed out that it seems a bit of headache to have to create your own functions, or at least having an initial collection would make it that much more powerful. While many can look forward to &lt;a href="http://www.postgresql.org/docs/9.3/static/functions-json.html">PostgreSQL 9.3&lt;/a> which will have a bit more built in support for JSON a few functions can really help make it more useful today.&lt;/p>
&lt;p>These are courtesy of &lt;a href="http://bitfission.com">Will Leinweber&lt;/a>. For each of the following functions I&amp;rsquo;ll highlight an example of using it as well. To get an idea of the data its being run on:&lt;/p>
&lt;pre>&lt;code>select * from example;
data
--------------------------------------------
{&amp;quot;name&amp;quot;:&amp;quot;Craig Kerstiens&amp;quot;, +
&amp;quot;age&amp;quot;:27, +
&amp;quot;siblings&amp;quot;:1, +
&amp;quot;numbers&amp;quot;:[ +
{&amp;quot;type&amp;quot;:&amp;quot;work&amp;quot;, +
&amp;quot;number&amp;quot;:&amp;quot;123-456-7890&amp;quot;}, +
{&amp;quot;type&amp;quot;:&amp;quot;home&amp;quot;, +
&amp;quot;number&amp;quot;:&amp;quot;456-123-7890&amp;quot;}]}
(1 row)
&lt;/code>&lt;/pre>
&lt;h3 id="get_text" >
&lt;div>
get_text
&lt;/div>
&lt;/h3>
&lt;pre>&lt;code>CREATE OR REPLACE FUNCTION
get_text(key text, data json)
RETURNS text AS $$
return data[key];
$$ LANGUAGE plv8 IMMUTABLE STRICT;
&lt;/code>&lt;/pre>
&lt;p>Then using the function:&lt;/p>
&lt;pre>&lt;code>select get_text('name', data) from example;
get_text
----------------
Craig Kerstiens
(1 row)
&lt;/code>&lt;/pre>
&lt;h3 id="get_numeric" >
&lt;div>
get_numeric
&lt;/div>
&lt;/h3>
&lt;pre>&lt;code>CREATE OR REPLACE FUNCTION
get_numeric(key text, data json)
RETURNS numeric AS $$
return data[key];
$$ LANGUAGE plv8 IMMUTABLE STRICT;
&lt;/code>&lt;/pre>
&lt;p>Then using the function:&lt;/p>
&lt;pre>&lt;code>select get_numeric('siblings', data) from example;
get_text
----------------
1
(1 row)
&lt;/code>&lt;/pre>
&lt;h3 id="json_select" >
&lt;div>
json_select
&lt;/div>
&lt;/h3>
&lt;pre>&lt;code>create or replace function
json_select(selector text, data json)
returns json as $$
exports = {};
(function(a){function z(a){return{sel:q(a)[1],match:function(a){return y(this.sel,a)},forEach:function(a,b){return x(this.sel,a,b)}}}function y(a,b){var c=[];x(a,b,function(a){c.push(a)});return c}function x(a,b,c,d,e,f){var g=a[0]===&amp;quot;,&amp;quot;?a.slice(1):[a],h=[],i=!1,j=0,k=0,l,m;for(j=0;j&amp;lt;g.length;j++){m=w(b,g[j],d,e,f),m[0]&amp;amp;&amp;amp;(i=!0);for(k=0;k&amp;lt;m[1].length;k++)h.push(m[1][k])}if(h.length&amp;amp;&amp;amp;typeof b==&amp;quot;object&amp;quot;){h.length&amp;gt;=1&amp;amp;&amp;amp;h.unshift(&amp;quot;,&amp;quot;);if(u(b))for(j=0;j&amp;lt;b.length;j++)x(h,b[j],c,undefined,j,b.length);else for(l in b)b.hasOwnProperty(l)&amp;amp;&amp;amp;x(h,b[l],c,l)}i&amp;amp;&amp;amp;c&amp;amp;&amp;amp;c(b)}function w(a,b,c,d,e){var f=[],g=b[0]===&amp;quot;&amp;gt;&amp;quot;?b[1]:b[0],h=!0,i;g.type&amp;amp;&amp;amp;(h=h&amp;amp;&amp;amp;g.type===v(a)),g.id&amp;amp;&amp;amp;(h=h&amp;amp;&amp;amp;g.id===c),h&amp;amp;&amp;amp;g.pf&amp;amp;&amp;amp;(g.pf===&amp;quot;:nth-last-child&amp;quot;?d=e-d:d++,g.a===0?h=g.b===d:(i=(d-g.b)%g.a,h=!i&amp;amp;&amp;amp;d*g.a+g.b&amp;gt;=0));if(h&amp;amp;&amp;amp;g.has){var j=function(){throw 42};for(var k=0;k&amp;lt;g.has.length;k++){try{x(g.has[k],a,j)}catch(l){if(l===42)continue}h=!1;break}}h&amp;amp;&amp;amp;g.expr&amp;amp;&amp;amp;(h=p(g.expr,a)),b[0]!==&amp;quot;&amp;gt;&amp;quot;&amp;amp;&amp;amp;b[0].pc!==&amp;quot;:root&amp;quot;&amp;amp;&amp;amp;f.push(b),h&amp;amp;&amp;amp;(b[0]===&amp;quot;&amp;gt;&amp;quot;?b.length&amp;gt;2&amp;amp;&amp;amp;(h=!1,f.push(b.slice(2))):b.length&amp;gt;1&amp;amp;&amp;amp;(h=!1,f.push(b.slice(1))));return[h,f]}function v(a){if(a===null)return&amp;quot;null&amp;quot;;var b=typeof a;b===&amp;quot;object&amp;quot;&amp;amp;&amp;amp;u(a)&amp;amp;&amp;amp;(b=&amp;quot;array&amp;quot;);return b}function u(a){return Array.isArray?Array.isArray(a):b.call(a)===&amp;quot;[object Array]&amp;quot;}function t(a,b,c){var d=b,g={},j=i(a,b);j&amp;amp;&amp;amp;j[1]===&amp;quot; &amp;quot;&amp;amp;&amp;amp;(d=b=j[0],j=i(a,b)),j&amp;amp;&amp;amp;j[1]===f.typ?(g.type=j[2],j=i(a,b=j[0])):j&amp;amp;&amp;amp;j[1]===&amp;quot;*&amp;quot;&amp;amp;&amp;amp;(j=i(a,b=j[0]));for(;;){if(j===undefined)break;if(j[1]===f.ide)g.id&amp;amp;&amp;amp;e(&amp;quot;nmi&amp;quot;,j[1]),g.id=j[2];else if(j[1]===f.psc)(g.pc||g.pf)&amp;amp;&amp;amp;e(&amp;quot;mpc&amp;quot;,j[1]),j[2]===&amp;quot;:first-child&amp;quot;?(g.pf=&amp;quot;:nth-child&amp;quot;,g.a=0,g.b=1):j[2]===&amp;quot;:last-child&amp;quot;?(g.pf=&amp;quot;:nth-last-child&amp;quot;,g.a=0,g.b=1):g.pc=j[2];else{if(j[1]!==f.psf)break;if(j[2]===&amp;quot;:val&amp;quot;||j[2]===&amp;quot;:contains&amp;quot;)g.expr=[undefined,j[2]===&amp;quot;:val&amp;quot;?&amp;quot;=&amp;quot;:&amp;quot;*=&amp;quot;,undefined],j=i(a,b=j[0]),j&amp;amp;&amp;amp;j[1]===&amp;quot; &amp;quot;&amp;amp;&amp;amp;(j=i(a,b=j[0])),(!j||j[1]!==&amp;quot;(&amp;quot;)&amp;amp;&amp;amp;e(&amp;quot;pex&amp;quot;,a),j=i(a,b=j[0]),j&amp;amp;&amp;amp;j[1]===&amp;quot; &amp;quot;&amp;amp;&amp;amp;(j=i(a,b=j[0])),(!j||j[1]!==f.str)&amp;amp;&amp;amp;e(&amp;quot;sex&amp;quot;,a),g.expr[2]=j[2],j=i(a,b=j[0]),j&amp;amp;&amp;amp;j[1]===&amp;quot; &amp;quot;&amp;amp;&amp;amp;(j=i(a,b=j[0])),(!j||j[1]!==&amp;quot;)&amp;quot;)&amp;amp;&amp;amp;e(&amp;quot;epex&amp;quot;,a);else if(j[2]===&amp;quot;:has&amp;quot;){j=i(a,b=j[0]),j&amp;amp;&amp;amp;j[1]===&amp;quot; &amp;quot;&amp;amp;&amp;amp;(j=i(a,b=j[0])),(!j||j[1]!==&amp;quot;(&amp;quot;)&amp;amp;&amp;amp;e(&amp;quot;pex&amp;quot;,a);var k=q(a,j[0],!0);j[0]=k[0],g.has||(g.has=[]),g.has.push(k[1])}else if(j[2]===&amp;quot;:expr&amp;quot;){g.expr&amp;amp;&amp;amp;e(&amp;quot;mexp&amp;quot;,a);var l=o(a,j[0]);j[0]=l[0],g.expr=l[1]}else{(g.pc||g.pf)&amp;amp;&amp;amp;e(&amp;quot;mpc&amp;quot;,a),g.pf=j[2];var m=h.exec(a.substr(j[0]));m||e(&amp;quot;mepf&amp;quot;,a),m[5]?(g.a=2,g.b=m[5]===&amp;quot;odd&amp;quot;?1:0):m[6]?(g.a=0,g.b=parseInt(m[6],10)):(g.a=parseInt((m[1]?m[1]:&amp;quot;+&amp;quot;)+(m[2]?m[2]:&amp;quot;1&amp;quot;),10),g.b=m[3]?parseInt(m[3]+m[4],10):0),j[0]+=m[0].length}}j=i(a,b=j[0])}d===b&amp;amp;&amp;amp;e(&amp;quot;se&amp;quot;,a);return[b,g]}function s(a){if(a[0]===&amp;quot;,&amp;quot;){var b=[&amp;quot;,&amp;quot;];for(var c=c;c&amp;lt;a.length;c++){var d=r(d[c]);b=b.concat(d[0]===&amp;quot;,&amp;quot;?d.slice(1):d)}return b}return r(a)}function r(a){var b=[],c;for(var d=0;d&amp;lt;a.length;d++)if(a[d]===&amp;quot;~&amp;quot;){if(d&amp;lt;2||a[d-2]!=&amp;quot;&amp;gt;&amp;quot;)c=a.slice(0,d-1),c=c.concat([{has:[[{pc:&amp;quot;:root&amp;quot;},&amp;quot;&amp;gt;&amp;quot;,a[d-1]]]},&amp;quot;&amp;gt;&amp;quot;]),c=c.concat(a.slice(d+1)),b.push(c);if(d&amp;gt;1){var e=a[d-2]===&amp;quot;&amp;gt;&amp;quot;?d-3:d-2;c=a.slice(0,e);var f={};for(var g in a[e])a[e].hasOwnProperty(g)&amp;amp;&amp;amp;(f[g]=a[e][g]);f.has||(f.has=[]),f.has.push([{pc:&amp;quot;:root&amp;quot;},&amp;quot;&amp;gt;&amp;quot;,a[d-1]]),c=c.concat(f,&amp;quot;&amp;gt;&amp;quot;,a.slice(d+1)),b.push(c)}break}if(d==a.length)return a;return b.length&amp;gt;1?[&amp;quot;,&amp;quot;].concat(b):b[0]}function q(a,b,c,d){c||(d={});var f=[],g,h;b||(b=0);for(;;){var j=t(a,b,d);f.push(j[1]),j=i(a,b=j[0]),j&amp;amp;&amp;amp;j[1]===&amp;quot; &amp;quot;&amp;amp;&amp;amp;(j=i(a,b=j[0]));if(!j)break;if(j[1]===&amp;quot;&amp;gt;&amp;quot;||j[1]===&amp;quot;~&amp;quot;)j[1]===&amp;quot;~&amp;quot;&amp;amp;&amp;amp;(d.usesSiblingOp=!0),f.push(j[1]),b=j[0];else if(j[1]===&amp;quot;,&amp;quot;)g===undefined?g=[&amp;quot;,&amp;quot;,f]:g.push(f),f=[],b=j[0];else if(j[1]===&amp;quot;)&amp;quot;){c||e(&amp;quot;ucp&amp;quot;,j[1]),h=1,b=j[0];break}}c&amp;amp;&amp;amp;!h&amp;amp;&amp;amp;e(&amp;quot;mcp&amp;quot;,a),g&amp;amp;&amp;amp;g.push(f);var k;!c&amp;amp;&amp;amp;d.usesSiblingOp?k=s(g?g:f):k=g?g:f;return[b,k]}function p(a,b){if(a===undefined)return b;if(a===null||typeof a!=&amp;quot;object&amp;quot;)return a;var c=p(a[0],b),d=p(a[2],b);return l[a[1]][1](c,d)}function o(a,b){function c(a){return typeof a!=&amp;quot;object&amp;quot;||a===null?a:a[0]===&amp;quot;(&amp;quot;?c(a[1]):[c(a[0]),a[1],c(a[2])]}var d=n(a,b?b:0);return[d[0],c(d[1])]}function n(a,b){b||(b=0);var c=m(a,b),d;if(c&amp;amp;&amp;amp;c[1]===&amp;quot;(&amp;quot;){d=n(a,c[0]);var f=m(a,d[0]);(!f||f[1]!==&amp;quot;)&amp;quot;)&amp;amp;&amp;amp;e(&amp;quot;epex&amp;quot;,a),b=f[0],d=[&amp;quot;(&amp;quot;,d[1]]}else!c||c[1]&amp;amp;&amp;amp;c[1]!=&amp;quot;x&amp;quot;?e(&amp;quot;ee&amp;quot;,a+&amp;quot; - &amp;quot;+(c[1]&amp;amp;&amp;amp;c[1])):(d=c[1]===&amp;quot;x&amp;quot;?undefined:c[2],b=c[0]);var g=m(a,b);if(!g||g[1]==&amp;quot;)&amp;quot;)return[b,d];(g[1]==&amp;quot;x&amp;quot;||!g[1])&amp;amp;&amp;amp;e(&amp;quot;bop&amp;quot;,a+&amp;quot; - &amp;quot;+(g[1]&amp;amp;&amp;amp;g[1]));var h=n(a,g[0]);b=h[0],h=h[1];var i;if(typeof h!=&amp;quot;object&amp;quot;||h[0]===&amp;quot;(&amp;quot;||l[g[1]][0]&amp;lt;l[h[1]][0])i=[d,g[1],h];else{i=h;while(typeof h[0]==&amp;quot;object&amp;quot;&amp;amp;&amp;amp;h[0][0]!=&amp;quot;(&amp;quot;&amp;amp;&amp;amp;l[g[1]][0]&amp;gt;=l[h[0][1]][0])h=h[0];h[0]=[d,g[1],h[0]]}return[b,i]}function m(a,b){var d,e=j.exec(a.substr(b));if(e){b+=e[0].length,d=e[1]||e[2]||e[3]||e[5]||e[6];if(e[1]||e[2]||e[3])return[b,0,c(d)];if(e[4])return[b,0,undefined];return[b,d]}}function k(a,b){return typeof a===b}function i(a,b){b||(b=0);var d=g.exec(a.substr(b));if(!d)return undefined;b+=d[0].length;var h;d[1]?h=[b,&amp;quot; &amp;quot;]:d[2]?h=[b,d[0]]:d[3]?h=[b,f.typ,d[0]]:d[4]?h=[b,f.psc,d[0]]:d[5]?h=[b,f.psf,d[0]]:d[6]?e(&amp;quot;upc&amp;quot;,a):d[8]?h=[b,d[7]?f.ide:f.str,c(d[8])]:d[9]?e(&amp;quot;ujs&amp;quot;,a):d[10]&amp;amp;&amp;amp;(h=[b,f.ide,d[10].replace(/\\([^\r\n\f0-9a-fA-F])/g,&amp;quot;$1&amp;quot;)]);return h}function e(a,b){throw new Error(d[a]+(b&amp;amp;&amp;amp;&amp;quot; in '&amp;quot;+b+&amp;quot;'&amp;quot;))}function c(a){try{if(JSON&amp;amp;&amp;amp;JSON.parse)return JSON.parse(a);return(new Function(&amp;quot;return &amp;quot;+a))()}catch(b){e(&amp;quot;ijs&amp;quot;,b.message)}}var b=Object.prototype.toString,d={bop:&amp;quot;binary operator expected&amp;quot;,ee:&amp;quot;expression expected&amp;quot;,epex:&amp;quot;closing paren expected ')'&amp;quot;,ijs:&amp;quot;invalid json string&amp;quot;,mcp:&amp;quot;missing closing paren&amp;quot;,mepf:&amp;quot;malformed expression in pseudo-function&amp;quot;,mexp:&amp;quot;multiple expressions not allowed&amp;quot;,mpc:&amp;quot;multiple pseudo classes (:xxx) not allowed&amp;quot;,nmi:&amp;quot;multiple ids not allowed&amp;quot;,pex:&amp;quot;opening paren expected '('&amp;quot;,se:&amp;quot;selector expected&amp;quot;,sex:&amp;quot;string expected&amp;quot;,sra:&amp;quot;string required after '.'&amp;quot;,uc:&amp;quot;unrecognized char&amp;quot;,ucp:&amp;quot;unexpected closing paren&amp;quot;,ujs:&amp;quot;unclosed json string&amp;quot;,upc:&amp;quot;unrecognized pseudo class&amp;quot;},f={psc:1,psf:2,typ:3,str:4,ide:5},g=new RegExp('^(?:([\\r\\n\\t\\ ]+)|([~*,&amp;gt;\\)\\(])|(string|boolean|null|array|object|number)|(:(?:root|first-child|last-child|only-child))|(:(?:nth-child|nth-last-child|has|expr|val|contains))|(:\\w+)|(?:(\\.)?(\\&amp;quot;(?:[^\\\\\\&amp;quot;]|\\\\[^\\&amp;quot;])*\\&amp;quot;))|(\\&amp;quot;)|\\.((?:[_a-zA-Z]|[^\\0-\\0177]|\\\\[^\\r\\n\\f0-9a-fA-F])(?:[_a-zA-Z0-9\\-]|[^\\u0000-\\u0177]|(?:\\\\[^\\r\\n\\f0-9a-fA-F]))*))'),h=/^\s*\(\s*(?:([+\-]?)([0-9]*)n\s*(?:([+\-])\s*([0-9]))?|(odd|even)|([+\-]?[0-9]+))\s*\)/,j=new RegExp('^\\s*(?:(true|false|null)|(-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)|(&amp;quot;(?:[^\\]|\\[^&amp;quot;])*&amp;quot;)|(x)|(&amp;amp;&amp;amp;|\\|\\||[\\$\\^&amp;lt;&amp;gt;!\\*]=|[=+\\-*/%&amp;lt;&amp;gt;])|([\\(\\)]))'),l={&amp;quot;*&amp;quot;:[9,function(a,b){return a*b}],&amp;quot;/&amp;quot;:[9,function(a,b){return a/b}],&amp;quot;%&amp;quot;:[9,function(a,b){return a%b}],&amp;quot;+&amp;quot;:[7,function(a,b){return a+b}],&amp;quot;-&amp;quot;:[7,function(a,b){return a-b}],&amp;quot;&amp;lt;=&amp;quot;:[5,function(a,b){return k(a,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;a&amp;lt;=b}],&amp;quot;&amp;gt;=&amp;quot;:[5,function(a,b){return k(a,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;a&amp;gt;=b}],&amp;quot;$=&amp;quot;:[5,function(a,b){return k(a,&amp;quot;string&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;string&amp;quot;)&amp;amp;&amp;amp;a.lastIndexOf(b)===a.length-b.length}],&amp;quot;^=&amp;quot;:[5,function(a,b){return k(a,&amp;quot;string&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;string&amp;quot;)&amp;amp;&amp;amp;a.indexOf(b)===0}],&amp;quot;*=&amp;quot;:[5,function(a,b){return k(a,&amp;quot;string&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;string&amp;quot;)&amp;amp;&amp;amp;a.indexOf(b)!==-1}],&amp;quot;&amp;gt;&amp;quot;:[5,function(a,b){return k(a,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;a&amp;gt;b}],&amp;quot;&amp;lt;&amp;quot;:[5,function(a,b){return k(a,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;k(b,&amp;quot;number&amp;quot;)&amp;amp;&amp;amp;a&amp;lt;b}],&amp;quot;=&amp;quot;:[3,function(a,b){return a===b}],&amp;quot;!=&amp;quot;:[3,function(a,b){return a!==b}],&amp;quot;&amp;amp;&amp;amp;&amp;quot;:[2,function(a,b){return a&amp;amp;&amp;amp;b}],&amp;quot;||&amp;quot;:[1,function(a,b){return a||b}]};a._lex=i,a._parse=q,a.match=function(a,b){return z(a).match(b)},a.forEach=function(a,b,c){return z(a).forEach(b,c)},a.compile=z})(typeof exports==&amp;quot;undefined&amp;quot;?window.JSONSelect={}:exports)
return JSON.stringify(
exports.match(selector,
data));
$$ LANGUAGE plv8 IMMUTABLE STRICT
&lt;/code>&lt;/pre>
&lt;p>Then using the function:&lt;/p>
&lt;pre>&lt;code>select json_select('.name nth-child(1)', data) as name, json_select('.numbers', data) as phone
from example;
name | phone
--------------------+------------------------------------------------------------------------------------------
[&amp;quot;Craig Kerstiens&amp;quot;] | [[{&amp;quot;type&amp;quot;:&amp;quot;work&amp;quot;,&amp;quot;number&amp;quot;:&amp;quot;456-123-7890&amp;quot;},{&amp;quot;type&amp;quot;:&amp;quot;home&amp;quot;,&amp;quot;number&amp;quot;:&amp;quot;123-456-7890&amp;quot;}]]
(1 row)
&lt;/code>&lt;/pre>
&lt;h3 id="javascript-injection-attack" >
&lt;div>
javascript injection attack
&lt;/div>
&lt;/h3>
&lt;pre>&lt;code>create or replace function
js(src text) returns text as $$
return eval(
&amp;quot;(function() { &amp;quot; + src + &amp;quot;})&amp;quot;
)();
$$ LANGUAGE plv8;
&lt;/code>&lt;/pre>
&lt;p>Have any others you feel are essential when starting to work with JSON? Let me know &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>. Beyond that give JSON and JavaScript a try inside your database.&lt;/p></description></item><item><title>Explaining your PostgreSQL data</title><link>/2013/06/13/Explaining-your-PostgreSQL-data/</link><pubDate>Thu, 13 Jun 2013 12:55:56 -0800</pubDate><guid>/2013/06/13/Explaining-your-PostgreSQL-data/</guid><description>&lt;p>I&amp;rsquo;ve written a bit before about &lt;a href="http://www.craigkerstiens.com/2013/01/10/more-on-postgres-performance/">understanding the output&lt;/a> from &lt;code>EXPLAIN&lt;/code> and &lt;code>EXPLAIN ANALYZE&lt;/code> in PostgreSQL. Though understandably getting a grasp on execution plans could probably use some more guidance. Yet, this time around I&amp;rsquo;m taking a bit of a cop out and highlighting a few tools instead of documenting myself, which I&amp;rsquo;ve done in a talk I&amp;rsquo;ve frequently given &lt;a href="https://speakerdeck.com/craigkerstiens/postgres-demystified-1">Postgres Demystified&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/2Y0A0H2B2q3C0622261C/Screenshot_6_13_13_9_57_AM.png" alt="Explain explained">&lt;/p>
&lt;h3 id="getting-at-the-data" >
&lt;div>
Getting at the Data
&lt;/div>
&lt;/h3>
&lt;p>The first small thing you can do is actually retrieve the data in JSON form. By adding in &lt;code>(format json)&lt;/code> right after your &lt;code>EXPLAIN&lt;/code> or &lt;code>EXPLAIN ANALYZE&lt;/code> command it&amp;rsquo;ll as you&amp;rsquo;d expect return it in JSON. To give an example:&lt;/p>
&lt;pre>&lt;code># EXPLAIN SELECT * FROM users LIMIT 1;
QUERY PLAN
--------------------------------------------------------------
Limit (cost=0.00..0.03 rows=1 width=812)
-&amp;gt; Seq Scan on users (cost=0.00..1.50 rows=50 width=812)
(2 rows)
&lt;/code>&lt;/pre>
&lt;p>Then in JSON format:&lt;/p>
&lt;pre>&lt;code>EXPLAIN (format json) SELECT * FROM users LIMIT 1;
QUERY PLAN
------------------------------------------------
[ +
{ +
&amp;quot;Plan&amp;quot;: { +
&amp;quot;Node Type&amp;quot;: &amp;quot;Limit&amp;quot;, +
&amp;quot;Startup Cost&amp;quot;: 0.00, +
&amp;quot;Total Cost&amp;quot;: 0.03, +
&amp;quot;Plan Rows&amp;quot;: 1, +
&amp;quot;Plan Width&amp;quot;: 812, +
&amp;quot;Plans&amp;quot;: [ +
{ +
&amp;quot;Node Type&amp;quot;: &amp;quot;Seq Scan&amp;quot;, +
&amp;quot;Parent Relationship&amp;quot;: &amp;quot;Outer&amp;quot;,+
&amp;quot;Relation Name&amp;quot;: &amp;quot;users&amp;quot;, +
&amp;quot;Alias&amp;quot;: &amp;quot;users&amp;quot;, +
&amp;quot;Startup Cost&amp;quot;: 0.00, +
&amp;quot;Total Cost&amp;quot;: 1.50, +
&amp;quot;Plan Rows&amp;quot;: 50, +
&amp;quot;Plan Width&amp;quot;: 812 +
} +
] +
} +
} +
]
(1 row)
&lt;/code>&lt;/pre>
&lt;p>While its on my list to build some interesting apps by pulling in the JSON input, others may be equally as interested in taking advantage of this data in its JSON form. If you take a shot at building something with this output, as always I&amp;rsquo;d love to hear about it - &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>&lt;/p>
&lt;h3 id="despez" >
&lt;div>
Despez
&lt;/div>
&lt;/h3>
&lt;p>Of course if you&amp;rsquo;re itch isn&amp;rsquo;t in better tools for Postgres, you may just want to have a solution that works today. While its not perfect, one of the best ones out there is &lt;a href="http://explain.depesz.com/">Dezpez&amp;rsquo;s explain tool&lt;/a>. You can take any execution plan and paste it in and get some better visual representation of the result. You can also &lt;a href="http://explain.depesz.com/s/vL1">share them as well&lt;/a>.&lt;/p></description></item><item><title>Postgres Indexing - A collection of indexing tips</title><link>/2013/05/30/Postgres-Indexing-A-collection-of-indexing-tips/</link><pubDate>Thu, 30 May 2013 12:55:56 -0800</pubDate><guid>/2013/05/30/Postgres-Indexing-A-collection-of-indexing-tips/</guid><description>&lt;p>Even from intial reviews of my previous post on expression based indexes I received a lot of questions and feedback around many different parts of indexing in Postgres. Here&amp;rsquo;s a mixed collection of valuable tips and guides around much of that.&lt;/p>
&lt;h3 id="unused-indexes" >
&lt;div>
Unused Indexes
&lt;/div>
&lt;/h3>
&lt;p>In an earlier tweet I joked about some SQL that would generate the SQL to add an index to every column:&lt;/p>
&lt;pre>&lt;code># SELECT 'CREATE INDEX idx_'
|| table_name || '_'
|| column_name || ' ON '
|| table_name || ' (&amp;quot;'
|| column_name || '&amp;quot;);'
FROM information_schema.columns;
?column?
---------------------------------------------------------------------
CREATE INDEX idx_pg_proc_proname ON pg_proc (&amp;quot;proname&amp;quot;);
CREATE INDEX idx_pg_proc_pronamespace ON pg_proc (&amp;quot;pronamespace&amp;quot;);
CREATE INDEX idx_pg_proc_proowner ON pg_proc (&amp;quot;proowner&amp;quot;);
&lt;/code>&lt;/pre>
&lt;!-- raw HTML omitted -->
&lt;p>The reasoning behind this is guessing whether an index will be helpful can be a bit hard within Postgres. So the easy solution is to add indexes to everything, then just observe if they&amp;rsquo;re being used. &lt;em>Of course you want to add it to all tables/columns because you never know if core of Postgres may be missing some needed ones&lt;/em>&lt;/p>
&lt;p>As included with the &lt;a href="https://github.com/heroku/heroku-pg-extras">pg-extras plugin for Heroku&lt;/a> you can run a query to show you all unused indexes. On Heroku simply install the plugin the run &lt;code>heroku pg:unused_indexes&lt;/code> to show the size and number of times an index scan has been used. On a non Heroku Postgres database you can run:&lt;/p>
&lt;pre>&lt;code># SELECT
schemaname || '.' || relname AS table,
indexrelname AS index,
pg_size_pretty(pg_relation_size(i.indexrelid)) AS index_size,
idx_scan as index_scans
FROM pg_stat_user_indexes ui
JOIN pg_index i ON ui.indexrelid = i.indexrelid
WHERE NOT indisunique AND idx_scan &amp;lt; 50 AND pg_relation_size(relid) &amp;gt; 5 * 8192
ORDER BY pg_relation_size(i.indexrelid) / nullif(idx_scan, 0) DESC NULLS FIRST,
pg_relation_size(i.indexrelid) DESC;
table | index | index_size | index_scans
---------------------+--------------------------------------------+------------+-------------
public.grade_levels | index_placement_attempts_on_grade_level_id | 97 MB | 0
public.observations | observations_attrs_grade_resources | 33 MB | 0
public.messages | user_resource_id_idx | 12 MB | 0
(3 rows)
&lt;/code>&lt;/pre>
&lt;h3 id="costs-of-indexing" >
&lt;div>
Costs of Indexing
&lt;/div>
&lt;/h3>
&lt;p>There are really a couple of primary costs when it comes to indexing your data. The first is the overall size of the index. Indexes take size on disk, fortunately in most cases disk is pretty cheap. If you&amp;rsquo;re limited on disk size and not on your current performance then its pretty clear the trade-off you want to take. If you do need to get the size of your index you can do that by running:&lt;/p>
&lt;pre>&lt;code># SELECT pg_size_pretty(pg_total_relation_size('idx_name'));
&lt;/code>&lt;/pre>
&lt;p>The harder trade off to look at is the cost in terms of throughput. As your data comes in there&amp;rsquo;s a cost for maintaining that index as the data within it has to be computed. If you&amp;rsquo;re doing crazy regex&amp;rsquo;s in your index then you can expect this to have an impact on your throughput.&lt;/p>
&lt;h3 id="composite-indexes-vs-multiple-indiviual-indexes" >
&lt;div>
Composite Indexes vs. Multiple Indiviual Indexes
&lt;/div>
&lt;/h3>
&lt;p>A composite index is an index that includes multiple columns. Given an example table of purchases:&lt;/p>
&lt;pre>&lt;code># \d purchases
Table &amp;quot;public.purchases&amp;quot;
Column | Type | Modifiers
-------------+-----------------------------+-----------
id | integer | not null
item | integer |
quantity | integer |
color | integer |
&lt;/code>&lt;/pre>
&lt;p>You might want to add an index on item and quantity together. You can do this with:&lt;/p>
&lt;pre>&lt;code>CREATE INDEX idx_purchases_item_quantity_color ON purchases (item, quantity, color)
&lt;/code>&lt;/pre>
&lt;p>From now on if you included item and quantity in a query its likely it would use this index just as it would if you used item, quantity and color. If you have a large varied set of data within each of these such an index can prove very useful. The caveat is that if you&amp;rsquo;re querying against only quantity and color then this index is useless, it &lt;strong>must&lt;/strong> include the item column.&lt;/p>
&lt;p>In contrast if you have three individual indexes Postgres may combine these or simply use one that would be the most efficient out of the three.&lt;/p>
&lt;pre>&lt;code>CREATE INDEX idx_purchases_item ON purchases (item);
CREATE INDEX idx_purchases_quantity ON purchases (quantity);
CREATE INDEX idx_purchases_color ON purchases (color);
&lt;/code>&lt;/pre>
&lt;p>Of course in this case if you query any individual column it would use the index if appropriate.&lt;/p>
&lt;h3 id="what-else" >
&lt;div>
What Else
&lt;/div>
&lt;/h3>
&lt;p>What else do you want to know about Postgres Indexing? Drop me a line &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens at gmail.com&lt;/a> or hop over to &lt;a href="http://www.postgresguide.com">Postgres Guide&lt;/a> and &lt;a href="http://postgresguide.com/performance/indexes.html">read a little there&lt;/a> or even contribute some articles of your own.&lt;/p></description></item><item><title>Postgres Indexes – Expression/Functional Indexing</title><link>/2013/05/29/Postgres-Indexes-Expression/Functional-Indexing/</link><pubDate>Wed, 29 May 2013 12:55:56 -0800</pubDate><guid>/2013/05/29/Postgres-Indexes-Expression/Functional-Indexing/</guid><description>&lt;p>Postgres is rich with options for indexing. First you&amp;rsquo;ve got a variety of types, and beyond that you can do a variety of things with each of these such as create unique indexes, use conditions to index only a portion of your data, or create indexes based on complex expressions or functions. In cases where you commonly use various PostgreSQL functions in your application or reporting you can get some great gains from this.&lt;/p>
&lt;p>Let&amp;rsquo;s take a look at a really simple case. Given a basic user table:&lt;/p>
&lt;pre>&lt;code># \dt users
Table &amp;quot;public.users&amp;quot;
Column | Type | Modifiers
------------+-----------------------------+-----------
id | integer | not null
email | character varying(255) |
created_at | timestamp without time zone |
&lt;/code>&lt;/pre>
&lt;p>You may commonly want to run a report against it showing your signups by date. Let&amp;rsquo;s say you do this by running the query:&lt;/p>
&lt;pre>&lt;code>SELECT
count(*),
date_trunc('day', created_at)
FROM
users
GROUP BY
2;
&lt;/code>&lt;/pre>
&lt;p>If you&amp;rsquo;re commonly using &lt;code>date_trunc('day', created_at)&lt;/code> for grouping, filtering, or projecting it out you can get some great gains by creating an index on this:&lt;/p>
&lt;pre>&lt;code># CREATE INDEX idx_user_created ON users(date_trunc('day', created_at));
&lt;/code>&lt;/pre>
&lt;p>Of course you can go beyond the built in functions of Postgres and use more complicated functions you create yourself. For example if you have JSON stored within PostgreSQL, have PLV8 enabled, and want to create a Javascript function to parse and return the text for a given key:&lt;/p>
&lt;pre>&lt;code># CREATE OR REPLACE FUNCTION
get_text(key text, data json)
RETURNS text $$
return data[key];
$$ LANGUAGE plv8 IMMUTABLE STRICT;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>Of note in the above function is &lt;code>IMMUTABLE&lt;/code> and &lt;code>STRICT&lt;/code>. Immutable specifies that the function given the same inputs will return the same result. Strict means that if you send in &lt;code>NULL&lt;/code> values you&amp;rsquo;ll get a null result.&lt;/em>&lt;/p>
&lt;p>Given some example data inside your JSON field:&lt;/p>
&lt;pre>&lt;code>{
&amp;quot;name&amp;quot;: &amp;quot;Craig Kerstiens&amp;quot;,
&amp;quot;location&amp;quot;: &amp;quot;San Francisco&amp;quot;,
&amp;quot;numbers&amp;quot;: [
{
&amp;quot;type&amp;quot;: &amp;quot;work&amp;quot;,
&amp;quot;number&amp;quot;: &amp;quot;123.456.7890&amp;quot;
},
{
&amp;quot;type&amp;quot;: &amp;quot;home&amp;quot;,
&amp;quot;number&amp;quot;: &amp;quot;987.654.3210&amp;quot;
}
]
}
&lt;/code>&lt;/pre>
&lt;p>If you wanted to return just the name you could index on:&lt;/p>
&lt;pre>&lt;code># CREATE INDEX idx_name ON users(get_text('name', json_data));
&lt;/code>&lt;/pre>
&lt;p>Or even combine with built ins for a case-insensitive version:&lt;/p>
&lt;pre>&lt;code># CREATE INDEX idx_name ON users(lower(get_text('name', json_data)));
&lt;/code>&lt;/pre>
&lt;p>Indexes like all of the above can be useful when you&amp;rsquo;re filtering on something that postgres can take advantage of. In most cases any conditions with the exception of a &lt;code>LIKE&lt;/code> beginning with a &lt;code>%&lt;/code> work for this. With Postgres 9.2 even a count(*) in certain cases can take advantage of the index because of index only scans.&lt;/p>
&lt;p>Whether you&amp;rsquo;re looking to take advantage of all the power of Javascript with JSON or another procedural langauge – or simply speed up a basic report using built in functions expression indexes can give you some great benefits.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>My SQL Bad Habits</title><link>/2013/05/26/My-SQL-Bad-Habits/</link><pubDate>Sun, 26 May 2013 12:55:56 -0800</pubDate><guid>/2013/05/26/My-SQL-Bad-Habits/</guid><description>&lt;p>I&amp;rsquo;m reasonably proficient at SQL – &lt;em>a coworker when pseudocoding some logic for him pointed out that my pseudocode is what he thought was executable SQL&lt;/em>. I&amp;rsquo;m fully capable of writing clear and readable SQL – which most SQL is not. Despite that I still have several bad habits when it comes to SQL. Without further adieu heres some of my dirty laundry so hopefully others can not make the same mistakes.&lt;/p>
&lt;h3 id="ordergroup-by-column-numbers" >
&lt;div>
Order/Group by Column Numbers
&lt;/div>
&lt;/h3>
&lt;p>When quickly iterating on a query its a lot less typing to put the column number as the thing you want to order by. Here&amp;rsquo;s a quick lightweight example:&lt;/p>
&lt;pre>&lt;code>SELECT
email,
created_at
FROM
users
ORDER BY 2 DESC
LIMIT 5;
&lt;/code>&lt;/pre>
&lt;p>This gives me my last 5 users that have signed up for my site. Of course as soon as I have this I may want to add some data to it, like their first name so I can send them a welcome email. I quickly alter the query to:&lt;/p>
&lt;pre>&lt;code>SELECT
email,
first_name,
created_at
FROM
users
ORDER BY 2 DESC
LIMIT 5;
&lt;/code>&lt;/pre>
&lt;p>And now I have 5 users that have signed up ordered by their first name. Sure its obvious when you have 1 column you&amp;rsquo;re ordering by, but when you have &lt;code>GROUP BY 1, 2, 3, 4, 5, 6&lt;/code> which is actually open in one of my tabs currently its a bit more confusing&amp;hellip;.&lt;/p>
&lt;p>&lt;em>Though if you really want to have some fun, share a query with someone that looks something like this:&lt;/em>&lt;/p>
&lt;pre>&lt;code>SELECT
email as &amp;quot;3&amp;quot;,
first_name &amp;quot;2&amp;quot;,
created_at &amp;quot;1&amp;quot;
FROM
users
ORDER BY &amp;quot;1&amp;quot;, &amp;quot;3&amp;quot; DESC
LIMIT 5;
&lt;/code>&lt;/pre>
&lt;h3 id="implicit-joins" >
&lt;div>
Implicit Joins
&lt;/div>
&lt;/h3>
&lt;p>I seldom use the syntax &lt;code>INNER JOIN&lt;/code>. Instead I simply put the two tables in my where clause and ensure I have a where condition. The problem with ensuring I have a where condition is sometimes I don&amp;rsquo;t, especially when you&amp;rsquo;re dealing with 3 tables.&lt;/p>
&lt;pre>&lt;code>SELECT
email,
product.name,
product.price
FROM
users,
orders,
items
WHERE users.id = orders.user_id
AND orders.id = items.order_id
&lt;/code>&lt;/pre>
&lt;p>Is less clear (especially when dealing with 5-6 tables) than the alternative:&lt;/p>
&lt;pre>&lt;code>SELECT
email,
product.name,
product.price
FROM users
INNER JOIN orders on users.id = orders.user_id
INNER JOIN items on orders.id = items.order_id
&lt;/code>&lt;/pre>
&lt;h3 id="lack-of-comments" >
&lt;div>
Lack of comments
&lt;/div>
&lt;/h3>
&lt;p>I comment my SQL far less than I comment my code, yet it can be done just as easily. For example I have this in one of my queries:&lt;/p>
&lt;pre>&lt;code>SELECT convert_from(CAST(E'\\x' || array_to_string(ARRAY(
SELECT
CASE
WHEN length(r.m[1]) = 1
THEN encode(convert_to(r.m[1], 'SQL_ASCII'), 'hex')
ELSE substring(r.m[1] from 2 for 2)
END
FROM regexp_matches(url_here, '%[0-9a-f][0-9a-f]|.', 'gi') AS r(m)
), '') AS bytea), 'UTF8');
&lt;/code>&lt;/pre>
&lt;p>While this has its own issues theres no documentation around what this actually does, in contrast:&lt;/p>
&lt;pre>&lt;code>--- DECODES url ---
SELECT convert_from(CAST(E'\\x' || array_to_string(ARRAY(
SELECT
CASE
WHEN length(r.m[1]) = 1
THEN encode(convert_to(r.m[1], 'SQL_ASCII'), 'hex')
ELSE substring(r.m[1] from 2 for 2)
END
FROM regexp_matches(url_here, '%[0-9a-f][0-9a-f]|.', 'gi') AS r(m)
), '') AS bytea), 'UTF8');
&lt;/code>&lt;/pre>
&lt;p>Comments also work well inline at the end of a line.&lt;/p>
&lt;h3 id="large-manually-generated-lists" >
&lt;div>
Large Manually Generated Lists
&lt;/div>
&lt;/h3>
&lt;p>A lot of times in working with some specific data set I&amp;rsquo;ll manually or automatically generate a list that I want to filter. A common example is filtering out staging/dev environments. I&amp;rsquo;ll often manually search and prune the list, then save that result for the queries I&amp;rsquo;m going to build going forward. This is a bit of effort but still feels reasonable the downside is it results in something like:&lt;/p>
&lt;pre>&lt;code>SELECT
foo
FROM
bar
WHERE
bar.id NOT IN (34723, 42735, 32321, 47205, 20375, 30261, 26194, 109371, 9313, 6351, 20184, 50273, 34735, 39854, 23954, 25323, 23405, 30528, 50182, 29340, 47659, ... and the list goes on)
&lt;/code>&lt;/pre>
&lt;p>SQL is meant to be reasonable for containing some level of logic. Data changes, hard coding keys is going to bite you at some point, spend the extra effort and re-use something thats clear.&lt;/p>
&lt;h3 id="what-else" >
&lt;div>
What else
&lt;/div>
&lt;/h3>
&lt;p>I&amp;rsquo;m sure theres plenty more; I suspect within a few minutes of sitting down with someone they could point out some other bad habits. While I know mine at least some of mine I still often know the trade-off. What are yours? I&amp;rsquo;d love to hear to document them for others so hopefully they can prevent developing the same bad habits. Let me know; &lt;!-- raw HTML omitted -->&lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>&lt;!-- raw HTML omitted -->&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>CX – Conference Experience (Facilitating Communication)</title><link>/2013/04/29/CX-Conference-Experience-Facilitating-Communication/</link><pubDate>Mon, 29 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/29/CX-Conference-Experience-Facilitating-Communication/</guid><description>&lt;p>Following up on my earlier post about CX or Conference Experience – I&amp;rsquo;m going to dig in a bit on how you get good conversation to happen. In the past two years I&amp;rsquo;ve been to nearly 20 conferences, I&amp;rsquo;ve been to conferences with great talks, with great parties, with great swag, and hands down my favorite conferences have always been a result of great conversation. With the number of talks that are recorded and immediately available online after, &lt;em>what can I say I&amp;rsquo;m a hallway track guy&lt;/em>.&lt;/p>
&lt;p>I&amp;rsquo;ve seen a number of conferences intentionally design around this concept, in some ways the unconference is purely a hallway track conference. I&amp;rsquo;ve also seen conferences that weren&amp;rsquo;t clearly planned for this and have pulled off some of the best situations where people turn their phones off and engage in real conversation.&lt;/p>
&lt;h2 id="breaks" >
&lt;div>
Breaks
&lt;/div>
&lt;/h2>
&lt;p>Breaks are always a hard part to balance. Every conference organizer I&amp;rsquo;ve talked to felt they had the perfect mix for breaks. If you&amp;rsquo;re designing for convesation then you need to allow time for conversation to actually happen. Whether a multi-track or single track conference 15 minutes for breaks doesn&amp;rsquo;t give you the time to actually engage in conversation. If multitrack its time enough to grab a drink then head to the next room. If single track its time to have the entire room leave and then come back.&lt;/p>
&lt;p>Even 30 minute breaks fall into this category. At a multitrack conference I&amp;rsquo;m usually saying hi to enough people during a 30 minute break that I don&amp;rsquo;t have the chance to really get deep into a conversation. If I do it usually results in skipping the next talk.&lt;/p>
&lt;h2 id="staggered-talks" >
&lt;div>
Staggered Talks
&lt;/div>
&lt;/h2>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;h2 id="locations-for-conversations" >
&lt;div>
Locations for Conversations
&lt;/div>
&lt;/h2>
&lt;p>Having places for people to get away an talk is critical, in a venue that only has 1 main room and no convenient places for a quick coffee or beer it becomes very hard for conversations to happen. If its on the agenda to facilitate such things thats great, but going a step further and allowing for it to be facilitated naturally is even better. On more than one occasion I&amp;rsquo;ve been mid conversation wtih someone, we cut it off agreeing to pick it back up at the next break only to never locate them again for the rest of the conference. I&amp;rsquo;d have just as much preferred to continue the conversation there, but sadly there was in the middle of a talk room with no where else feasible to go.&lt;/p>
&lt;h2 id="water" >
&lt;div>
Water
&lt;/div>
&lt;/h2>
&lt;!-- raw HTML omitted -->
&lt;p>This one caught me by surprise&amp;hellip; The event was &lt;a href="http://py.codeconf.com/">PyCodeConf in Miami&lt;/a> and it was one of the evening activities – a pool party with food, drinks, and mariachi band. Early into the evening, inevitably someone was thrown into the pool (by friends in a general good nature), but thus ruining a lovely iPhone. As a result I&amp;rsquo;m pretty most people, just as I did, went to their rooms but their cell phone away, or set it near their stuff. Much of the rest of the evening was an entirely internet and twitter free evening. Causing lots of uninterrupted conversations to happen and resulted in a pool full of geeks.&lt;/p>
&lt;h2 id="welcoming-noobs" >
&lt;div>
Welcoming noobs
&lt;/div>
&lt;/h2>
&lt;p>The big difference between just assuming this will happen and actively working to facilitate it is who gets involved in the conversation. For a first time presenter there&amp;rsquo;s a wealth of nerves about talking. For a first time attendee there&amp;rsquo;s a wealth of knowledge to soak up. First time attendees may not feel as comfortable interjecting them into a conversation, approaching presenters, or talking to someone they&amp;rsquo;ve been following for years – &lt;em>yet they have just as much to add as anyone else&lt;/em>.&lt;/p>
&lt;p>Creating places where more conversation is happening helps ease this and build a better community.&lt;/p></description></item><item><title>CX – Conference Experience (People)</title><link>/2013/04/29/CX-Conference-Experience-People/</link><pubDate>Mon, 29 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/29/CX-Conference-Experience-People/</guid><description>&lt;p>Following up on my earlier post about CX or Conference Experience – I&amp;rsquo;m going to dig in a bit on getting the right people there. There&amp;rsquo;s a lot of different ways to approach this from having a good ratio of:&lt;/p>
&lt;ul>
&lt;li>Designers to Developers&lt;/li>
&lt;li>Females to Males&lt;/li>
&lt;li>Noobs to well known community members&lt;/li>
&lt;li>Overall lack of suits&lt;/li>
&lt;/ul>
&lt;p>While this is by no means a how we can solve all of the above problems, theres some bas&lt;/p>
&lt;h2 id="talks" >
&lt;div>
Talks
&lt;/div>
&lt;/h2>
&lt;p>Quality talks are obviously important. A conference should at whatever cost ensure that the talks are good. This can happen a variety of ways, but regardless of the method you should ensure talks are worthwhile; since this is largely what most people are paying to attend for.&lt;/p>
&lt;h3 id="invite-only" >
&lt;div>
Invite-only
&lt;/div>
&lt;/h3>
&lt;p>Perhaps the easiest way to do this is via invite only to speakers you know will do a good job. The downside ot this of course is that you must already know enough people to fill out a good agenda, and also you limit the ability for others to contribute.&lt;/p>
&lt;h3 id="coachingpracticing" >
&lt;div>
Coaching/Practicing
&lt;/div>
&lt;/h3>
&lt;p>This is not an either/or option with any of the other pieces for getting a good agenda. Having presenters do a trial run can ensure a minimum level of quality, and working with them to coach them can help make the talk even more effective. Its likely that the organizers know the audience as well as anyone, so no one better than them to help with this. Of course this is a time sink for both parties, but can give good returns. Of course this could be done independent of a specific conference such as through &lt;a href="http://speakup.io/">speakup&lt;/a>.&lt;/p>
&lt;p>&lt;em>At a very least getting a quick run through, outline, or something of that nature can ensure that a presenter doesn&amp;rsquo;t fill a 45 minute talk slot with only 5 minutes of content.&lt;/em>&lt;/p>
&lt;h3 id="open-cfp" >
&lt;div>
Open CFP
&lt;/div>
&lt;/h3>
&lt;p>Likely the most common approach to getting speakers is having an entirely open CFP. Its typical then that either the organizers or a speaker selection commitee then discusses and makes selections. This can usually work to have a nice balance of experienced and known to be good speakers and newer less experienced speakers that can have great potential as well.&lt;/p>
&lt;h3 id="open-open-cfp" >
&lt;div>
Open Open CFP
&lt;/div>
&lt;/h3>
&lt;p>Going even further is an open CFP where all talks are published after the CFP then voted on. While this does a great deal to ensure transparency, it doesn&amp;rsquo;t necessarily improve ensuring theres a great line up of speakers. Being able to write an interesting talk proposal is an entirely separate process from delivering an interesting talk.&lt;/p>
&lt;h3 id="blind" >
&lt;div>
Blind?
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s a common question lately for both the open CFP and open open ones one whether to do blind review of the talks. The logic here is an attempt to be entirely fair, versus having some bias. This is an understandable goal, but can come at the expense of quality. Truth be told; I&amp;rsquo;m not entirely sure of a way to balance this.&lt;/p>
&lt;h2 id="choosing" >
&lt;div>
Choosing
&lt;/div>
&lt;/h2>
&lt;p>There&amp;rsquo;s definitely not a one size fits all. If you&amp;rsquo;re goal is to provide a good list of talks then you should keep that in mind in how you decide your talks. If you&amp;rsquo;re goal is to pull others in then it should be shaped differently. Zach Holman recently talked a bit about this and had some interesting ideas to &lt;a href="http://zachholman.com/posts/the-conference-circuit/">minimize risk for new speakers&lt;/a>.&lt;/p></description></item><item><title>CX – Conference Experience (Talks)</title><link>/2013/04/27/CX-Conference-Experience-Talks/</link><pubDate>Sat, 27 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/27/CX-Conference-Experience-Talks/</guid><description>&lt;p>A couple of weekends ago I had the great opportunity to attend &lt;a href="http://lessconf.com">lessconf&lt;/a>. It was an all around great conference, and as a result of the greatness I ended up having a conversation with a few people around conference experience. I must give much of the credit to &lt;a href="http://twitter.com/swiftalphaone">Swift&lt;/a>, as he mentioned he&amp;rsquo;d already been thinking alot about this since &lt;a href="http://waza.heroku.com">Waza&lt;/a>. In general it feels like there&amp;rsquo;s a few key themes that any conference should focus on, then a lot of small things that can really push it over the top. Here&amp;rsquo;s a few:&lt;/p>
&lt;p>In general the key areas for any great conference are:&lt;/p>
&lt;ul>
&lt;li>Talks&lt;/li>
&lt;li>Great people&lt;/li>
&lt;li>Ensuring communication happens&lt;/li>
&lt;li>Bonus points&lt;/li>
&lt;/ul>
&lt;p>Digging in deeper on the first area&amp;hellip;&lt;/p>
&lt;h2 id="talks" >
&lt;div>
Talks
&lt;/div>
&lt;/h2>
&lt;p>Quality talks are obviously important. A conference should at whatever cost ensure that the talks are good. This can happen a variety of ways, but regardless of the method you should ensure talks are worthwhile; since this is largely what most people are paying to attend for.&lt;/p>
&lt;h3 id="invite-only" >
&lt;div>
Invite-only
&lt;/div>
&lt;/h3>
&lt;p>Perhaps the easiest way to do this is via invite only to speakers you know will do a good job. The downside ot this of course is that you must already know enough people to fill out a good agenda, and also you limit the ability for others to contribute.&lt;/p>
&lt;h3 id="coachingpracticing" >
&lt;div>
Coaching/Practicing
&lt;/div>
&lt;/h3>
&lt;p>This is not an either/or option with any of the other pieces for getting a good agenda. Having presenters do a trial run can ensure a minimum level of quality, and working with them to coach them can help make the talk even more effective. Its likely that the organizers know the audience as well as anyone, so no one better than them to help with this. Of course this is a time sink for both parties, but can give good returns. Of course this could be done independent of a specific conference such as through &lt;a href="http://speakup.io/">speakup&lt;/a>.&lt;/p>
&lt;p>&lt;em>At a very least getting a quick run through, outline, or something of that nature can ensure that a presenter doesn&amp;rsquo;t fill a 45 minute talk slot with only 5 minutes of content.&lt;/em>&lt;/p>
&lt;h3 id="open-cfp" >
&lt;div>
Open CFP
&lt;/div>
&lt;/h3>
&lt;p>Likely the most common approach to getting speakers is having an entirely open CFP. Its typical then that either the organizers or a speaker selection commitee then discusses and makes selections. This can usually work to have a nice balance of experienced and known to be good speakers and newer less experienced speakers that can have great potential as well.&lt;/p>
&lt;h3 id="open-open-cfp" >
&lt;div>
Open Open CFP
&lt;/div>
&lt;/h3>
&lt;p>Going even further is an open CFP where all talks are published after the CFP then voted on. While this does a great deal to ensure transparency, it doesn&amp;rsquo;t necessarily improve ensuring theres a great line up of speakers. Being able to write an interesting talk proposal is an entirely separate process from delivering an interesting talk.&lt;/p>
&lt;h3 id="blind" >
&lt;div>
Blind?
&lt;/div>
&lt;/h3>
&lt;p>There&amp;rsquo;s a common question lately for both the open CFP and open open ones one whether to do blind review of the talks. The logic here is an attempt to be entirely fair, versus having some bias. This is an understandable goal, but can come at the expense of quality. Truth be told; I&amp;rsquo;m not entirely sure of a way to balance this.&lt;/p>
&lt;h2 id="choosing" >
&lt;div>
Choosing
&lt;/div>
&lt;/h2>
&lt;p>There&amp;rsquo;s definitely not a one size fits all. If you&amp;rsquo;re goal is to provide a good list of talks then you should keep that in mind in how you decide your talks. If you&amp;rsquo;re goal is to pull others in then it should be shaped differently. Zach Holman recently talked a bit about this and had some interesting ideas to &lt;a href="http://zachholman.com/posts/the-conference-circuit/">minimize risk for new speakers&lt;/a>.&lt;/p></description></item><item><title>Heroku's Acquisition 2 Years Later</title><link>/2013/04/18/Herokus-Acquisition-2-Years-Later/</link><pubDate>Thu, 18 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/18/Herokus-Acquisition-2-Years-Later/</guid><description>&lt;p>Just over two years ago, Heroku was acquired. I was around and peripheral to this just before the acquisition and came on board only barely after. While there is a large group of people that have been there longer than I have (several for 4+ years) I&amp;rsquo;m still commonly asked how things have changed, how things work, and other questions of that nature. I wrote about some of these processes over a year ago in the months after joining Heroku around our &lt;a href="/2011/12/02/how-heroku-works-hiring/">hiring&lt;/a>, our &lt;a href="/2011/11/02/how-heroku-works-teams-tools/">teams&lt;/a>, and &lt;a href="/2011/11/07/how-heroku-works-maker-day/">how we work&lt;/a>. Many of these things haven&amp;rsquo;t changed, and yet almost always at a conference I&amp;rsquo;m asked how are things different since being acquired.&lt;/p>
&lt;p>Here&amp;rsquo;s my personal take (and while I don&amp;rsquo;t typically include this – &lt;em>to be safe, this is not an official Heroku view of what&amp;rsquo;s changed&lt;/em>).&lt;/p>
&lt;h3 id="are-things-different-since-the-acquisition" >
&lt;div>
Are things different since the acquisition?
&lt;/div>
&lt;/h3>
&lt;p>Heroku in many ways operates like a wholly owned subsidiary or as an independent business within Salesforce. We still have our own office space, our own IT (if you can even call it that), and in general entirely own workflow. I have a salesforce email account that automatically forwards to my Heroku google apps account, and that&amp;rsquo;s about as much as I know about it. In fact, we&amp;rsquo;re currently preparing for our new office and its planned to be our home for somewhere between the next 5-10 years.&lt;/p>
&lt;p>At the same time some things do flow through Salesforce, some of those things are logistical some strategic. First the perhaps most unfortunate part – hiring. This has not really changed &lt;a href="/2011/12/02/how-heroku-works-hiring/">how we hire&lt;/a>, but rather once you are coming on board theres more paperwork. In general this is the most painful part that instead of 1/2 pieces of paper theres a few to sign. At the same time some of these come with some greater gains such as benefit, etc. To be honest I dont fully recall what all of the paper work is, but either way there is a bit more of it. The other area we really see this effect is expense accounts. All expenses flow through concur, which in my opinion is a pretty good solution. I&amp;rsquo;ve used many worse expense solutions and seen few if any better.&lt;/p>
&lt;h3 id="do-they-influence-the-product" >
&lt;div>
Do they influence the product?
&lt;/div>
&lt;/h3>
&lt;p>&lt;em>Not really&lt;/em>&lt;/p>
&lt;p>In general we at Heroku aim to have some broader alignment around what we&amp;rsquo;re trying to accomplish. Salesforce believes in helping their customers become a &lt;a href="http://www.youtube.com/watch?v=BwaZwm2dTCA">customer company&lt;/a>. We believe that developers are worth of great experiences. Salesforce believes in ensuring its customers are successful. Heroku believes that developers should focus on adding value of their customers not just keeping the lights on. In all of these things its important to have alignment. Not for the company we&amp;rsquo;re building for the next six weeks or six months, but for the next six years. Given both Salesforce&amp;rsquo;s and Heroku&amp;rsquo;s worldview I believe what we&amp;rsquo;re trying to accomplish is in good alignment.&lt;/p>
&lt;p>But does Salesforce influence our product roadmap? No, we aim to listen to our customers problems and build to solve those problems and through that improve the way software is delivered. At the time Salesforce acquired us, the pieces of &lt;a href="https://blog.heroku.com/archives/2011/5/31/celadon_cedar">Cedar&lt;/a> were already in motion; including Procfile support, logplex, and other pieces. Later was fully productized Cedar and which was a goal we&amp;rsquo;d long had – making other languages such as Node, &lt;a href="https://blog.heroku.com/archives/2011/8/25/java">Java&lt;/a>, and &lt;a href="https://blog.heroku.com/archives/2011/9/28/python_and_django">Python&lt;/a> available. This wasn&amp;rsquo;t driven because Salesforce wanted Java, but because we saw value in delivering the same value of the platform to other communities.&lt;/p>
&lt;h3 id="have-we-changed" >
&lt;div>
Have we changed?
&lt;/div>
&lt;/h3>
&lt;p>Sure, we&amp;rsquo;ve changed, but I&amp;rsquo;d surmise very little if at all due to Salesforce. We&amp;rsquo;ve grown from a 20 person company to now over 100. We were a primarily local team and now have people all over. Company offsites get a bit harder to coordinate with 100 people, and finding a date that absoluely everyone can make it is nearly impossible. Many of our changes are more strictly a change of growth than they are because of Salesforce.&lt;/p>
&lt;h3 id="i-dont-get-it-why-acquire-you-then" >
&lt;div>
I dont get it, why acquire you then?
&lt;/div>
&lt;/h3>
&lt;p>Because we&amp;rsquo;re aligned in a much bigger vision, we can both work together long term to accomplish our goal.&lt;/p>
&lt;p>&lt;em>The internet is changing the world; software is everywhere.&lt;/em>&lt;/p>
&lt;p>I believe Salesforce truly understands this. Heroku does as well (though, at the time of the acquisition I fully suspect many Herokai held their breath to see how it would all go). Six weeks went by without trying to &amp;lsquo;change us&amp;rsquo;, then six months, and here we are over two years later. In many ways so many of us have started to better understand that Salesforce truly understands the above.&lt;/p>
&lt;p>If you understand the above, then you know that delivering software and improving that process gives any business a competitive advantage. This is at the core of the value we aim to provide. E.g. If you ranked all companies in terms of how strong they aligned with Heroku, Salesforce might be at the &lt;em>very&lt;/em> top.&lt;/p></description></item><item><title>Using array_agg in Postgres – powerful and flexible</title><link>/2013/04/17/Using-array_agg-in-Postgres-powerful-and-flexible/</link><pubDate>Wed, 17 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/17/Using-array_agg-in-Postgres-powerful-and-flexible/</guid><description>&lt;p>In almost any application it&amp;rsquo;s common to want to aggregate some set of values together, commonly in a comma separated form. Most developers do this by running a query to get much of the raw data, looping over the data and pushing it into a set, appending each new value to the appropriate key. Hopefully, it&amp;rsquo;s not a surprise that there&amp;rsquo;s a much better way to do this with PostgreSQL.&lt;/p>
&lt;p>Postgres has a flexible and robust &lt;a href="/2012/08/20/arrays-in-postgres/">array datatype&lt;/a> that comes with a variety of functions. Even without taking advantage of the array datatype in &lt;a href="/2012/11/06/django-and-arrays/">your application&lt;/a>, you can still take advantage of some of the functions to get the functionality you need. Lets take a look at an example schema and use case.&lt;/p>
&lt;h3 id="an-example" >
&lt;div>
An example
&lt;/div>
&lt;/h3>
&lt;p>Given a project management application, you may have &lt;code>users&lt;/code> who have &lt;code>projects&lt;/code> that have &lt;code>tasks&lt;/code>. An example piece of functionality might be to send an email with a list of all projects that have tasks that are past their due dates of completion. Your schema might look something like this:&lt;/p>
&lt;pre>&lt;code> # \d users
Table &amp;quot;public.users&amp;quot;
Column | Type | Modifiers
------------+-----------------------------+-----------
id | integer | not null
email | character varying(255) |
...
# \d projects
Table &amp;quot;public.projects&amp;quot;
Column | Type | Modifiers
------------+-----------------------------+-----------
id | integer | not null
user_id | integer | not null
name | character varying(255) | not null
...
# \d tasks
Table &amp;quot;public.tasks&amp;quot;
Column | Type | Modifiers
--------------+-----------------------------+-----------
id | integer | not null
project_id | integer | not null
completed_at | timestamp without time zone |
due_at | timestamp without time zone |
...
&lt;/code>&lt;/pre>
&lt;p>To get a list of all projects that have tasks that haven&amp;rsquo;t been completed, you would start with something like:&lt;/p>
&lt;pre>&lt;code>SELECT
projects.name
FROM
projects,
tasks
WHERE projects.id = tasks.project_id
AND tasks.due_at &amp;gt; tasks.completed_at
AND tasks.due_at &amp;gt; now()
&lt;/code>&lt;/pre>
&lt;p>This would give you a list of projects which you could then easily join this with users:&lt;/p>
&lt;pre>&lt;code>SELECT
users.email
projects.name
FROM
projects,
tasks,
users
WHERE projects.id = tasks.project_id
AND tasks.due_at &amp;gt; tasks.completed_at
AND tasks.due_at &amp;gt; now()
AND users.id = projects.user_id
&lt;/code>&lt;/pre>
&lt;p>At this point you&amp;rsquo;ve got everything you need to pull this up into Ruby, Python, or other language of your choice and then build the full set. However if this is thousands or even hundreds of results you&amp;rsquo;ll be spending more time than necessary, grouping this data for a sensible email. With 3 other small changes you can have this already formatted for you to immediately send of in an email. The first is using a handy function called &lt;code>array_agg&lt;/code> which will aggregate items and then you can format them how you wish. The second is just ensuring you&amp;rsquo;re grouping correctly. Finally you&amp;rsquo;ll want to unnest the array so it formats the data in a clean way for you.&lt;/p>
&lt;p>Looking at it all put together:&lt;/p>
&lt;pre>&lt;code>SELECT
users.email,
array_to_string(array_agg(projects.name), ',')) as projects
FROM
projects,
tasks,
users
WHERE projects.id = tasks.project_id
AND tasks.due_at &amp;gt; tasks.completed_at
AND tasks.due_at &amp;gt; now()
AND users.id = projects.user_id
GROUP BY
users.email
&lt;/code>&lt;/pre>
&lt;p>This would give you a nice clean result of projects that have overdue tasks that you could then send to the user in an email:&lt;/p>
&lt;pre>&lt;code> email | projects
---------------------------+-------------------
craig.kerstiens@gmail.com | blog, timetracker
craig@heroku.com | foo, bar, baz
&lt;/code>&lt;/pre></description></item><item><title>Scaling Evangelism – Creating Advocates</title><link>/2013/04/16/Scaling-Evangelism-Creating-Advocates/</link><pubDate>Tue, 16 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/16/Scaling-Evangelism-Creating-Advocates/</guid><description>&lt;p>The first area I tend to think about when it comes to developer marketing is around advocates. A simple definition of an advocate is &lt;em>someone that speaks/writes in favor of some thing&lt;/em>.&lt;/p>
&lt;p>Creating advocates is a means of creating more of myself to go out and talk loudly and ideally effectively. However, they do take time to cultivate and it is a hard item to track. But by cultivating advocates I&amp;rsquo;m able to scale what would otherwise be a bottleneck of my own personal time.&lt;/p>
&lt;h3 id="mentorship" >
&lt;div>
Mentorship
&lt;/div>
&lt;/h3>
&lt;!-- raw HTML omitted -->
&lt;p>The people in your group of 3 you&amp;rsquo;ll have nearly daily communications with, even if quick. These are the first people you think to work and collaborate with. It&amp;rsquo;s the case with all, but especially so here that there may be some strong mutual benefit. With both the groups of 3 and 12 you&amp;rsquo;ll be looking to:&lt;/p>
&lt;ul>
&lt;li>Co-author content with&lt;/li>
&lt;li>Collaborate on projects&lt;/li>
&lt;li>Help amplify their content&lt;/li>
&lt;/ul>
&lt;h3 id="helping-them-succeed" >
&lt;div>
Helping them Succeed
&lt;/div>
&lt;/h3>
&lt;p>For a few years I&amp;rsquo;ve followed a similar process to this. Essentially creating advocates is done through first &lt;strong>making them successful&lt;/strong>, then empowering to talk about their success. I&amp;rsquo;ve often done this by giving people a private channel to me – through IM, SMS, Phone, Skype, or even in person. Sure its easy enough to get my work email address, its a pretty easy one to guess, and even at that address I do aim to respond to every request. These channels in reality don&amp;rsquo;t make me more available; but they do allow a different type of communication to happen.&lt;/p>
&lt;p>My personal approach has found it more out of place to ask how someones weekend was over email – IM or Skype make this easy. Broader questions of how someones actually doing in life generally are much easier to do over a coffee or a beer. This allows for a deeper relationship; at the same time I can ensure everyone I interact with is successful. It&amp;rsquo;s easier to ensure someones successful if they&amp;rsquo;re willing to talk to you, actually connecting with people enables this.&lt;/p>
&lt;h3 id="communicate" >
&lt;div>
Communicate
&lt;/div>
&lt;/h3>
&lt;p>Once someones been successful theres usually some value in their story. This doesn&amp;rsquo;t need to come in a marketing-ese approach though. Instead contribute back the value of what you did to the broader community with &lt;a href="http://blog.mailgun.net/post/how-tealeaf-academy-increased-student-engagement-3x/">clear steps how they can get the same benefit&lt;/a>. For many developers they feel talking about their own success is a bit of imposter syndrome. While this isn&amp;rsquo;t always the case; if it is you can help to work with someone to highlight the value in what they&amp;rsquo;ve done. This could be as simple as some encouragement to actually helping review drafts of blog posts.&lt;/p>
&lt;p>Of course once someones started talking about what they were able to accomplish help them celebrate the success. Yelling from the rooftops only helps to further their efforts and give them the confidence to do it all over again.&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>To create advocates you don&amp;rsquo;t have to write a list of people you wish to shoot for, but realizing there are limiitations on your time can help you be more intentional. Knowing that where you spend your time and who you spend it with has a cost can allow you to be more explicit about ensuring you&amp;rsquo;re providing value to them, from there it should naturally run its course. Want to discuss this more? Email me at &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens at gmail.com&lt;/a>.&lt;/p></description></item><item><title>Doing Marketing (for developers) Differently</title><link>/2013/04/12/perspective-on-developer-marketing/</link><pubDate>Fri, 12 Apr 2013 12:55:56 -0800</pubDate><guid>/2013/04/12/perspective-on-developer-marketing/</guid><description>&lt;p>As developers we can tend to be a fickle bunch; especially in certain open source communities. We like to see intelligence and systems applied to things, hope for a better world through making things open, and appreciate when others relate to our world as we often attempt to relate to theirs. Marketing is often a loaded word when it comes to developers – leaving mixed feelings about webinars, email campaigns, and the like.&lt;/p>
&lt;p>&lt;em>A quick clarification in terms of marketing I&amp;rsquo;m referring to product marketing, but of a technical product. This is based on the idea that &lt;a href="http://thenewkingmakers.com/">developers are the new kingmakers&lt;/a> and when marketing a product to them it needs to be done differently.&lt;/em>&lt;/p>
&lt;p>While many of the above steps can add immense value, they often miss when it comes to developers. By changing these processes only slightly there can be much more efficiency in connecting with and actually delivering the value you hope for to developers.&lt;/p>
&lt;h3 id="email-marketing" >
&lt;div>
Email Marketing
&lt;/div>
&lt;/h3>
&lt;p>This is an area that there are more and more companies already starting to solve the right problems. Companies like &lt;a href="http://intercom.io">intercom.io&lt;/a> and &lt;a href="http://customer.io">customer.io&lt;/a> are allowing for better tracking of what users are doing and notifying them at the &lt;em>right&lt;/em> time instead of via massive impersonal campaigns. Developers build systems that take into account similar factores every day, you should be doing the same.&lt;/p>
&lt;p>Emails that are sent at the wrong time or miss on what someone is trying to do can often do more damage towards building a rapport than good. Pushing content to solve a recent issue or problem at a relevant time should be table stakes for any email thats sent.&lt;/p>
&lt;h3 id="community-engagement" >
&lt;div>
Community Engagement
&lt;/div>
&lt;/h3>
&lt;p>Whether at conferences or in online collaborations developers are more social than so many give them credit for. We appreciate when things are done to improve the greater good particularly for developers, but often for the world as well. From supporting individual developers or projects financially such as through &lt;a href="http://www.gittip.com">gittip&lt;/a> or &lt;a href="http://www.kickstarter.com/projects/andrewgodwin/schema-migrations-for-django">certain kickstarter projects&lt;/a> all the way to employing developers to &lt;a href="http://www.twitter.com/tenderlove">work full time on open source&lt;/a>.&lt;/p>
&lt;h3 id="being-better-than-webinars" >
&lt;div>
Being Better Than Webinars
&lt;/div>
&lt;/h3>
&lt;p>After doing a webinar for a particular audience I had a &lt;a href="http://www.heroku.com">Heroku&lt;/a> co-worker come up to me. This individual has contributed many ideas that have become core functionality such as the &lt;a href="#">Cedar stack&lt;/a> and is generally open minded and listens very well. He came up to me and genuinely asked, &amp;ldquo;so what is a webinar?&amp;rdquo; I explained its like a live webcast with an opportunity for questions at the end. He was quiet for minute and responded, &amp;ldquo;Why can&amp;rsquo;t we just say that?&amp;rdquo;&lt;/p>
&lt;p>There are some words that simply send off the wrong signals. Webinar rather clearly is one of those. As a community we&amp;rsquo;ve shown that we have a desire for this kind of content. The &lt;a href="http://www.lanyrd.com">conference community&lt;/a> has continued to grow steadily, and while they are many parts to every conference a pretty common one is the talk track itself. A talk at a conference is essentially a live in person webinar, of course the experience is often a bit richer.&lt;/p>
&lt;p>Instead of the term webinar what is wrong with online office hours or webcasts with an opportunity for questions? Even doing the same thing with a different name is underdelivering on what we&amp;rsquo;re capable of.&lt;/p>
&lt;p>I welcome hearing from others directly at &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a> on what they&amp;rsquo;re doing to engage with developers thats working. Not only working in the sense of eyeballs or dollars, but in adding value, in improving communities, in make the world better for developers. If there&amp;rsquo;s enough interest would be happy to post more detail around things I&amp;rsquo;ve seen work and what I hear works for others.&lt;/p></description></item><item><title>Why I Blog</title><link>/2013/03/31/Why-I-Blog/</link><pubDate>Sun, 31 Mar 2013 12:55:56 -0800</pubDate><guid>/2013/03/31/Why-I-Blog/</guid><description>&lt;p>I blog because I&amp;rsquo;m lazy. There&amp;rsquo;s more too it though: In any given day I may explain something to someone, the first time I do this I make a bit of a mental note. The second time I do this, especially within a short time frame I make a physical note of this in the form of the title of a blog post. Once I&amp;rsquo;m already to a second time of doing this its almost inevitable I&amp;rsquo;ll continue repeating myself – and its valuable to others.&lt;/p>
&lt;h3 id="becoming-replaceable" >
&lt;div>
Becoming replaceable
&lt;/div>
&lt;/h3>
&lt;p>My goal in doing this is actually to become heavily replaceable. Keeping information locked away means I&amp;rsquo;m the only one capable of doing it. Making myself highly replaceable means I can continue to work on new and interesting things.&lt;/p>
&lt;h3 id="lots-can-be-shared" >
&lt;div>
Lots can be shared
&lt;/div>
&lt;/h3>
&lt;p>I don&amp;rsquo;t recall exactly where I read it, I believe it may have been &lt;a href="http://www.twitter.com/monkchips">James Governor&lt;/a>, but any email that doesn&amp;rsquo;t contain proprietary info or trade secrets should be blogged. I fully expect the sentiment around this is something to the effect that anything that contains good ideas/learning/processes can also be helpful to others.&lt;/p>
&lt;h3 id="distilling-information" >
&lt;div>
Distilling information
&lt;/div>
&lt;/h3>
&lt;p>For every time I explain something I often linger about one piece too long, hit something that doesn&amp;rsquo;t need to be discussed, or miss something entirely. Putting an idea or guide together in written form you re-read it, which is hard to do when simply verbally explaining. If you&amp;rsquo;ve video taped yourself before for public speaking practice you know this is an awkward but valuable experience. Its much easier to practice as an exercise in writing.&lt;/p>
&lt;h3 id="economies-of-scale" >
&lt;div>
Economies of scale
&lt;/div>
&lt;/h3>
&lt;p>While in some ways I am absolutely lazy when I blog I get economies of scale I couldn&amp;rsquo;t otherwise have. On a given day on a high day I may have 15 one on one conversations. Every post has the opportunity to become a one on one conversation.&lt;/p>
&lt;p>&lt;em>One on one conversation is my preferred method instead of in a large group. In a related area I&amp;rsquo;ve been having an ongoing conversation wth &lt;a href="http://www.twitter.com/rwdaigle">Ryan Daigle&lt;/a> on whether blog posts should have comments. I opt for having you reach out to me directly via &lt;a href="mailto:craig.kerstiens@gmail.com">email&lt;/a>, he believes comments should be available. Putting this in words crystalizes that to me its just relative to how you prefer to interact.&lt;/em>&lt;/p>
&lt;h3 id="summary" >
&lt;div>
Summary
&lt;/div>
&lt;/h3>
&lt;p>As with any other post, this is one conversation I&amp;rsquo;ve now had a few times over. Hopefully this gives some basis to why I feel others should contribute content as well. Whether you want make your self dispensible, refine your thoughts, or reach new economies of scale I believe its a worthwhile exercise for many. If you have other reasons you feel its valuable as always please &lt;a href="mailto:craig.kerstiens@gmail.com">reach out&lt;/a>.&lt;/p></description></item><item><title>Prioritizing and Planning within Heroku Postgres</title><link>/2013/03/13/planning-and-prioritizing/</link><pubDate>Wed, 13 Mar 2013 12:55:56 -0800</pubDate><guid>/2013/03/13/planning-and-prioritizing/</guid><description>&lt;p>Over a year ago I blogged about Heroku&amp;rsquo;s approach to &lt;a href="http://www.craigkerstiens.com/2011/11/02/how-heroku-works-teams-tools/">Teams and Tools&lt;/a>. Since that time Heroku has grown from around 25 people to over 100, we&amp;rsquo;ve continued to iterate and find new tools that work for how we do things. For many of the &lt;a href="http://www.amazon.com/Inspired-Create-Products-Customers-Love/dp/0981690408?ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=mypred-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0932633439">product management&lt;/a> and software engineering books I&amp;rsquo;ve read I&amp;rsquo;ve yet to find something that helps a team priorize in a fashion I that feels right.&lt;/p>
&lt;p>One process emerged nearly a year ago from within the &lt;a href="https://postgres.heroku.com">Heroku Postgres&lt;/a> team and is now followed by many others. Within a team this process is now commonly conducted each 6 months. Lets take a look at how this process looks&lt;/p>
&lt;h3 id="it-starts-with-ideas" >
&lt;div>
It Starts with Ideas
&lt;/div>
&lt;/h3>
&lt;p>Hopefully having ideas of things to work on isn&amp;rsquo;t a problem, if it is just go spend some time with customers – listen to their problems, see how they use the product, then come back and write down the ideas. For most teams this is simply an excercise of thinking back and writing it down. Some teams at Heroku have resorted to keeping running backlogs of things they&amp;rsquo;d like to do this. We do this by keeping a Trello board which columns for:&lt;/p>
&lt;ul>
&lt;li>New ideas&lt;/li>
&lt;li>Ponies&lt;/li>
&lt;li>Stallions&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Ponies and Stallions are things that would be great to do, however a sizeable amount of work must be done on them and we&amp;rsquo;re not currently tackling them. Ponies are less sizeable and likely to get done not in coming weeks but perhaps in coming months up to a year. Stallions are great but large effort and may or may not get done but in the category of things we would like to be able to do.&lt;/em>&lt;/p>
&lt;p>Once you&amp;rsquo;ve got your ideas whether in your head on a backlog we begin by writing them out typically on sticky notes or index cards.&lt;/p>
&lt;h3 id="laying-it-all-out" >
&lt;div>
Laying it all out
&lt;/div>
&lt;/h3>
&lt;p>From here we create a simple grid:&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/1x1J2u0g390C1u1A1R1a/Screenshot_3_8_13_10_37_AM.png" alt="grid">&lt;/p>
&lt;p>The grid has two axis. One is for impact the other for difficulty. At this point we aim to lay out every idea that we&amp;rsquo;ve already written down into a quadrant. Commonly this is done at team offsites where the team is free of distractions and able to devote appropriate time to it. Being able to accomplish this in one sitting with the team is important to having cohesion around the result.&lt;/p>
&lt;h3 id="a-plan" >
&lt;div>
A plan
&lt;/div>
&lt;/h3>
&lt;p>At this point hopefully its quite obvious what you want to tackle. If there&amp;rsquo;s anything in the top right it should be an easy win for something for you to focus on. From we often transcribe this into a powerpoint/keynote document and highlight things that we will definitely aim to accomplish in the next 6 months as well as things we&amp;rsquo;re intentionally not working on. This leaves us with an artifact of both things we will work on and explicit things we wont work on.&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/2J3K2E0q2z2P0y0C0M3B/Screenshot_3_9_13_8_45_AM.png" alt="grid">&lt;/p>
&lt;h3 id="what-works-for-us" >
&lt;div>
What works for us
&lt;/div>
&lt;/h3>
&lt;p>In general we try to have more work than we can tackle to ensure we&amp;rsquo;re constrained in a good form and not wasting idle time of people. Ensuring we&amp;rsquo;re selective about the things we&amp;rsquo;re working on and that we&amp;rsquo;re working on the right things works for us. We&amp;rsquo;ve found this simple exercise valuable for many teams to plan and ensure we&amp;rsquo;re working on those right things. Of course this may not work for everyone but for our goals and culture aligns well for us.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;ve got simple but unique techniques that work for your team as always would love to hear about them – &lt;a href="mailto:craig.kerstiens@gmail.com">craig.kerstiens@gmail.com&lt;/a>&lt;/em>&lt;/p></description></item><item><title>Fixing Database Connections in Django</title><link>/2013/03/07/Fixing-django-db-connections/</link><pubDate>Thu, 07 Mar 2013 12:55:56 -0800</pubDate><guid>/2013/03/07/Fixing-django-db-connections/</guid><description>&lt;p>If you&amp;rsquo;re looking to get better performance from your Django apps you can check out &lt;a href="http://www.amazon.com/Pro-Django-Experts-Voice-Development/dp/1430210478?ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=mypred-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0932633439">Pro Django&lt;/a>, &lt;a href="http://www.amazon.com/PostgreSQL-High-Performance-Gregory-Smith/dp/184951030X?ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=mypred-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0932633439">PostgreSQL High Performance&lt;/a>, or read some my earlier posts on &lt;a href="http://www.craigkerstiens.com/2013/01/10/more-on-postgres-performance/">Postgres Performance&lt;/a>. All of these are of course good things to do – you can also start by correcting an incredibly common but also painful performance issue, that until 1.6 is unaddressed in Django.&lt;/p>
&lt;p>Django&amp;rsquo;s current default behavior is to establish a connection for each request within a Django application. In many cases any particularly in distributed cloud environments this is a large time sink of your response time. An example application running on &lt;a href="http://www.heroku.com">Heroku&lt;/a> shows a typical connection time of 70ms. A large part of this time is the SSL negotiation that occurs in connecting to your database, &lt;em>which is a good practice to ensure security of your data&lt;/em>. Regardless, this is a long time in simply establishing a connection. As a point of comparisson its commonly encourage that most queries to your database are under 10ms.&lt;/p>
&lt;p>An example that highlights this in a small lightweight application shows the bulk of a request time being within a connection displayed by &lt;a href="http://www.newrelic.com">New Relic&lt;/a>:&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/0X3u0e3Q3G0L19263k2Z/Screenshot_3_6_13_1_12_PM.png" alt="connection time">&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/1h2w450F3n0X1m1c0S38/Screenshot_2_22_13_3_18_PM-2.png" alt="connection time">&lt;/p>
&lt;p>One option to remedy this is by running a connection pooler on your Database side such as &lt;a href="http://www.pgpool.net/mediawiki/index.php/Main_Page">Pgpool&lt;/a> or &lt;a href="http://pgfoundry.org/projects/pgbouncer">PgBouncer&lt;/a>. In fact &lt;a href="http://www.askthepony.com/blog/2011/07/getting-django-on-heroku-prancing-8-times-faster/">Ask the Pony&lt;/a> already highlighted these potential gains. While running an external DB they&amp;rsquo;re essentially testing the benefits of conncetion pooling. This is an obvious gain and can be in a much more lightweight format.&lt;/p>
&lt;h3 id="connection-pooling-in-django" >
&lt;div>
Connection Pooling in Django
&lt;/div>
&lt;/h3>
&lt;p>As Django establishes a connection on each request it has an opportunity to both pool connections and persist connections. There are two major options for pooling, each works quite well with Django and provides some dramatic improvements. While the first request may take the 70ms of connection time, subsequent requests show absolutely no connection time since the connection already exists. This is highlighed by these two comparissons of before and after in actually the times it grabs a connection:&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/2H0J2x3P2L2K2n0M3i38/Screen_Shot_2013-02-22_at_8.28.21_PM.png" alt="before">
&lt;img src="https://f.cl.ly/items/0T1l1I03433u0c0t3e2o/Screen_Shot_2013-02-22_at_8.28.36_PM.png" alt="after">&lt;/p>
&lt;p>Clearly theres plenty of value to having a persistent connection or a pool within Django itself. As of today theres a few options for that:&lt;/p>
&lt;h3 id="django-postgrespool" >
&lt;div>
Django-PostgresPool
&lt;/div>
&lt;/h3>
&lt;p>The first &lt;a href="https://github.com/kennethreitz/django-postgrespool">Django-PostgresPool&lt;/a> is created by &lt;a href="http://twitter.com/kennethreitz">kennethreitz&lt;/a>. As in general I&amp;rsquo;d encourage the use of &lt;a href="">dj_database_url&lt;/a> you can easily begin using his package (once installed) with:&lt;/p>
&lt;pre>&lt;code>import dj_database_url
DATABASE = { 'default': dj_database_url.config() }
DATABASES['default']['ENGINE'] = 'django_postgrespool'
&lt;/code>&lt;/pre>
&lt;p>An important thing to note is if you&amp;rsquo;re using &lt;a href="http://south.aeracode.org/">South&lt;/a> you&amp;rsquo;ll also want to setup the adapter for it:&lt;/p>
&lt;pre>&lt;code>SOUTH_DATABASE_ADAPTERS = {
'default': 'south.db.postgresql_psycopg2'
}
&lt;/code>&lt;/pre>
&lt;h3 id="djorm-ext-pool" >
&lt;div>
djorm-ext-pool
&lt;/div>
&lt;/h3>
&lt;p>The second option &lt;a href="https://github.com/niwibe/djorm-ext-pool">djorm-ext-pool&lt;/a> is created by &lt;a href="http://twitter.com/niwibe">niwibe&lt;/a>. Once you&amp;rsquo;ve installed &lt;code>djorm-ext-pool&lt;/code> you then add it to your &lt;code>INSTALLED_APPS&lt;/code> within your &lt;code>settings.py&lt;/code>. From here then you can setup your pool:&lt;/p>
&lt;pre>&lt;code>DJORM_POOL_OPTIONS = {
&amp;quot;pool_size&amp;quot;: 20,
&amp;quot;max_overflow&amp;quot;: 0
}
&lt;/code>&lt;/pre>
&lt;h3 id="django-db-pool" >
&lt;div>
django-db-pool
&lt;/div>
&lt;/h3>
&lt;p>The third and final option is &lt;a href="https://github.com/gmcguire/django-db-pool">django-db-pool&lt;/a>. You can set it up with:&lt;/p>
&lt;pre>&lt;code>DATABASES = {'default': dj_database_url.config()}
DATABASES['default']['ENGINE'] = 'dbpool.db.backends.postgresql_psycopg2'
DATABASES['default']['OPTIONS'] = {
'MAX_CONNS': 10
}
&lt;/code>&lt;/pre>
&lt;h3 id="gotchas" >
&lt;div>
Gotchas
&lt;/div>
&lt;/h3>
&lt;p>Each of these does work with recent versions of Django, though in some cases there are gotchas. If using a prodution worthy python web server such as Gunicorn or uwsgi and running with gevent or eventlet some edge cases can present themselves. Regardless of potential gotchas it is worth attempting this and of course providing feedback to maintainers and the community as you find those.&lt;/p>
&lt;h3 id="the-future" >
&lt;div>
The future
&lt;/div>
&lt;/h3>
&lt;p>Django more recently has directly started to address these issues of large costs of establishing a connection. The first major step here is &lt;a href="https://github.com/django/django/commit/2ee21d">this patch&lt;/a> from &lt;a href="http://twitter.com/aymericaugustin">Aymeric&lt;/a>. You can find more dicussion around this particular patch &lt;a href="https://groups.google.com/forum/#!topic/django-developers/NwY9CHM4xpU/discussion">here&lt;/a>. Essentially with this patch which will hit in Django 1.6 developers then get a persistent connection which will help reduce the time. If you&amp;rsquo;re interested in trying the 1.6 master you can do this by adding it to your requirements.txt as:&lt;/p>
&lt;pre>&lt;code>https://github.com/django/django/archive/master.zip
&lt;/code>&lt;/pre>
&lt;p>At this point it does not introduce pooling which could allow even more gains, though I&amp;rsquo;m sure if there&amp;rsquo;s enough need it&amp;rsquo;ll be on a roadmap at some point. Though, as it stands today before 1.6 your best bet is one of the above options.&lt;/p></description></item><item><title>Simple database read scaling without sharding in rails</title><link>/2013/03/06/Simple-database-read-scaling-without-sharding-in-rails/</link><pubDate>Wed, 06 Mar 2013 12:55:56 -0800</pubDate><guid>/2013/03/06/Simple-database-read-scaling-without-sharding-in-rails/</guid><description>&lt;p>In an earlier post I provided a high level &lt;a href="http://www.craigkerstiens.com/2012/11/30/sharding-your-database/">overview of sharding&lt;/a>. Sharding while a very solid approach to scaling capacity versus simply only relying on vertical scaling can also be a time intensive one. Additionally in some cases certain sites may only need extra capacity for a short lived period of time. Fortunately theres a nice middle ground alternative for scaling capacity that works well in quite a few cases. It even has a benefit that can potentially in place of sharding.&lt;/p>
&lt;p>This method results in scaling your reads to replica databases, you can do this on Heroku by taking advantage of followers. A follower is a read only database on Heroku Postgres that receives asynchronous updates of your data usually only lagging a very few commits behind. This means you can write all of your data to the leader (main) database, and then read from another.&lt;/p>
&lt;p>&lt;em>While you can arbitrarily do this there&amp;rsquo;s some major benefits to doing it based on the models. This is because Postgres maintains a cache on each instance its running on. Though you may have the same dataset, Postgres maintains frequently accessed or queried data in the cache giving you better performance. For more on this you can read earlier posts on &lt;a href="http://www.craigkerstiens.com/2012/11/30/sharding-your-database/">PostgreSQL Performance&lt;/a>.&lt;/em>&lt;/p>
&lt;h3 id="setting-it-up-with-rails" >
&lt;div>
Setting it up with Rails
&lt;/div>
&lt;/h3>
&lt;p>With a follower database created you can begin adding support for this to your application. The first thing is to add the gem to your Gemfile:&lt;/p>
&lt;pre>&lt;code>gem 'ar-octopus', :require =&amp;gt; &amp;quot;octopus&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>Then of course to install it with &lt;code>bundle install&lt;/code>. Now we can actually begin to add the code needed to have specific models access the follower.&lt;/p>
&lt;pre>&lt;code>octopus:
shards:
shard_sqlite:
adapter: sqlite3
database: db/db_one.sqlite3
pool: 5
timeout: 5000
shard_pgsql:
adapter: postgresql
username: postgres
password:
database: db_two
encoding: unicode
&lt;/code>&lt;/pre>
&lt;p>a&lt;/p>
&lt;pre>&lt;code>class Project &amp;lt; ActiveRecord::Base
octopus_establish_connection(:adapter =&amp;gt; &amp;quot;sqlite3&amp;quot;, :database =&amp;gt; &amp;quot;db_one&amp;quot;)
end&lt;/code>&lt;/pre></description></item><item><title>Getting more out of psql (The PostgreSQL CLI)</title><link>/2013/02/21/more-out-of-psql/</link><pubDate>Thu, 21 Feb 2013 12:55:56 -0800</pubDate><guid>/2013/02/21/more-out-of-psql/</guid><description>&lt;p>&lt;em>After my last post I had a variety of readers reach out about many different tweaks they&amp;rsquo;d made to their workflows using with psql. One people &lt;a href="https://github.com/chanmix51/">Grégoire Hubert&lt;/a> had a wondeful extensive list of items. Grégoire has been a freelance in web development and he has worked with Postgresql for some time now in addition to being the author of Pomm. Without further ado heres what he has to say on how he uses psql:&lt;/em>&lt;/p>
&lt;h2 id="get-the-most-of-psql" >
&lt;div>
Get the most of psql
&lt;/div>
&lt;/h2>
&lt;p>Psql, the CLI postgreSQL client, is a powerful tool. Sadly, lot of developers are not aware of the features and instead look for a GUI to provide what they need. Let&amp;rsquo;s fly over what can psql do for you.&lt;/p>
&lt;h2 id="feel-yourself-at-home" >
&lt;div>
Feel yourself at home
&lt;/div>
&lt;/h2>
&lt;p>One of the most common misconception people have about CLI is «They are a poor user interface». C&amp;rsquo;mon, the CLI is &lt;strong>the most efficient user interface ever&lt;/strong>. There is nothing to disturb you from what you are doing and you are by far fastest without switching to your mouse all the time. Let&amp;rsquo;s see how we can configure psql at our convenience.&lt;/p>
&lt;p>First, you&amp;rsquo;ll have managed to choose a nice and fancy &lt;a href="http://hivelogic.com/articles/top-10-programming-fonts">terminal font&lt;/a> like monofur or inconsolata. Do not underestimate the power of the font&lt;/p>
&lt;p>&lt;img src="https://public.coolkeums.org/github/power_font.png" alt="monofur font in action">&lt;/p>
&lt;p>The nice line style shown above can be set with &lt;code>\pset linestyle unicode&lt;/code> and &lt;code>\pset border 2&lt;/code>. This is just an example of the many environment variables you can play with to get your preferred style of working out of psql.&lt;/p>
&lt;p>For example, I found the character ¤ the most accurate to express nullity (instead of default &lt;code>NULL&lt;/code>). Let&amp;rsquo;s just &lt;code>\pset null ¤&lt;/code> and here it is:&lt;/p>
&lt;pre>&lt;code>SELECT * FROM very_interesting_stat;
┌──────┬──────┬──────┬──────┬──────┐
│ a │ b │ c │ d │ e │
├──────┼──────┼──────┼──────┼──────┤
│ 9.06 │ ¤ │ ¤ │ ¤ │ ¤ │
│ 7.30 │ 3.55 │ 7.57 │ 3.31 │ ¤ │
│ 7.20 │ 5.08 │ ¤ │ 6.58 │ 5.90 │
...
&lt;/code>&lt;/pre>
&lt;p>Another hugely value to get environment variables is colors in the prompt. Colors in the prompt are important because it makes easier to spot where output starts and ends between two interactions at the console. The &lt;a href="http://www.postgresql.org/docs/9.2/static/app-psql.html#APP-PSQL-PROMPTING">PROMPT1&lt;/a> environment variable will even let you set an indicator to notify you are inside a transaction or not, give this a try for a sweet surprise&amp;hellip;&lt;/p>
&lt;pre>&lt;code>\set PROMPT1 '%[%033[33;1m%]%x%[%033[0m%]%[%033[1m%]%/%[%033[0m%]%R%# '
&lt;/code>&lt;/pre>
&lt;p>I also like to disable the pager by default &lt;code>\pset pager off&lt;/code> and display the time every issued query takes &lt;code>\timing&lt;/code>. If you are used to psql, you may notice in the picture above, some content is wrapped. This is &lt;code>\pset format wrapped&lt;/code> option.&lt;/p>
&lt;p>Of course, writing all that on every connection would be a pain, so just write them in a &lt;code>~/.psqlrc&lt;/code> file, it will be sourced every time psql is launched.&lt;/p>
&lt;p>If you are familiar with &lt;code>bash&lt;/code> or other recent unix shells, you might also declare aliases in your configuration file. You can do the same with psql. For example if you want to have a query for slow queries such as from this &lt;a href="/2013/01/10/more-on-postgres-performance/">earlier post&lt;/a> but not have to remember the query every time you can set it up as:&lt;/p>
&lt;pre>&lt;code>\set show_slow_queries
'SELECT
(total_time / 1000 / 60) as total_minutes,
(total_time/calls) as average_time, query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 100;'
&lt;/code>&lt;/pre>
&lt;p>Now, just entering &lt;code>:show_slow_queries&lt;/code> in your psql client will launch this query and give you the results:&lt;/p>
&lt;pre>&lt;code> total_time | avg_time | query
------------------+------------------+------------------------------------------------------------
295.761165833319 | 10.1374053278061 | SELECT id FROM users WHERE email LIKE ?
219.138564283326 | 80.24530822355305 | SELECT * FROM address WHERE user_id = ? AND current = True
&lt;/code>&lt;/pre>
&lt;h2 id="psql-at-your-fingertips" >
&lt;div>
Psql at your fingertips
&lt;/div>
&lt;/h2>
&lt;p>Now you have got a fancy prompt, here is the real question you ask, what can psql do for me ? and &lt;code>\?&lt;/code> has all of the answers. It has built-in queries to describe almost all database objects from tables to operators, indexes, triggers etc&amp;hellip; with clever auto-completion. Not only completion on tables and columns &amp;ndash; but also on aliases (sweet), &lt;strong>SQL commands&lt;/strong> (w00t) and database objects.&lt;/p>
&lt;p>Now we can enter some SQL commands. As usual, you need to check in the documentation how the heck to write this damn &lt;code>ALTER TABLE&lt;/code>. Relax, psql proposes inline documentation. Just enter &lt;code>\h alter table&lt;/code> (auto complete w00t) and you ll be ok.&lt;/p>
&lt;h3 id="interacting-with-your-editor" >
&lt;div>
Interacting with your editor
&lt;/div>
&lt;/h3>
&lt;p>psql provides two very handy commands: \e and \i. This last command sources a sql file in the client&amp;rsquo;s current session. \e edits the last command using the editor defined in the &lt;code>EDITOR&lt;/code> shell environment variables (aka vim). This grant you with real editor feature when it comes to writing long queries. What psql does, it saves the buffer in a temporary file and fires up the editor with that file. Once the editor is terminated, psql sources the file. Of course, you can use your editor to save queries in other places where they would be under version control, but the \e has a serious limitation: it spawns only the last query. Even if you sent several queries on the same line. (Note that \r clears psql&amp;rsquo;s last query buffer).&lt;/p>
&lt;p>Note: &lt;code>\ef my_function&lt;/code> opens stored function source code (With auto completion, I know, it&amp;rsquo;s awesome).&lt;/p>
&lt;p>Vim users can here benefit from Vim&amp;rsquo;s server mode. If you launch a vim specifying a server name (let&amp;rsquo; say &amp;ldquo;PSQL&amp;rdquo;) somewhere, and set the EDITOR variable as is &lt;code>export EDITOR=&amp;quot;vim --servername PSQL --remote-tab-wait&lt;/code> then psql will open a new tab on the running vim with the last query and run it as soon as you close this tab. Tmux or gnu/screen users will split their screen to have Vim and psql running on the same terminal window.&lt;/p>
&lt;p>&lt;img src="https://public.coolkeums.org/github/vim_tmux.png" alt="Vim, psql and tmux">&lt;/p>
&lt;h3 id="call-a-friend" >
&lt;div>
Call a friend
&lt;/div>
&lt;/h3>
&lt;p>Vim power users know it is possible to pipe a buffer (or selection) directly in a program that can be &amp;hellip; psql (Using the &lt;code>:w !psql&lt;/code> syntax). Even from the shell, you might want to take advantage of the fantastic &lt;code>\copy&lt;/code> feature that loads formated file in the database (I use it to load apache logs). But always having to specify connection parameters are a hassle. Let&amp;rsquo;s use shell environment instead. Psql is sensitive to the following variables:&lt;/p>
&lt;ul>
&lt;li>PGDATABASE&lt;/li>
&lt;li>PGHOST&lt;/li>
&lt;li>PGPORT&lt;/li>
&lt;li>PGUSER&lt;/li>
&lt;li>PGCLUSTER (debian wrapper).&lt;/li>
&lt;/ul>
&lt;p>Set them once for all in you shell environment and call &lt;code>psql&lt;/code> to connect to the database. In case you want to skip password prompt, you can store your pass in a 600 mode access file named &lt;code>.pgpass&lt;/code> in your home (do not do that on shared or exposed computers). Although this is nice for development database servers, I do NOT recommend this for production servers since it should not be easy to mess with them.&lt;/p>
&lt;p>Resource for additional information is &amp;hellip; the man page and &lt;a href="http://www.postgresql.org/docs/9.2/static/index.html">Postgres Docs&lt;/a>. All &lt;a href="http://www.postgresql.org/docs/9.2/static/index.html">PostgreSQL documentation&lt;/a> is an example of what software reference documentation should be. Enjoy!&lt;/p></description></item><item><title>How I work with Postgres – psql, My PostgreSQL Admin</title><link>/2013/02/13/How-I-Work-With-Postgres/</link><pubDate>Wed, 13 Feb 2013 12:55:56 -0800</pubDate><guid>/2013/02/13/How-I-Work-With-Postgres/</guid><description>&lt;p>On at least a weekly basis and not uncommonly multiple times in a single week I get this question:&lt;/p>
&lt;blockquote>
&lt;p>&lt;a href="https://twitter.com/neilmiddleton">@neilmiddleton&lt;/a>
I&amp;rsquo;ve been hunting for a nice PG interface that works within other things. PGAdmin kinda works, except the SQL editor is a piece of shit&lt;/p>
&lt;/blockquote>
&lt;p>Sometimes it leans more to, what is the Sequel Pro equivilant for Postgres. My default answer is I just use psql, though I do have to then go on to explain how I use it. For those just interested you can read more below or just get the highlights here:&lt;/p>
&lt;ul>
&lt;li>Set your default &lt;code>EDITOR&lt;/code> then use \e&lt;/li>
&lt;li>On postgres 9.2 and up &lt;code>\x auto&lt;/code> is your friend&lt;/li>
&lt;li>Set history to unlimited&lt;/li>
&lt;li>&lt;code>\d&lt;/code> all the things&lt;/li>
&lt;/ul>
&lt;p>Before going into detail on why psql works perfectly fine as an interface I want to rant for a minute about what the problems with current editors are and where I expect them to go in the future. First this is not a knock on the work thats been done on previous ones, for their time PgAdmin, phpPgAdmin, and others were valuable tools, but we&amp;rsquo;re coming to a point where theres a broader set of users of databases than ever before and empowering them is becoming ever more important.&lt;/p>
&lt;p>Empowering developers, DBA&amp;rsquo;s, product people, marketers and others to be comfortable with their database will lead to more people taking advantage of whats in their data. &lt;a href="/2013/01/10/more-on-postgres-performance/">pg_stat_statements&lt;/a> was a great start to this laying a great foundation for valuable information being captured. Even with all of the powerful stats being captured in the statistics of PostgreSQL so many are still terrified when they see something like:&lt;/p>
&lt;pre>&lt;code> QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Hash Join (cost=4.25..8.62 rows=100 width=107) (actual time=0.126..0.230 rows=100 loops=1)
Hash Cond: (purchases.user_id = users.id)
-&amp;gt; Seq Scan on purchases (cost=0.00..3.00 rows=100 width=84) (actual time=0.012..0.035 rows=100 loops=1)
-&amp;gt; Hash (cost=3.00..3.00 rows=100 width=27) (actual time=0.097..0.097 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 6kB
-&amp;gt; Seq Scan on users (cost=0.00..3.00 rows=100 width=27) (actual time=0.007..0.042 rows=100 loops=1)
Total runtime: 0.799 ms
(7 rows)
&lt;/code>&lt;/pre>
&lt;p>Empowering more developers by surfacing this information in a digestable form, such as building on top of &lt;code>pg_stat_statements&lt;/code> tools such as &lt;a href="http://datascope.heroku.com">datascope&lt;/a> by &lt;a href="http://www.twitter.com/leinweber">@leinweber&lt;/a> and getting this to be part of the default admin we will truly begin empowering a new set of user.&lt;/p>
&lt;p>But enough of a detour, those tools aren&amp;rsquo;t available today. If you&amp;rsquo;re interested in helping build those to make the community better please reach out. For now I live in a work where I&amp;rsquo;m quite content with simple ole &lt;code>psql&lt;/code> here&amp;rsquo;s how:&lt;/p>
&lt;h3 id="editor" >
&lt;div>
Editor
&lt;/div>
&lt;/h3>
&lt;p>Ensuring you&amp;rsquo;ve exported your preferred editor to the environment variable &lt;code>EDITOR&lt;/code> when you run \e it will allow you to view and edit your last run query in your editor of choice. This works for vim, emacs, or even sublime text.&lt;/p>
&lt;pre>&lt;code>export EDITOR=subl
psql
\e
&lt;/code>&lt;/pre>
&lt;p>Gives me:&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/2I0f3M0B1T3k0d290v3k/Screenshot_2_12_13_9_58_AM.png" alt="sublime text">&lt;/p>
&lt;p>&lt;em>Note you need to make sure you connect with psql and have your editor set, once you do that saving and exiting the file will then execute the query&lt;/em>&lt;/p>
&lt;h3 id="x-auto" >
&lt;div>
\x auto
&lt;/div>
&lt;/h3>
&lt;p>psql has long had a method of formatting output. You can toggle this on and off easily by just running the &lt;code>\x&lt;/code> command. Running a basic query you get the output:&lt;/p>
&lt;pre>&lt;code>SELECT *
FROM users
LIMIt 1;
id | first_name | last_name | email | data | created_at | updated_at | last_login
----+------------+-----------+----------------------------+------------+---------------------+---------------------+---------------------
1 | Rosemary | Wassink | Rosemary.Wassink@yahoo.com | &amp;quot;sex&amp;quot;=&amp;gt;&amp;quot;F&amp;quot; | 2010-07-01 18:16:00 | 2011-05-14 11:47:00 | 2011-06-07 23:04:00
&lt;/code>&lt;/pre>
&lt;p>With toggling the output and re-running the same query we can see how its now formatted:&lt;/p>
&lt;pre>&lt;code>\x
Expanded display is on.
craig=# SELECT * from users limit 1;
-[ RECORD 1 ]--------------------------
id | 1
first_name | Rosemary
last_name | Wassink
email | Rosemary.Wassink@yahoo.com
data | &amp;quot;sex&amp;quot;=&amp;gt;&amp;quot;F&amp;quot;
created_at | 2010-07-01 18:16:00
updated_at | 2011-05-14 11:47:00
last_login | 2011-06-07 23:04:00
&lt;/code>&lt;/pre>
&lt;p>Using &lt;code>\x auto&lt;/code> will automatically put this in what Postgres believes is the most intelligible format to read it in.&lt;/p>
&lt;h3 id="psql-history" >
&lt;div>
psql history
&lt;/div>
&lt;/h3>
&lt;p>Hopefully this needs no justification&amp;hellip; having an unlimited history of all your queries is incredibly handy. Ensuring you set the following environment variables will ensure you never lose that query you ran several months ago again:&lt;/p>
&lt;pre>&lt;code>export HISTFILESIZE=
export HISTSIZE=
&lt;/code>&lt;/pre>
&lt;h3 id="d" >
&lt;div>
\d
&lt;/div>
&lt;/h3>
&lt;p>And while the last on the list one of the first things I do when connecting to any database is check out whats in it. I don&amp;rsquo;t do this by running a bunch of queries but rather checking out the schema and then poking at definitions of specific tables. &lt;code>\d&lt;/code> and variations on it are incredibly handy for this. Here&amp;rsquo;s a few highlights below:&lt;/p>
&lt;p>Listing all relations with simply &lt;code>\d&lt;/code>:&lt;/p>
&lt;pre>&lt;code>\d
List of relations
Schema | Name | Type | Owner
--------+------------------+---------------+-------
public | products | table | craig
public | products_id_seq | sequence | craig
public | purchases | table | craig
public | purchases_id_seq | sequence | craig
public | redis_db0 | foreign table | craig
public | users | table | craig
public | users_id_seq | sequence | craig
(7 rows)
&lt;/code>&lt;/pre>
&lt;p>List only all tables with &lt;code>dt&lt;/code>:&lt;/p>
&lt;pre>&lt;code>\dt
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+-------
public | products | table | craig
public | purchases | table | craig
public | users | table | craig
(3 rows)
&lt;/code>&lt;/pre>
&lt;p>Describe a specific relation with &lt;code>\d RELATIONNAMEHERE&lt;/code>:&lt;/p>
&lt;pre>&lt;code>\d users
Table &amp;quot;public.users&amp;quot;
Column | Type | Modifiers
------------+-----------------------------+----------------------------------------------------
id | integer | not null default nextval('users_id_seq'::regclass)
first_name | character varying(50) |
last_name | character varying(50) |
email | character varying(255) |
data | hstore |
created_at | timestamp without time zone |
updated_at | timestamp without time zone |
last_login | timestamp without time zone |
&lt;/code>&lt;/pre>
&lt;p>One more pro-tip if you&amp;rsquo;re running a transaction with many tables and forget which are involved in it you can run &amp;lsquo;\d *transaction*&amp;rsquo; and it&amp;rsquo;ll display tables curently affected.&lt;/p>
&lt;p>&lt;em>Have a tool you prefer, have something you use daily in psql that I missed, or interested in helping create a new admin experience please reach out and lets talk craig.kerstiens at gmail.com&lt;/em>&lt;/p></description></item><item><title>Introducing django-db-tools</title><link>/2013/02/08/Introducing-django-db-tools/</link><pubDate>Fri, 08 Feb 2013 12:55:56 -0800</pubDate><guid>/2013/02/08/Introducing-django-db-tools/</guid><description>&lt;p>For any successful web application there is likely to come a time when you need to conduct some large migration on the backend. I dont mean simple add a &lt;a href="http://www.craigkerstiens.com/2012/05/07/why-postgres-part-2/">column here or add an index there&lt;/a>, but rather truly sizeable migrations&amp;hellip; Going from &lt;a href="http://lanyrd.com/blog/2012/lanyrds-big-move/">MySQL to Postgres&lt;/a> or migrating from an older version of Postgres such as a &lt;a href="http://blog.sendhub.com/post/30041247598/how-to-upgrade-a-legacy-heroku-database">32 bit instance&lt;/a> to a newer 64 bit instance. In these cases the default approach is to just schedule downtime often throwing up a splash screen saying so.&lt;/p>
&lt;p>For many sites this approach is simply wrong and lazy, with little effort you can improve the experience and there by ease the burden in conducting these types of migrations. By having the ability to turn your site into a read only mode which &lt;a href="http://twitter.com/simonw">Simon Wilson&lt;/a> talked about in his post on Lanyrd you can still continue to operate just in a limited capacity. &lt;a href="http://www.aeracode.org/2012/11/13/one-change-not-enough/">Andrew Godwin&lt;/a> further talks about some of this as well in regards to the Lanyrd move and even includes the script they used to &lt;a href="https://github.com/lanyrd/mysql-postgresql-converter/">migrate data from MySQL to Postgres&lt;/a>. Though just in talking with Simon about this a week ago it occurred to me they had not released the code for their read-only mode.&lt;/p>
&lt;p>Finally onto the announcing, today I&amp;rsquo;m releasing &lt;a href="https://github.com/craigkerstiens/django-db-tools">django-db-tools&lt;/a>. This is currently a very lightweight utility that allows you to flip your site into two modes.&lt;/p>
&lt;h3 id="anonymous-mode" >
&lt;div>
Anonymous Mode
&lt;/div>
&lt;/h3>
&lt;p>For sites that offer a bulk of their data to unauthenticated users anonymous mode will be what you want. This ensures all users appear logged out and thus cannot interact with data. To enable anonymous mode you&amp;rsquo;d simple set the environment variable or config var on heroku as follows:&lt;/p>
&lt;pre>&lt;code>READ_ONLY_MODE = True
&lt;/code>&lt;/pre>
&lt;h3 id="restricting-posts" >
&lt;div>
Restricting POSTs
&lt;/div>
&lt;/h3>
&lt;p>The other bucket of sites is one that allows users to stay logged in but not insert data. Django did not appear to have a convenient means to know whether data was actually being inserted into the DB or not. As a good practice when inserting data it should be receiving a HTTP POST. The &lt;code>GET_ONLY_MODE&lt;/code> mimmicks all POSTs as if they were sent via GETs thus hopefully eliminating inserting data into your application. To turn it on simply set the environment variabel or config var on heroku to:&lt;/p>
&lt;pre>&lt;code>GET_ONLY_MODE = True
&lt;/code>&lt;/pre>
&lt;h3 id="installing" >
&lt;div>
Installing
&lt;/div>
&lt;/h3>
&lt;p>The tool itself is largely middleware, to install:&lt;/p>
&lt;ol>
&lt;li>Run &lt;code>pip install django-db-tools&lt;/code> or add it to your &lt;code>requirements.txt&lt;/code>&lt;/li>
&lt;li>Add &lt;code>db_tools&lt;/code> to your &lt;code>INSTALLED_APPS&lt;/code> in your &lt;code>settings.py&lt;/code>&lt;/li>
&lt;li>Add &lt;code>'dbtools.middleware.ReadOnlyMiddleware',&lt;/code> to your &lt;code>MIDDLEWARE_CLASSES&lt;/code> in &lt;code>settings.py&lt;/code>&lt;/li>
&lt;/ol>
&lt;h3 id="contributing" >
&lt;div>
Contributing
&lt;/div>
&lt;/h3>
&lt;p>As with all code this is largely a work in progress. There&amp;rsquo;s many items still to do such as providing default copy and error pages and potentially handling other edge cases. I&amp;rsquo;d welcome others to contribute and give feedback if they find it helpful or how it can be improved on Github.&lt;/p></description></item><item><title>More on Postgres Performance</title><link>/2013/01/10/More-on-Postgres-Performance/</link><pubDate>Thu, 10 Jan 2013 12:55:56 -0800</pubDate><guid>/2013/01/10/More-on-Postgres-Performance/</guid><description>&lt;p>If you missed my previous post on &lt;a href="/2012/10/01/understanding-postgres-performance/">Understanding Postgres Performance&lt;/a> its a great starting point. On this particular post I&amp;rsquo;m going to dig in to some real life examples of optimizing queries and indexes.&lt;/p>
&lt;h3 id="it-all-starts-with-stats" >
&lt;div>
It all starts with stats
&lt;/div>
&lt;/h3>
&lt;p>I wrote about some of the &lt;a href="https://postgres.heroku.com/blog/past/2012/12/6/postgres_92_now_available/">great new features in Postgres 9.2&lt;/a> in the recent announcement on support of Postgres 9.2 on &lt;a href="https://www.heroku.com">Heroku&lt;/a>. One of those awesome features, is &lt;a href="http://www.postgresql.org/docs/9.2/static/pgstatstatements.html">pg_stat_statements&lt;/a>. Its not commonly known how much information Postgres keeps about your database (beyond the data of course), but in reality it keeps a great deal. Ranging from basic stuff like table size to cardinality of joins to distribution of indexes, and with pg_stat_statments it keeps a normalized record of when queries are run.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>First you&amp;rsquo;ll want to turn on pg_stat_statments:&lt;/p>
&lt;pre>&lt;code>CREATE extension pg_stat_statements;
&lt;/code>&lt;/pre>
&lt;p>What this means it would record both:&lt;/p>
&lt;pre>&lt;code>SELECT id
FROM users
WHERE email LIKE 'craig@heroku.com';
&lt;/code>&lt;/pre>
&lt;p>and&lt;/p>
&lt;pre>&lt;code>SELECT id
FROM users
WHERE email LIKE 'craig.kerstiens@gmail.com';
&lt;/code>&lt;/pre>
&lt;p>To a normalized form which looks like this:&lt;/p>
&lt;pre>&lt;code>SELECT id
FROM users
WHERE email LIKE ?;
&lt;/code>&lt;/pre>
&lt;h3 id="understanding-them-from-afar" >
&lt;div>
Understanding them from afar
&lt;/div>
&lt;/h3>
&lt;p>While Postgres collects a great deal of this information dissecting it to something useful is sometimes more mystery than it should be. This simple query will show a few very key pieces of information that allow you to begin optimizing:&lt;/p>
&lt;pre>&lt;code>SELECT
(total_time / 1000 / 60) as total_minutes,
(total_time/calls) as average_time,
query
FROM pg_stat_statements
ORDER BY 1 DESC
LIMIT 100;
&lt;/code>&lt;/pre>
&lt;p>The above query shows three key things:&lt;/p>
&lt;ol>
&lt;li>The total time a query has occupied against your system in minutes&lt;/li>
&lt;li>The average time it takes to run in milliseconds&lt;/li>
&lt;li>The query itself&lt;/li>
&lt;/ol>
&lt;p>Giving an output something like:&lt;/p>
&lt;pre>&lt;code> total_time | avg_time | query
------------------+------------------+------------------------------------------------------------
295.761165833319 | 10.1374053278061 | SELECT id FROM users WHERE email LIKE ?
219.138564283326 | 80.24530822355305 | SELECT * FROM address WHERE user_id = ? AND current = True
(2 rows)
&lt;/code>&lt;/pre>
&lt;h3 id="what-to-optimize" >
&lt;div>
What to optimize
&lt;/div>
&lt;/h3>
&lt;p>A general rule of thumb is that most of your very common queries that return 1 or a small set of records should return in ~ 1 ms. In some cases there may be queries that regularly run in 4-5 ms, but in most cases ~ 1 ms or less is an ideal.&lt;/p>
&lt;p>To pick where to begin I usually attempt to strike some balance between total time and long average time. In this case I&amp;rsquo;d start with the second probably, as on the first one I could likely shave an order of magnitude off, on the second I&amp;rsquo;m hopeful to shave two order of magnitudes off thus reducing the time spent on that query from a cumulative 220 minutes down to 2 minutes.&lt;/p>
&lt;h3 id="optimizing" >
&lt;div>
Optimizing
&lt;/div>
&lt;/h3>
&lt;p>From here you probably want to first example my other detail on understanding the explain plan. I want to highlight some of this with a more specific case based on the second query above. The above second query on an example data set does contain an index on user_id and yet there&amp;rsquo;s still high query times. To start to get an idea of why I would run:&lt;/p>
&lt;pre>&lt;code>EXPLAIN ANALYZE
SELECT *
FROM address
WHERE user_id = 245
AND current = True
&lt;/code>&lt;/pre>
&lt;p>This would yield results:&lt;/p>
&lt;pre>&lt;code> QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=4690.88..4690.88 rows=1 width=0) (actual time=519.288..519.289 rows=1 loops=1)
-&amp;gt; Nested Loop (cost=0.00..4690.66 rows=433 width=0) (actual time=15.302..519.076 rows=213 loops=1)
-&amp;gt; Index Scan using idx_address_userid on address (cost=0.00..232.52 rows=23 width=4) (actual time=10.143..62.822 rows=1 loops=8)
Index Cond: (user_id = 245)
Filter: current
Rows Removed by Filter: 14
Total runtime: 219.428 ms
(1 rows)
&lt;/code>&lt;/pre>
&lt;p>Hopefully not being too overwhelmed by this due to having read the other detail on &lt;a href="/2012/10/01/understanding-postgres-performance/">query plans&lt;/a> we can see that it is using an index as expected. The difference is its having to fetch 15 different rows from the index then discard the bulk of them. The number of rows discarded is showcased by the line:&lt;/p>
&lt;pre>&lt;code>Rows Removed by Filter: 14
&lt;/code>&lt;/pre>
&lt;p>&lt;em>This is just one more of the many improvements in Postgres 9.2 alongside pg_stat_statements.&lt;/em>&lt;/p>
&lt;p>To further optimize this we would great a conditional OR composite index. A conditional would be where only current = true, where as the composite would index both values. A conditional is commonly more valuable when you have a smaller set of what the values may be, meanwhile the composite is when you have a high variability of values. Creating the conditional index:&lt;/p>
&lt;pre>&lt;code>CREATE INDEX CONCURRENTLY idx_address_userid_current ON address(user_id) WHERE current = True;
&lt;/code>&lt;/pre>
&lt;p>We can then see the query plan is now even further improved as we&amp;rsquo;d hope:&lt;/p>
&lt;pre>&lt;code>EXPLAIN ANALYZE
SELECT *
FROM address
WHERE user_id = 245
AND current = True
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=4690.88..4690.88 rows=1 width=0) (actual time=519.288..519.289 rows=1 loops=1)
-&amp;gt; Index Scan using idx_address_userid_current on address (cost=0.00..232.52 rows=23 width=4) (actual time=10.143..62.822 rows=1 loops=8)
Index Cond: ((user_id = 245) AND (current = True))
Total runtime: .728 ms
(1 rows)
&lt;/code>&lt;/pre>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Sharding your database</title><link>/2012/11/30/Sharding-your-database/</link><pubDate>Fri, 30 Nov 2012 12:55:56 -0800</pubDate><guid>/2012/11/30/Sharding-your-database/</guid><description>&lt;p>I&amp;rsquo;m increasingly encountering users on &lt;a href="http://www.heroku.com">Heroku&lt;/a> that are encountering the need to [shard](&lt;a href="http://en.wikipedia.org/wiki/Shard_(database_architecture">http://en.wikipedia.org/wiki/Shard_(database_architecture&lt;/a>)) their data. For most users this is something you delay as long as possible as you can generally go for sometime before you have to worry about it. Additionally scaling up your database is often a reasonable approach early on and something I encourage as a starting point as scaling up is easy to do with regards to databases. However, for the 1% of users that do need to shard when the time comes many are left wondering where to start, hence the following guide.&lt;/p>
&lt;h3 id="what-and-why" >
&lt;div>
What and Why
&lt;/div>
&lt;/h3>
&lt;p>Sharding is the process of splitting up your data so it resides in different tables or often different physical databases. Sharding is helpful when you have some specific set of data that outgrows either storage or reasonable performance within a single database.&lt;/p>
&lt;h3 id="logical-shards" >
&lt;div>
Logical Shards
&lt;/div>
&lt;/h3>
&lt;p>First when initially implementing sharding you&amp;rsquo;ll want to create an arbitrary number of logical shards. This will allow you to change less code later when it comes to adding more shards. You&amp;rsquo;ll also want to define your shards to the power of 2. Generally I&amp;rsquo;d recommend for most services 1024 can be a good number, I believe Instagram actually used 4096, either can really be an appropriate number. For simplicity sake lets start with an example of using 4 logical shards. First lets look at an example set of users:&lt;/p>
&lt;pre>&lt;code> id | email | name
----+---------------------------+-----------------
1 | craig.kerstiens@gmail.com | Craig Kerstiens
2 | john.doe@gmail.com | John Doe
3 | jane.doe@gmail.com | Jane Doe
4 | user4@gmail.com | User 4
5 | user5@gmail.com | User 5
6 | user6@gmail.com | User 6
7 | user7@gmail.com | User 7
8 | user8@gmail.com | User 8
&lt;/code>&lt;/pre>
&lt;p>Dividing these up into logical shards we&amp;rsquo;re going to have something that looks roughly like this:&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/0Q1A38191Q0N3G0L413K/Screenshot%2011:29:12%209:45%20AM.png" alt="sharding layout">&lt;/p>
&lt;p>Its important when sharding that you find a mechanism that requires you to not hit the database. As the above example shows its using the ID of the row inside the database instead we&amp;rsquo;re likely going to want to determine the shard based on a hash of some value such as the email:&lt;/p>
&lt;pre>&lt;code>logical_shard = hash(User.email) % 4
&lt;/code>&lt;/pre>
&lt;h3 id="physical-shards" >
&lt;div>
Physical Shards
&lt;/div>
&lt;/h3>
&lt;p>From here we&amp;rsquo;ll then take the logical shards and create actual physical shards. If you have a single physical shard you&amp;rsquo;re using a single database, but the rest of your application code is ready to handle additional shards. For now lets use an example of two physical shards, the end result would be dividing our data up somehow like this:&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/0A3b3O3A3K28043Y2s0j/Screenshot%2011:29:12%209:46%20AM.png" alt="sharding layout">&lt;/p>
&lt;p>The physical shard to access can easily be counted by taking the modulus of the logical shard its on by the physical shards that exist:&lt;/p>
&lt;pre>&lt;code>total_physical_shards = 2
total_logical_shards = 4
logical_shard = hash(User.email) % total_logical_shards
physical_shard = logical_shard % total_physical_shards
&lt;/code>&lt;/pre>
&lt;h3 id="generating-ids-primary-keys" >
&lt;div>
Generating IDs (Primary Keys)
&lt;/div>
&lt;/h3>
&lt;p>As you&amp;rsquo;re distributing data across multiple databases you&amp;rsquo;ll want to avoid using an integer as your primary key. This would cause for keys to be duplicated within your database and make for a headache when attempting to report against your data. Instead the ideal is to use a UUID as the primary key. By using a UUID and generating this in either your application code or within your database you ensure each User ID is actually unique.&lt;/p>
&lt;h3 id="adding-capacity" >
&lt;div>
Adding Capacity
&lt;/div>
&lt;/h3>
&lt;p>The best case scenario for most web applications, such is the case for &lt;a href="http://www.databasesoup.com/2012/04/sharding-postgres-with-instagram.html">Instagram&lt;/a>, is to have to scale beyond their initial capacity, in order to do this you&amp;rsquo;ll simple expand the number of physical shards. In order to do this you&amp;rsquo;ll want to move data from one physical shard to another, then remove data from the old physical shard. Its also generally a good practice to grow your physical shards in powers of 2 the same way you would your logical shards. Lets take a look at a clearer example of how we would do this using the &lt;a href="https://postgres.heroku.com">Heroku Postgres Service&lt;/a>&amp;hellip;&lt;/p>
&lt;p>First we&amp;rsquo;re going to add a &lt;a href="https://postgres.heroku.com/blog/past/2012/10/25/announcing_follow/">follower&lt;/a> for each shard we have:&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/1N233k203j2d1O2l2w47/Screenshot%2011:29:12%202:36%20PM.png" alt="Followers">&lt;/p>
&lt;p>We&amp;rsquo;re then going to promote our followers to be their own independent databases which can accept writes. This means we&amp;rsquo;ll have two copies that can be written to with the same data:&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/3Q1D2O0J0o2b0e051t46/Screenshot%2011:29:12%202:39%20PM.png" alt="Promotion">&lt;/p>
&lt;p>At this point you can update your application code to have the new number of physical shards and it should begin writing data to the appropriate place. Of course you do still want to clean up some of that extra data. To do this you&amp;rsquo;ll want to remove the data that doesn&amp;rsquo;t belong in the appropriate shard. For example, id of 3 wouldn&amp;rsquo;t belong in physical shard 1 any more. Now we can run a background process to clean up such data:&lt;/p>
&lt;p>&lt;img src="https://f.v1.n0.cdn.getcloudapp.com/items/0a2r132M1f1m171B3y3R/Screenshot%2011:29:12%202:42%20PM.png" alt="Cleanup">&lt;/p>
&lt;h3 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h3>
&lt;p>While many applications may never need to scale out their database, when they do, sharding can be both straight forward and effective. While I would encourage many to scale up first as it is an easy option, hopefully this provides further guidance to how to scale out. For those that do anticipate this needed planning for it early with key things such as using UUID&amp;rsquo;s can make the process less painful.&lt;/p>
&lt;p>This article of course only grazes the surface, if there&amp;rsquo;s interest from readers there will be more specifics to follow with actual code examples.&lt;/p></description></item><item><title>How I Write SQL</title><link>/2012/11/17/How-I-Write-SQL/</link><pubDate>Sat, 17 Nov 2012 12:55:56 -0800</pubDate><guid>/2012/11/17/How-I-Write-SQL/</guid><description>&lt;p>I recently got asked by &lt;a href="http://rzrsharp.net/">a friend&lt;/a> and former co-worker how I write SQL. At first this caught me by surprise and I assumed there was nothing different, but after a few additional comments on it, it became clear most people have no concept for creating clean readable SQL. So without further adieu here&amp;rsquo;s how I write SQL, with a built up example query.&lt;/p>
&lt;p>First let&amp;rsquo;s understand an example schema:&lt;/p>
&lt;pre>&lt;code># \dt
Schema | Name | Type | Owner
--------+----------------------------+-------+----------------
public | app_rating | table | craig
public | app_recommendation | table | craig
public | app_userprofile | table | craig
public | app_wine | table | craig
public | app_winemakeup | table | craig
public | app_winery | table | craig
public | auth_user | table | craig
&lt;/code>&lt;/pre>
&lt;p>The above schema contains wines from wineries, that users give ratings and notes to. Especially relevant is the app_rating table, it contains a variety of things we&amp;rsquo;re going to want report against:&lt;/p>
&lt;pre>&lt;code># \d app_rating
Table &amp;quot;public.app_rating&amp;quot;
Column | Type | Modifiers
------------+--------------------------+---------------------------------------------------------
id | integer | not null default nextval('app_rating_id_seq'::regclass)
user_id | integer | not null
wine_id | integer | not null
rated_at | date | not null
rating | integer | not null
notes | text |
tags | character varying(255)[] |
created_at | timestamp with time zone | not null
&lt;/code>&lt;/pre>
&lt;p>Most of the above should be pretty straightforward, though if you&amp;rsquo;re unfamiliar with Arrays in Postgres check out &lt;a href="/2012/08/20/arrays-in-postgres/">this earlier article&lt;/a>&lt;/p>
&lt;p>Given all this data lets say we want to produce some query that for a given wine contains the winery, the average rating, the tags for it. Diving in I&amp;rsquo;ll typically start by creating each key part then pulling it together. Let&amp;rsquo;s start with grabbing the average.&lt;/p>
&lt;p>But first some basic structure, for maximum readability I make sure to use all caps for reserved SQL words. For a large query I make sure all my columns/conditions are on their own line. So to get the average it would look something like this:&lt;/p>
&lt;pre>&lt;code>SELECT
avg(rating),
wine_id
FROM
app_wine
GROUP BY
wine_id;
&lt;/code>&lt;/pre>
&lt;p>Next I&amp;rsquo;ll work with the array of tags which has some specific things to Postgres:&lt;/p>
&lt;pre>&lt;code>SELECT DISTINCT
unnest(tags) as tag,
wine_id
FROM
app_rating
GROUP BY
wine_id, tags;
&lt;/code>&lt;/pre>
&lt;p>Finally I&amp;rsquo;m going to put it all together. This is going to have an additional query to get the winery and the wine name as well. We&amp;rsquo;re also going to use CTE&amp;rsquo;s (Common Table Expressions), think of these as temporary views that can make your query more readable:&lt;/p>
&lt;pre>&lt;code>WITH
wine_ratings as (
SELECT
avg(rating) as rating,
wine_id
FROM
app_rating
GROUP BY
wine_id),
wine_tags as (
SELECT DISTINCT
unnest(tags) as tag,
wine_id
FROM
app_rating
GROUP BY
wine_id, tags),
wine_detail as (
SELECT
app_wine.name as name,
app_wine.id,
app_winery.name as winery
FROM
app_wine,
app_winery
WHERE app_wine.winery_id = app_winery.id
)
SELECT
name,
rating,
array_agg(tag),
winery
FROM
wine_ratings,
wine_detail
LEFT OUTER JOIN
wine_tags ON wine_detail.id = wine_tags.wine_id
WHERE wine_detail.id = wine_ratings.wine_id
GROUP BY
name,
rating,
winery
ORDER BY
rating DESC
&lt;/code>&lt;/pre>
&lt;p>One thing to point out, is &lt;code>SELECT&lt;/code>, &lt;code>FROM&lt;/code> and &lt;code>ORDER BY&lt;/code> are followed by a new line. When I have &lt;code>WHERE&lt;/code> multiple conditions I ensure the &lt;code>AND&lt;/code> and the condition occur on the same line. This is intentional to make those easier to read as well as easy to remove/add. The key to allowing it to still be readable is an extra two spaces before the &lt;code>AND&lt;/code> so the condition aligns with the above one. This would appear something similar to:&lt;/p>
&lt;pre>&lt;code>SELECT foo
FROM bar
WHERE foo.id = bar.foo_id
AND foo.created_at &amp;gt; now() - '7 days'::INTERVAL
&lt;/code>&lt;/pre>
&lt;p>And just for an example we get this result from the query:&lt;/p>
&lt;pre>&lt;code> name | rating | array_agg | winery
-----------------------+--------+--------------------+------------------------
Bordeaux Blend | 5.0 | {'dry', 'smooth'} | Chateau Rahoul
Cabernet Franc | 5.0 | {'chocolate'} | Beaucanon
Cabernet Sauvignon | 5.0 | {'young', 'dry'} | Hawkes
&lt;/code>&lt;/pre>
&lt;p>While very long, this should ideally be quite legible.&lt;/p></description></item><item><title>Using Postgres Arrays in Django</title><link>/2012/11/06/django-and-arrays/</link><pubDate>Tue, 06 Nov 2012 12:55:56 -0800</pubDate><guid>/2012/11/06/django-and-arrays/</guid><description>&lt;p>A few weeks back I did a brief &lt;a href="/2012/08/20/arrays-in-postgres/">feature highlight on Postgres arrays&lt;/a>. Since that time I&amp;rsquo;ve found myself using them with increasing regularity on small side projects. Much of this time I&amp;rsquo;m using Django and of course not opting to write raw SQL to be able to use arrays. Django actually makes it quite simple to work with Arrays in Postgres with a package by &lt;a href="http://www.niwi.be/about.html">Andrey Antukh&lt;/a>. Lets get started by installing two libraries:&lt;/p>
&lt;pre>&lt;code>pip install djorm-ext-pgarray
pip install djorm-ext-expressions
&lt;/code>&lt;/pre>
&lt;p>The first library is for support for the array field type, the second allows us to more easily mix bits of SQL within the Django ORM.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Now within our &lt;code>models.py&lt;/code> we&amp;rsquo;ll want import the library then we&amp;rsquo;ll have an entirely new field type available to us:&lt;/p>
&lt;pre>&lt;code>from djorm_pgarray.fields import ArrayField
from djorm_expressions.models import ExpressionManager
class Post(models.Model):
subject = models.CharField(max_length=255)
content = models.TextField()
tags = ArrayField(dbtype=&amp;quot;varchar(255)&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>Now we can begin using this. For example to create a simple blog post:&lt;/p>
&lt;pre>&lt;code>Post(subject='foo', content='bar', tags=['hello','world'])
post.save()
&lt;/code>&lt;/pre>
&lt;p>In this example we&amp;rsquo;re able to tag blog posts as one normally might, without requiring an extra model to join against. Taking advantage of the SQL Expressions library by Andrey as well we can query a blog post contains a certain tag:&lt;/p>
&lt;pre>&lt;code>qs = Posts.objects.where(
SqlExpression(&amp;quot;tags&amp;quot;, &amp;quot;@&amp;gt;&amp;quot;, ['postgres', 'django'])
)
&lt;/code>&lt;/pre>
&lt;p>Now to show some contrast lets take a look at how you would do the same thing without using the Array field:&lt;/p>
&lt;pre>&lt;code>class Tag(models.Model):
name = models.CharField(max_length=255)
class Post(models.Model):
subject = models.CharField(max_length=255)
content = models.TextField()
tags = models.ManyToManyField(Tag)
&lt;/code>&lt;/pre>
&lt;p>Using the many-to-many relationship within Django requires you to save the Post, then add your tag is it requires having a primary key first:&lt;/p>
&lt;pre>&lt;code> post = Post(subject='foo', content='bar')
post.save()
post.tags.add('hello','world')
&lt;/code>&lt;/pre>
&lt;p>This means we have two calls to save it, and similarly querying it is less clean as well:&lt;/p>
&lt;pre>&lt;code>posts = Post.objects.filter(tags__name=&amp;quot;hello&amp;quot;).distinct()
&lt;/code>&lt;/pre>
&lt;p>This would gives us all posts that have the tag hello in them. We could also search for multiple ones:&lt;/p>
&lt;pre>&lt;code>posts = Post.objects.filter(tags__in=[&amp;quot;hello&amp;quot;,&amp;quot;world&amp;quot;]).distinct()
&lt;/code>&lt;/pre>
&lt;p>In the latter case distinct is especially important since it could return a post twice if its tagged with both hello and world.&lt;/p>
&lt;p>In addition to an improvement on performance the gotchas are far less in dealing with a single array datatype and make it a quick but great win in certain cases like above.&lt;/p></description></item><item><title>Redis in my Postgres</title><link>/2012/10/18/connecting_to_redis_from_postgres/</link><pubDate>Thu, 18 Oct 2012 12:55:56 -0800</pubDate><guid>/2012/10/18/connecting_to_redis_from_postgres/</guid><description>&lt;p>Yesterday there was a post which hit &lt;a href="http://news.ycombinator.com/item?id=4664178">Hacker News&lt;/a> that talked about using &lt;a href="http://www.citusdata.com/blog/51-run-sql-on-mongodb">SQL to access Mongo&lt;/a>. While this is powerful I think much of the true value was entirely missed within the post.&lt;/p>
&lt;p>SQL is an expressive language, though people are often okay with accessing Mongo data through its own ORM. The real value is that you could actually query the data from within Postgres then join across your data stores, without having to do some ETL process to move data around. Think&amp;hellip; joining sales data from Postgres with user reviews stored in Mongo or searching for visits to a website (retained in redis) against purchases by user in Postgres.&lt;/p>
&lt;p>The mechanism pointed out was a MongoDB Foreign Data Wrapper. A Foreign Data Wrapper or FDW essentially lets you connect to an external datastore from within a Postgres database. In addition to the Mongo FDW released the other day there&amp;rsquo;s many others. For example Postgres 9.0 and up ships with one called &lt;code>db_link&lt;/code>, which lets you query and join across two different Postgres databases. Beyond that there&amp;rsquo;s support for a variety of other data stores including some you may have never expected:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://pgxn.org/dist/redis_fdw/">Redis&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/file_textarray_fdw/">Textfile&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/mysql_fdw/">MySQL&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/oracle_fdw/">Oracle&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/odbc_fdw/">ODBC&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/ldap_fdw/">LDAP&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/twitter_fdw/">Twitter&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/tag/fdw/">More&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Lets look at actually getting the Redis one running then see what some of the power of it really looks like. First we have to get the code then build it:&lt;/p>
&lt;p>git clone git://github.com/antirez/hiredis.git
cd hiredis
make
sudo make install&lt;/p>
&lt;p>Then download the FDW from &lt;a href="http://pgxn.org/dist/redis_fdw/">PGXN&lt;/a>&lt;/p>
&lt;pre>&lt;code>PATH=/Applications/Postgres.app/Contents/MacOS/bin/:$PATH USE_PGXS=1 make
sudo PATH=/Applications/Postgres.app/Contents/MacOS/bin/:$PATH USE_PGXS=1 make install
&lt;/code>&lt;/pre>
&lt;p>Now you&amp;rsquo;ll want to connect to your Postgres database, using &lt;code>psql&lt;/code> and enable the extension, and finally create your foreign table to your redis server. This is assuming a locally running redis, though you could connect to a remote just as easily:&lt;/p>
&lt;pre>&lt;code>CREATE EXTENSION redis_fdw;
CREATE SERVER redis_server
FOREIGN DATA WRAPPER redis_fdw
OPTIONS (address '127.0.0.1', port '6379');
CREATE FOREIGN TABLE redis_db0 (key text, value text)
SERVER redis_server
OPTIONS (database '0');
CREATE USER MAPPING FOR PUBLIC
SERVER redis_server
OPTIONS (password 'secret');
&lt;/code>&lt;/pre>
&lt;p>With &lt;code>dt&lt;/code> we can now see the list of all of our tables:&lt;/p>
&lt;pre>&lt;code># \dt
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+-------
public | products | table | craig
public | purchases | table | craig
public | users | table | craig
(3 rows)
&lt;/code>&lt;/pre>
&lt;p>And with a full &lt;code>\d&lt;/code> we can see not just the tables but also see we have a foreign table as well:&lt;/p>
&lt;pre>&lt;code># \d
List of relations
Schema | Name | Type | Owner
--------+------------------+---------------+-------
public | products | table | craig
public | purchases | table | craig
public | redis_db0 | foreign table | craig
public | users | table | craig
(4 rows)
&lt;/code>&lt;/pre>
&lt;p>Finally we can actually query against it:&lt;/p>
&lt;pre>&lt;code># SELECT * from redis_db0 limit 5;
key | value
---------+-------
user_40 | 44
user_41 | 32
user_42 | 11
user_43 | 3
user_80 | 7
(5 rows)
&lt;/code>&lt;/pre>
&lt;p>Or more interestingly we can join it against other parts of our data and filter accordingly. Below we&amp;rsquo;ll show users that have logged in at least 40 times:&lt;/p>
&lt;pre>&lt;code>SELECT
id,
email,
value as visits
FROM
users,
redis_db0
WHERE
('user_' || cast(id as text)) = cast(redis_db0.key as text)
AND cast(value as int) &amp;gt; 40;
id | email | visits
----+----------------------------+--------
40 | Cherryl.Crissman@gmail.com | 44
44 | Brady.Paramo@gmail.com | 44
46 | Laronda.Razor@yahoo.com | 44
47 | Karole.Sosnowski@gmail.com | 44
12 | Jami.Jeon@yahoo.com | 49
14 | Jenee.Morrissey@gmail.com | 47
16 | Yuki.Alber@yahoo.com | 48
18 | Marquis.Tartaglia@aol.com | 44
31 | Collin.Parrilla@gmail.com | 46
39 | Nydia.Bukowski@aol.com | 47
2 | Gaye.Monteith@aol.com | 48
6 | Letitia.Tripodi@aol.com | 41
(12 rows)
&lt;/code>&lt;/pre>
&lt;p>While several of the current FDWs are not production ready yet, some are more battle tested including db_link, textfile, ODBC and MySQL ones.&lt;/p></description></item><item><title>Postgres Pooling with Django</title><link>/2012/10/02/Postgres-Pooling-with-Django/</link><pubDate>Tue, 02 Oct 2012 12:55:56 -0800</pubDate><guid>/2012/10/02/Postgres-Pooling-with-Django/</guid><description>&lt;p>A feature thats glaringly missing within Django and common in many other frameworks including many Java frameworks and Rails is connection pooling for your database connection. As most Django users are Postgres users the default answer is to use something like pgPool or pgBouncer. This are tools that you can run that will persist a connection to your Postgres database intended to offer:&lt;/p>
&lt;ul>
&lt;li>Connection Pooling&lt;/li>
&lt;li>Replication&lt;/li>
&lt;li>Load Balancing&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Its of not that PgBouncer is intended very specifically for pooling while pgPool does much more.&lt;/em>&lt;/p>
&lt;p>Each of these in many cases can come with caveats though. If there are issues within your network they may not re-establish the connection properly. They also are not known to handle SSL renegotiation very well. Finally given running one more piece of software to reduce connection times it seems like a lot of overhead to simply reduce the connection time to your database.&lt;/p>
&lt;h2 id="is-connection-time-a-real-problem" >
&lt;div>
Is connection time a real problem?
&lt;/div>
&lt;/h2>
&lt;p>Given a well refined app, with a well refined schema with appropriate indexes your view should be doing things pretty quickly. If this is the case without some form of connection pooling and running in a cloud environment (in this case Heroku) your application performance looks like:&lt;/p>
&lt;p>If you&amp;rsquo;ll notice that about 50% of our request time was in Postgres. The hard part to see is how much of this is actually doing something. In this case its issuing some very basic queries then rendering a very basic view.&lt;/p>
&lt;h2 id="the-solution" >
&lt;div>
The solution
&lt;/div>
&lt;/h2>
&lt;p>By using something in &lt;em>the other Python ORM&lt;/em>, SQLAlchemy, we can take advantage of its connection pooling. Large thanks to &lt;a href="https://twitter.com/kennethreitz">Kenneth Reitz&lt;/a> for packaging this up into an easy to install and easy to use format as a Django DB backend. Using django_postgrespool it will take advantage of connection pooling and we can then see the performance after:&lt;/p></description></item><item><title>Understanding Postgres Performance</title><link>/2012/10/01/Understanding-Postgres-Performance/</link><pubDate>Mon, 01 Oct 2012 12:55:56 -0800</pubDate><guid>/2012/10/01/Understanding-Postgres-Performance/</guid><description>&lt;p>&lt;em>Update theres a more &lt;a href="/2013/01/10/more-on-postgres-performance/">recent post that expands further on where to start optimizing&lt;/a> specific queries, and of course if you want to dig into optimizing your infrastructure &lt;a href="http://www.amazon.com/dp/184951030X?tag=mypred-20">High Performance PostgreSQL is still a great read&lt;/a>&lt;/em>&lt;/p>
&lt;p>For many application developers their database is a black box. Data goes in, comes back out and in between there developers hope its a pretty short time span. Without becoming a DBA there&amp;rsquo;s a few pieces of data that most application developers can easily grok which will help them understand if their database is performing adequately. This post will provide some quick tips that allow you to determine whether your database performance is slowing down your app, and if so what you can do about it.&lt;/p>
&lt;h3 id="understanding-your-cache-and-its-hit-rate" >
&lt;div>
Understanding your Cache and its Hit Rate
&lt;/div>
&lt;/h3>
&lt;p>The typical rule for most applications is that only a fraction of its data is regularly accessed. As with many other things data can tend to follow the 80/20 rule with 20% of your data accounting for 80% of the reads and often times its higher than this. Postgres itself actually tracks access patterns of your data and will on its own keep frequently accessed data in cache. Generally you want your database to have a cache hit rate of about 99%. You can find your cache hit rate with:&lt;/p>
&lt;pre>&lt;code>SELECT
sum(heap_blks_read) as heap_read,
sum(heap_blks_hit) as heap_hit,
sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio
FROM
pg_statio_user_tables;
&lt;/code>&lt;/pre>
&lt;!-- raw HTML omitted -->
&lt;p>We can see in this &lt;a href="https://postgres.heroku.com/dataclips/jfrtizxdthixfxkcdesxwesiibly">dataclip&lt;/a> that the cache rate for &lt;a href="https://postgres.heroku.com?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">Heroku Postgres&lt;/a> is 99.99%. If you find yourself with a ratio significantly lower than 99% then you likely want to consider increasing the cache available to your database, you can do this on Heroku Postgres by &lt;a href="https://devcenter.heroku.com/articles/fast-database-changeovers?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">performing a fast database changeover&lt;/a> or on something like EC2 by performing a dump/restore to a larger instance size.&lt;/p>
&lt;h3 id="understanding-index-usage" >
&lt;div>
Understanding Index Usage
&lt;/div>
&lt;/h3>
&lt;p>The other primary piece for improving performance is &lt;a href="https://devcenter.heroku.com/articles/postgresql-indexes?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">indexes&lt;/a>. Several frameworks will add indexes on your primary keys, though if you&amp;rsquo;re searching on other fields or joining heavily you may need to manually add such indexes.&lt;/p>
&lt;p>Indexes are most valuable across large tables as well. While accessing data from cache is faster than disk, even data within memory can be slow if Postgres must parse through hundreds of thousands of rows to identify if they meet a certain condition. To generate a list of your tables in your database with the largest ones first and the percentage of time which they use an index you can run:&lt;/p>
&lt;pre>&lt;code>SELECT
relname,
100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used,
n_live_tup rows_in_table
FROM
pg_stat_user_tables
WHERE
seq_scan + idx_scan &amp;gt; 0
ORDER BY
n_live_tup DESC;
&lt;/code>&lt;/pre>
&lt;p>While there is no perfect answer, if you&amp;rsquo;re not somewhere around 99% on any table over 10,000 rows you may want to consider adding an index. When examining where to add an index you should look at what kind of queries you&amp;rsquo;re running. Generally you&amp;rsquo;ll want to add indexes where you&amp;rsquo;re looking up by some other id or on values that you&amp;rsquo;re commonly filtering on such as created_at fields.&lt;/p>
&lt;p>Pro tip: If you&amp;rsquo;re adding an index on a production database use &lt;code>CREATE INDEX CONCURRENTLY&lt;/code> to have it build your index in the background and not hold a lock on your table. The limitation to creating indexes &lt;a href="http://www.postgresql.org/docs/9.1/static/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY">concurrently&lt;/a> is they can typically take 2-3 times longer to create and can&amp;rsquo;t be run within a transaction. Though for any large production site these trade-offs are worth the trade-off in experience to your end users.&lt;/p>
&lt;h3 id="heroku-dashboard-as-an-example" >
&lt;div>
Heroku Dashboard as an Example
&lt;/div>
&lt;/h3>
&lt;p>Looking at a real world example of the recently launched Heroku dashboard, we can run this query and see our results:&lt;/p>
&lt;pre>&lt;code># SELECT relname, 100 * idx_scan / (seq_scan + idx_scan) percent_of_times_index_used, n_live_tup rows_in_table FROM pg_stat_user_tables ORDER BY n_live_tup DESC;
relname | percent_of_times_index_used | rows_in_table
---------------------+-----------------------------+---------------
events | 0 | 669917
app_infos_user_info | 0 | 198218
app_infos | 50 | 175640
user_info | 3 | 46718
rollouts | 0 | 34078
favorites | 0 | 3059
schema_migrations | 0 | 2
authorizations | 0 | 0
delayed_jobs | 23 | 0
&lt;/code>&lt;/pre>
&lt;p>From this we can wee the events table which has around 700,000 rows has no indexes that have been used. From here you could investigate within my application and see some of the common queries that are used, one example is pulling the events for this blog post which you are reaching. You can see your &lt;a href="https://postgresguide.com/performance/explain.html?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">execution plan&lt;/a> by running an &lt;a href="https://postgresguide.com/performance/explain.html?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">&lt;code>EXPLAIN ANALYZE&lt;/code>&lt;/a> which gives you can get a better idea of the performance of a specific query:&lt;/p>
&lt;pre>&lt;code>EXPLAIN ANALYZE SELECT * FROM events WHERE app_info_id = 7559; QUERY PLAN
-------------------------------------------------------------------
Seq Scan on events (cost=0.00..63749.03 rows=38 width=688) (actual time=2.538..660.785 rows=89 loops=1)
Filter: (app_info_id = 7559)
Total runtime: 660.885 ms
&lt;/code>&lt;/pre>
&lt;p>Given there&amp;rsquo;s a sequential scan across all that data this is an area we can optimize with an index. We can add our index concurrently to prevent locking on that table and then see how performance is:&lt;/p>
&lt;pre>&lt;code>CREATE INDEX CONCURRENTLY idx_events_app_info_id ON events(app_info_id);
EXPLAIN ANALYZE SELECT * FROM events WHERE app_info_id = 7559;
----------------------------------------------------------------------
Index Scan using idx_events_app_info_id on events (cost=0.00..23.40 rows=38 width=688) (actual time=0.021..0.115 rows=89 loops=1)
Index Cond: (app_info_id = 7559)
Total runtime: 0.200 ms
&lt;/code>&lt;/pre>
&lt;p>While we can see the obvious improvement in this single query we can examine the results in &lt;a href="https://addons.heroku.com/newrelic">New Relic&lt;/a> and see that we&amp;rsquo;ve significantly reduced our time spent in the database with the addition of this and a few other indexes:&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/2x3g2h2220162C2M0w0r/Pasted%20Image%2010:1:12%208:55%20AM-2.png" alt="NewRelicGraph">&lt;/p>
&lt;h3 id="index-cache-hit-rate" >
&lt;div>
Index Cache Hit Rate
&lt;/div>
&lt;/h3>
&lt;p>Finally to combine the two if you&amp;rsquo;re interested in how many of your indexes are within your cache you can run:&lt;/p>
&lt;pre>&lt;code>SELECT
sum(idx_blks_read) as idx_read,
sum(idx_blks_hit) as idx_hit,
(sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) as ratio
FROM
pg_statio_user_indexes;
&lt;/code>&lt;/pre>
&lt;p>Generally, you should also expect this to be in the 99% similar to your regular cache hit rate.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Arrays in Postgres</title><link>/2012/08/20/Arrays-in-Postgres/</link><pubDate>Mon, 20 Aug 2012 12:55:56 -0800</pubDate><guid>/2012/08/20/Arrays-in-Postgres/</guid><description>&lt;p>Postgres out of the box has an abundance of datatypes, from standard &lt;a href="http://www.postgresql.org/docs/9.1/static/datatype.html#DATATYPE-NUMERIC">numeric datatypes&lt;/a> to &lt;a href="http://www.postgresql.org/docs/9.1/static/datatype-geometric.html">geometric&lt;/a> or even &lt;a href="http://www.postgresql.org/docs/9.1/static/datatype-net-types.html">network datatypes&lt;/a>. With extensions you can get even more out of it as earlier discussed with &lt;a href="http://craigkerstiens.com/2012/06/11/schemaless-django/">hStore&lt;/a>. Though with all of the datatypes its easy to miss out on some of them that are there, in fact one of my favorites is often missed entirely. The &lt;a href="http://www.postgresql.org/docs/9.1/static/arrays.html">Array&lt;/a> datatype lets you do just as you&amp;rsquo;d expect, store an array inside Postgres. With this you can often get some of the functionality you&amp;rsquo;d want in a single table when you might traditionally have expanded to multiple tables.&lt;/p>
&lt;p>The broader question may be why you&amp;rsquo;d actually want to use an array. One good reason may be if you&amp;rsquo;re an application developer its how you think of your data, so why not model it the same way. As you&amp;rsquo;ll see below it can be easier than joining and aggregating across a set of rows. Also depending on your case you performance could be improved, though mileage may vary here as it does depend on the data you&amp;rsquo;re storing.&lt;/p>
&lt;p>First a bit of a hacky example&amp;hellip; Lets say you have a basic website that sells stuff, and instead of having a purchase ID and a total you want to include the quantity, id, and price of each item in a single row. With a bit of a messy foreign key (using a decimal) you could store all of this within a single row:&lt;/p>
&lt;pre>&lt;code>CREATE TABLE purchases (
id integer NOT NULL,
user_id integer,
items decimal(10,2) [100][1],
occurred_at timestamp
);
&lt;/code>&lt;/pre>
&lt;p>With this table I could have an array that holds multiple records of:&lt;/p>
&lt;ul>
&lt;li>The item purchased&lt;/li>
&lt;li>The quantity&lt;/li>
&lt;li>The price&lt;/li>
&lt;/ul>
&lt;!-- raw HTML omitted -->
&lt;p>An insert to this table would look something like:&lt;/p>
&lt;pre>&lt;code>INSERT INTO purchases VALUES (1, 37, '\{\{15.0, 1.0, 25.0\}, \{15.0, 1.0, 25.0\}\}', now());
INSERT INTO purchases VALUES (2, 2, '{{11.0, 1.0, 4.99}}', now());
&lt;/code>&lt;/pre>
&lt;p>You can see a full example with UDF&amp;rsquo;s to compute total &lt;a href="https://github.com/craigkerstiens/postgres-demo">here&lt;/a>&lt;/p>
&lt;p>A more practical example may actually be using an array for tags. If you were to tag your purchases:&lt;/p>
&lt;pre>&lt;code>CREATE TABLE products (
id integer NOT NULL,
title character varying(255),
description text,
tags text[],
price numeric(10,2)
);
&lt;/code>&lt;/pre>
&lt;p>You could then query those just as you&amp;rsquo;d expect with a basic select statement, or could even expand the array to have an individual result per row:&lt;/p>
&lt;pre>&lt;code> SELECT title, unnest(tags) items
FROM products
&lt;/code>&lt;/pre>
&lt;p>Protip: If you&amp;rsquo;re using arrays you can also use Postgres&amp;rsquo; &lt;a href="http://www.postgresql.org/docs/9.1/static/textsearch-indexes.html">Gin and Gist&lt;/a> indexes to search for products quickly that contain certain tags. Given an index you could search where its tagged with some id:&lt;/p>
&lt;pre>&lt;code>-- Search where product contains tag ids 1 AND 2
SELECT *
FROM products
WHERE tags @&amp;gt; ARRAY[1, 2]
-- Search where product contains tag ids 1 OR 2
SELECT *
FROM products
WHERE tags &amp;amp;&amp;amp; ARRAY[1, 2]
&lt;/code>&lt;/pre></description></item><item><title>Rapid API Prototyping with Heroku Postgres Dataclips</title><link>/2012/07/19/Rapid-API-Prototyping-with-Heroku-Postgres-Dataclips/</link><pubDate>Thu, 19 Jul 2012 12:55:56 -0800</pubDate><guid>/2012/07/19/Rapid-API-Prototyping-with-Heroku-Postgres-Dataclips/</guid><description>&lt;p>For small and large applications there often comes a time where you&amp;rsquo;re busy creating an API. The API creation process usually takes the form of something like: Design your API, Implement your API, Test and Evaluate, Rinse and Repeat. Historically with implementing the API fully you can&amp;rsquo;t see how you truly feel about the result, causing this cycle to take longer than it should. Heroku Postgres has &lt;a href="https://postgres.heroku.com/blog/past/2012/1/31/simple_data_sharing_with_data_clips/">Dataclips&lt;/a>, which (among other things) can be used for quickly prototyping APIs. &lt;a href="https://postgres.heroku.com/dataclips">Dataclips&lt;/a> allows you to easily share data, but more importantly consume it in a form much like you would a restful API. Lets take a look at how this would work:&lt;/p>
&lt;h2 id="given-a-schema" >
&lt;div>
Given a schema
&lt;/div>
&lt;/h2>
&lt;p>We can see from the screen shot of the schema above we can see we have a few tables. These tables are the complete works of Shakespeare thanks to &lt;a href="http://www.opensourceshakespeare.org/downloads/">opensourceshakespeare&lt;/a>. Lets take a couple of hypothetical endpoints we&amp;rsquo;ve decided on that we&amp;rsquo;d like to expose for users and test as an API.&lt;/p>
&lt;ul>
&lt;li>The number of works per year&lt;/li>
&lt;li>Drone factory (this is a fun one courtesy of Richard Morrison - &lt;a href="https://twitter.com/mozz100">@mozz100&lt;/a> essentially who has the longest paragraphs on average in his works.&lt;/li>
&lt;/ul>
&lt;!-- raw HTML omitted -->
&lt;h2 id="create-a-dataclip" >
&lt;div>
Create a dataclip
&lt;/div>
&lt;/h2>
&lt;p>Now we open up our database on Heroku Postgres and go down near the bottom to the dataclips section. Click the plus to create a new dataclip and we can enter our queries.&lt;/p>
&lt;pre>&lt;code>SELECT
year,
count(*)
FROM
works
GROUP BY
year
ORDER BY
year ASC
&lt;/code>&lt;/pre>
&lt;p>Click &lt;code>Create Clip&lt;/code> and you&amp;rsquo;ll be redirected to your new dataclip. This unique URL will always return the results of that query and if you want to shift it to a real time API that re-runs the query you can flip the &lt;code>now&lt;/code> switch. For my simple example above my url for this dataclip is now &lt;a href="https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex">https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex&lt;/a>.&lt;/p>
&lt;h2 id="using-the-dataclip-as-a-prototype-api" >
&lt;div>
Using the dataclip as a prototype API
&lt;/div>
&lt;/h2>
&lt;p>There are many different use cases for dataclips, but of course for our sake we care about prototyping an API instead of sharing the data. To do this you can simply append the format you want to the url above and test as if it were an API:&lt;/p>
&lt;ul>
&lt;li>JSON - &lt;a href="https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex.json">https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex.json&lt;/a>&lt;/li>
&lt;li>CSV - &lt;a href="https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex.csv">https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex.csv&lt;/a>&lt;/li>
&lt;li>XLS - &lt;a href="https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex.xls">https://dataclips.heroku.com/fcroecrluhwltbjinstfqmwyneex.xls&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Essentially anything you can bake down to a query (much like you would in your App&amp;rsquo;s API layer) you can expose in this form to quickly test. For a more complicated example you can check out the &lt;a href="https://postgres.heroku.com/dataclips/tzvzbnnijzezyvzwjeoibwdpfjqb">Drone factor query&lt;/a>.&lt;/p></description></item><item><title>Protips for Conference Talks</title><link>/2012/06/19/pro-tips-for-conference-talks/</link><pubDate>Tue, 19 Jun 2012 12:55:56 -0800</pubDate><guid>/2012/06/19/pro-tips-for-conference-talks/</guid><description>&lt;p>A few weeks ago I was sitting at the hotel in Zurich with &lt;a href="http://www.twitter.com/jacobian">Jacob Kaplan Moss&lt;/a> prior to &lt;a href="http://klewel.com/conferences/djangocon-2012/">DjangoCon EU&lt;/a> enjoying a beer, talking about Django, and discussing a bit about our upcoming talks for the conference. He talked briefly about his upcoming &lt;a href="http://klewel.com/conferences/djangocon-2012/index.php?talkID=2">keynote&lt;/a> and how he was doing something different, including essentially 5 mini-talks. This seemed interesting enough, but the part that surprised me was when Jacob said, &amp;ldquo;I&amp;rsquo;m among friends here so it&amp;rsquo;ll be a good place to test this format.&amp;rdquo; Many if not all in the community know who Jacob is as one of the creators of Django, though still to be &amp;ldquo;among friends&amp;rdquo; at a roughly 300 person conference surprised me. However, as someone thats keynoted several times, spoken at conferences for many years, and familiar with many people in the community; for the 150-200 people there he had not met before, he was still truly among friends. While giving a keynote is never an easy feat, it seems to ease the worry ahead of time of doing such.&lt;/p>
&lt;p>Saturday night there was a bit of conversation on twitter that had some related discussion. In the last minute rush for DjangoCon US talk submissions a few that have been involved in the community for some time discussed submitting their first talk proposals. In parallel to that was some discussion around diversity, I volunteered the idea of not including presenters name&amp;rsquo;s in the list when reviewing and voting on talks. While both of the above are controversial topics alone, I hope that can be left to another later time. The key idea that emerged that can be helpful to anyone looking to submit a talk to a conference is how the &amp;ldquo;pro&amp;rsquo;s do it&amp;rdquo;, as &lt;a href="http://www.twitter.com/jdunck">Jeremy Dunck&lt;/a> put it.&lt;/p>
&lt;p>So without further adieu, hopefully without speaking too much for him here&amp;rsquo;s likely why Jacob viewed his 300 person keynote as being among friends:&lt;/p>
&lt;h2 id="1-start-small" >
&lt;div>
1. Start small
&lt;/div>
&lt;/h2>
&lt;p>Whether its practicing the talk itself or writing the abstract for a proposal practicing each step lets you refine this well ahead of time. In my experience, providing a talk description for a meetup can often be far harder than for a conference. For a meetup I feel confined to 2-3 sentences, versus an abstract a solid paragraph or two. Yet, I still have to make it as exciting, because of course I don&amp;rsquo;t want 4 people to show up to the meetup because it sounds uninteresting. In the case I&amp;rsquo;m most familiar with &lt;a href="http://www.djangocon.us/">DjangoCon&lt;/a> and DjangoCon.eu both happen once a year, though many smaller regional conferences related to Python exist and especially meetup groups:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h3 id="regional-conferences" >
&lt;div>
Regional Conferences
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.pytexas.org/2011/">PyTexas&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pyarkansas.wordpress.com/">PyArkansas&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://pygotham.org/">PyGotham&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pyohio.org/">PyOhio&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="meetups" >
&lt;div>
Meetups
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.meetup.com/pythonkc/">Kansas City&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.djangonyc.org/">NYC&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.meetup.com/The-San-Francisco-Django-Meetup-Group/">SF&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.meetup.com/austinwebpythonusergroup/">Austin&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.meetup.com/pdxpython/">Portland&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.meetup.com/python-atlanta/">Atlanta&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://chipy.org/">Chicago&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="other-avenues" >
&lt;div>
Other avenues
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://igniteshow.com/cities/all">Ignite&lt;/a>&lt;/li>
&lt;li>At your office to colleagues&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Check &lt;a href="http://lanyrd.com/topics/python/">lanyard&lt;/a> for a list of relevant events where you might be able to start at&lt;/em>&lt;/p>
&lt;p>Take your pick, there&amp;rsquo;s a conference or a meet-up near you. Even better if you can manage to do both at some point.&lt;/p>
&lt;h2 id="2-get-feedback-early" >
&lt;div>
2. Get feedback early
&lt;/div>
&lt;/h2>
&lt;p>If you&amp;rsquo;ve been around the community you may know what talks would be interesting. Though even if you&amp;rsquo;ve been involved in the community and not given a talk at a conference before, this may be harder to come up with than you realize. If you&amp;rsquo;re thinking about submitting a talk, its likely you have many you can get feedback from. Do this early and often, if you&amp;rsquo;re submitting a talk its likely you have something interesting to say, the hardest part can be having that succinctly come across in an abstract. Sure there&amp;rsquo;s certain hot topics, such as in the Django community:&lt;/p>
&lt;ul>
&lt;li>Diversity&lt;/li>
&lt;li>Class Based Views&lt;/li>
&lt;li>Testing&lt;/li>
&lt;li>APIs/Services&lt;/li>
&lt;/ul>
&lt;p>At almost every Django and Python conference there will probably be 3+ talks on each of these topics submitted. Why does yours stand out differently? Its likely in how you position the problem and the answer you can deliver in a talk, which isn&amp;rsquo;t a quality of the talk but the abstract rather.&lt;/p>
&lt;h2 id="3-focus-on-your-talk-more-than-others" >
&lt;div>
3. Focus on your talk more than others
&lt;/div>
&lt;/h2>
&lt;p>I&amp;rsquo;m not sure this is the case of all presenters at every conference, but every time I&amp;rsquo;ve paid attention to it; presenters seem to make themselves slightly less available during a conference. Or at least they do this up until they give their talk. Often you&amp;rsquo;ll have several of the presenters missing other talks while they&amp;rsquo;re holed up in their room prepping or maybe their enjoying a hallway track with other presenters. Either way they&amp;rsquo;re likely walking through their slides and talk key points in some form. As a presenter the dynamic of the conference changes ever so slightly, you spend a little less time on all of the talks that happen (fortunately videos help for catching up later). Though on the plus side, you also get the opportunity to have engaging conversations after your talk about a topic you hopefully find interesting.&lt;/p>
&lt;h2 id="4-get-the-critical-feedback" >
&lt;div>
4. Get the critical feedback
&lt;/div>
&lt;/h2>
&lt;p>People know its nerve wrecking to give a talk in front of a crowd. Each time you do it, it becomes easier, but in my experience its never as easy as a conversation over a cup of coffee. Because of this, most people will be quite encouraging of any job you do. This isn&amp;rsquo;t a bad thing, encouragement is good, your talk will be better the second time you give it. However, by getting the critical feedback out of people you&amp;rsquo;ll be able to improve your talk much more the second/third/fourth time around.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Schemaless Postgres in Django</title><link>/2012/06/11/schemaless-django/</link><pubDate>Mon, 11 Jun 2012 12:55:56 -0800</pubDate><guid>/2012/06/11/schemaless-django/</guid><description>&lt;p>Earlier this week while I was at &lt;a href="http://lanyrd.com/2012/djangocon-europe/">DjangoCon EU&lt;/a> there seemed to be a surprising amount of talk about MongoDB. My problem with this isn&amp;rsquo;t with MongoDB, but in the assumption that only Mongo can solve what you&amp;rsquo;re looking for. By and far the most common feature is people want schemaless. It gives them flexibility in their data model and lets them iterate quickly. While I still opt for relational models that map cleanly to a relational database, there are cases where developers may want schemaless. I gave a quick lightning talk on this with slides &lt;a href="https://speakerdeck.com/u/craigkerstiens/p/django-and-hstore">here&lt;/a>, but it is worth recapping.&lt;/p>
&lt;p>The example given by &lt;a href="http://www.twitter.com/pydanny">pydanny&lt;/a> was a product catalog. You may have different items you want to store for a catalog. Lets take an example below:&lt;/p>
&lt;pre>&lt;code>django_pony = {'name': 'Django Pony', 'rating': '5'}
pink_pony = {'name': 'Pink Pony', 'rating': '4', 'color': 'pink'}
&lt;/code>&lt;/pre>
&lt;p>In the case of a product catalog it could be understandable you don&amp;rsquo;t want to normalize every possible spec for the product. The argument for Mongo is so commonly that you can easily work with this data model. Admittedly it is quite simple:&lt;/p>
&lt;pre>&lt;code>from pymongo import Connection
connection = Connection()
django_pony = {'name': 'Django Pony', 'rating': '5'}
connection.product.insert(django_pony)
&lt;/code>&lt;/pre>
&lt;p>The problem is that this assumes other schemaless options don&amp;rsquo;t exist or are inferior.&lt;/p>
&lt;h2 id="enter-hstore" >
&lt;div>
Enter hStore
&lt;/div>
&lt;/h2>
&lt;p>&lt;a href="http://www.postgresql.org/docs/8.4/static/hstore.html">hStore&lt;/a> is a column type within Postgres. It is a key value store that allows you to store a dictionary, with text values. It alone is not a full document store replacement, but allows for flexibility in your data model where you need it while letting you use relational models elsewhere. Its not exactly new within Postgres either, as its been available since 8.4, however its recently become easier to work with and is supported in some form or another by more frameworks.&lt;/p>
&lt;p>To do the same as above we only need to do a few steps:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Within your Postgres 9.1 or higher database:&lt;/p>
&lt;pre>&lt;code>create extension hstore;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>If you don&amp;rsquo;t have Postgres already if you&amp;rsquo;re on a Mac quickly grab and install &lt;a href="http://postgresapp.com">Postgres.app&lt;/a>.&lt;/em>&lt;/p>
&lt;p>Now for actually using it within your Django application. You first need to install django-hstore to your project:&lt;/p>
&lt;pre>&lt;code>pip install django-hstore
&lt;/code>&lt;/pre>
&lt;p>Then you can add it to your models:&lt;/p>
&lt;pre>&lt;code>from django.db import models
from django_hstore import hstore
class Product(models.Model):
name = models.CharField(max_length=250)
data = hstore.DictionaryField(db_index=True)
objects = hstore.Manager()
def __unicode__(self):
return self.name
&lt;/code>&lt;/pre>
&lt;p>Once you&amp;rsquo;ve sync&amp;rsquo;ed your database models you can now add your products in a very similar form to above:&lt;/p>
&lt;pre>&lt;code>Product.objects.create(name='Django Pony', data={'rating': '5'})
Product.objects.create(name='Pony', data={'color': 'pink', 'rating': '4'})
&lt;/code>&lt;/pre>
&lt;p>At this point you&amp;rsquo;ve got your schemaless data into Postgres and can interact with it. However, this is where the benefits of Postgres quickly start to come into play. In addition to the schemaless model you&amp;rsquo;re able to add indexes and filter on keys/values just as you would expect. In fact within Django it maps similarly to how it would within the ORM:&lt;/p>
&lt;pre>&lt;code>colored_ponies = Product.objects.filter(data__contains='color')
print colored_ponies[0].data['color']
favorite_ponies = Product.objects.filter(data__contains={'rating': '5'})
print colored_ponies[0]
&lt;/code>&lt;/pre>
&lt;p>To add indexes within postgres we could index on the same items that we&amp;rsquo;re filtering above:&lt;/p>
&lt;pre>&lt;code>create index on product(((data-&amp;gt;'color')::int)) where ((data-&amp;gt;'size') is not null);
create index on product(((data-&amp;gt;'rating')::int)) where ((data-&amp;gt;'rating') = '5');
&lt;/code>&lt;/pre>
&lt;p>If you need a sample project to start with immediately check out this one on &lt;a href="https://github.com/craigkerstiens/hstore-demo">github&lt;/a>.&lt;/p>
&lt;p>When evaluating any database its important to choose the features you&amp;rsquo;re evaluating it on, then examine further. Mongo may be great because its schemaless, this doesn&amp;rsquo;t mean an RDMS can&amp;rsquo;t be schemaless as well (and do a good job of it). In the long run, schemaless is likely to just become another feature in databases, but more on that later.&lt;/p></description></item><item><title>Why PostgreSQL Part 2</title><link>/2012/05/07/why-postgres-part-2/</link><pubDate>Mon, 07 May 2012 12:55:56 -0800</pubDate><guid>/2012/05/07/why-postgres-part-2/</guid><description>&lt;p>&lt;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 &lt;a href="http://www.postgresguide.com">PostgresGuide.com&lt;/a>. If you need to get started check out &lt;a href="http://postgresapp.com">Postgres.app&lt;/a> for Mac, or get a Cloud instance at &lt;a href="https://postgres.heroku.com/?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">Heroku Postgres&lt;/a> for free&lt;/em>&lt;/p>
&lt;p>Last week I did a post on the &lt;a href="/2012/04/30/why-postgres/">many reasons to use Postgres&lt;/a>. My goal with the post was two fold:&lt;/p>
&lt;ul>
&lt;li>Call out some of the historical arguments against it that don&amp;rsquo;t hold any more&lt;/li>
&lt;li>Highlight some of the awesome but more unique features that are less commonly found in databases.&lt;/li>
&lt;/ul>
&lt;p>Once I published the post it was clear and was immediately pointed out in the comments and on &lt;a href="http://news.ycombinator.com/item?id=3910743">hacker news&lt;/a> that I missed quite a few features that I&amp;rsquo;d mostly come to take for granted. &lt;em>Perhaps this is due to so much awesomeness existing within Postgres.&lt;/em> A large thanks to everyone for calling these out. To help consolidate many of these, here&amp;rsquo;s a second list of the many reasons to use PostgreSQL:&lt;/p>
&lt;h2 id="create-index-concurrently" >
&lt;div>
Create Index Concurrently
&lt;/div>
&lt;/h2>
&lt;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&amp;rsquo;re starting out this isn&amp;rsquo;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 &lt;a href="http://www.postgresql.org/docs/9.1/static/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY">&lt;code>CREATE INDEX CONCURRENTLY&lt;/code>&lt;/a> instead of &lt;code>CREATE INDEX&lt;/code> will create your index without holding the lock.&lt;/p>
&lt;p>&lt;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&lt;/em>&lt;/p>
&lt;h2 id="transactional-ddl" >
&lt;div>
Transactional DDL
&lt;/div>
&lt;/h2>
&lt;p>If you&amp;rsquo;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.&lt;/p>
&lt;h2 id="foreign-data-wrappers" >
&lt;div>
Foreign Data Wrappers
&lt;/div>
&lt;/h2>
&lt;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&amp;rsquo;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&amp;rsquo;s a sampling of just a few of the foreign data wrappers that exist:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://pgxn.org/dist/oracle_fdw/">Oracle&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/mysql_fdw/">MySQL&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/redis_fdw/">Redis&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://pgxn.org/dist/twitter_fdw/">Twitter&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>In fact you can even use &lt;a href="http://multicorn.org/">Multicorn&lt;/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 &lt;a href="http://blog.database.com/blog/2011/11/21/a-database-comforce-com-foreign-data-wrapper-for-postgresql/">here&lt;/a>&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="conditional-constraints-and-partial-indexes" >
&lt;div>
Conditional Constraints and Partial Indexes
&lt;/div>
&lt;/h2>
&lt;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&amp;rsquo;ve had multiple ones over recent years. You likely wouldn&amp;rsquo;t care about the past addresses being indexed, but would want everyones current address to be indexed. With &lt;a href="http://www.postgresql.org/docs/9.1/static/indexes-partial.html">Partial Indexes&lt;/a> becomes simple and straight forward:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> CREATE INDEX idx_address_current ON address &lt;span style="color:#f92672">(&lt;/span>user_id&lt;span style="color:#f92672">)&lt;/span> WHERE current IS True;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="postgres-in-the-cloud" >
&lt;div>
Postgres in the Cloud
&lt;/div>
&lt;/h2>
&lt;p>Postgres has been chosen by individual shops and been proven to scale by places such as &lt;a href="http://media.postgresql.org/sfpug/instagram_sfpug.pdf">Instagram&lt;/a> and &lt;a href="http://ontwik.com/python/disqus-scaling-the-world%E2%80%99s-largest-django-application/">Disqus&lt;/a>. Perhaps even more importantly it&amp;rsquo;s becoming easy to use PostgreSQL due to the many clouds that are running Postgres as a Service, such as:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://postgres.heroku.com">Heroku Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.vmware.com/products/application-platform/vfabric-data-director/features.html">VMware vFabric&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.enterprisedb.com/">Enterprise DB&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.cloudpostgres.com">Cloud Postgres&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Full disclosure, I work at &lt;a href="http://www.heroku.com">Heroku&lt;/a>, and am also a large fan of their database service&lt;/em>&lt;/p>
&lt;h2 id="listennotify" >
&lt;div>
Listen/Notify
&lt;/div>
&lt;/h2>
&lt;p>If you want to use your database as a queue there&amp;rsquo;s some cases where it just won&amp;rsquo;t work, as heavily discussed in a &lt;a href="http://mikehadlow.blogspot.se/2012/04/database-as-queue-anti-pattern.html">recent write-up&lt;/a>. However, much of this could be discarded if you included Postgres in this discussion due to Listen/Notify. Postgres will allow you to &lt;a href="http://www.postgresql.org/docs/9.1/static/sql-listen.html">LISTEN&lt;/a> to an event and of course &lt;a href="http://www.postgresql.org/docs/9.1/static/sql-notify.html">NOTIFY&lt;/a> for when the event has occurred. A great example of this in action is &lt;a href="http://www.twitter.com/ryandotsmith">Ryan Smith&amp;rsquo;s&lt;/a> &lt;a href="https://github.com/ryandotsmith/queue_classic">Queue Classic&lt;/a>.&lt;/p>
&lt;h2 id="fast-column-additionremoval" >
&lt;div>
Fast column addition/removal
&lt;/div>
&lt;/h2>
&lt;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&amp;rsquo;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.&lt;/p>
&lt;h2 id="table-inheritance" >
&lt;div>
Table Inheritance
&lt;/div>
&lt;/h2>
&lt;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&amp;rsquo;d like on your data model. The Postgres docs on &lt;a href="http://www.postgresql.org/docs/9.1/static/ddl-inherit.html">DDL Inheritance&lt;/a> do a great job of documenting how to use this and giving a very simple but clear use case.&lt;/p>
&lt;h2 id="per-transaction-synchronous-replication" >
&lt;div>
Per transaction synchronous replication
&lt;/div>
&lt;/h2>
&lt;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 &lt;a href="http://www.postgresql.org/docs/current/static/warm-standby.html#SYNCHRONOUS-REPLICATION">synchronous&lt;/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.&lt;/p>
&lt;h2 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h2>
&lt;p>Hopefully you&amp;rsquo;re convinced on why Postgres is a great tool, if not take a look back at my &lt;a href="/2012/04/30/why-postgres/">previous post&lt;/a>.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Feedback for Conference Organizers</title><link>/2012/05/04/Feedback-for-Conference-Organizers/</link><pubDate>Fri, 04 May 2012 12:55:56 -0800</pubDate><guid>/2012/05/04/Feedback-for-Conference-Organizers/</guid><description>&lt;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.&lt;/p>
&lt;p>As for some guidance. I&amp;rsquo;ve been on nearly all sides of the conference with the exception of organizing, so again organizers please don&amp;rsquo;t take offense to the feedback.&lt;/p>
&lt;h2 id="first-on-timeline" >
&lt;div>
First on timeline
&lt;/div>
&lt;/h2>
&lt;p>&lt;em>Please publish this early on your site and on &lt;a href="http://www.lanyrd.com">lanyrd&lt;/a>&lt;/em>&lt;/p>
&lt;ul>
&lt;li>Deadline for CFP&lt;/li>
&lt;li>Deadline for Call for Sponsorship&lt;/li>
&lt;li>Publish speaker list&lt;/li>
&lt;li>Early bird registration ends&lt;/li>
&lt;li>Regular registration ends&lt;/li>
&lt;/ul>
&lt;!-- raw HTML omitted -->
&lt;h2 id="as-a-sponsor" >
&lt;div>
As a sponsor
&lt;/div>
&lt;/h2>
&lt;h3 id="early-dates-and-times" >
&lt;div>
Early dates and times
&lt;/div>
&lt;/h3>
&lt;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&amp;rsquo;m able to make it to the conference. As a sponsor unfortunately I&amp;rsquo;m more restricted by budgets and timelines.&lt;/p>
&lt;h3 id="give-me-options-on-sponsorship" >
&lt;div>
Give me options on sponsorship
&lt;/div>
&lt;/h3>
&lt;p>A prospectus is great, and often times I&amp;rsquo;m completely happy with it. Other times there&amp;rsquo;s things I may want to sponsor that are not on the list. If videos aren&amp;rsquo;t already being recorded I&amp;rsquo;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&amp;rsquo;t cause me to sponsor or not, but it does leave a clear reminder of my experience.&lt;/p>
&lt;h3 id="location-of-exhibit-hall" >
&lt;div>
Location of exhibit hall
&lt;/div>
&lt;/h3>
&lt;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.&lt;/p>
&lt;h2 id="as-a-speaker" >
&lt;div>
As a speaker
&lt;/div>
&lt;/h2>
&lt;h3 id="have-previous-years-talks-available" >
&lt;div>
Have previous years talks available
&lt;/div>
&lt;/h3>
&lt;p>If you are interested in attracting new speakers to your conference, please include last years talks. As a speaker there&amp;rsquo;s often a new conference I&amp;rsquo;d be interested in attending, if I&amp;rsquo;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.&lt;/p>
&lt;h3 id="publish-the-cfp" >
&lt;div>
Publish the CFP
&lt;/div>
&lt;/h3>
&lt;p>This is especially key to have on &lt;a href="http://www.lanyrd.com">lanyrd&lt;/a>, above all the other timelines. There&amp;rsquo;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 &lt;a href="http://lanyrd.com/calls/">upcoming calls&lt;/a>.&lt;/p>
&lt;p>&lt;em>Bonus if you give me a signup form to get notified via email when the CFP is open&lt;/em>&lt;/p>
&lt;h3 id="turnaround" >
&lt;div>
Turnaround
&lt;/div>
&lt;/h3>
&lt;p>I understand there&amp;rsquo;s a lot to do when organizing a conference. As much as possible keep the turnaround fast on these. There&amp;rsquo;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&amp;rsquo;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.&lt;/p>
&lt;h3 id="speaker-dinner" >
&lt;div>
Speaker dinner
&lt;/div>
&lt;/h3>
&lt;p>As a speaker, I&amp;rsquo;ll be missing a few talks as I prep for mine and of course give mine. Additionally there&amp;rsquo;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.&lt;/p>
&lt;h3 id="notice" >
&lt;div>
Notice
&lt;/div>
&lt;/h3>
&lt;p>If your CFP is well in advance of the conference, advertise it early and often.&lt;/p>
&lt;h2 id="as-an-attendee" >
&lt;div>
As an attendee
&lt;/div>
&lt;/h2>
&lt;h3 id="power-and-internet" >
&lt;div>
Power and Internet
&lt;/div>
&lt;/h3>
&lt;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.&lt;/p>
&lt;p>&lt;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.&lt;/em>&lt;/p>
&lt;h3 id="hallway-tracks" >
&lt;div>
Hallway Tracks
&lt;/div>
&lt;/h3>
&lt;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.&lt;/p>
&lt;h3 id="evening-events" >
&lt;div>
Evening events
&lt;/div>
&lt;/h3>
&lt;p>I don&amp;rsquo;t want to get into the debate about drinking (coffee or alcohol), but evening events encourage socialization. &lt;a href="http://max.adobe.com/">Adobe&amp;rsquo;s MAX&lt;/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&amp;rsquo;t something the conference wants to condone or organize itself, there&amp;rsquo;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.&lt;/p></description></item><item><title>Why Postgres</title><link>/2012/04/30/Why-Postgres/</link><pubDate>Mon, 30 Apr 2012 12:55:56 -0800</pubDate><guid>/2012/04/30/Why-Postgres/</guid><description>&lt;p>&lt;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 &lt;a href="http://www.postgresguide.com">PostgresGuide.com&lt;/a>. If you need to get started check out &lt;a href="http://postgresapp.com">Postgres.app&lt;/a> for Mac, or get a Cloud instance at &lt;a href="https://postgres.heroku.com/?utm_source=referral&amp;amp;utm_medium=content&amp;amp;utm_campaign=craigkerstiens">Heroku Postgres&lt;/a> for free&lt;/em>&lt;/p>
&lt;p>&lt;em>UPDATE: A &lt;a href="/2012/05/07/why-postgres-part-2/">part 2&lt;/a> has been posted on &lt;a href="/2012/05/07/why-postgres-part-2/">Why Use Postgres&lt;/a>&lt;/em>&lt;/p>
&lt;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.&lt;/p>
&lt;h2 id="replication" >
&lt;div>
Replication
&lt;/div>
&lt;/h2>
&lt;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 &lt;a href="http://www.postgresql.org/docs/8.4/static/high-availability.html">8.4 Postgres&amp;rsquo;s&lt;/a> story around replication quickly became much better.&lt;/p>
&lt;p>&lt;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?&lt;/em>&lt;/p>
&lt;h2 id="window-functions" >
&lt;div>
Window functions
&lt;/div>
&lt;/h2>
&lt;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&amp;rsquo;t live without; the other options that existed before were slower and much more complicated. With the release of &lt;a href="http://www.postgresql.org/docs/9.1/static/tutorial-window.html">8.4&lt;/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 &lt;a href="http://postgresguide.com/tips/window.html">PostgresGuide.com&lt;/a>.&lt;/p>
&lt;h2 id="flexible-datatypes" >
&lt;div>
Flexible Datatypes
&lt;/div>
&lt;/h2>
&lt;p>Creating a custom column is simpler in Postgres than any other database I&amp;rsquo;ve used by far. Excluding custom datatypes, even Postgres&amp;rsquo;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 &lt;a href="http://www.postgresql.org/docs/9.1/static/arrays.html">Array&lt;/a> of some datatype. Want to store a game of tic-tac-toe in a database, or an array of 1 user&amp;rsquo;s phone numbers? It simply becomes a single column that can contain multiple phone numbers for a user.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="functions" >
&lt;div>
Functions
&lt;/div>
&lt;/h2>
&lt;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 &lt;a href="http://www.postgresql.org/docs/9.1/static/functions-aggregate.html">array_agg a look&lt;/a>. Need to split a string and grab a part of it or some other string action, there&amp;rsquo;s a &lt;a href="http://www.postgresql.org/docs/9.1/static/functions-string.html">function for that&lt;/a>.&lt;/p>
&lt;h2 id="custom-languages" >
&lt;div>
Custom Languages
&lt;/div>
&lt;/h2>
&lt;p>Want to use another language inside your database? Postgres probably supports it:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.postgresql.org/docs/9.1/static/plpython.html">Python in Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/knu/postgresql-plruby">Ruby in Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.joeconway.com/plr/">R in Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://code.google.com/p/plv8js/wiki/PLV8">V8 in Postgres&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="extensions" >
&lt;div>
Extensions
&lt;/div>
&lt;/h2>
&lt;p>Need to go beyond standard Postgres? There&amp;rsquo;s a good chance that someone else has, and that there&amp;rsquo;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 - &lt;a href="http://blog.railsware.com/2012/04/23/postgresql-most-useful-extensions/">PostgreSQL Most Useful Extensions&lt;/a>.&lt;/p>
&lt;h2 id="nosql-gives-flexibility" >
&lt;div>
NoSQL gives flexibility
&lt;/div>
&lt;/h2>
&lt;p>I don&amp;rsquo;t want to get too NoSQL versus SQL debate&amp;hellip;. no matter which side you fall on you can get both in Postgres. With hstore and &lt;a href="http://code.google.com/p/plv8js/wiki/PLV8">PLV8&lt;/a> you&amp;rsquo;ll get the flexibility in your data that you would with Mongo along with all of the above features. &lt;a href="http://www.twitter.com/leinweber">Will Leinweber&lt;/a> has a talk that he&amp;rsquo;s given at several conferences recently that highlights &lt;a href="http://ssql-railsconf.herokuapp.com/">Schemaless SQL&lt;/a>.&lt;/p>
&lt;h2 id="custom-functions" >
&lt;div>
Custom Functions
&lt;/div>
&lt;/h2>
&lt;p>Didn&amp;rsquo;t find the function you wanted in the above? Try creating it yourself:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> CREATE FUNCTION awesomeness&lt;span style="color:#f92672">(&lt;/span>varchar&lt;span style="color:#f92672">)&lt;/span> RETURNS boolean
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> AS &lt;span style="color:#e6db74">&amp;#39;CASE WHEN $1 == \&amp;#39;&lt;/span>postgres&lt;span style="color:#ae81ff">\&amp;#39;&lt;/span> THEN TRUE ELSE FALSE END;&lt;span style="color:#960050;background-color:#1e0010">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> LANGUAGE SQL
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> IMMUTABLE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RETURNS NULL ON NULL INPUT;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="common-table-expressions" >
&lt;div>
Common Table Expressions
&lt;/div>
&lt;/h2>
&lt;p>Often times when exploring data or creating a new view you&amp;rsquo;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. &lt;a href="http://www.postgresql.org/docs/8.4/static/queries-with.html">Common Table Expressions&lt;/a> let you accomplish just that.&lt;/p>
&lt;h2 id="development-pace" >
&lt;div>
Development Pace
&lt;/div>
&lt;/h2>
&lt;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 &lt;a href="http://en.wikipedia.org/wiki/PostgreSQL#Major_releases">Major Releases&lt;/a>.&lt;/p>
&lt;h2 id="conclusion" >
&lt;div>
Conclusion
&lt;/div>
&lt;/h2>
&lt;p>Hopefully you&amp;rsquo;re convinced on why Postgres is a great tool. Next take a visit to &lt;a href="http://www.postgresguide.com">PostgresGuide&lt;/a> if you need some direction on where to start or how to use many of the above features.&lt;/p>
&lt;p>&lt;em>If you&amp;rsquo;re looking for a deeper resource on Postgres I recommend the book &lt;a href="https://theartofpostgresql.com/?affiliate=cek">The Art of PostgreSQL&lt;/a>. It is by a personal friend that has aimed to create the definitive guide to Postgres, from a developer perspective. If you use code CRAIG15 you&amp;rsquo;ll receive 15% off as well.&lt;/em>&lt;/p></description></item><item><title>Apps to Services</title><link>/2012/04/13/Apps-to-Services/</link><pubDate>Fri, 13 Apr 2012 12:55:56 -0800</pubDate><guid>/2012/04/13/Apps-to-Services/</guid><description>&lt;p>&lt;em>Update the talk for this is now viewable on YouTube &lt;a href="http://www.youtube.com/watch?v=ztGpK-v2Oow">here&lt;/a>&lt;/em>&lt;/p>
&lt;p>When I first came across Django I was an immediate fan. It featured:&lt;/p>
&lt;ul>
&lt;li>Good documentation&lt;/li>
&lt;li>Steady but stable progress&lt;/li>
&lt;li>Community around apps which encouraged &lt;em>DRY&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>I&amp;rsquo;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&amp;rsquo;ve worked on and encountered more complex applications there&amp;rsquo;s one thing that has time and again broke down for me, which is the Django apps model. It hasn&amp;rsquo;t broken down due to Django only though, I&amp;rsquo;ve seen it break down in Ruby (Rails), Java, .Net, take you&amp;rsquo;re pick of language or framework.&lt;/p>
&lt;p>The breakdown of this model is due to several things:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;ul>
&lt;li>Successful applications grow which mean more complex applications and more developers&lt;/li>
&lt;li>More complex applications often mean larger code bases
&lt;ul>
&lt;li>Deprecating code is good, but not always easy in large code bases&lt;/li>
&lt;li>More code means more testing, but slower releases&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>At Heroku one way we often describe the platform to others is &lt;em>&amp;ldquo;A distributed Unix in the cloud.&amp;rdquo;&lt;/em> There may be many reasons for this, but one of which is that we love the Unix approach and philosophy of &lt;em>Small sharp tools&lt;/em>. Sticking to that, many of our internal pieces are small individual apps that talk across defined contracts or APIs.&lt;/p>
&lt;p>Back to Django&amp;rsquo;s app structure&amp;hellip; 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&amp;rsquo;t mean you should. This doesn&amp;rsquo;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.&lt;/p>
&lt;p>A Django app is defined as &lt;em>A web application that does something. I.e. Weblog, Poll, Ticket system&lt;/em>. Within Django an app contains:&lt;/p>
&lt;ul>
&lt;li>Models&lt;/li>
&lt;li>Views&lt;/li>
&lt;li>URLs&lt;/li>
&lt;/ul>
&lt;p>I couldn&amp;rsquo;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&amp;rsquo;d love to have a definition from a source other than myself). For the sake setting something in place I&amp;rsquo;m defining a service as &lt;em>Method of communication over the web with a provider using a defined contract&lt;/em>. By this definition a service contains:&lt;/p>
&lt;ul>
&lt;li>Provider&lt;/li>
&lt;li>Endpoint&lt;/li>
&lt;li>Contract&lt;/li>
&lt;/ul>
&lt;p>Let me clarify this a bit further&amp;hellip;&lt;/p>
&lt;p>Tangible example/parable:&lt;/p>
&lt;p>Django Apps::&lt;/p>
&lt;ul>
&lt;li>Ticket&lt;/li>
&lt;li>FAQ&lt;/li>
&lt;/ul>
&lt;p>Company Teams::&lt;/p>
&lt;ul>
&lt;li>Support&lt;/li>
&lt;li>Community Evangelist&lt;/li>
&lt;/ul>
&lt;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&amp;rsquo;s no finger to point, but more importantly, you don&amp;rsquo;t know how to contact to resolve. Neither team wants to deploy, so you test more. Before every deploy you run tests&amp;hellip; and validate a build&amp;hellip; and deployment slows&amp;hellip; 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?&lt;/p>
&lt;p>So within Django maybe you go from apps all in the same codebase to releasing private versions of apps&amp;hellip;&lt;/p>
&lt;p>Your requirements.txt for a main site looks like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>FAQ&lt;span style="color:#f92672">==&lt;/span>&lt;span style="color:#ae81ff">0.2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You have 3 apps which depend on it, support, marketing, billing. You bump a version &lt;code>FAQ==0.3&lt;/code> but then all three or no teams have to upgrade the version to the new APIs. However if your interface was:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>data &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>question&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>: &lt;span style="color:#960050;background-color:#1e0010">“&lt;/span>my question&lt;span style="color:#960050;background-color:#1e0010">”&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>source&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>: &lt;span style="color:#ae81ff">123&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>requests&lt;span style="color:#f92672">.&lt;/span>POST(os&lt;span style="color:#f92672">.&lt;/span>environ[&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>FAQ_API&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>&lt;span style="color:#f92672">/&lt;/span>v1&lt;span style="color:#f92672">/&lt;/span>create&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>, data&lt;span style="color:#f92672">=&lt;/span>data)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You could also have:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>data &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>question&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>: &lt;span style="color:#960050;background-color:#1e0010">“&lt;/span>my question&lt;span style="color:#960050;background-color:#1e0010">”&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>source&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>: &lt;span style="color:#ae81ff">123&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>related&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>: [&lt;span style="color:#ae81ff">456&lt;/span>, &lt;span style="color:#ae81ff">789&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>requests&lt;span style="color:#f92672">.&lt;/span>POST(os&lt;span style="color:#f92672">.&lt;/span>environ[&lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>FAQ_API&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">‘&lt;/span>&lt;span style="color:#f92672">/&lt;/span>v2&lt;span style="color:#f92672">/&lt;/span>create&lt;span style="color:#960050;background-color:#1e0010">’&lt;/span>, data&lt;span style="color:#f92672">=&lt;/span>data)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then you can easily support both, deprecate v1, and track its usage easily. This doesn&amp;rsquo;t guarantee, but it does enable &lt;em>re-usability&lt;/em>, &lt;em>scalability&lt;/em>, &lt;em>maintainability&lt;/em>. And of course continues to let you build features instead of maintaining software.&lt;/p>
&lt;p>In the next post I&amp;rsquo;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.&lt;/p>
&lt;p>&lt;em>Slides from a corresponding talk at DjangoCong are &lt;a href="http://bit.ly/djangocong">here&lt;/a>&lt;/em>&lt;/p></description></item><item><title>Sphinx Build Pack on Heroku</title><link>/2012/01/25/Sphinx-Build-Pack-on-Heroku/</link><pubDate>Wed, 25 Jan 2012 12:55:56 -0800</pubDate><guid>/2012/01/25/Sphinx-Build-Pack-on-Heroku/</guid><description>&lt;p>Heroku&amp;rsquo;s latest Cedar stack supports running anything. Heroku&amp;rsquo;s officially supported languages actually have their buildpacks public via &lt;a href="http://github.com/heroku/">Heroku&amp;rsquo;s github&lt;/a>, you can view several of them at:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/heroku/heroku-buildpack-python">Python Build Pack&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/heroku/heroku-buildpack-ruby">Ruby Build Pack&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/heroku/heroku-buildpack-scala">Scala Build Pack&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;em>There have even been some created as fun weekend hacks such as the &lt;a href="http://github.com/hone/heroku-buildpack-jsnes">NES Rom Buildpack&lt;/a>.&lt;/em>&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;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&amp;rsquo;re less familiar with is an overhead we were aiming to reduce. As a result we&amp;rsquo;ve tried a few things, the first was simply using a github repo to edit markdown.&lt;/p>
&lt;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 &lt;code>heroku config:add DOMAIN=mydomain.com&lt;/code>.&lt;/p>
&lt;p>&lt;em>If you need more information about setting up OpenID check out my recent post &lt;a href="/2012/01/23/securing-your-organization/">Securing your organization with OpenID &lt;/a>&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> $ sphinx-quickstart
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ git init .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ git add .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ git commit -m initial
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ heroku create -s cedar -b http://github.com/craigkerstiens/heroku-buildpack-sphinx.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ git push heroku master
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ heroku open
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Securing your Internal Organization with OpenID</title><link>/2012/01/23/Securing-your-Internal-Organization-with-OpenID/</link><pubDate>Mon, 23 Jan 2012 12:55:56 -0800</pubDate><guid>/2012/01/23/Securing-your-Internal-Organization-with-OpenID/</guid><description>&lt;p>I&amp;rsquo;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&amp;hellip; &lt;em>Google Apps&lt;/em>. I fully expect companies to use google apps, its more of the former that surprises me most. For a long time OpenID wasn&amp;rsquo;t at a usable point, even today it still isn&amp;rsquo;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&amp;rsquo;re used to using elsewhere.&lt;/p>
&lt;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&amp;rsquo;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&amp;rsquo;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.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;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?&lt;/p>
&lt;p>The problem comes in that OpenId with google has an initial setup overhead, but after that works unbelievably well.&lt;/p>
&lt;h2 id="the-catch" >
&lt;div>
The catch
&lt;/div>
&lt;/h2>
&lt;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:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;xrds:XRDS&lt;/span> &lt;span style="color:#a6e22e">xmlns:xrds=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;xri://$xrds&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">xmlns=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;xri://$xrd*($v*2.0)&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;XRD&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;Service&lt;/span> &lt;span style="color:#a6e22e">priority=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;0&amp;#34;&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;Type&amp;gt;&lt;/span>http://specs.openid.net/auth/2.0/signon&lt;span style="color:#f92672">&amp;lt;/Type&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;URI&amp;gt;&lt;/span>https://www.google.com/a/craigkerstiens.com/o8/ud?be=o8&lt;span style="color:#f92672">&amp;lt;/URI&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/Service&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;/XRD&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;lt;/xrds:XRDS&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>This is due to an issue of OpenID discovery which you can read more on at: &lt;a href="https://groups.google.com/group/google-federated-login-api/browse_thread/thread/4a7dd2312a47a082/9285cec18a30b9d3?lnk=gst&amp;amp;q=apps+discovery&amp;amp;pli=1#9285cec18a30b9d3">https://groups.google.com/group/google-federated-login-api/browse_thread/thread/4a7dd2312a47a082/9285cec18a30b9d3?lnk=gst&amp;amp;q=apps+discovery&amp;amp;pli=1#9285cec18a30b9d3&lt;/a>. In short, setting up the above can save you a lot of time&lt;/em>&lt;/p>
&lt;h2 id="setting-up-in-apps" >
&lt;div>
Setting up in apps
&lt;/div>
&lt;/h2>
&lt;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.&lt;/p>
&lt;h3 id="rails" >
&lt;div>
Rails
&lt;/div>
&lt;/h3>
&lt;p>In case your admin controller isn&amp;rsquo;t already generated:&lt;/p>
&lt;pre tabindex="0">&lt;code>rails g controller admin/users
&lt;/code>&lt;/pre>&lt;p>Then anything you want to secure:&lt;/p>
&lt;pre tabindex="0">&lt;code>module Admin
class UsersController &amp;lt; ApplicationController
before_filter :admin_required
def index
render :text =&amp;gt; &amp;#39;Hello from the admin panel!&amp;#39;
end
end
end
&lt;/code>&lt;/pre>&lt;h3 id="django" >
&lt;div>
Django
&lt;/div>
&lt;/h3>
&lt;p>Finally sync your database:&lt;/p>
&lt;pre tabindex="0">&lt;code>python yourapp/manage.py syncdb
&lt;/code>&lt;/pre>&lt;p>Secure any view with the &lt;code>login_required&lt;/code> decorator as your typically would with Django.&lt;/p>
&lt;h2 id="summary" >
&lt;div>
Summary
&lt;/div>
&lt;/h2>
&lt;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.&lt;/p></description></item><item><title>How Heroku Works - Hiring</title><link>/2011/12/02/How-Heroku-Works-Hiring/</link><pubDate>Fri, 02 Dec 2011 12:55:56 -0800</pubDate><guid>/2011/12/02/How-Heroku-Works-Hiring/</guid><description>&lt;p>I alluded in earlier posts of &lt;a href="http://www.craigkerstiens.com/2011/11/02/how-heroku-works-teams-tools/">How Heroku Works&lt;/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&amp;rsquo;re a fit within our organization.&lt;/p>
&lt;p>&lt;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).&lt;/em>&lt;/p>
&lt;p>So what&amp;rsquo;s our hiring process look like&amp;hellip;.&lt;/p>
&lt;ol>
&lt;li>&lt;!-- raw HTML omitted -->Review Resume/Github Profile&lt;!-- raw HTML omitted -->&lt;/li>
&lt;li>&lt;!-- raw HTML omitted -->Initial Screen&lt;!-- raw HTML omitted -->&lt;/li>
&lt;li>&lt;!-- raw HTML omitted -->Second Screen&lt;!-- raw HTML omitted -->&lt;/li>
&lt;li>&lt;!-- raw HTML omitted -->Starter Project&lt;!-- raw HTML omitted -->&lt;/li>
&lt;/ol>
&lt;p>While there&amp;rsquo;s definitely a process that we follow that&amp;rsquo;s not what&amp;rsquo;s interesting. We way too often get worried about the steps 1, 2, 3&amp;hellip; Instead you should focus on what&amp;rsquo;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&amp;rsquo;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.&lt;/p>
&lt;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 (&lt;em>not an HR person&lt;/em>). The hiring manager will be your manager once at Heroku it&amp;rsquo;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&amp;rsquo;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:&lt;/p>
&lt;p>&lt;img src="https://f.cl.ly/items/462y1J3G0L3q1f3v1o1U/hiring-1.png" alt="Hiring Manager = Manager">&lt;/p>
&lt;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.&lt;/p>
&lt;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&amp;rsquo;d like to work on. Sometimes there&amp;rsquo;s a pressing need that the candidate can jump right in and add some value. It&amp;rsquo;s &lt;strong>always&lt;/strong> important that the starter project is achievable, if it&amp;rsquo;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&amp;rsquo;s far more than an exercise on a white board, it&amp;rsquo;s actually what life is like at Heroku. We have lunch at the &lt;a href="http://www.flickr.com/photos/teich/4928103311/">same table&lt;/a> that we eat at every other day, we interact just as we normally would, and after work there may or may not &lt;a href="http://drunken-samurai-42.tumblr.com/">be drinks&lt;/a> just like any other day.&lt;/p>
&lt;p>&lt;em>As a slight aside, we even conduct starter projects when current Herokai move from one team to another&lt;/em>&lt;/p>
&lt;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&amp;rsquo;s a bit harder for all us to fit into one conference room, though there&amp;rsquo;s an open invite and anyone that wishes can sit in (often 10-20 Herokai). At the end of the starter project there&amp;rsquo;s no question that the candidate fits or doesn&amp;rsquo;t, often from both sides. Of course if it&amp;rsquo;s a fit we make an offer and welcome them into the family.&lt;/p></description></item><item><title>Getting Started with Django</title><link>/2011/11/12/Getting-Started-with-Django/</link><pubDate>Sat, 12 Nov 2011 19:55:56 -0800</pubDate><guid>/2011/11/12/Getting-Started-with-Django/</guid><description>&lt;p>For those completely new to web development, Django is a web framework that makes it easier to build web applications with Python. For those that have some knowledge of other web frameworks and Django you may be able to fly through much of the following. Django is a slight modification on the &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC&lt;/a> construct which views itself as a &lt;a href="https://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names">MVT&lt;/a> Model, View, Template. Django views a website as a project and within it smaller apps are contained.&lt;/p>
&lt;p>Earlier we installed Django into your virtual environment. If your environment is loaded we can get started with a Django project. First lets create the project:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>django-admin.py startproject myproject
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This should have created a directory for your project called myproject. Within the myproject folder you&amp;rsquo;ll find some core files to every Django project.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>myproject venv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls myproject
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>manage.py myproject
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls myproject/myproject
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>__init__.py settings.py urls.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Let&amp;rsquo;s examine a little of each of the files and what they&amp;rsquo;re used for:&lt;/p>
&lt;p>&lt;code>manage.py&lt;/code> - A management utility for interacting with your Django project. In addition to the default commands available which you see by running &lt;code>python manage.py&lt;/code>, you can create custom commands (we&amp;rsquo;ll get into that much later).
&lt;code>settings.py&lt;/code> - This is the settings file for your application. Here you&amp;rsquo;ll put various configuration and load things such as your database connection.
&lt;code>urls.py&lt;/code> - This is the place to setup how your urls will work. You&amp;rsquo;ll define a path for the url and then which code is to be executed when you visit that url.&lt;/p></description></item><item><title>Postgres... The death of NoSQL</title><link>/2011/11/08/Postgres...-The-death-of-NoSQL/</link><pubDate>Tue, 08 Nov 2011 12:55:56 -0800</pubDate><guid>/2011/11/08/Postgres...-The-death-of-NoSQL/</guid><description>&lt;p>NoSQL has long been a trend that many have talked about. While there&amp;rsquo;s a place for various key-value stores and tools such as memcache and redis, this will address most specifically how NoSQL is attempting to replace a traditional database. I&amp;rsquo;ve long been a fan of postgres and in general traditional relational databases. In a broad sense traditional databases offer multiple things.&lt;/p>
&lt;h2 id="rdms" >
&lt;div>
RDMS
&lt;/div>
&lt;/h2>
&lt;h3 id="data-guarantees" >
&lt;div>
Data guarantees
&lt;/div>
&lt;/h3>
&lt;p>The current major SQL databases (SQL Server, Postgres, MySQL, Oracle) offer guarantees around your data that doesn&amp;rsquo;t always exist with other systems. At a very high level this means when they say they have the data there&amp;rsquo;s not a chance they&amp;rsquo;ll loose it. When using something as a primary datastore this is always my first requirement. Data is a valuable commodity so keeping it around is obviously important. There are cases where exceptions exist (reporting applications are common here). The specific thing I always look for is that a system upholds the ACID properties. For a quick breakdown of these:&lt;/p>
&lt;ul>
&lt;li>&lt;em>A&lt;/em> is for atomic. In short it means no transaction can be partially completed, its all or nothing.&lt;/li>
&lt;li>&lt;em>C&lt;/em> is for consistent. This means you go from one consistent state to another. Meaning things like cascades and constraints are upheld and can&amp;rsquo;t be ignored for a period of time.&lt;/li>
&lt;li>&lt;em>I&lt;/em> is for isolation. This means transactions don&amp;rsquo;t get to interfere with each other.&lt;/li>
&lt;li>&lt;em>D&lt;/em> is for durability. This means once the transactions there its not going anywhere.&lt;/li>
&lt;/ul>
&lt;p>These basic principles make me feel pretty content with my data being safe. This doesn&amp;rsquo;t include things like backups and replication, but rather is a baseline for me feeling safe with a system.&lt;/p>
&lt;p>&lt;em>Here&amp;rsquo;s a hint, many NoSQL solutions don&amp;rsquo;t enforce these which is where they get speed from&lt;/em>&lt;/p>
&lt;h3 id="consistent-means-for-accessing-data-sql" >
&lt;div>
Consistent means for accessing data (SQL)
&lt;/div>
&lt;/h3>
&lt;p>Many people complain about SQL and while its not a perfect language it is a common standard for accessing data. There are idioms that exist in Oracle that do not in Postgres and ones that exist in MySQL that do not in SQL Server, but on the whole ANSI-SQL is a common standard. This means if you learn one in large part you learn another (from an application developers perspective). This means you have a broader people to pull from when you consider moving from one to another, and that skills are more portable. While Mongo may be growing, its in no way guaranteed to be around in 5 years, nor is CouchDB. In fact there have been many NoSQL databases that have come and gone:&lt;/p>
&lt;ul>
&lt;li>Tokyo Cabinent&lt;/li>
&lt;li>&lt;/li>
&lt;/ul>
&lt;h2 id="postgres" >
&lt;div>
Postgres
&lt;/div>
&lt;/h2>
&lt;p>So there&amp;rsquo;s some shared things that make databases great, but in particular Postgres aims to be the single database capable of ushering in a death to NoSQL. While each item could easily be its own blog post hopefully the following calls out they key values and allows people to dive in deeper.&lt;/p>
&lt;h3 id="hstore" >
&lt;div>
HStore
&lt;/div>
&lt;/h3>
&lt;p>I strongly debated saving the best for last, but really just couldn&amp;rsquo;t wait. If there&amp;rsquo;s a single feature in Postgres that will kill NoSQL its HStore. HStore is a data-type that allows you to store a dictionary within postgres.&lt;/p>
&lt;h3 id="custom-datatypes" >
&lt;div>
Custom datatypes
&lt;/div>
&lt;/h3>
&lt;h3 id="postgis" >
&lt;div>
PostGIS
&lt;/div>
&lt;/h3>
&lt;p>Location is all the buzz these days and more and more applications have some tough of location involved in them.&lt;/p></description></item><item><title>How Heroku Works - Maker's Day</title><link>/2011/11/07/how-heroku-works-maker-day/</link><pubDate>Mon, 07 Nov 2011 12:55:56 -0800</pubDate><guid>/2011/11/07/how-heroku-works-maker-day/</guid><description>&lt;p>In my earlier post on &lt;a href="/2011/11/02/how-heroku-works-teams-tools/">Teams and Tools at Heroku&lt;/a>, I mentioned how we value engineers&amp;rsquo; time; their work has enabled us to build a great platform. As a result of what we&amp;rsquo;ve built, we&amp;rsquo;ve had great growth both of our platform and of our teams internally. With that growth inevitably comes different distractions on engineers&amp;rsquo; 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&amp;rsquo;s Day.&lt;/p>
&lt;p>&lt;em>Maker&amp;rsquo;s Day ensures that engineers get a full day of uninterrupted time to focus on making things.&lt;/em>&lt;/p>
&lt;p>&lt;img src="/images/makerday.png" alt="Maker&amp;rsquo;s Day">&lt;/p>
&lt;p>The more consistent interruptions are throughout an engineer&amp;rsquo;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 &lt;a href="http://www.amazon.com/gp/product/0932633439/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=mypred-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0932633439">Peopleware: Productive Projects and Teams&lt;/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:&lt;/p>
&lt;p>&lt;img src="/images/contextswitch.png" alt="Cost of context switching">&lt;/p>
&lt;p>For more on how interruptions or context switching decreases productivity, Jeff Atwood has a great post about &lt;a href="http://www.codinghorror.com/blog/2006/09/the-multi-tasking-myth.html">The Multi-Tasking Myth&lt;/a>, which demonstrates &amp;hellip;&lt;/p>
&lt;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&amp;rsquo;t always feasible; after all, we do work together, and each team at times may need something from another team. This is where Maker&amp;rsquo;s Day starts to come in. Every Thursday at Heroku is Maker&amp;rsquo;s Day.&lt;/p>
&lt;p>&lt;strong>Maker&amp;rsquo;s day is meant for making shit. Meetings don&amp;rsquo;t happen on Maker&amp;rsquo;s Day&lt;/strong>. If someone asks if that time on your calendar works for a meeting, the simple response is no&amp;ndash;it&amp;rsquo;s Maker&amp;rsquo;s Day. Because Maker&amp;rsquo;s Day has been ingrained into our culture, engineers have no problem giving that response when there&amp;rsquo;s a request on their time on Maker&amp;rsquo;s Day. If someone in marketing, sales, or another non-engineering role wants to book meetings, they’re welcome to do so, but they&amp;rsquo;re going to be without engineers. However, even for non-engineers, Maker&amp;rsquo;s Day is equally invaluable; uninterrupted hours of focus at a time are amazing for productivity in any role.&lt;/p>
&lt;p>Maker&amp;rsquo;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&amp;rsquo;t be pulled into meetings that distract you from features, and you know it&amp;rsquo;s an opportunity to accomplish a bulk of work laid out from your weekly planning meeting.&lt;/p>
&lt;p>As Heroku has grown, meetings have increased, and the value of Maker Day&amp;rsquo;s has increased exponentially.&lt;/p>
&lt;p>Whether you&amp;rsquo;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&amp;rsquo;s Day is a fantastic way to ensure this happens on a weekly basis.&lt;/p></description></item><item><title>How Heroku Works - Teams and Tools</title><link>/2011/11/02/how-heroku-works-teams-tools/</link><pubDate>Wed, 02 Nov 2011 12:55:56 -0800</pubDate><guid>/2011/11/02/how-heroku-works-teams-tools/</guid><description>&lt;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&amp;rsquo;s many valuable insights into how Heroku runs efficiently for engineering.&lt;/p>
&lt;p>I&amp;rsquo;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.&lt;/p>
&lt;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 &lt;a href="http://www.amazon.com/gp/product/0131429019/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;tag=mypred-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0131429019">as in The Art of Unix Programming&lt;/a> applied to teams and people.&lt;/p>
&lt;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 &lt;!-- raw HTML omitted -->very&lt;!-- raw HTML omitted --> important to note that planning tasks for the week doesn&amp;rsquo;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 &lt;a href="http://www.pivotaltracker.com">pivotal tracker&lt;/a>, one uses &lt;a href="http://www.scrumy.com">scrumy&lt;/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 &lt;a href="http://www.github.com">github&lt;/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.&lt;/p>
&lt;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.&lt;/p>
&lt;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 &lt;a href="http://typewith.me/">typewith.me&lt;/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 &lt;a href="http://campfirenow.com/">campfire&lt;/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.&lt;/p>
&lt;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&amp;rsquo;t commonly interact with. Along with common status updates there will be broader company updates.&lt;/p>
&lt;p>Consistently across all teams you&amp;rsquo;ll find these principles which allow us to ensure the quality of engineering as we continue to grow:&lt;/p>
&lt;ul>
&lt;li>Small teams that talk across defined API&amp;rsquo;s and data contracts&lt;/li>
&lt;li>Teams using the tool that they believe is best for the job&lt;/li>
&lt;li>Frequent asynchronous communication&lt;/li>
&lt;li>Collaboration (including for remote employees)&lt;/li>
&lt;/ul>
&lt;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.&lt;/p></description></item><item><title>Installing Python Packages</title><link>/2011/11/01/Installing-Python-Packages/</link><pubDate>Tue, 01 Nov 2011 12:55:56 -0800</pubDate><guid>/2011/11/01/Installing-Python-Packages/</guid><description>&lt;p>Now that you have you system and project environment all setup you probably want to start developing. But you likely don&amp;rsquo;t want to start writing an entire project fully from scratch, as you dive in you&amp;rsquo;ll quickly realize theres many tools helping you build projects and sites faster. For example making a request to a website there&amp;rsquo;s &lt;a href="http://docs.python-requests.org/en/latest/index.html">Requests&lt;/a>, for handling processing images there&amp;rsquo;s &lt;a href="http://www.pythonware.com/products/pil/">Python Imaging Library&lt;/a>, or for a full framework to help you in building a site there&amp;rsquo;s &lt;a href="http://www.djangoproject.com">Django&lt;/a>. With all of these there&amp;rsquo;s one simple and common way to install them. But first a little more on how it all works.&lt;/p>
&lt;p>All major Python packages are hosted on &lt;a href="http://pypi.python.org/">PyPi&lt;/a> (Pronounced Pi-P or Cheeseshop). When you use a common python installer it will:&lt;/p>
&lt;ol>
&lt;li>Search for the package you specify&lt;/li>
&lt;li>If you specify a version will use it, otherwise will use the latest&lt;/li>
&lt;li>Will download the source for that package&lt;/li>
&lt;li>Install it into your Python environment&lt;/li>
&lt;/ol>
&lt;p>Now for actually installing&amp;hellip; Lets get started with installing the three packages below. At this point you should at least have a fresh Python environment, however you don&amp;rsquo;t have an immediate way to install packages. The defacto Python package installer is &lt;a href="http://pip-installer.org">pip&lt;/a>.&lt;/p>
&lt;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&amp;rsquo;ll work on:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir myapp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd myapp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ virtualenv --no-site-packages venv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we list the contents of the directory you&amp;rsquo;ll now see a folder venv. Within this folder you&amp;rsquo;ll find all the parts of the environment that virtualenv just created:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>venv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls venv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bin include lib
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now you&amp;rsquo;ve got a sandboxed environment that exists but you haven&amp;rsquo;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&amp;rsquo;ve installed for this environment. To load your environment when in the myapp directory:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ source venv/bin/activate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To deactivate this simple:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ deactivate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now that we&amp;rsquo;ve got your environment loaded installing your packages should be pretty simple. Ensure that you have your virtualenv loaded and then run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ pip install requests
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ pip install PIL
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ pip install Django
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now that you&amp;rsquo;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:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ pip freeze
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;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.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ pip freeze &amp;gt; requirements.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next we&amp;rsquo;ll talk about a few more advanced items in dependency management, then finally we&amp;rsquo;ll get started on building an application.&lt;/p></description></item><item><title>Getting Setup with Python</title><link>/2011/10/27/Getting-Setup-with-Python/</link><pubDate>Thu, 27 Oct 2011 19:55:56 -0800</pubDate><guid>/2011/10/27/Getting-Setup-with-Python/</guid><description>&lt;p>This is the first of a multipart series to getting started with Python. Throughout this guide we&amp;rsquo;ll walk you through a full setup. For starters if you&amp;rsquo;re a mac or linux user you already have &lt;a href="http://python.org">Python&lt;/a> on your system. You should be able to confirm you have python my opening up a terminal window and running:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Python 2.7.2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As long as you see a Python version 2.5.x-2.7.x you should be fine to continue. From here we&amp;rsquo;re going to work through setting up your Python project environment. For this we&amp;rsquo;re going to use &lt;a href="http://virtualenv.org">virtualenv&lt;/a>. For those of you not familiar &lt;a href="http://virtualenv.org">virtualenv&lt;/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.&lt;/p>
&lt;p>While we&amp;rsquo;re installing virtualenv we&amp;rsquo;re also going to go ahead and setup PostgreSQL as we&amp;rsquo;ll be using it later. If you&amp;rsquo;re on a mac you&amp;rsquo;ll first need to setup homebrew. Homebrew is used for installing various system packages. If you&amp;rsquo;re on linux, in particular Ubuntu you can skip down to the steps for setting up your environment.&lt;/p>
&lt;p>First for Mac users lets setup homebrew which will allow us to install various system packages:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ /usr/bin/ruby -e &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#66d9ef">$(&lt;/span>curl -fsSL https://raw.github.com/gist/323731&lt;span style="color:#66d9ef">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- raw HTML omitted -->
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;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
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ easy_install virtualenv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ brew install postgresql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- raw HTML omitted -->
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo apt-get install virtualenv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo apt-get install postgresql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now you have Python, virtualenv, and postgresql all installed. We can now focus on setting up the initial start to a project.&lt;/p>
&lt;p>In the next part we can start with installing some Python packages.&lt;/p></description></item><item><title>Environment Structure for Django Apps</title><link>/2011/05/16/Environment-Structure-for-Django-Apps/</link><pubDate>Mon, 16 May 2011 19:55:56 -0800</pubDate><guid>/2011/05/16/Environment-Structure-for-Django-Apps/</guid><description>&lt;p>I&amp;rsquo;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 &amp;ldquo;The Web framework for perfectionists with deadlines&amp;rdquo;. Among the things I love about it are:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>However, after using the framework for nearly 4 years I&amp;rsquo;m just now discovering my preferred way of managing environments. I know there&amp;rsquo;s still a bit of back and forth on development environment/IDE, but as far as configuring actual project environment I&amp;rsquo;ve become very comfortable with what I&amp;rsquo;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.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo port install python27
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo port install py27-virtualenv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo port install postgresql90
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now for setting up your project:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ virtualenv-2.7 --no-site-packages .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ source bin/activate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- raw HTML omitted -->
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo brew install python
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo brew install virtualenv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo brew install postgresql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now for setting up your project:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ virtualenv --no-site-packages .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ source bin/activate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;!-- raw HTML omitted -->
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo aptitude install python
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo aptitude install virtualenv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo aptitude install postgresql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now for setting up your project:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd example
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ virtualenv --no-site-packages .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ source bin/activate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;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&amp;rsquo;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:&lt;/p>
&lt;p>Add to a .gitignore file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>bin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>build
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>include
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>lib
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.Python
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*.pyc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Add to a requirements.txt file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>Django&lt;span style="color:#f92672">==&lt;/span>1.3.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>psycopg2&lt;span style="color:#f92672">==&lt;/span>2.4.1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ bin/pip install -r requirements.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;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:&lt;/p>
&lt;pre>&lt;code>$ git init
$ git add .
$ git commit -m 'my first django virtualenv'
&lt;/code>&lt;/pre></description></item><item><title>Attribution 101</title><link>/2011/03/18/Attribution-101/</link><pubDate>Fri, 18 Mar 2011 19:55:56 -0800</pubDate><guid>/2011/03/18/Attribution-101/</guid><description>&lt;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.&lt;/p>
&lt;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:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Its really wonderful when there&amp;rsquo;s a direct mapping in correlation. Take for example the case where:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p> &lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->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.&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>Startup/Bootstrapped Marketing Recap</title><link>/2011/03/07/Startup/Bootstrapped-Marketing-Recap/</link><pubDate>Mon, 07 Mar 2011 19:55:56 -0800</pubDate><guid>/2011/03/07/Startup/Bootstrapped-Marketing-Recap/</guid><description>&lt;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&amp;rsquo;re short on time and want the high level summary here&amp;rsquo;s the quick recap:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->Part 1 - Focus on SEO&lt;!-- raw HTML omitted -->&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Reading Metrics to Evaluate Marketing</title><link>/2011/03/02/Reading-Metrics-to-Evaluate-Marketing/</link><pubDate>Wed, 02 Mar 2011 19:55:56 -0800</pubDate><guid>/2011/03/02/Reading-Metrics-to-Evaluate-Marketing/</guid><description>&lt;p>A short while backed I talked about &lt;!-- raw HTML omitted -->tactically measuring metrics&lt;!-- raw HTML omitted --> for your site/company. Recently I talked a bit about &lt;!-- raw HTML omitted -->methods of marketing&lt;!-- raw HTML omitted -->. 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&amp;rsquo;m going to make the assumption you&amp;rsquo;ve read those posts, if you haven&amp;rsquo;t go back and do that. Next this is heavily on the assumption that you&amp;rsquo;re using Google Analytics as your primary tool for measuring metrics and have setup goals appropriately.&lt;/p>
&lt;p>Within measuring you&amp;rsquo;re metrics you&amp;rsquo;ll have abandonment at each level. You may have some visitors that never register, and many that register but never purchase anything. It&amp;rsquo;s wonderful if you&amp;rsquo;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.&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Acquisition -&amp;gt; Activation&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;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&amp;rsquo;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&amp;rsquo;ve created a custom report in google.&lt;/p>
&lt;p>To create your own custom report simply click Manage Custom Reports under the Custom Reports area then &amp;ldquo;Create new custom report&amp;rdquo;. 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&amp;rsquo;d create something that looks like:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>Here while very simple we&amp;rsquo;re able to see some very key information quickly. Here&amp;rsquo;s an example of how it would appear over a few day period:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p> &lt;/p>
&lt;p>As you progress in your stage of bootstrapping or growing your startup you&amp;rsquo;ll want to grow custom reports that allow you to report against as many &lt;!-- raw HTML omitted -->metrics&lt;!-- raw HTML omitted --> 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.&lt;/p></description></item><item><title>Setting up Goals and Funnels - Google Analytics</title><link>/2011/02/28/Setting-up-Goals-and-Funnels-Google-Analytics/</link><pubDate>Mon, 28 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/28/Setting-up-Goals-and-Funnels-Google-Analytics/</guid><description>&lt;p>I had a recent request on how to setup a funnel in Google Analytics. If you&amp;rsquo;ve missed by first post on some tips for &lt;!-- raw HTML omitted -->Google Analytics&lt;!-- raw HTML omitted --> 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&amp;rsquo;ll want to &lt;!-- raw HTML omitted -->fake a page view&lt;!-- raw HTML omitted --> instead of an event in order to entirely use it in funnels and goals.&lt;/p>
&lt;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 &lt;!-- raw HTML omitted -->Registry Stop&lt;!-- raw HTML omitted --> we&amp;rsquo;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.&lt;/p>
&lt;p>A key to getting the most use out of your funnels is to know that there is a &lt;!-- raw HTML omitted -->workflow to follow&lt;!-- raw HTML omitted --> to getting to that end goal. To highlight this slightly more visually let me walk through an example:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>The parts of your funnel will be:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;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 &lt;!-- raw HTML omitted -->Registry Stop&lt;!-- raw HTML omitted --> 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:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;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.&lt;/p>
&lt;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:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>This results in a funnel report that looks like:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p> &lt;/p></description></item><item><title>Evaluating Paying for a Blog Post</title><link>/2011/02/25/Evaluating-Paying-for-a-Blog-Post/</link><pubDate>Fri, 25 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/25/Evaluating-Paying-for-a-Blog-Post/</guid><description>&lt;p>At a recent meetup I talked a bit about how I&amp;rsquo;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&amp;rsquo;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.&lt;/p>
&lt;p>In contrast the wedding industry is very much a pay to play space. If you give some money you can get some attention.&lt;/p>
&lt;p>First things first, contact the blog you&amp;rsquo;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&amp;rsquo;t always the case, if you&amp;rsquo;ve noticed posts on their blog that have been sponsored posts but pricing isn&amp;rsquo;t called out in their blog then email them explicitly and inquire.&lt;/p>
&lt;p>Once you&amp;rsquo;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&amp;rsquo;re outright lying on your stats, or that you&amp;rsquo;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&amp;rsquo;m checking only the primary. Regardless, if you&amp;rsquo;re numbers aren&amp;rsquo;t close, it often means you&amp;rsquo;re not as together as we&amp;rsquo;d like.&lt;/p>
&lt;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&amp;rsquo;s a big factor, unique visitors are important as well as page views. Next we&amp;rsquo;ll typically look for how active your users are. Do users actively engage in comments, where there are active commenters there&amp;rsquo;s usually opportunity to get a bit more out of your post.&lt;/p>
&lt;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&amp;rsquo;ve historically done this on a subjective basis, but it could easily be a number that is calculated and factored in.&lt;/p>
&lt;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&amp;rsquo;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.&lt;/p>
&lt;p>A quick recap of the basic formula:&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>JQuery and Django Autocomplete</title><link>/2011/02/25/JQuery-and-Django-Autocomplete/</link><pubDate>Fri, 25 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/25/JQuery-and-Django-Autocomplete/</guid><description>&lt;p>In a couple of various places I&amp;rsquo;ve seen light requests of how to put autocomplete in for a Django web application. Here&amp;rsquo;s a really light weight version with a view and autocomplete functionality using:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> django.utils &lt;span style="color:#f92672">import&lt;/span> simplejson
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">autocompleteModel&lt;/span>(request):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> search_qs &lt;span style="color:#f92672">=&lt;/span> ModelName&lt;span style="color:#f92672">.&lt;/span>objects&lt;span style="color:#f92672">.&lt;/span>filter(name__startswith&lt;span style="color:#f92672">=&lt;/span>request&lt;span style="color:#f92672">.&lt;/span>REQUEST[&lt;span style="color:#e6db74">&amp;#39;search&amp;#39;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> results &lt;span style="color:#f92672">=&lt;/span> []
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> r &lt;span style="color:#f92672">in&lt;/span> search_qs:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> results&lt;span style="color:#f92672">.&lt;/span>append(r&lt;span style="color:#f92672">.&lt;/span>name)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> resp &lt;span style="color:#f92672">=&lt;/span> request&lt;span style="color:#f92672">.&lt;/span>REQUEST[&lt;span style="color:#e6db74">&amp;#39;callback&amp;#39;&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#39;(&amp;#39;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> simplejson&lt;span style="color:#f92672">.&lt;/span>dumps(result) &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#39;);&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> HttpResponse(resp, content_type&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;application/json&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For the jQuery autocomplete and call:&lt;/p></description></item><item><title>Bootstrapped/Startup Marketing Part 4</title><link>/2011/02/22/Bootstrapped/Startup-Marketing-Part-4/</link><pubDate>Tue, 22 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/22/Bootstrapped/Startup-Marketing-Part-4/</guid><description>&lt;p>We&amp;rsquo;ve talked some about &lt;!-- raw HTML omitted -->SEO&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->media/blog posts&lt;!-- raw HTML omitted -->, 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&amp;rsquo;t checked out the post on &lt;!-- raw HTML omitted -->tactically measuring metrics&lt;!-- raw HTML omitted --> 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&amp;rsquo;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.&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Retargetting&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
Retargetting is the idea of showing an ad to a user that has already visited your site. It&amp;rsquo;s pretty basic, someone comes to your site and you have a pixel that loads telling your ad network they&amp;rsquo;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&amp;rsquo;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.&lt;/p>
&lt;p>How do you do retargetting? Sounds like a complicated process slightly&amp;hellip; Well it&amp;rsquo;s simple you don&amp;rsquo;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&amp;rsquo;ll want are:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;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&amp;rsquo;ll get some confidence that you&amp;rsquo;re a real online brand with a presence.&lt;/p></description></item><item><title>Bootstrapped/Startup Marketing Part 3</title><link>/2011/02/18/Bootstrapped/Startup-Marketing-Part-3/</link><pubDate>Fri, 18 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/18/Bootstrapped/Startup-Marketing-Part-3/</guid><description>&lt;p>For this third part on the series I&amp;rsquo;m going to dive into what people perhaps most traditionally think of with marketing startups, online advertising. Online advertising can work, but its definitely not cheap and it does take a good about of pounding at it to know what works. I&amp;rsquo;m going to break up the three key types of advertising, based on the way I&amp;rsquo;ve utilized them and evaluated them recently.&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Contextual&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
The first is search advertising, or contextual. The biggest usage of this has of course most recently been with google AdWords. For the complete novices out there, this is where you&amp;rsquo;re ad would appear as text based on certain search keywords. You&amp;rsquo;re the one that is able to determine the keywords, though google does rank you for relevance and how much you are willing to pay respective of the other person bidding on the same keywords.&lt;/p>
&lt;p>For a startup I&amp;rsquo;d very strongly discourage advertising for keywords you already appear as the first result. A part of this goes back to &lt;!-- raw HTML omitted -->part one of the series&lt;!-- raw HTML omitted -->, SEO doesn&amp;rsquo;t cost you anything other than time, so invest in it. If you&amp;rsquo;re already at the top of the results, why potentially pay $2 for a click, when you&amp;rsquo;re already there. With limited budget you want to be very selective about which keywords you target. In our experiences the best targetting can be with regards to your competitors or similar products. Also take advantage of google&amp;rsquo;s tools here. There are many tools within adwords that will suggest new keywords, rank your relevance, and show traffic to certain keywords.&lt;/p>
&lt;p>Always remember, &lt;!-- raw HTML omitted -->what you really want is conversion&lt;!-- raw HTML omitted -->, so make sure that&amp;rsquo;s what you&amp;rsquo;re tracking against performance. The key to doing this is linking your Google AdWords account to your Google Analytics. Google mentions in several places you should do this, but is very light on the instructions of how. So for a really quick how to:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>We followed a rather structured process to identify what worked. If there&amp;rsquo;s enough interest in this specifically I&amp;rsquo;ll do a full follow up post later but the high level steps:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Vertical&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
Most people term this display advertising, display is typically a banner/image ad going up on some website. I prefer viewing it as vertical, because if you target your display advertising correctly on sites you want to be on, its definitely more targetted than a standard billboard. Google does have some options for display advertising, but I&amp;rsquo;ve found their image approval process very painful.&lt;/p>
&lt;p>With display or vertical advertising there&amp;rsquo;s a few key&amp;rsquo;s I&amp;rsquo;ve found valuable:&lt;/p>
&lt;ol>
&lt;li>Image approval process matters as you dont have multiple weeks to spare&lt;/li>
&lt;li>The ability to target/select your sites is an obvious must&lt;/li>
&lt;li>Filtering out MFA (Made for Adsense) sites in the case you do open it up slightly by site type&lt;/li>
&lt;/ol>
&lt;p>On the third item theres two ways of doing this, you can manually check daily in google, and exclude sites. What you&amp;rsquo;re looking for here is sites with &amp;lt; 100 impressions and abnormally high click through rates. The other option for managing and tweaking these vertical campaigns is to let someone else do much of the optimization. My recent favorite for this is &lt;!-- raw HTML omitted -->AdRoll&lt;!-- raw HTML omitted -->. There&amp;rsquo;s definitely a slight premium over going directly to google, but they do let you easily get your campaign running and very much help optimize.&lt;/p></description></item><item><title>Bootstrapped/Startup Marketing Part 2</title><link>/2011/02/16/Bootstrapped/Startup-Marketing-Part-2/</link><pubDate>Wed, 16 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/16/Bootstrapped/Startup-Marketing-Part-2/</guid><description>&lt;p>For the second part of the series we&amp;rsquo;re going talk a bit about finding the influencers in certain industries. We&amp;rsquo;ll get to more traditional means that people think of later, and if you&amp;rsquo;ve missed our first post that dealt mostly with SEO make sure you check it out first. In most online ventures there&amp;rsquo;s a key set of influencers, often times these are blogs or podcasts. Blogs can receive a huge readership, which are often very loyal.&lt;/p>
&lt;p>The first step to taking advantage of this is obviously finding the correct blogs. As a byproduct of being in the valley I spend plenty of time reading Techcrunch among many other blogs. While a post on Techcrunch might result in massive traffic spike, or some moderate feedback, its definitely not in our target demographic. If our goal was investors then Techcrunch might be viable, but here we&amp;rsquo;re talking about marketing and marketing to core users at that. The blogs for your core demographic should be pretty straight forward and you can find them through google or other basic means.&lt;/p>
&lt;p>The hard part might be once you&amp;rsquo;ve found them, how do you get on them. The first thing to do is work on networking with them if at all possible. If you&amp;rsquo;re in the same area as bloggers try seeing if they typically attend certain meetups or go one step further and simply organize a meetup or tweetup yourself. Or simply network, find others in your space that can make in intro. Hands down a first person intro will work better than any other method.&lt;/p>
&lt;p>If for whatever reason networking and getting directly in touch doesnt work (which can often be the case). You can always resort to cold emailing them. This can work. There&amp;rsquo;s a few keys to this approach though:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>The next step will bleed a bit more into the next post in this series, but here&amp;rsquo;s a small preview: Advertise to your influencers, not your users. If you have a limited ad budget, don&amp;rsquo;t advertise to your target user. Advertise to the influencer of your target user. We&amp;rsquo;ll get into more detail on this in the next post but a quick example:&lt;/p>
&lt;p>If you&amp;rsquo;re building a sports site, why advertise on facebook for people who like sports &lt;!-- raw HTML omitted -->when&lt;!-- raw HTML omitted --> you could advertise to someone that works on espon.com. If the latter notices you and see&amp;rsquo;s interest they could potentially write you up or refer you to people that might be of interest.&lt;/p></description></item><item><title>Bootstrapped/Startup Marketing Part 1</title><link>/2011/02/14/Bootstrapped/Startup-Marketing-Part-1/</link><pubDate>Mon, 14 Feb 2011 19:55:56 -0800</pubDate><guid>/2011/02/14/Bootstrapped/Startup-Marketing-Part-1/</guid><description>&lt;p>This is the first of a 4 part series on marketing for startups/bootstrapped companies. Much of the learnings from this are a result of experiences with Registry Stop. The key to each of these is going to be measuring and reacting to your efforts. If you need help on this, check out previous post around metrics for startups.&lt;/p>
&lt;p>So without further adieu, on this initial post of the series we&amp;rsquo;re going to talk a bit about the biggest free way to get traction and traffic for your startup. The best way to aquire free traffic to your site, is to ensure your site is optimized for search engines or more commonly &lt;!-- raw HTML omitted -->SEO&lt;!-- raw HTML omitted -->. Sure you can pay $3 for your ad to show up on certain keywords, but why spend the $3 per click if you can simply ensure you&amp;rsquo;re the first search result. There are slightly different methods for this for each search engine, but we&amp;rsquo;ll cover a broad set of items to pay attention to.&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Sitemap&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
Most sites have a sitemap.xml at their root level. This could perhaps be one of the biggest pieces of getting indexed that you can pay attention to. This xml tells search engines what pages they should index, how frequently they are updated, and the priority of the page. If you have dynamic pages, you should have this sitemap.xml generated so that it captures all pages.&lt;/p>
&lt;p>If you need a little more reading on creating your sitemap take a look at:
&lt;!-- raw HTML omitted --> &lt;a href="http://www.google.com/support/webmasters/bin/answer.py?answer=183668">http://www.google.com/support/webmasters/bin/answer.py?answer=183668&lt;/a>&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Meta Tags&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
Many search engines pay little attention to these tags, but that doesn&amp;rsquo;t mean that all don&amp;rsquo;t. You do want these tags to be as unique as possible per page and relate as much as possible to the content. The really key meta tags you want to have would be your description and your keywords. For a little more information you can check out:
&lt;!-- raw HTML omitted --> &lt;a href="http://searchenginewatch.com/2167931">http://searchenginewatch.com/2167931&lt;/a>&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Other Tags&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
While meta tags make pretty straight forward sense, other tags are immensly powerful in how a search engine indexes your site. The first is the title tag, you absolutely want it in &lt;!-- raw HTML omitted -->and&lt;!-- raw HTML omitted --> want it to be &lt;!-- raw HTML omitted -->unique&lt;!-- raw HTML omitted --> per page. You also want to correctly use html markup throughout your page. Just because your page looks like you want, doesn&amp;rsquo;t mean a search engine will understand it the same way. It&amp;rsquo;s important to use proper headings, including h1, h2, h3, to show just that, your headings and importance. You also want to be careful about the use of tables when not representing tabular data.&lt;/p>
&lt;p>Once your page is live, you&amp;rsquo;ll want to submit it to google and other search engines. &lt;!-- raw HTML omitted -->Do Not&lt;!-- raw HTML omitted --> use a tool to do this, submit to the major search engines manually. Once you&amp;rsquo;ve done this you&amp;rsquo;ll start to appear in search results. The key from here is to begin monitoring what users are searching for, from within google analytics, and when they visit your site.
A few key links to submit and manage your sites, as well as evaluate how you&amp;rsquo;re doing include:&lt;/p>
&lt;ul>
&lt;li>&lt;!-- raw HTML omitted --> &lt;a href="https://www.google.com/webmasters/tools/home?hl=en">https://www.google.com/webmasters/tools/home?hl=en&lt;/a>&lt;!-- raw HTML omitted -->&lt;/li>
&lt;li>&lt;!-- raw HTML omitted --> &lt;a href="http://siteexplorer.search.yahoo.com/">http://siteexplorer.search.yahoo.com/&lt;/a>&lt;!-- raw HTML omitted -->&lt;/li>
&lt;li>&lt;!-- raw HTML omitted --> &lt;a href="http://websitegrader.com/">http://websitegrader.com/&lt;/a>&lt;!-- raw HTML omitted -->&lt;/li>
&lt;/ul></description></item><item><title>Requirements Gathering for Consumer Startups</title><link>/2011/02/08/Requirements-Gathering-for-Consumer-Startups/</link><pubDate>Tue, 08 Feb 2011 06:49:20 -0800</pubDate><guid>/2011/02/08/Requirements-Gathering-for-Consumer-Startups/</guid><description>&lt;p>Most all development projects start with a hunch at a problem. Seldom do you have the opportunity of enough resources prior beginning building to fully vet all assumptions and define all requirements. Or at the very least if you do, you&amp;rsquo;re not in startup mode. For this reason the very first thing you build is often not the perfect solution. If you&amp;rsquo;re lucky its a start at a solution, and even if its not, if you&amp;rsquo;re close users will tell you what they want.&lt;/p>
&lt;p>What this leaves you with is a couple of key items. First is get to the minimum product you can to vet your idea. Most commonly known as Minimally Viable Product. This should be the minimum product you need to vet your idea, and add some form of value for users. Once you&amp;rsquo;ve created this, don&amp;rsquo;t refine, don&amp;rsquo;t keep iterating, &lt;!-- raw HTML omitted -->launch&lt;!-- raw HTML omitted -->. More time won&amp;rsquo;t let you perfectly solve the problem, getting it in front of users will help you solve things perfect.&lt;/p>
&lt;p>Second is make feedback simple. Often times support can be difficult, if its a form that requires 5 fields on your website forget it. If at all possible, provide multiple ways for users to give feedback. ALL ways should be simple for users. Email is great, because every user already has it. If it can be built on your website, great, but you should make registering as light as possible. Personally, I&amp;rsquo;m a big fan of &lt;!-- raw HTML omitted -->Get Satisfaction&lt;!-- raw HTML omitted -->. They give a great embeddable widget and provide a service that just simply works.&lt;/p>
&lt;p>Third, and perhaps most important: Listen to your users! When users start to give you feedback, that&amp;rsquo;s the best requirements you can receive. There&amp;rsquo;s a couple of pieces to this step. When users give you feedback, you want to acknowledge them. Give some recognition for giving feedback; respond as positively and supportively as possible. If at all possible to act on requests do it, it will set you apart from the typical services they use of never getting a response and never seeing a change.&lt;/p>
&lt;p>In short three key steps make for requirements gathering that trumps all else:&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>Tactical Steps for Startup Metrics</title><link>/2011/02/03/Tactical-Steps-for-Startup-Metrics/</link><pubDate>Thu, 03 Feb 2011 19:39:54 -0800</pubDate><guid>/2011/02/03/Tactical-Steps-for-Startup-Metrics/</guid><description>&lt;p>Metrics are obviously a very valuable area for start-ups, if you don&amp;rsquo;t believe in metrics and think you&amp;rsquo;re idea wins just because its great then you better start searching for your next day job. &lt;!-- raw HTML omitted -->Dave McClure&lt;!-- raw HTML omitted --> has done a great talk on start-ups several times over, you can check out a video and corresponding slide show at:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;a href="http://www.ustream.tv/recorded/5336115">http://www.ustream.tv/recorded/5336115&lt;/a>&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->&lt;a href="http://www.slideshare.net/dmc500hats/startup-metrics-for-pirates-long-version">http://www.slideshare.net/dmc500hats/startup-metrics-for-pirates-long-version&lt;/a>&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>And besides, it&amp;rsquo;s a pirates acronym, so it&amp;rsquo;s got to be great. But translating these from concept to actual technology metrics is also something that needs discussion. You can&amp;rsquo;t exactly say we&amp;rsquo;re going to use Google Analytics and let it magically tell you everything, furthermore all of the web developers out there talking about tweaks on Google Analytics do little to actually tell you what you need to know.&lt;/p>
&lt;p>To start with I&amp;rsquo;m going to lay out a few of the key features of Google Analytics, assuming it&amp;rsquo;s the key backbone for web analytics, and because it really is an amazing free tool.If you&amp;rsquo;re not familiar with google analytics go and explore before reading this, we&amp;rsquo;re going to skip right over the basics of what are visitors and traffic sources directly to what you need to use and customise to get valuable metrics for a start-up. Diving right in a few key items:&lt;/p>
&lt;p>Goals - These are custom items that you want to setup. What is a goal? Well that can be a bit abstract but it can be a specific page that was visited, time spent on the site, or a certain number of pages per visit.&lt;/p>
&lt;p>Events - Here you can start track events to any type of your liking. In most cases this can be some in page action, but the key here is to each event you can track a value. This starts to become useful if you want to track most shared content, most liked products, or other items. Typically those kinds of items might exist within your in-house database, but exposing it to Google Analytics gives you an extra level of reporting integration&lt;/p>
&lt;p>Custom Reporting - Google is great out of the box, if you feel like it just grazes the surface then you haven&amp;rsquo;t explored it. But in some cases it&amp;rsquo;s easier to create a custom report of data that you can&amp;rsquo;t get exactly to, or to get very quick insight into similar data.&lt;/p>
&lt;p>So this is a really high level, but how do you use each of the above to tie to actually implementing the metrics you care about? We&amp;rsquo;ll go through an example of how you track each of Dave McClure&amp;rsquo;s 5 key metrics based. For those of you not familiar with his metrics, please go to the above links and listen to his presentation first.&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>Events with Google Analytics and Tricking Pageviews</title><link>/2011/02/02/Events-with-Google-Analytics-and-Tricking-Pageviews/</link><pubDate>Wed, 02 Feb 2011 16:28:56 -0800</pubDate><guid>/2011/02/02/Events-with-Google-Analytics-and-Tricking-Pageviews/</guid><description>&lt;p>Google analytics is great out of the box, the basic tracking tag on every page will do a lot for you. Unfortunately most people never get beyond this. There are two key items with tracking that you can do that will let you get a bit further. There&amp;rsquo;s also plenty more on the reporting side, but we&amp;rsquo;ll get to some of that later. On the tracking side the first item is event tracking. This is perhaps most commonly used for tracking various Javascript events that occur during a visit, however it can also be a bit more flexible towards tracking values. A very simple example might be:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Or a real life example of this, might be on a FAQ screen, clicking the link to an anchored section of the page:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>But events by their sheer nature give a bit more flexibility with that value field. In the case of a user sending a message&lt;/p>
&lt;p>you might be able to track how many recipients it has, or any other numeric value you want to track.&lt;/p>
&lt;p>Events overall are great, but you&amp;rsquo;re limited to the set Google Analytics report to know whats happening with them. So much of Google Analytics is based around page views, fortunately Google makes it easy to entirely fake a page view. If you&amp;rsquo;re wondering why you&amp;rsquo;d care whether it&amp;rsquo;s a page view versus events, we&amp;rsquo;ll get to that in a later post. For now what&amp;rsquo;s important to know is that you can fake any page view with:
&lt;!-- raw HTML omitted -->_gaq.push([&amp;rsquo;_trackPageview&amp;rsquo;, &amp;lsquo;/somepagenamehere]);&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>While seemingly small tweaks and extra additions these two items will create massive value for what you can actually do with Google Analytics. Stayed tuned later for how you use these with the base Google Analytics to actually get the value.&lt;/p></description></item><item><title>Converting Bookmarklet to Chrome Extension</title><link>/2011/02/02/Converting-Bookmarklet-to-Chrome-Extension/</link><pubDate>Wed, 02 Feb 2011 00:34:49 -0800</pubDate><guid>/2011/02/02/Converting-Bookmarklet-to-Chrome-Extension/</guid><description>&lt;p>Google&amp;rsquo;s documentation is pretty good when it comes to how to create an extension that opens a full page and has large functionality. But if you&amp;rsquo;re more interested in transforming an existing bookmarklet into an extension there&amp;rsquo;s not great quality on it. The steps themselves are really quite simple. The big key that&amp;rsquo;s not heavily documented is creating a background html that creates an event listener. After the jump is a full sample that would then call your javascript to activate the bookmarklet:&lt;/p>
&lt;p>manifest.json&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>background.html&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.sendRequest(tab.id, {fun: &amp;ldquo;callBM&amp;rdquo;})
});
&amp;lt;/script&amp;gt;&lt;!-- raw HTML omitted -->
bm.js&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Selling Something New</title><link>/2010/12/27/Selling-Something-New/</link><pubDate>Mon, 27 Dec 2010 17:04:50 -0800</pubDate><guid>/2010/12/27/Selling-Something-New/</guid><description>&lt;p>I have a tendency of really latching onto very simple ideas. Typically these ideas don&amp;rsquo;t require complex engineering to make them happen. This is not to say the engineering is not important, but more so that it is some variation of engineering feats that have been done before. The reason I tend to like these over more complex engineering that really makes something better is that making something better is typically a marginal improvement. When it&amp;rsquo;s a marginal improvement it&amp;rsquo;s a lot harder to sell.&lt;/p>
&lt;p>With marginal improvements you have to:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>In contrast if I address a problem that hasn&amp;rsquo;t been solved my life instantly becomes a lot easier. I no longer have an argument of something not being good enough today, it becomes a question of value and how much its worth to solve the problem. Haggling over price is a conversation I&amp;rsquo;d rather have than trying to justify value and convince a customer they&amp;rsquo;ve been wrong in their choice for so many years.&lt;/p></description></item><item><title>Interviewing, A Reflection of the Company</title><link>/2010/08/29/Interviewing-A-Reflection-of-the-Company/</link><pubDate>Sun, 29 Aug 2010 17:39:05 -0700</pubDate><guid>/2010/08/29/Interviewing-A-Reflection-of-the-Company/</guid><description>&lt;p>The more I&amp;rsquo;ve been exposed to it the more the way a company conducts interviews is a very strong reflection of how the company&amp;rsquo;s current state is. If you experience a very half hazard interview it&amp;rsquo;s likely a result that the person interviewing is half hazard in other aspects of their day to day. If you experience that someone is very set in their mind in what they want, and expecting a very cookie cutter answer, it&amp;rsquo;s a reflection of how they think. There are some cases in which the interviewers simply do not know various methods/styles as such I&amp;rsquo;d like to address what I feel should be appropriate interviewing process. I&amp;rsquo;ve been in situations where more of this process was followed than not, and in those cases bad hires were the exception not the norm. The biggest unknown after that was how long until someone was fully integrated into the culture and not a noob but a veteran in some area that others deferred to.&lt;/p>
&lt;p>In the interviewing process the very first key is knowing your role. Hopefully there&amp;rsquo;s at least more than one person interviewing. If you&amp;rsquo;re interviewing you have the need, the person on the other side of the table from you may or may not. It may just be an opportunistic interview for them, or they may be avidly looking for an opportunity. Either way you should ALWAYS be in a sell mode of some form, the only question is how heavy this sell mode is. Are you 10% selling, 50% selling, 70% selling, 90% selling? In my experience I&amp;rsquo;ve never been in an interview of less than 50% selling to whomever I&amp;rsquo;m interviewing. Being in this mode is only going to convince them to come if they&amp;rsquo;re not looking that hard OR make them even more desperate to join you, which means you could offer them less (While I do have issues with this, the fact remains that it happens).&lt;/p>
&lt;p>So back to your role, the key roles correspond pretty directly to the type of interviews you should conduct. These can be blurred/mixed and can be conducted by different/same people, but I would at the very least not mix the questions at least follow some structured order. The key types are:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Next is the Behavioral/Contextual interview. This will consist of many what would you do in this situation. There are books and books that exist on example questions and how to respond to these. The key that an interviewer is looking for is that you solve a particular issue and follow a logical process here. If they ask a question about dealing with conflict, they don&amp;rsquo;t want to see that you just ignored it. There&amp;rsquo;s a fine line of addressing the conflict so the working environment is better, but also ensuring the project makes progress.&lt;/p>
&lt;p>Finally is the Technical interview. Approaching this from a very technical area of programming, you should not be testing syntax. You should be testing generic programming thoughts/concepts. If you want to give a syntax test go online and find one of the thousands that exist. If I&amp;rsquo;m not confident someone can pick up a language knowing general constructs, I would never hire them and they wouldn&amp;rsquo;t have made it this far in the process. If you want to throw in 1-2 questions about such that&amp;rsquo;s a manageable amount, but most of the interview should follow more open ended questions, questions that have multiple answers. How to write a for loop in Java is not acceptable, how to write a function that produces fibonnaci and a corresponding test is acceptable. Any time someone asks a question like this, I&amp;rsquo;m open to working at the company. It shows they put thought into the interview process and care about quality of their hires. Those types of questions test several concepts at once:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>As I mentioned before there&amp;rsquo;s several types of interviews and various levels of selling that occur. During EVERY interview you should give the person you are interviewing the opportunity to ask questions. Whenever this occurs you&amp;rsquo;re in selling mode, and often after a question you&amp;rsquo;re in selling mode. Your answers should NOT be 1 word answers, they should be thorough and open the opportunity for follow up questions on your answer. With any of these questions you should be able to interview someone at a level lower than you, or even higher than you. There are some job specific ones, sometimes of managing people or budgets when interviewing upwards that you may not address, but a lower level employee interviewing a manager is a valuable part of the process.&lt;/p>
&lt;p>With regards to your role it should be discussed ahead of time, you should conduct 2 behavioral interviews if the first you have an unsure result from. You should not ask the same questions if they passed with flying colors the first time. If you do this, and there are cases its relevant know your reasoning behind such. The bottom line is know the types of interview you&amp;rsquo;re conducting, discuss it internally, and know what you&amp;rsquo;re looking for as a result. If you haven&amp;rsquo;t put this much thought and effort into the process it will be apparent and the resulting quality of person you get will be a direct reflection of that.&lt;/p></description></item><item><title>Selling... Seduction... same difference</title><link>/2010/05/03/Selling...-Seduction...-same-difference/</link><pubDate>Mon, 03 May 2010 21:25:01 -0700</pubDate><guid>/2010/05/03/Selling...-Seduction...-same-difference/</guid><description>&lt;p>On an entirely separate blog I have a full write up on seduction. The other posts contain steps for how a guy would seduce a girl, I think it&amp;rsquo;s actually quite pertinent to selling sighing business. Before you start making to many assumptions about the other post let me explain a little further, but dorm the selling side within business.&lt;/p>
&lt;p>You see in selling something there&amp;rsquo;s usually a lot of sides to what you&amp;rsquo;re selling, just as there are to a person. The real key to this is to know which features are relevant, while you might like the option of mind reading, a more likely one is to become friendly early. Become buddy and friendly with them quickly, commiserate with their woes and try to bond with them over similar experiences. This will make the initial conversation over what they&amp;rsquo;re looking for much more constructive. And while I say this is a conversation about what they&amp;rsquo;re looking for, what you should be asking is what their pains are.&lt;/p>
&lt;p>For every pain that exists, theres 5 to 10 ways to solve it. However if you miss the pain points and problems they&amp;rsquo;re having, you&amp;rsquo;re more than likely to miss on the pitch. IF you are able to get the pain points correctly it simple becomes a process of guiding them in ways to solve their problem. This process usually starts with dissecting the fundamental issues in the process, then building it back up with your product or solution being the backbone. In the same way it&amp;rsquo;s hard to win someone over on a 1 on 1 personal level without knowing what they want, you can&amp;rsquo;t sell to someone that doesn&amp;rsquo;t have a problem, and won&amp;rsquo;t be able to pitch well without knowing it.&lt;/p></description></item><item><title>Why The Cloud Will Finally Work</title><link>/2010/04/05/Why-The-Cloud-Will-Finally-Work/</link><pubDate>Mon, 05 Apr 2010 17:29:35 -0700</pubDate><guid>/2010/04/05/Why-The-Cloud-Will-Finally-Work/</guid><description>&lt;p>The cloud has a lot of technical arguments going for it. The problem is consumers don&amp;rsquo;t understand the cloud, they don&amp;rsquo;t understand virtual storage and growth and syncing and the complexities of things. The average consumer is generally pretty dumb, they just want to be able to do things and it just work. If they ask a question they want an answer, not the deduction behind the answer. It&amp;rsquo;s why I loved mint.com so much when it launched. I gave it accounts and it told me everything I wanted to know. If it was wrong I seldom noticed it, such as classifying a purchase into a wrong category. My suspicion is that 98% of the users don&amp;rsquo;t notice much of the mis-classification that happens. They look the first time and it looks pretty good so they trust it, because if you look at 90% of purchases and classify them, why use mint, why not just use excel, or even go back to a paper and notebook?&lt;/p>
&lt;p>Cloud is that same type of issue, it needs to just work, users need to just expect their document to always be the same. I think the iPad but more specifically MobileMe will have a great shot at doing this. The reason the iPad will play a role is now the average consumer will have more than 1 device. They&amp;rsquo;ll have their laptop/desktop and an iPad. This user will want to work on the device, and more than just email. Having their application open a file, work for 15 minutes on a train/bus, turn it off, walk in their front door and open the same file on their computer will really bring cloud storage/computing to a consumer. Because apple controls the reins on the primary applications where this has value:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>This will push the expectation on developers to deliver the same kind of experience with the cloud, it&amp;rsquo;s going to become the norm now. Not because its cost effective, not because of the technical benefits, but because it&amp;rsquo;s going to be transparent to users, and users are just going to expect it from now on.&lt;/p></description></item><item><title>Valuing Employees</title><link>/2010/02/27/Valuing-Employees/</link><pubDate>Sat, 27 Feb 2010 17:10:23 -0800</pubDate><guid>/2010/02/27/Valuing-Employees/</guid><description>&lt;p>A coworker and I were recently having conversations over employee compensation. We covered the gambit around employee feedback, evals, and compensation. He mentioned Joel Spolsky, and his format of being very open about where individuals were ranked. He also pointed me to: &lt;a href="http://alumnit.ca/~apenwarr/log/?m=200904#05">http://alumnit.ca/~apenwarr/log/?m=200904#05&lt;/a> which provided good insight, though I most like his final point. The end goal with evaluating your employees and compensation for them is to make sure they&amp;rsquo;re happy. Sure the business should make sure they feel like you&amp;rsquo;re worth what you&amp;rsquo;re being paid, but usually there is no question about this, or if there is you&amp;rsquo;re quickly escorted out the door. While this is an interesting model, I think it can be much simpler, but companies usually confine themselves too much in giving credit to employees.&lt;/p>
&lt;p>There was another recent occasion where a statement was made of &amp;rsquo;no more playing stick them up, until next year&amp;rsquo;. When I first thought about this, I knew I didn&amp;rsquo;t like the statement, but was unsure of why. The reason is that there can be several reasons why employees leave. Only one of which is compensation. If you feel you&amp;rsquo;re being adequately compensated for the job you&amp;rsquo;re doing it makes sense.&lt;/p>
&lt;p>But there&amp;rsquo;s another reason thats very clear in the valley but less clear in other parts of the country. Paul Buchheit at Startup School this weekend in Berkeley said it very well: If you&amp;rsquo;ve been at your job too long, QUIT. Meaning if you&amp;rsquo;re comfortable, you know the people, you know how to do your job, and you&amp;rsquo;re not being challenged, then you should go somewhere where you are challenged.&lt;/p>
&lt;p>So what does this have to do in regards to playing stick em up? Well if you&amp;rsquo;re at a comfortable place you should be compensate appropriately that&amp;rsquo;s fair. However if you&amp;rsquo;re at a comfortable place, you should either find ways to be challenged there or move on. If you&amp;rsquo;re challenged there it means your role over time will change, there&amp;rsquo;s not a standard guide for how quickly you become experienced in that role. It it&amp;rsquo;s two weeks, then salary should be re-evaluated then, if it&amp;rsquo;s 3 years salary should perhaps be re-evaluated yearly to keep up with changes in value to the dollar, but nothing more substantial to that.&lt;/p>
&lt;p>At the end of the day it means you have to deliver value to an employer, and as long as your doing that the employer should recognize you for the value you deliver, based on merit, not based on policies laid out. Whether you jump to an extreme of merit/value being very clear such as a Joel Spolsky method, or follow something more traditional of a large company, the bottom line is you should give your employees what they&amp;rsquo;re worth, and as an employee its what you should expect.&lt;/p>
&lt;p>A coworker (&lt;!-- raw HTML omitted -->@danfarina&lt;!-- raw HTML omitted -->) and I were recently having conversations over employee compensation. We covered the gambit around employee feedback, evals, and compensation. He mentioned Joel Spolsky, and his format of being very open about where individuals were ranked. He also pointed me to: &lt;!-- raw HTML omitted -->&lt;a href="http://alumnit.ca/~apenwarr/log/?m=200904#05">http://alumnit.ca/~apenwarr/log/?m=200904#05&lt;/a>&lt;!-- raw HTML omitted --> which provided good insight, though I most like his final point. The end goal with evaluating your employees and compensation for them is to make sure they&amp;rsquo;re happy. Sure the business should make sure they feel like you&amp;rsquo;re worth what you&amp;rsquo;re being paid, but usually there is no question about this, or if there is you&amp;rsquo;re quickly escorted out the door. While this is an interesting model, I think it can be much simpler, but companies usually confine themselves too much in giving credit to employees.&lt;/p>
&lt;p>There was another recent occasion where a statement was made of &amp;rsquo;no more playing stick them up, until next year&amp;rsquo;. When I first thought about this, I knew I didn&amp;rsquo;t like the statement, but was unsure of why. The reason is that there can be several reasons why employees leave. Only one of which is compensation. If you feel you&amp;rsquo;re being adequately compensated for the job you&amp;rsquo;re doing it makes sense.&lt;/p>
&lt;p>But there&amp;rsquo;s another reason thats very clear in the valley but less clear in other parts of the country. Paul Buchheit at Startup School this weekend in Berkeley said it very well: If you&amp;rsquo;ve been at your job too long, QUIT. Meaning if you&amp;rsquo;re comfortable, you know the people, you know how to do your job, and you&amp;rsquo;re not being challenged, then you should go somewhere where you are challenged.&lt;/p>
&lt;p>So what does this have to do in regards to playing stick em up? Well if you&amp;rsquo;re at a comfortable place you should be compensate appropriately that&amp;rsquo;s fair. However if you&amp;rsquo;re at a comfortable place, you should either find ways to be challenged there or move on. If you&amp;rsquo;re challenged there it means your role over time will change, there&amp;rsquo;s not a standard guide for how quickly you become experienced in that role. It it&amp;rsquo;s two weeks, then salary should be re-evaluated then, if it&amp;rsquo;s 3 years salary should perhaps be re-evaluated yearly to keep up with changes in value to the dollar, but nothing more substantial to that.&lt;/p>
&lt;p>At the end of the day it means you have to deliver value to an employer, and as long as your doing that the employer should recognize you for the value you deliver, based on merit, not based on policies laid out. Whether you jump to an extreme of merit/value being very clear such as a Joel Spolsky method, or follow something more traditional of a large company, the bottom line is you should give your employees what they&amp;rsquo;re worth, and as an employee its what you should expect.&lt;/p></description></item><item><title>Who will filter the stream first?</title><link>/2010/01/26/Who-will-filter-the-stream-first/</link><pubDate>Tue, 26 Jan 2010 17:56:01 -0800</pubDate><guid>/2010/01/26/Who-will-filter-the-stream-first/</guid><description>&lt;p>Facebook is where I have more noise than any other social site, twitter may even tie facebook at amount of sheer content I receive in my feed. With regards to the ratio of what I care about to what I see facebook is a lot better, due to their news feed versus live feed. However, their news feed is still very often off. I wrote some time back about web 3.0, and how essentially showing what I want to see is what the web will become. You&amp;rsquo;ll take the vast amount of content and distill it into what I want to see. People seem to be taking very half-hazard shots at it and its quite a let down.&lt;/p>
&lt;p>I&amp;rsquo;ll start with twitter, twitter gives no filtering on the content based on their view. Instead they put the control in the users hands for me to create filters based on friends. This means I have to take time to go through all of my 600+ people I follow and group them into lists, then navigate each list when I want to view such topics. This is not only time intensive it still doesn&amp;rsquo;t accomplish what I want which is information by topic in a lot of cases, especially on twitter.&lt;/p>
&lt;p>Moving on to facebook, they at least take care of the process (almost transparently) of who I want to see. If someone shows up, I can simply say hide from the news feed. I have a strong hunch that when I click out of the news feed and go to someone&amp;rsquo;s profile it weights that person to be more frequent. This is a very logical deduction to make, and in most cases I&amp;rsquo;m pretty pleased with the result. The big problem with this is it&amp;rsquo;s still all about the people, not about the content. If I clicked on someone because they mentioned coming to visit California, I may have not talked to them in 2 years, but would simply like to offer up my help when they visit. This doesn&amp;rsquo;t mean I want to get updates about them after they visit.&lt;/p>
&lt;p>Facebook is definitely a leader in this space, first they&amp;rsquo;re one of the few with enough content in a feed that filtering even matters. Then the fact that they get a user beyond analysis-paralysis it&amp;rsquo;s a positive move, however the classification is wrong. Whether it&amp;rsquo;s twitter, facebook, or some other service that hasn&amp;rsquo;t emerged yet, filtering a mass of information to what a user cares about will be huge.&lt;/p>
&lt;p>Amazon and Netflix have done this for products, why has no one tried this for information?&lt;/p></description></item><item><title>Issues Aren't Always Bad</title><link>/2010/01/25/Issues-Arent-Always-Bad/</link><pubDate>Mon, 25 Jan 2010 17:30:10 -0800</pubDate><guid>/2010/01/25/Issues-Arent-Always-Bad/</guid><description>&lt;p>I often encounter people whether at my office or at other places of employment that are distraught after getting an earful from a manager from some problem arising. The problem usually isn&amp;rsquo;t in their control, and therefore they don&amp;rsquo;t understand why they get heat for this. Most managers though do actually understand when issues come up, however what they don&amp;rsquo;t appreciate is late notice, lack of problem solving, and dictating what should be done next.&lt;/p>
&lt;p>Managers typically want individuals to take control of a situation and work towards resolving it.&lt;/p>
&lt;p>One thing you can do to ease the backlash that may occur for issues coming up is to communicate proactively as things develop/occur or lack there of. Keep in mind this should relate well to your managers style, some managers only want details when they absolutely have to have them. In that case you&amp;rsquo;ll want to gradually give your manager a heads up, but not burden him with too much information. I would venture to say however that most managers appreciate details, details are great to give them insight into how things are going and allow them to feel engaged at a lower level.&lt;/p>
&lt;p>So assume you&amp;rsquo;ve communicated regularly to your manager, this still does not prevent any issues from happening, but rather reduces the shock when something does. At this point a manager still does not want a fact stated that there&amp;rsquo;s a problem. In every case I&amp;rsquo;ve encountered the manager wants you to take ownership of the issue, meaning to give some options. Once the problem has arisen you should instantly start looking for ways to solve it. Often time these ways are not within your power to make the final decision, though you do have a great deal of control in presenting the case to a manager.&lt;/p>
&lt;p>Finally if you want brownie points, take less credit for any of the work you&amp;rsquo;ve done and give your manager more. If you&amp;rsquo;ve communicated early, laid out various options for how to resolve the issue with pros and cons of each you&amp;rsquo;ve done what you can. This should make it very easy on your manager to simple say, go with Option B, and follow back up with me on Monday. At this point if you give your manager most of the credit for helping the issue, it will only come back to you. While this is potentially the least critical of the three points, it can often pay off equally as much.&lt;/p>
&lt;p>This is easier to do as you pay attention to issues and start to become pro-active. Taking ownership may not be in your job title or description, but it will definitely get you less earfuls from managers, and likely move you through the ranks faster.&lt;/p></description></item><item><title>Forget Doing Something Better, Do Something Different</title><link>/2010/01/21/Forget-Doing-Something-Better-Do-Something-Different/</link><pubDate>Thu, 21 Jan 2010 14:49:33 -0800</pubDate><guid>/2010/01/21/Forget-Doing-Something-Better-Do-Something-Different/</guid><description>&lt;p>I have a tendency of really latching onto very simple ideas. Typically these ideas don&amp;rsquo;t require complex engineering to make them happen. This is not to say the engineering is not important, but more so that it is some variation of engineering feats that have been done before. The reason I tend to like these over more complex engineering that really makes something better is that making something better is typically a marginal improvement. When it&amp;rsquo;s a marginal improvement it&amp;rsquo;s a lot harder to sell.&lt;/p>
&lt;p>With marginal improvements you have to:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>In contrast if I address a problem that hasn&amp;rsquo;t been solved my life instantly becomes a lot easier. I no longer have an argument of something not being good enough today, it becomes a question of value and how much its worth to solve the problem. Haggling over price is a conversation I&amp;rsquo;d rather have than trying to justify value and convince a customer they&amp;rsquo;ve been wrong in their choice for so many years.&lt;/p>
&lt;p>Over the coming days I&amp;rsquo;m going to be posting a few of these examples/ideas and why I like them. Many of them are still being thought through, and while as I sort them out, I&amp;rsquo;m generally happy to publish high points about them. The even bigger key here is that success is typically in the execution and less so in the idea, though even then I&amp;rsquo;d prefer to execute on something that has less battles than something that from the onset has more. By doing something that is being done today you get no advantages of penetrating the market.&lt;/p></description></item><item><title>Parallelizing the Product Process?</title><link>/2010/01/20/Parallelizing-the-Product-Process/</link><pubDate>Wed, 20 Jan 2010 14:42:49 -0800</pubDate><guid>/2010/01/20/Parallelizing-the-Product-Process/</guid><description>&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Who Cares About Visitors?</title><link>/2010/01/19/Who-Cares-About-Visitors/</link><pubDate>Tue, 19 Jan 2010 15:55:22 -0800</pubDate><guid>/2010/01/19/Who-Cares-About-Visitors/</guid><description>&lt;p>The web is becoming saturated. It&amp;rsquo;s no longer the pimply faced 20 somethings living in their mom&amp;rsquo;s basements that are the key users and the source of most of the traffic on the web. Now you have communities for pregnant moms, sites for elderly widows looking to date, and social sites for kids from the time they&amp;rsquo;re able to talk. So now that the web is hitting its saturation point of types of people interacting it becomes a critical issue to take advantage of those users and get them to do more.&lt;/p>
&lt;p>Up until this point it&amp;rsquo;s been about getting more users, more people, that easily translated into more hits of course. But now what people want is richer engagement, they want users to be active, then to contribute the content. When users are more active it means just as many hits, but more engagement is a harder issue than more users. More users usually meant more marketing budget and a piece of allowing the market to mature. More engagement means you actually have to be more methodical about what you&amp;rsquo;re doing. It means you have to more closely balance the quality of what is one your site versus how you manage the ad&amp;rsquo;s which equate to revenue.&lt;/p>
&lt;p>The news that facebook is exposing how many impressions a page gets versus the amount of feedback has been received is a driver in this direction. Fortunately for facebook, they don&amp;rsquo;t have control over Fan Pages so it&amp;rsquo;s not their job to drive up engagement on a per page basis. Unfortunately for other major publishers this is a very unscientific science, and what works and doesn&amp;rsquo;t work can only be a result of trying out new options. There&amp;rsquo;s a lot of opportunity here for those that really figure out what key drivers are of engagement, it&amp;rsquo;s one thing to measure it, it&amp;rsquo;s another to be able to readily define out to improve it, and no one has repeatedly done that on the web yet.&lt;/p></description></item><item><title>Behavioral Targeting versus Contextual Advertising</title><link>/2010/01/14/Behavioral-Targeting-versus-Contextual-Advertising/</link><pubDate>Thu, 14 Jan 2010 17:25:37 -0800</pubDate><guid>/2010/01/14/Behavioral-Targeting-versus-Contextual-Advertising/</guid><description>&lt;p>There&amp;rsquo;s a continual shift that seems to be happening on whether contextual advertising is better than behavioral. It seems that most people are becoming bigger and bigger on behavioral, and assuming that contextual has reached it&amp;rsquo;s peak. After meeting with a company that at first started to do both, blurring the lines, taking advantage of each when they had appropriate data it started to become clear that they more so have their place and time. Behavioral and Contextual shouldn&amp;rsquo;t be direct competitors.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Does Authenticity Matter?</title><link>/2009/10/09/Does-Authenticity-Matter/</link><pubDate>Fri, 09 Oct 2009 20:36:41 -0700</pubDate><guid>/2009/10/09/Does-Authenticity-Matter/</guid><description>&lt;!-- raw HTML omitted -->
&lt;p>Facebook is as authentic of a network as you can have, you have you, you are you, you&amp;rsquo;re not FunChick21, or MotorcycleGuy42, You&amp;rsquo;re Craig Kerstiens. You have a birthdate, which is likely you&amp;rsquo;re birthdate, you have a job that is your job, you have friends that are you&amp;rsquo;re friends. Facebook is probably as close to a virtual representation of your true life as you can get on a social network.&lt;/p>
&lt;p>Then you have Twitter. Twitter is probably as inauthentic as they come. You ARE FunChick21 or MotorcycleGuy42. You have that name, and that&amp;rsquo;s it. You have friends, but they&amp;rsquo;re up to you, it&amp;rsquo;s a one way relationship, not confirmation of friendship. For that reason you have 1,000,000 people following Ashton Kutcher, and he follows under 100. You&amp;rsquo;re friends could be celebrities, they could be friends, they could be random people that you liked their tweets.&lt;/p>
&lt;p>Facebook from an ad perspective I know almost everything I could want to about you from an ad targeting perspective. Few sites could give much more demographic info that I&amp;rsquo;d want to target effectively. Twitter I have next to nothing, I have a user name, and the content of what you say.&lt;/p>
&lt;p>So there&amp;rsquo;s an advantage to facebook. But then you have the context of what I&amp;rsquo;m trying to do. If you&amp;rsquo;re facebook, you have users engaged in the site not wanting to leave. If you&amp;rsquo;re Twitter you have users that won&amp;rsquo;t be on the site for beyond 60 seconds. Getting them to leave shouldn&amp;rsquo;t be an issue, which means if you can drive where they are leaving to it should work out well for you.&lt;/p>
&lt;p>But there&amp;rsquo;s a final piece. It&amp;rsquo;s a heavily growing marketplace, that really neither of the major communities picks up on, and it&amp;rsquo;s virtual goods. Virtual goods exist in either form of network, but neither seems to take advantage, meanwhile it&amp;rsquo;s the entire basis behinds such communities as World of Warcraft. How will they start to roll into mainstream networks, that&amp;rsquo;s yet to be seen, but I&amp;rsquo;ll be curious if virtual goods can become dominant in authentic networks or if they&amp;rsquo;ll primarily reside in inauthentic networks as they do today.&lt;/p></description></item><item><title>Motivating Users</title><link>/2009/09/30/Motivating-Users/</link><pubDate>Wed, 30 Sep 2009 22:25:24 -0700</pubDate><guid>/2009/09/30/Motivating-Users/</guid><description>&lt;p>I&amp;rsquo;ve done some recent advising for someone working on a site that&amp;rsquo;s of a social nature. The site is intended in some form to motivate users, the initial thought on this was to define a lot of rules, and send automated messages to users. To me this approach felt very 1990&amp;rsquo;s. So assuming that were true, then comes the question of how do you motivate users?&lt;/p>
&lt;p>I think rules do usually come somewhere in the process, you need to know when to motivate the users, however the catch is how you expose the results of those rules. And in thinking about it there&amp;rsquo;s a variety of levels at which you can expose those rules from more raw data forms, to several steps of analysis or actions on top of them. Raw data works for analytical users, users that naturally consume data AND are already heavily motivated for the set goal. Lets say for sake of argument this is 10% of users. This means by exposing very little gloss, and mostly the data which the rules are run on you&amp;rsquo;ll lose 90% of users.&lt;/p>
&lt;p>The other extreme is to almost entirely hide the rule and obfuscate this with actions that you know can lead the user back to their goal. I feel not quite this, but some derivative of it, in the form of social nudging could be incredibly useful for many different means. There&amp;rsquo;s many real world situations where people rely on each other for support, you can think of traditional AA type settings, or weight loss, or other groups with a central focus of accountability. But these forms of groups seem to be largely absent in the virtual space, or when they are present are realistic groups simple dropped into a virtual space.&lt;/p>
&lt;p>What happens when users want some mixed level of privacy, but encouragement? What you need to do is to have your rules define when you need to have users get motivation from others. The fun part is how you drive users to interact at those times, this can be through a variety of options, all depending on your site. A very basic example of this is the birthday reminder on facebook. They&amp;rsquo;re not just reminding you of it for the sake of it, they&amp;rsquo;re reminding you, so you use applications to send virtual birthday cards to users and messages, therefore enriching the user experience. If other sites were able to apply this to goal setting, and use social nudging over system rules, users will feel more connected to others and it will likely increase effectiveness.&lt;/p></description></item><item><title>Micromanaging</title><link>/2009/09/24/Micromanaging/</link><pubDate>Thu, 24 Sep 2009 12:41:57 -0700</pubDate><guid>/2009/09/24/Micromanaging/</guid><description>&lt;p>Three times in recent years I&amp;rsquo;ve had to micromanage others. Though probably in the contrary form to what you would expect. Most people think of micromanagement as their manager wanting to know every detail about their day, and be involved in every minute task. In most cases this form of micromanagement is never received well. Generally my feelings are that if I have to micromanage you, you don&amp;rsquo;t belong in the role you&amp;rsquo;re in, though I suppose exception cases may exist.&lt;/p>
&lt;p>But the form of micromanagement I&amp;rsquo;m talking about is upward management. This could be needed for a variety of reasons:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>First it&amp;rsquo;s helpful to start with a regular process. Sending status emails every morning or every afternoon, will keep them in the loop. It&amp;rsquo;ll prevent them from asking too many questions, and will keep them in the loop, but mainly with knowledge you feel is pertinent.&lt;/p>
&lt;p>Discussions and calls with insider info will allow them to feel as if they&amp;rsquo;re driving the process. If you provide information as factual and provide the facts of how certain things have historically worked, or do would at a tactical level from you&amp;rsquo;re experiences it will help to steer the process in that direction. If they&amp;rsquo;re outside they&amp;rsquo;re comfort zone they&amp;rsquo;re going to take their best guess, it&amp;rsquo;s 50-50 if that&amp;rsquo;s the same as you&amp;rsquo;d see fit.&lt;/p>
&lt;p>But, do let them drive the process at hand. If they feel as if you&amp;rsquo;re attempting to drive it, then they&amp;rsquo;re going to feel as if they&amp;rsquo;re authority is being challenged. It&amp;rsquo;s more a kin to telling them the directions of how to get their and letting them drive the car. If they&amp;rsquo;re slightly off path, but in the right direction let it go because otherwise you&amp;rsquo;re time will be consumed with trying to get the exact directions.&lt;/p></description></item><item><title>Why the enterprise cant reach consumers</title><link>/2009/09/07/Why-the-enterprise-cant-reach-consumers/</link><pubDate>Mon, 07 Sep 2009 20:21:08 -0700</pubDate><guid>/2009/09/07/Why-the-enterprise-cant-reach-consumers/</guid><description>&lt;p>Most of my working career has been in what many would call an enterprise environment. Corporate structure well in place at most of them and in those cases any development followed closely to a waterfall methodology. You laid out requirements strictly and then built to those requirements. You essentially had nothing to show until you got to the end product.&lt;/p>
&lt;p>Having been in the valley for several years and interacting with some startups and in other settings, I&amp;rsquo;ve seen a very opposite mindset. The &amp;ldquo;release early, release often&amp;rdquo; concept. First you never have clear requirements when dealing with anything a startup should be tackling, if it&amp;rsquo;s a very clear easy to solve problem, then someone else will have already tackled it. If you&amp;rsquo;re doing something new, which you should be you can&amp;rsquo;t gauge how users react, until you actually have something in front of them.&lt;/p>
&lt;p>A prime example would be twitter. Twitter was a simple concept, yet it has been done before in many ways, what&amp;rsquo;s the difference in blogging and twitter? Well twitter requires you&amp;rsquo;re shorter, has no title, just content, and centralizes the data. It actually incredibly reduced what the user could do, and in doing that created new and broader functionality.&lt;/p>
&lt;p>As a more general principle users don&amp;rsquo;t know what they want. Users will complain about how gmail doesn&amp;rsquo;t have folders, but they use folders in outlook only because they can&amp;rsquo;t properly search. If you take away something from a user, they&amp;rsquo;re going to complain about it. This is fine, it&amp;rsquo;s not a problem, as long as they didn&amp;rsquo;t actually use the feature, and there&amp;rsquo;s other steps you can use to manage this backlash.&lt;/p>
&lt;p>But I&amp;rsquo;d believe the over arching key is that you can&amp;rsquo;t ask users what they want. If you presume to know you&amp;rsquo;re going to be wrong, so what does this mean. This means that you build something and you launch it. You don&amp;rsquo;t test it in user groups, you don&amp;rsquo;t test it in a lab, you don&amp;rsquo;t test it in an invite only beta, you launch it. You launch for users, and if they don&amp;rsquo;t like it, you haven&amp;rsquo;t upset thousands of customers because you don&amp;rsquo;t have that many. In consumer land you can launch something without anyone knowing who you are, and then truly test how users will respond, this is far more powerful than the traditional model used in enterprise. It&amp;rsquo;s the reason most of the biggest sites used today are emergent from startups and similar environments, because they built themselves on what users want.&lt;/p></description></item><item><title>How to succeed in the workplace? Go to lunch!</title><link>/2009/09/06/How-to-succeed-in-the-workplace-Go-to-lunch/</link><pubDate>Sun, 06 Sep 2009 17:20:45 -0700</pubDate><guid>/2009/09/06/How-to-succeed-in-the-workplace-Go-to-lunch/</guid><description>&lt;p>Something I learned very early on in my working career, not so much from my experiences but from observing the results of others, was to engage at a social level as early possible. This doesn&amp;rsquo;t mean you have to take time after 5:00 to get to know someone, the best opportunity exists every single day during what you would already do, lunch! Everyone usually takes a break and eats lunch during the day, usually there&amp;rsquo;s two groups in an office. Those that always go out, and those that bring their lunch or meet others for lunch or maybe even work through it. If you notice those in the first group in your office my guess it&amp;rsquo;s usually easier for them to get things done, they&amp;rsquo;re normally a little more in touch with things that are going on. Especially if you can manage to branch out a little and go outside of the people you work with every moment of the day.&lt;/p>
&lt;p>It&amp;rsquo;s generally one thing when you come to work and do you&amp;rsquo;re job. But no matter how large or small the company you can&amp;rsquo;t entirely separate the work from the personal, and personalities come out and it becomes some form of factor. Yes, most people are professional, but at the end of the day you&amp;rsquo;re more likely to help someone that you like even if you&amp;rsquo;re busy, than someone you don&amp;rsquo;t. Maybe you have a 50-50 chance of being liked, but I&amp;rsquo;d say by being disliked you&amp;rsquo;re not going to get help any slower really.&lt;/p>
&lt;p>I know there&amp;rsquo;s a few people reading this and thinking, this is fine, but I don&amp;rsquo;t really want to spend money on eating out every day. In my experience the extra knowledge you gain is well worth the price. When you through an executive level person, a developer, a sales guy, a marketing person, and some middle management into a single lunch outing, all come away with a lot of insight into area&amp;rsquo;s of the business they had little exposure to. This come&amp;rsquo;s back to my post about &lt;!-- raw HTML omitted -->leaders and developers&lt;!-- raw HTML omitted -->, if the people in your business only understand what they do and nothing outside you&amp;rsquo;re as a whole going to be less effective. Most people in your company don&amp;rsquo;t think this way, by doing it you&amp;rsquo;ll become more effective than the average person.&lt;/p>
&lt;p>And to think, it all starts with something as simple as going out to lunch. It&amp;rsquo;s the reason that from day 1, to being a veteran in a company, when someone asks &amp;ldquo;Do you have plans for lunch?&amp;rdquo; 90% of the time my answer is &amp;ldquo;No, when do you want to go?&amp;rdquo;&lt;/p></description></item><item><title>Building apps from the echo chamber</title><link>/2009/07/23/Building-apps-from-the-echo-chamber/</link><pubDate>Thu, 23 Jul 2009 17:20:04 -0700</pubDate><guid>/2009/07/23/Building-apps-from-the-echo-chamber/</guid><description>&lt;!-- raw HTML omitted --></description></item><item><title>Leaders and Developers</title><link>/2009/07/13/Leaders-and-Developers/</link><pubDate>Mon, 13 Jul 2009 22:56:16 -0700</pubDate><guid>/2009/07/13/Leaders-and-Developers/</guid><description>&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Mentoring</title><link>/2009/06/16/Mentoring/</link><pubDate>Tue, 16 Jun 2009 17:29:38 -0700</pubDate><guid>/2009/06/16/Mentoring/</guid><description>&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted --></description></item><item><title>Takeaways from Consulting</title><link>/2009/06/13/Takeaways-from-Consulting/</link><pubDate>Sat, 13 Jun 2009 20:46:39 -0700</pubDate><guid>/2009/06/13/Takeaways-from-Consulting/</guid><description>&lt;!-- raw HTML omitted -->
&lt;ol start="2">
&lt;li>Take ownership of the process&lt;!-- raw HTML omitted -->&lt;/li>
&lt;/ol>
&lt;!-- raw HTML omitted --></description></item><item><title>Why Google Wave Will Fail</title><link>/2009/06/08/Why-Google-Wave-Will-Fail/</link><pubDate>Mon, 08 Jun 2009 01:00:26 -0700</pubDate><guid>/2009/06/08/Why-Google-Wave-Will-Fail/</guid><description>&lt;p>Google doesn&amp;rsquo;t understand social or collaboration. There&amp;rsquo;s not much more to it than that, though for the sake of making this a an actual blog post I&amp;rsquo;ll explain a bit more.&lt;/p>
&lt;p>Blogger was huge, it was the place to go if you were creating a blog. There weren&amp;rsquo;t many &lt;a href="https://www.mybloghere.com">www.mybloghere.com&lt;/a>, many of the largest most popular blogs on the internet were on blogger. People had accounts, people registered to post comments, people had full fledged profiles that could have easily preceded a facebook profile page. Google bought blogger and had more than enough resources to grow blogger into a sizable social community. But if you visit it looks much the same as it did 5 and almost 10 years ago.&lt;/p>
&lt;p>Google spreadsheets is one of the best online spreadsheet programs, and you can even collectively work on a spreadsheet with others at the same time thousands of miles away. Who do you know that uses google spreadsheets that isn&amp;rsquo;t some form of a techie? It likely has a user base of under 1% of users of spreadsheets, and its not because it&amp;rsquo;s missing the power features of pivot tables and such. If you re-brand it as a collaboration tool when working and throw chat/video/whiteboarding in the same application google would have an instant growth 10 fold of users, but they don&amp;rsquo;t understand that a user seeing the same thing on a spreadsheet and seeing what the other types in a single document isn&amp;rsquo;t collaboration!&lt;/p>
&lt;p>To jump ahead of the curve, counter arguments I&amp;rsquo;ve already heard are around ads and gmail. Gmail, google didn&amp;rsquo;t improve email, they simply give you lots of space for free, if gmail were to cease to exist tomorrow users would simply jump over to yahoo or microsoft. Ads, google changed the ad industry by making search effective, they&amp;rsquo;re good at algorithms and such, but they don&amp;rsquo;t get users and collaboration, and at their current rate they never will.&lt;/p>
&lt;p>Wave isn&amp;rsquo;t meant to just improve email, it&amp;rsquo;s meant to be a tool for collaboration, to view a conversation as an entity, and google just doesn&amp;rsquo;t get the conversation part.&lt;/p></description></item><item><title>The benefit of leverage</title><link>/2009/05/23/The-benefit-of-leverage/</link><pubDate>Sat, 23 May 2009 20:13:53 -0700</pubDate><guid>/2009/05/23/The-benefit-of-leverage/</guid><description>&lt;p>Due to many recent events, which I&amp;rsquo;m sure I&amp;rsquo;ll disclose later, I&amp;rsquo;ve been in an interesting situation of a good bit of leverage. While leverage can of course be taken advantage of and misused, it also plays a very fair role in business. When hiring a new college graduate in most cases you take the offer you are given, some are able to negotiate for a higher salary, but most are quite unsuccessful. This is because they don&amp;rsquo;t have any leverage. If you ended up walking away from the job offer they would simply hire another college graduate. While yes you may have a lot of potential, it&amp;rsquo;s only that potential and not proven.&lt;/p>
&lt;p> &lt;/p>
&lt;p>Additionally within a corporation, the company will often do just enough to keep an employee there. If a company does a great job, an employee gets a pat on the back. If an employee is indispensable (though no company will ever admit to this), they may get a noticeable reward, but it still doesn&amp;rsquo;t usually cover the value the individual is actually providing.&lt;/p>
&lt;p>This responsibility to get what you are truly worth usually lies with the employee. The hard part of this, is knowing when and how to use your leverage. First you must actually have leverage, this commonly in potential revenue you would bring in, or internal knowledge that you may have. Though I&amp;rsquo;m sure others have varying experiences, mine have been to make your dissatisfaction with a situation known, but in a light manner. Meanwhile make it visible that you&amp;rsquo;re open to other opportunities as they may come along, this can be via twitter, blog post, or water cooler talk. The final thing, and hopefully this is an easier one, is make it clear that you have the leverage, the sale should be a big one, or the internal knowledge should be costly should they lose it.&lt;/p>
&lt;p>The most unfortunate part of all of this is that, in my experiences the leverage is typically needed to get a fair deal. And the single point of requiring leverage no longer makes it fair, but at least knowing this ensures you&amp;rsquo;re not left out in the cold.&lt;/p></description></item><item><title>Why Twitter Is About To Get Old</title><link>/2009/05/08/Why-Twitter-Is-About-To-Get-Old/</link><pubDate>Fri, 08 May 2009 21:23:41 -0700</pubDate><guid>/2009/05/08/Why-Twitter-Is-About-To-Get-Old/</guid><description>&lt;p>Twitter has finally hit mainstream, it was bound to happen and with Ashton, Oprah, Shaq, among many others it&amp;rsquo;s now going to be around for a while. This means a lot of interesting things for twitter such as scalability to handle this new massive growth which will be much more regular unlike the more sparse spikes they would see before. But as user of twitter it means something far different, it means twitter is about to run out of usefulness. Before twitter was a nice resource to be able to regularly communicate with micromessaging, now it&amp;rsquo;s quickly going to become one of the noisiest things on the web. This would be a fine case, IF there were ways to manage the noise. However with twitter you either get really focused drops or the entire firehose, there is no medium in between. Sure twitter searches can be nice, but this requires maybe 20-30 constant searches to be up to date on what you care about.&lt;/p>
&lt;p>If someone is able to find some way to manage the firehose of information it will prove as valuable tool as twitter itself. But if that doesn&amp;rsquo;t happen in a respectable time, twitter is going to get really exciting to a lot of people, and just as quickly turn a lot of people off.&lt;/p></description></item><item><title>Takeaways for a startup</title><link>/2008/11/04/Takeaways-for-a-startup/</link><pubDate>Tue, 04 Nov 2008 19:19:30 -0800</pubDate><guid>/2008/11/04/Takeaways-for-a-startup/</guid><description>&lt;p>I&amp;rsquo;ve learned a great deal since being out in the valley, first, is the confirmation that I do love the atmosphere. Second that I really miss the fall, but more importantly I&amp;rsquo;ve learned a lot that I feel is useful in a startup environment. The startup environment and business model is a very unique one, especially in recent years. It seems to not require a business model to get someone just to give you $10 million and hope you come out with one at some point. And in some cases it works, I mean it did for google, but well the failure stories are a lot more abudant than the success ones.&lt;/p>
&lt;p>Here&amp;rsquo;s a quick run down of how I think one can build a successful startup in any economy, and why I feel our current state is prime for someone following these steps.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Have a business model. Yeah, it&amp;rsquo;s less glamorous that a facebook that has millions of people log on to it each hour. Take for example the guys at 37 signals, they&amp;rsquo;re probably happy to get a million uniques in a month, or perhaps even a year. But per employee, per their cost, their revenues are at least 10x if not 100x of facebook&amp;rsquo;s. And they most likely see that in revenue per employee as well. Why is this the case? Simple put, they have a business model. They have some product they build and people want it, not want it in the sense that they will spend hours of time aimlessly using it if its free and convenient. It accomplishes some actual goal, and saves people time and makes their lives easier. Oh and something I&amp;rsquo;ve probably said too many times on here, but ad&amp;rsquo;s isn&amp;rsquo;t a business model, unless your specifically an ad company.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Get competent employees, I want to even take this a step further and say to get employees that believe in the technology but also in the business. Its one thing when your at a large company to have someone that&amp;rsquo;s extremely specialized. But at a startup everyone wears a variety of hats. Your secretary could land a big lead on a sale, your intern developer could come up with your future marketing slogan, and because of this everyone you bring on board needs to be fully on board with every aspect of your business. If you&amp;rsquo;re growing slower than you hoped it&amp;rsquo;s fine, and worth it to be short rather than over inflated.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Part of the reason you&amp;rsquo;d rather be short than inflated is you don&amp;rsquo;t want to take on capital. To quote someone else I&amp;rsquo;ve recently come into contact with, &amp;lsquo;you want to get off the tit as fast as possible&amp;rsquo;. To give a little more explanation, most startups take sizable investments from VC&amp;rsquo;s or other parties to get going. The problem here is that you then have to answer to them, if you&amp;rsquo;re the one with the idea, with the vision, why would you want to give up any control of that. And the fact is you shouldn&amp;rsquo;t, going back to point 1 and 2, if you have the business model it shouldn&amp;rsquo;t be long before you see revenue, and if all your employees believe in the company, they wont expect a high cushy salary, they&amp;rsquo;ll take ownership in the company as part of their compensation.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Keep your employees happy, the easiest way to do this is pizza and beer. It&amp;rsquo;s simple, but works. If you have happy employees enjoying what they do they&amp;rsquo;ll work harder and longer. The smaller you are the more poisonous it is to have employees that don&amp;rsquo;t fit in and embrace your culture. Sure diversity can be a good thing, and you do need some balance of it. But more than that you don&amp;rsquo;t want to ruin the atmosphere and comraderier that comes along with a startup. In addition to keeping your employees happy those small things help, pizza and beer for 20 to get an extra hour of work and the intangibles of helping build relationships that allow them to work better is far cheaper than paying them extra dollars to work late.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Don&amp;rsquo;t overspend, this may seem in contrast to 4, and often times poeple go with one extreme or the other. Pizza and beer makes sense, Lobster lunches do not, I don&amp;rsquo;t care if you are google, they still don&amp;rsquo;t make sense. If you are doing extremely well and want to give back to employees give it with cash, they&amp;rsquo;ll appreciate it more. Bsimilar search for John McCain shows a normal pro-McCainut order in lunches every day and pool tables are no necessary expenses.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>If there&amp;rsquo;s enough response I&amp;rsquo;ll follow up with some of the more tangible ways of making this happen, but for now, enjoy these big picture take aways.&lt;/p></description></item><item><title>All the bubbles haven't burst yet</title><link>/2008/11/03/All-the-bubbles-havent-burst-yet/</link><pubDate>Mon, 03 Nov 2008 00:51:54 -0800</pubDate><guid>/2008/11/03/All-the-bubbles-havent-burst-yet/</guid><description>&lt;p>As I watch the news and posts roll in each day with new layoffs in the valley, ranging from large corporations such as HP and EA, down to the small guys such as seesmic, imeem, searchme, and zillow to name only a few, there still seems to be a demand for &lt;!-- raw HTML omitted -->certain job skills&lt;!-- raw HTML omitted -->. While as I look down the list some of these I dont feel are any longer demanded skills, and others will soon be there. In part I want to call attention to facebook first. While everyone and their brother, when launching a website wants to build a facebook app to deliver some of their content on to facebook, the time and effort put into this is no where near the return. The market has become so flooded the penetration you will get is quite trivial. Futhermore cpm&amp;rsquo;s have already plummeted for advertising on facebook, ranging in some cases around .10-.15.&lt;/p>
&lt;p>Meanwhile iphone developers are still rushing to get their idea into the app store. While a decent idea, and I more than support new applications, so that I can use them on my phone, a 10 million person marketplace is still extremely small, especially if you&amp;rsquo;re not a mainstream application. It used to be that one million users on your website was the golden point in social networks when you could really go for significant funding, or you could start talking a selling price. But thats not the case anymore, much less to reach that on the iphone you would have to be somewhere between the top 10 and top 25 elite apps. &lt;/p>
&lt;p>So sure, you might not have that many users that download your app right? But theres ad revenue possibilities. Well that works right now, the iphone is seeing insane cpm&amp;rsquo;s in some cases as high as $50. This is simply not sustainable. While some claim that mobile advertising is the holy grail of ad&amp;rsquo;s, that only works if you can capture user intent, which in contrast isn&amp;rsquo;t so simple. It works for search, because well when I&amp;rsquo;m searching for something that usually captures my intent, not so for when I&amp;rsquo;m using my phone. I strongly suspect that as these new hot markets calm down, companies will do proper analysis of ROI and no longer want many of these niche skills.&lt;/p>
&lt;p>In these cases I think there&amp;rsquo;s going to be able more smaller bubbles bursting and a lot more niche developers searching for something more than developing the occasional website for the store down the street.&lt;/p></description></item><item><title>Ads is not a business model</title><link>/2008/09/13/Ads-is-not-a-business-model/</link><pubDate>Sat, 13 Sep 2008 03:10:15 -0700</pubDate><guid>/2008/09/13/Ads-is-not-a-business-model/</guid><description>&lt;p>I recently attended part of the recent Techcrunch 50 conference, and when I wasn&amp;rsquo;t there I was watching much of it online. For probably 80% of the companies when it came time to ask about their business model, they said ads. Then they talked about cause they have all of this great information about the user they can advertise better than they used to. The problem is they&amp;rsquo;re forgetting all about user intent. This is why ads on facebook simply arent working, with some CPM&amp;rsquo;s being as low as .05. &lt;/p>
&lt;p> &lt;/p>
&lt;p>Ads work on search because users are looking for something, and if you place an ad for it they&amp;rsquo;re fine with it, because they didn&amp;rsquo;t want to stay on the search page. When a user goes to facebook they want to stay on facebook, not leave. When a user is in an application they want to stay in the application, as long as the site or application is a destination or resides on a destination it will not make great revenue from traditional ads. Yeah, theres oppportunities for newer creative advertising, but this form of ad&amp;rsquo;s will not provide the same revenue &lt;!-- raw HTML omitted -->yet &lt;!-- raw HTML omitted -->as others. If you&amp;rsquo;re launching a product or site, actually consider how your worth making money, just saying ads in most cases is not a business model.&lt;/p></description></item><item><title>Google did something right . . . . Finally</title><link>/2008/09/04/Google-did-something-right-.-.-.-.-Finally/</link><pubDate>Thu, 04 Sep 2008 17:21:56 -0700</pubDate><guid>/2008/09/04/Google-did-something-right-.-.-.-.-Finally/</guid><description>&lt;p>Forget the benchmarks, forget whether its truly faster or slower, forget whether the market share is 30% for non-IE browsers (though is this only for US or internationally). Google Chrome evolution or revolution, whatever you want to call it, it makes me actually want to stay in the browser. I just want plugins, that function as well as the browser alone does. Yeah theres rendering problems, and some oddities, but the browser as a whole is smooth. I actually feel thus far its the best of IE and safari melded together. The only problem I see right now is the lack of plugins, which my guess is will come VERY SOON. Meanwhile firefox when having the plugins I want enabled can be sluggish, if Chrome plugins are of equivilant quality then I can&amp;rsquo;t see how the browser wouldn&amp;rsquo;t be at LEAST as smooth.&lt;/p>
&lt;p>Chrome really is a win for Google, whether they can monetize it or not. It helps them to keep people off the desktop and in the browser. I could go on for hours about bad moves they&amp;rsquo;ve made, such as picasa, but Chrome was actually a good one.&lt;/p></description></item><item><title>Being an employee</title><link>/2008/08/29/Being-an-employee/</link><pubDate>Fri, 29 Aug 2008 17:44:19 -0700</pubDate><guid>/2008/08/29/Being-an-employee/</guid><description>&lt;p>As I currently work at a startup I have a small stake in the company. When talking with one friend of something I have been working with someone with on the side, the question came up over if this was a conflict of interest. I was actually quite shocked to hear the question at first, not only did I expect them to do likewise, as I know many that do. The full on conflict of interest statement just shocked me. Being at a startup it does make it slightly more of an interesting statement, but I received similar comments sometimes at my former Fortune 100 employer. I&amp;rsquo;ll start with that place and then migrate to the startup environment.&lt;/p>
&lt;p>I could not disagree more being an employee at some place, and working on additional things being a conflict of interest. In short you are an employee, not property, your best interests lie with yourself. Sure its great if you believe in the company and what they do, but in our generation you are not attached for life to the company you work for. The company has claim on what you do between 8-5 with regards to work, sure if you do things that may damange a company brand or your effectiveness to do business its fair for them not to retain you, but simply doing additional work in your spare time? Hardly!&lt;/p>
&lt;p>Now as we move on to the startup atmosphere, where it&amp;rsquo;s pretty standard that when becoming employed you receive some amount of equity in the company. In most cases with not being a founder this stake is of relatively small size. Sure you could consider Google where I believe it was over 400 employees that were made millionaires by their IPO, but these situations are very rare. The equity receive normally vessts over a period of time, and from my perception is simply equivilant to a portion of your pay no more no less. Sure it does make you feel more of a sense of ownership, but does not extend to the full extent of the business owning you.&lt;/p>
&lt;p>As an employee you&amp;rsquo;re being paid to perform a job, they don&amp;rsquo;t have full claim to what you do on your time.&lt;/p></description></item><item><title>A Lesson from the Wal-Mart Model</title><link>/2008/08/19/A-Lesson-from-the-Wal-Mart-Model/</link><pubDate>Tue, 19 Aug 2008 03:43:42 -0700</pubDate><guid>/2008/08/19/A-Lesson-from-the-Wal-Mart-Model/</guid><description>&lt;p>Many people criticize Wal-Mart for the way they run their business. I personally find no problems with it, as their goal is simply to make prices competitive. If you care about the other details then either A. shop else where or B. donate to those causes you feel should be supported with the money you save. While sure some of these qualms may be justified I&amp;rsquo;d like to hint at another thought, of why people don&amp;rsquo;t take advantage of the same approaches.&lt;/p>
&lt;p>You see I recently started using a service, which I&amp;rsquo;d prefer not to disclose yet that gives me access to completing very monotonous and tedious tasks for very low price. Indeed there is some overhead involved but once you learn to manage it effectively, and that is the key to do it effectively. Because in reality anyone can manage, but the vast majority over manage things, rather than giving them just the right amount of attention. But back to the primary point, the idea of taking tasks that you normally wouldn&amp;rsquo;t do because of their tedious low value nature and getting those completed for a very low cost can become extremely valuable for you. When you start to think out if you had more time to do those tasks hundreds of things probably come to mind, so I&amp;rsquo;ve encourage everyone to explore the low cost options for work/support and try to leverage them to your advantage&lt;/p></description></item><item><title>Why Qik Matters</title><link>/2008/08/14/Why-Qik-Matters/</link><pubDate>Thu, 14 Aug 2008 17:15:34 -0700</pubDate><guid>/2008/08/14/Why-Qik-Matters/</guid><description>&lt;p>Live video streaming from your phone might just seem like another form of lifecasting, a video form of twitter, or even a mobile version of ustream.com or justin.tv, but it really is far more than that. A few people have taken these mobile streaming services such as Qik, Flixwagon, and Kyte and really used them to their fullest capacity. Sure you can go to an extreme like Robert Scoble, but admittedly most of his content from Qik can be pretty good.&lt;/p>
&lt;p>The real thing about mobile video streaming is something that some people have mentioned about twitter. Twitter often breaks the news, or has more information about breaking news than anywhere else. As much as anything thing else it allows for quick live footage of events. Whether its breaking news or an impromptu interview that someone happens to come across. Those willing to embrace this new form of potential reporting, and sacrifice expensive editing and high end video equipment will come away with more interesting pieces and find a rapidly growing following of consumers that tune in.&lt;/p>
&lt;p>Mobile video streaming is far far bigger than ustream and justin.tv. It&amp;rsquo;s about more than showing the day to day happenings of your life whenever you want, and more about continuous access to news and happenings.&lt;/p></description></item><item><title>Don't Do It Yourself</title><link>/2008/08/09/Dont-Do-It-Yourself/</link><pubDate>Sat, 09 Aug 2008 16:08:32 -0700</pubDate><guid>/2008/08/09/Dont-Do-It-Yourself/</guid><description>&lt;p>So traditionally I&amp;rsquo;ve been a very do it yourself person. I wanted to be the person that didn&amp;rsquo;t have to rely on anyone, and thus far it&amp;rsquo;s worked pretty well. I can handle my day to day chores, as well as do my job, and most any side project of venture I take on I feel like I can accomplish pretty well. However, I recently asked my question if that was the best approach. While it&amp;rsquo;s good to be self reliant, the people at the top seldom do everything on their own. If I take notice of where I spend my time, most of it is on tasks that produce very very little value. Meanwhile there&amp;rsquo;s other tasks where I only have time to spend a few hours a week that produce much larger value.&lt;/p>
&lt;p>On this point what I&amp;rsquo;m looking into is outsourcing many of these tasks. While it will take additional time to manage that process and delegate the tasks I believe I&amp;rsquo;m currently at a break even point where it makes sense. From there it can only go uphill and not down. I&amp;rsquo;ll likely post again in a few weeks after I&amp;rsquo;ve seen how this is progressed, but it seems those that are accomplishing a lot, in large part its because others do so much for them.&lt;/p></description></item><item><title>Fotoviewr</title><link>/2008/08/08/Fotoviewr/</link><pubDate>Fri, 08 Aug 2008 14:34:49 -0700</pubDate><guid>/2008/08/08/Fotoviewr/</guid><description>&lt;p>In the coming weeks I&amp;rsquo;m going to be working with a friend to help his venture in a new partnership that someone has approached him about. This partnership is rather large and I&amp;rsquo;m not at liberty to disclose details yet, and while this is indeed great news for the site, the great news for users is the site is already fully available.&lt;/p>
&lt;p>In short &lt;!-- raw HTML omitted -->fotoviewr&lt;!-- raw HTML omitted --> is one half of an online photo album, it doesn&amp;rsquo;t store your photos for you, but allows you to take your existing photos from &lt;!-- raw HTML omitted -->flickr&lt;!-- raw HTML omitted --> or &lt;!-- raw HTML omitted -->smugmug&lt;!-- raw HTML omitted --> (with other support coming soon) and instantly put them into a visually appealing gallery. To me the nicest thing about it is the variety. I&amp;rsquo;ve used piclens before, and while I love piclens to scroll through 1000&amp;rsquo;s of pictures quickly, that seems to be the extent to which I use it. I can&amp;rsquo;t use piclens to show off my photo&amp;rsquo;s to friends or family. While browsing through a standard flickr page isn&amp;rsquo;t a bad experience, it isn&amp;rsquo;t a good one. &lt;!-- raw HTML omitted -->Fotoviewr&lt;!-- raw HTML omitted --> really does seem to deliver the other piece of what is missing from online photo sites.&lt;/p>
&lt;p>Check out a few of the sample&amp;rsquo;s below, I&amp;rsquo;ve taken a few of my personal pictures from the past 4th of July and put them into a few of his views that are available. All-in-all this took me a fraction of the time it took to type this post, which is how more things should be online, simple.&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>How Ebay Missed the Boat</title><link>/2008/08/08/How-Ebay-Missed-the-Boat/</link><pubDate>Fri, 08 Aug 2008 00:05:21 -0700</pubDate><guid>/2008/08/08/How-Ebay-Missed-the-Boat/</guid><description>&lt;p>At a conversation today we got into a discussion about how ebay can compete with amazon. Which alone is enough content for an entire post, as they really aren&amp;rsquo;t playing the same game so not really competing. Instead I&amp;rsquo;d like to talk about where the conversation progressed to. To me the most interesting thing about ebay isn&amp;rsquo;t how they won the long tail, or how users are unhappy with the increasing costs placed on them. Instead its more at the level of where they really lost out.&lt;/p>
&lt;p>You see, ebay had a devoted following back around 2000. Millions of people would visit their site, buy items, focus on their feedback rating, often spending time in the same category. While at the time most of this was indeed innovative, they stopped there. If they had only taken it a step futher and exposed the final piece of the puzzle by allowing users to interact with each other. If they had developed a network of users that could communicate with each other, that shared interests based on product categories, they could have easily been one of the largest early social networking sites out there. As facebook initially exploded as a social network for college students, and other more recent ones focusing on younger crowds, meanwhile you have linkedin to as a professional network. Ebay could have very much been the network for collectors, or anyone purchasing similar items. Not only would have this increased user engagement, it would have driven more sales.&lt;/p>
&lt;p>Take for example if I&amp;rsquo;m a fan of a particular brand of jeans. I may be very proud of the brand I&amp;rsquo;ve found, but recently discovered some that were newer and more hip. Well I&amp;rsquo;m going to be a bit more hesitant to share that with my friends I hang out with as I want to be the one that&amp;rsquo;s hip versus everyone else having them as well. However if I have a similar community that I connect with online, I can share this information, build a repoire with them, and still maintain my step ahead of friends. It allows your users to become you product recommendation engine versus the Amazon approach of through a lot of machine learning at the problem.&lt;/p>
&lt;p>And the most unfortunate part of it all, I&amp;rsquo;m not sure ebay even realizes they missed the boat.&lt;/p></description></item><item><title>How social networking advertising should work</title><link>/2008/07/22/How-social-networking-advertising-should-work/</link><pubDate>Tue, 22 Jul 2008 18:10:12 -0700</pubDate><guid>/2008/07/22/How-social-networking-advertising-should-work/</guid><description>&lt;p>Social advertising is a very different than traditional web advertising. The thing about social media advertisers, is users aren&amp;rsquo;t looking for a product. They&amp;rsquo;re already engaged in some activity, and don&amp;rsquo;t necessarily want to be drawn away from that. But that does not mean there isn&amp;rsquo;t value in it, it&amp;rsquo;s just a different form of value than search advertising.&lt;/p>
&lt;p>When a user is searching from google, they are actually looking for something. They&amp;rsquo;re often looking for products, which is why advertising in its current form works great on search. It&amp;rsquo;s logical if a user is searching for shampoo, that proctor and gamble would want to pay to have their products show up on the right. This is vastly different from when I&amp;rsquo;m playing a racing game on facebook, and Ford shows me a commercial for their product, they&amp;rsquo;re not the same thing.&lt;/p>
&lt;p>However there is still HUGE value in social advertising. Since you know so much more about a user you can target them even better, I can know, age, gender, music/movie preferenes, interests, hobbies, among many other things. Where this can help is branding, if there is a car game, and you can present a solid brand in places throughout that game I become brand loyal without realizing it. I don&amp;rsquo;t become disengaged, but I do take notice of it. It&amp;rsquo;s much like the branding that takes place in movies, or console games, with large negotiated contracts, however it needs to occur on a micro-level.&lt;/p></description></item><item><title>Microsoft vs. Apple</title><link>/2008/07/16/Microsoft-vs.-Apple/</link><pubDate>Wed, 16 Jul 2008 00:19:48 -0700</pubDate><guid>/2008/07/16/Microsoft-vs.-Apple/</guid><description>&lt;p>I find it extremely amusing that Microsoft and Apple are in many senses the very same company, at least in their actions, yet people feel very different about the two. For the average person they aren&amp;rsquo;t really a fan of Microsoft, and many love Apple. While I&amp;rsquo;m not really suggesting anyone should love Microsoft, why are people such Apple fanboys. Apple makes the same bad moves as Microsoft, they control their software and limit functionality in order to drive sales in the future.&lt;/p>
&lt;p>For example with the iPhone, by disabling video streaming they are simply leaving something to be supported for next year. There&amp;rsquo;s now doubt that the phone is fully capable, especially with 3g, as qik is already supporting it. However they are having to jump through hoops to do it, when Apple could have simply enabled it in the SDK, and yet they didn&amp;rsquo;t. It&amp;rsquo;s unfortunate for AT&amp;amp;T in the process as well, because as people are die hard Apple fans, they feel Apple can do no wrong. This wasn&amp;rsquo;t quite the case in recent days, first with the launch of the iPhone 3g, there were many many bricked iPhones for that morning. Almost every complaint I saw on twitter drawed attention to AT&amp;amp;T screwing it up. However, from a source very close to the issue, the problem was entirely on Apple&amp;rsquo;s end, as they had tested for only a fraction of the traffic they got that day, and were not able to scale up new machines nearly fast enough.&lt;/p>
&lt;p>Now Apple woes seem to continue as with &lt;!-- raw HTML omitted -->MobileMe&lt;!-- raw HTML omitted -->. For all the fan boys out there, and while I agree they make a good product, they should still be help to the same regard of anyone else that makes a product, and be complained to when they screw up. Apple has indeed done a great job with marketing and a reasonable job with products, however they keep a strong reign on applications, which is why I like the applications that are on OSX, but hate that its suchaÂ  smaller number.&lt;/p>
&lt;p>I&amp;rsquo;m not saying love Microsoft, or even hate Apple. But people judge them on their actions, and while they drive the boundaries, theres still no hard in calling them out when they hold back just for more revenue.&lt;/p></description></item><item><title>Facebook apps worth using</title><link>/2008/07/12/Facebook-apps-worth-using/</link><pubDate>Sat, 12 Jul 2008 19:30:15 -0700</pubDate><guid>/2008/07/12/Facebook-apps-worth-using/</guid><description>&lt;p>Facebook applications to check out,&lt;/p>
&lt;p>Windows:
&lt;!-- raw HTML omitted -->Digsby&lt;!-- raw HTML omitted --> - Facebook Im on your desktop
&lt;!-- raw HTML omitted -->Fonebook&lt;!-- raw HTML omitted --> - sync outlook and facebook
&lt;!-- raw HTML omitted -->iDeskbook&lt;!-- raw HTML omitted --> - Browse facebook on the desktop
&lt;!-- raw HTML omitted -->Photosaver&lt;!-- raw HTML omitted --> - Friends photos as your screensaver&lt;/p>
&lt;p>OSx:
&lt;!-- raw HTML omitted -->Friend Photos Screensaver&lt;!-- raw HTML omitted --> - Friend&amp;rsquo;s photos as your screensaver
&lt;!-- raw HTML omitted -->Facebook exporter for iphoto&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->Adium&lt;!-- raw HTML omitted --> - Chat with facebook support
&lt;!-- raw HTML omitted -->Photobook&lt;!-- raw HTML omitted --> - Miss your camera at an event, just steal your friends album
&lt;!-- raw HTML omitted -->EventSync&lt;!-- raw HTML omitted --> - Sync event calendar with iCal&lt;/p>
&lt;p>Web:
&lt;!-- raw HTML omitted -->Wordpress fotobook&lt;!-- raw HTML omitted --> - Facebook albums inside your wordpress blog&lt;/p></description></item><item><title>Conversation aggregators vs. social network aggegators</title><link>/2008/07/10/Conversation-aggregators-vs.-social-network-aggegators/</link><pubDate>Thu, 10 Jul 2008 18:44:02 -0700</pubDate><guid>/2008/07/10/Conversation-aggregators-vs.-social-network-aggegators/</guid><description>&lt;p>I recently posted about web 2.5, and since that time have been diving into two sites that attempt to do this. The first is &lt;!-- raw HTML omitted -->friendfeed&lt;!-- raw HTML omitted -->, I&amp;rsquo;ve commented about it before. It&amp;rsquo;s overall a great site, however the community is still growing on it, and most of my personal friends are not on there, only those that I follow and interact with in a tech or professional community. And there&amp;rsquo;s the ability to go through and create an imaginary personality for friends, but for me that could take days, and while its still tempting I can&amp;rsquo;t quite commit that strongly. Yeah friend feed is great, but I find myself using it more for having a conversation with whoever is there, rather than using it to follow individual people.&lt;/p>
&lt;p>With the emergence of rooms in &lt;!-- raw HTML omitted -->friendfeed&lt;!-- raw HTML omitted --> it seems they realize its more about being able to have a conversation around a similar topic than it is to track individual people.&lt;/p>
&lt;p>However it seems that &lt;!-- raw HTML omitted -->socialthing&lt;!-- raw HTML omitted -->, which I recently got access to, thanks &lt;!-- raw HTML omitted -->socialthing&lt;!-- raw HTML omitted --> team, is a slightly better aggregator at least for my demographic. Friendfeed works well for those that use blogs, google reader, photo albums and the like. But friendfeed is seriously lacking on the facebook front, meanwhile socialthing is accomplishing this very well. While I&amp;rsquo;m not sure which one I&amp;rsquo;ll be engaged more in, in the coming weeks though I imagine it will depend on the purpose.&lt;/p>
&lt;p>Friendfeed works for following information about tech, news, or similar broad topics. Socialthing works for keeping up with friends, when they&amp;rsquo;ve uploaded pictures from last friday night, or when that girl you have a crush on in high school breaks up with a long-term boyfriend and needs a rebound, and the like. I&amp;rsquo;m not sure how friendfeed would work if they did just enable the same time of features for facebook, I imagine it might not catch as right now its about conversations more than it is a singular feed. Socialthing has a chance to win this one, but you really need to have more than 10 services you connect to.&lt;/p></description></item><item><title>The problem with facebook's platform, is the problem isn't the platform</title><link>/2008/07/08/The-problem-with-facebooks-platform-is-the-problem-isnt-the-platform/</link><pubDate>Tue, 08 Jul 2008 15:42:46 -0700</pubDate><guid>/2008/07/08/The-problem-with-facebooks-platform-is-the-problem-isnt-the-platform/</guid><description>&lt;p>Facebook&amp;rsquo;s development platform just over a year ago seemed like a genius idea, with an almost infinite amount of potential. While it&amp;rsquo;s still a very hot topic, and most sites these days when they lauch attempt to have a facebook version of their site or service available at almost at the same time. However, I believe we are already over the peak of this, as more controls are being put in place to slow viral growth, and users are spending less time on the site and engaged in the applications.&lt;/p>
&lt;p>My problem though is not with the slowing rate of engagement in applications developed on the facebook platform, but rather on what are the primary applications. Facebook seems to have done a very good job of keeping users to stay within the confines of the site, rather than simply using it as a utility. For most facebook is their personal planner for events, their personal datebook for friends/contacts, their online photo album, their email/messaging system, and more for some. And while it&amp;rsquo;s fine and dandy for some of these things, facebook is not the best endpoint to interact with when getting things to and from facebook.&lt;/p>
&lt;p>Take for example the facebook chat. This is a great utility to be able to talk with friends that I may not have spoken with in years, my AIM list has around 200 users, meanwhile my facebook has over 500. No I do not wish to speak to all of these all the time, but in the rare occasion that I do it&amp;rsquo;s convenient. However IM chat within a browser just doesn&amp;rsquo;t do it for me, not on facebook, or meebo for that matter. The nice fact is that there is a solution and more being developed. Personally if I&amp;rsquo;m at home I use adium (Mac only) for my instant messaging which supports facebook. If I&amp;rsquo;m on a windows machine I use digsby to chat with my facebook friends and monitor what friends are doing. While digsby isn&amp;rsquo;t a perfect solution, I strongly prefer it to the other option of chatting within the browser.&lt;/p>
&lt;p>What about pictures, that&amp;rsquo;s probably the single busiest activity outside of updating status. Here I know of multiple friends that have attempted to use the site&amp;rsquo;s interface for uploading pictures, only to have completed in double the time expected with much much more frustration than anticipated. Meanwhile, I simple select the photos I want to upload in iPhoto (there are options for mac and pc here), select export, click facebook, and off they go. This is the way it should be, I can do likewise for smugmug, flickr, etc.&lt;/p>
&lt;p>Facebook has done a reasonable job at giving developers access to to facebook to allow them to build reasonable applications. While there&amp;rsquo;s a lot of junk out there, there is also some reasonable applications to really make facebook a reasonable utility. The problem lies that these seem to be hidden gems, whether its facebook or some third party, someone needs to start bringing these to the attention of others. Unless facebook transitions to themselves as strictly a utility and differentiates themselves on the quality of service the utility gives, and less on their UI and stronghold of data, they will be in for a world of hurt in a few years.&lt;/p></description></item><item><title>Web 2.5</title><link>/2008/07/03/Web-2.5/</link><pubDate>Thu, 03 Jul 2008 19:03:41 -0700</pubDate><guid>/2008/07/03/Web-2.5/</guid><description>&lt;p>I&amp;rsquo;ve talked about web 2.0, talked about web 3.0, but today realized theres still a middle ground we have to reach in between the two. It&amp;rsquo;s quite a pain that I really have no idea when my friends do certain things online. While some use facebook for absolutely everything, this is most certainly NOT the best option. Throwing your data into their walled garden is one thing, but for this to be the one and only place you store your online data is quite stupid. Facebook will only open up when they&amp;rsquo;re absolutely forced to, and may not even open up then. To migrate &amp;rsquo;notes&amp;rsquo; or rather blog posts out of facebook, or all of your pictures, or you&amp;rsquo;re messages can be an absolute pain. Why not use a service built for just those things, such as a wordpress blog, or flickr/picasa, or twitter/jaiku? Well most people don&amp;rsquo;t because of the simplicity of facebook being the central place for your data and your friend&amp;rsquo;s data.&lt;/p>
&lt;p>Well there is a solution to it, though it&amp;rsquo;s not ideal yet, it will soon hit a tipping point of when it will be the solution. Well first I guess I should clearly layout the problem:&lt;/p>
&lt;p>web 2.0 - the dynamic web emerged, users started publishing content
&amp;hellip;. Mass amounts of data, problems getting to it all &amp;hellip;..&lt;/p>
&lt;p>thus in the future we have&amp;hellip;
web 2.5 - content aggregation became nessecary, via friend feed&lt;/p>
&lt;p>and eventually&amp;hellip;
web 3.0 - the semantic web, services understand you and your needs and provide content around context&lt;/p>
&lt;p>In short this is a small plug for friendfeed, but if anyone else knows of a better service to in essence create a feed of you, please send them this way. I&amp;rsquo;ll be posting a full review on friendfeed soon, but for the time being just want to point out the value in such a service. Right now I post on multiple sites, I twitter, I blog, I use facebook, I use smugmug, I use picasa, I use last.fm, I use ilike, I use librarything, I use tumblr, I use google talk, among others. While personally I might be a little more invested than most, still the point remains that a lot of people are on more than one of these services. While I know them and follow them on the ones I know about, chances are I will never see their flickr accounts, or last.fm accounts. While some people worry about privacy and this being a stalker&amp;rsquo;s nightmare, I really don&amp;rsquo;t see it making things that much easier. Much less, most people are making a pretty big assumption assuming that they&amp;rsquo;re worth being stalked. I personally hope I could have a stalker come out of such, as it would give me a definifitive answer that someone actually reads and find me interesting. I just hope she&amp;rsquo;s 5'6&amp;quot;, and a blonde bombshell, but then again I&amp;rsquo;ll take whatever stalkers I can get.&lt;/p>
&lt;p>But the point remains that before we get to web 3.0 and the ability to deliver content based on context, we need to aggregate the content. Sites like friendfeed (and eventually socialthing) are a reasonable first step.&lt;/p>
&lt;p>Check out my friendfeed at: &lt;!-- raw HTML omitted -->&lt;a href="https://www.friendfeed.com/craig081785">www.friendfeed.com/craig081785&lt;/a>&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>A Generation</title><link>/2008/06/29/A-Generation/</link><pubDate>Sun, 29 Jun 2008 18:51:47 -0700</pubDate><guid>/2008/06/29/A-Generation/</guid><description>&lt;p>I&amp;rsquo;ve written many posts here about business, technology, and the like. The reason I&amp;rsquo;ve been so delayed in updating, in addition to the busyness of life, is because this post has been brewing in my head for quite some time. I just haven&amp;rsquo;t been able to sit down and actually compose it until now for some reason.&lt;/p>
&lt;p>So many of my posts have been about the web and how things will change in the future. Well while in this post it is still strongly related I want to talk a bit more about the social aspect. Of how I feel the next generation will insight change in much of the world because of the web. With the web and all of its utilities, youtube, aim, twitter, email, people no longer feel they&amp;rsquo;re separated by thousands of miles. Also its allowed any old joe to take on the form of publisher. I&amp;rsquo;ll concede that my generation watches more television than any generation prior, that sex and STD&amp;rsquo;s are at a higher rate than ever before. But in large part I believe the whole of the generation is following and simply consuming then information put out by the generation ahead of them.&lt;/p>
&lt;p>BUT, there is a small group within the generation that cares about change. That small group is now able to gather mass following, to cause others to thing, and to actually make a difference. This generation seems to have done this through simply expressing themselves. To them its not about making money, or having a cult following, its about personal expression.&lt;/p>
&lt;p>Here&amp;rsquo;s a few examples of what I mean about people expressing themselves:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->wefeelfine.org&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->Kiva.org&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>The site that gets it right</title><link>/2008/06/19/The-site-that-gets-it-right/</link><pubDate>Thu, 19 Jun 2008 17:17:55 -0700</pubDate><guid>/2008/06/19/The-site-that-gets-it-right/</guid><description>&lt;p>This week I want to talk about one of the hands-down best sites on the internet. Mint.com, in case you haven&amp;rsquo;t heard about Mint yet, it&amp;rsquo;s like Quicken or Microsoft Money just online. You create an account on the website, login, add your account information. From there mint connects to each of your accounts, pulls down your transaction history, automatically categorizes your spending into categories, and then will send you alerts for budgets or other settings via text or email. Oh, and best of all since it knows where you&amp;rsquo;re spending your money, it tells you how you can save.&lt;/p>
&lt;p>So since mint sounds great and wonderful, and it indeed is, I&amp;rsquo;m going to jump straight in and start addressing issues people may already have about this kind of site. The first is security, why would I give all of my account information away to a single place so someone could walk in and take every penny I have? Well first account information is hashed, it&amp;rsquo;s not just sitting in some text file on some desktop, its quite secure. Next, well mint gives you warnings right? So if someone goes and buys a car with you&amp;rsquo;re credit card you&amp;rsquo;ll get a text message about it. Now I may be missing something, but my bank has never offered me that kind of service. Oh and best of all, just because you put your account information, you still have the normal security backing of your bank and liability.&lt;/p>
&lt;p>Worried about a company having so much information on you? What if I told you in a matter of minutes if I know you&amp;rsquo;re name I could likely have your past 3 residences, phone numbers, and other information. Or for that matter if you&amp;rsquo;re concerned with a company having that information, do you pay cash for everything. Because if you don&amp;rsquo;t the credit card companies have just as much information, and they and other companies often sell this information. Mint.com &lt;!-- raw HTML omitted -->promises not to do such&lt;!-- raw HTML omitted -->. So if your argument is that you don&amp;rsquo;t want people to know that much information about you, its a very valid one, but hypocritical if you don&amp;rsquo;t always use cash which, which in ways can still be traceable.&lt;/p>
&lt;p>Finally I just want to highlight my favorite thing about mint.com. They get web 3.0, sure they have a rich interface, decent categorization, and good alerts. But best of all, they know where I spend my money, they know generic stuff about me, but because of that they can recommend to me ways I can actually save money. Now it may be just me, but I&amp;rsquo;m pretty sure everyone out there would like to save money. So its great to show ways that I truly can save money, not typical propaganda that is a waste of time for me.&lt;/p></description></item><item><title>Site Review: Friendfeed</title><link>/2008/06/12/Site-Review-Friendfeed/</link><pubDate>Thu, 12 Jun 2008 23:37:30 -0700</pubDate><guid>/2008/06/12/Site-Review-Friendfeed/</guid><description>&lt;p>There&amp;rsquo;s been a lot of buzz in the valley lately around this very small startup, that has a few pretty heavy hitters. Between the four founders they have worked on nearly all of the Google products so many know and love, with the exception of search. &lt;!-- raw HTML omitted -->Paul Bucheit&lt;!-- raw HTML omitted -->, is even responsible for Google&amp;rsquo;s current motto, &amp;ldquo;don&amp;rsquo;t be evil&amp;rdquo;. These four guys not only are visionaries within the web space, they also know how to deliver a product, having helped build and scale gmail and google maps is indeed a noteworthy accomplishment.&lt;/p>
&lt;p>But what about their current task at hand, to be &lt;!-- raw HTML omitted -->web 3.0&lt;!-- raw HTML omitted --> and r&lt;!-- raw HTML omitted -->educe the noise of all of the web 2.0&lt;!-- raw HTML omitted --> tools out there. Well, first let me summarize what friendfeed does. When you sign up for friendfeed you add your web 2.0 accounts (currently supporting 35), some of note are: facebook, google talk, iLike, digg, twitter, flickr, picasa, youtube, yelp, and others. &lt;!-- raw HTML omitted -->Friendfeed &lt;!-- raw HTML omitted -->then creates a feed of you, so you can send the link to anyone and they can have a single source for updates to all of your web 2.0 interactions. &lt;!-- raw HTML omitted -->Friendfeed &lt;!-- raw HTML omitted -->does do a little more than that though, they attempt to filter out some of the noise by grouping your interactions together. For someone like Robert Scoble that on a given day could post 1000 tweets, you likely don&amp;rsquo;t want to see each one as a single line item. Friendfeed will group these and give you a short preview, then allow you to drill down.&lt;/p>
&lt;p>All-in-all &lt;!-- raw HTML omitted -->friendfeed &lt;!-- raw HTML omitted -->is a reasonable service and will continue to be talked about in the valley for the coming year and then spread elsewhere in the world. However there are some problems with the service. First is the lag time, due to the restrictions of some of the services they connect to, sometimes your feed is twenty minutes behind your original posts/updates. Though this is no fault of their own, but nonetheless something users will not be excited over.&lt;/p>
&lt;p>But more importantly &lt;!-- raw HTML omitted -->friendfeed &lt;!-- raw HTML omitted -->doesn&amp;rsquo;t have a concept of context. This would be my number one complaint that they&amp;rsquo;re not approaching web 3.0 yet. My most likely favorite site (well second to &lt;!-- raw HTML omitted -->twitter&lt;!-- raw HTML omitted -->), which will be reviewed next week, does a great job of understanding you and your context. When it recommends something it&amp;rsquo;s doing based on your history and it&amp;rsquo;s knowledge of you, and its often right. Indeed grouping messages together does have value, but until it can show me the messages I &lt;!-- raw HTML omitted -->want&lt;!-- raw HTML omitted --> to see and hide the ones I do not I won&amp;rsquo;t be amazed.&lt;/p>
&lt;p>Whether or not you should be on it strictly depends on your involvement in web 2.0 sites. If you&amp;rsquo;re on more than 5 of the sites listed in their 35, it may be a worthwhile investment. While it won&amp;rsquo;t make the noise quiet, it will likely reduce it by 10-20%, which is better than nothing.&lt;/p>
&lt;p>Other sites to watch out for (if they ever release): &lt;!-- raw HTML omitted -->socialthing &lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>For those interested, &lt;!-- raw HTML omitted -->my friendfeed&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>iPhone 1.1</title><link>/2008/06/11/iPhone-1.1/</link><pubDate>Wed, 11 Jun 2008 12:54:32 -0700</pubDate><guid>/2008/06/11/iPhone-1.1/</guid><description>&lt;p>So this week they announced what many expected was coming the iPhone 3g. However off the shelf it&amp;rsquo;s still not webÂ  2.0, while a great device its not a web 2.0 device yet. Apple without a doubt understands user experience, but they do not fully grasp web 2.0 yet. Microsoft seems to even have a better understanding with the products they are looking to role out with Mesh and their enterprise social/collaboration tools. Lot&amp;rsquo;s of great applications were highlighted at the keynote, but only one of those talking about publishing content (with the exception of mobileme, which is a paid service). While there&amp;rsquo;s no doubt I will be getting the new iPhone when it is released in July, I will not talk about how it is a great web 2.0 device.&lt;/p>
&lt;p>If the application store is as open as Apple alludes to it being, then I can see how it will quickly become a web 2.0 device. Loopt is likely the strongest contender for helping to build a location based social network, and when they release for the iPhone can turn it into a web 2.0 device. I&amp;rsquo;ll be most anxious to see how the push based services they announced will help to allow developers to turn it into a web 2.0 device as well. If I had to have my application constantly up it just doesn&amp;rsquo;t work out as a full enabler for web 2.0. BUT if you allow notifications to be regularly pushed it just simplifies and increases the regularity of community and people staying in touch.&lt;/p>
&lt;p>The tipping point though for me at least will be if or when Apple finally allows video on the video. No, not playing video, but recording and streaming video. The kind of abilities available on a nokia n95, or available in my apple computer through iChat. When I can pull my phone out of my pocket and display to the world what I&amp;rsquo;m doing or where I&amp;rsquo;m at, you will have a device that allows you to communicate and most of all collaborate like any other before. It doesnt require more power than is already there, in fact I can record video on my jailbroken phone right now. The nokia n95 does a great job of streaming live video to qik, which is how I watched much of the Apple Keynote, it simply takes Apple finally understanding web 2.0 and embracing it.&lt;/p></description></item><item><title>How not to be successful in the valley</title><link>/2008/06/10/How-not-to-be-successful-in-the-valley/</link><pubDate>Tue, 10 Jun 2008 18:48:53 -0700</pubDate><guid>/2008/06/10/How-not-to-be-successful-in-the-valley/</guid><description>&lt;p>While I may or may not know how to be successful in silicon valley, I feel pretty confident that I can point out a few ways to not be successful in valley terms. What follows is my thoughts on how you can best limit yourself to own, run, or be involved in the entrepreneurial spirit of the valley.&lt;/p>
&lt;p>The first is keeping yourself in a bubble, by not diving into the new technologies, new services, and new age of the web there&amp;rsquo;s little possibility you can be at the next steps of it. While I concede you don&amp;rsquo;t always have to explain it or understand it, you at least need to &lt;!-- raw HTML omitted -->use it&lt;!-- raw HTML omitted -->. The prestigious attitude of standing against something just for the sake of it won&amp;rsquo;t get you very far when people attempt to find you and communicate and can&amp;rsquo;t. There will be few individuals in the future similar to Jobs and Ellison that are a box of mysteries that no one has access to. Instead you will simply filter out noise that is relevant, but regardless your presence will be felt. It&amp;rsquo;s not only about making your life easier with useful tools like mint or dropbox and thinking about the next useful utility, but also about communicating and relating to others. Final thought &amp;hellip; facebook be on it, twitter use it (don&amp;rsquo;t understand it, don&amp;rsquo;t explain it, just use it), friendfeed (jury&amp;rsquo;s out, but you better know what it is).&lt;/p>
&lt;p>The second biggest thing you can do is to be patient. So many seem to sit around, wanting to have their own big thing, but are waiting for that one great idea to come to them. In most cases something probably does, the only problem is they&amp;rsquo;re not seasoned or practiced at building something. Yeah a few get lucky on the first try, but as a whole for those that are successful its due to persistence and not patience. Waiting for the right time in the market, the right time in your life, or just the right idea is wasting time you can&amp;rsquo;t get back. If you truly want to run something, start running something, and when the right idea does finally come along you&amp;rsquo;ll be prepared to build it up and run with it.&lt;/p>
&lt;p>Third thing you can do is not to network. Yeah it&amp;rsquo;s easier than before to build a product and get people to adopt it because of the web, but that doesn&amp;rsquo;t mean you can do it on your own. If you want to have a great idea with a lot of potential go to waste, sit at home on a Friday night, work away alone and you will have no worries about having too much traffic or too many users. Most likely your idea will only appeal to you and miss various features and miss the needs of some of the users that would have been happy to tell you what they wanted.&lt;/p>
&lt;p>Fourth, spend all your time networking. So you go to the events, meet the people, know people to fund you, have a great idea, and finally decide you&amp;rsquo;re going to actually start working on a product. The same night you sit down to code, you read of your product launching with someone else. With less funding, less knowledge, and less experience, all because they&amp;rsquo;ve actually been working on it. It&amp;rsquo;s a fine balance, but err on the side of not having &lt;!-- raw HTML omitted -->every&lt;!-- raw HTML omitted --> connection that you will need for a successful launch, and instead having a working demo or product to show to the connections that you do have.&lt;/p></description></item><item><title>The value in content as a commodity</title><link>/2008/06/09/The-value-in-content-as-a-commodity/</link><pubDate>Mon, 09 Jun 2008 19:22:55 -0700</pubDate><guid>/2008/06/09/The-value-in-content-as-a-commodity/</guid><description>&lt;p>There was a recent post over at &lt;!-- raw HTML omitted -->ReadWriteWeb&lt;!-- raw HTML omitted --> about how content is becoming a commodity. I don&amp;rsquo;t believe many people would argue with this. While at first this wasn&amp;rsquo;t something I viewed in a positive light the more I think over it the more I see some value in it. As content does become more and more of a commodity the value in who is publishing or producing that content goes up. Five years ago if someone would have talked about some trade-secret they learned about from Google many people would have perked up and listened. Today however rumors spread faster than ever and before you know it google calendars now predicts when your appointments are, puts them in your calendar, and sends you text messages with directions 30 minutes before each meeting. While this may very well happen some day, I&amp;rsquo;m pretty sure they won&amp;rsquo;t be rolling it out next week.&lt;/p>
&lt;p>Now with so much content being produced and spread all over the place there is still some value in the quality of content (which there always has been). However, now there is much heavier focus on the source it came from. This comes to the principle of branding, and not necessarily like a wal-mart or coke brand, but a personal branding. My guess is that in the future, and by future I mean sooner than later (likely 2-3 years), personal brands as a whole will carry more weight than the companies they work for.&lt;/p>
&lt;p>Take for example &lt;!-- raw HTML omitted -->Digg&lt;!-- raw HTML omitted -->, when &lt;!-- raw HTML omitted -->Digg &lt;!-- raw HTML omitted -->makes some announcement or stance a few people listen and it does get noticed. But this is only when the content or opinion falls within the &lt;!-- raw HTML omitted -->Digg &lt;!-- raw HTML omitted -->world. Meanwhile when &lt;!-- raw HTML omitted -->Kevin Rose&lt;!-- raw HTML omitted --> makes an announcement many more people than just in the realm of &lt;!-- raw HTML omitted -->Digg &lt;!-- raw HTML omitted -->notice. He&amp;rsquo;s a prime example of someone that has built a personal brand, he&amp;rsquo;s name carries weight, and more so than just that of &lt;!-- raw HTML omitted -->Digg&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->Pownce&lt;!-- raw HTML omitted -->, or &lt;!-- raw HTML omitted -->Revision3 &lt;!-- raw HTML omitted -->(even though they are nearly one in the same).&lt;/p>
&lt;p>Some might view content becoming a commodity as a bit of a blow. I believe we will see more individuals emerge with an understanding of personal branding in part to help us sort through the content, but also to provide quality content in repeatable manners.&lt;/p></description></item><item><title>Nearsighted Business</title><link>/2008/06/05/Nearsighted-Business/</link><pubDate>Thu, 05 Jun 2008 18:26:27 -0700</pubDate><guid>/2008/06/05/Nearsighted-Business/</guid><description>&lt;p>Adobe&amp;rsquo;s former CEO, Bruce Chizen, when asked &amp;lsquo;What advice do you have for new/young public companies?&amp;rsquo;, gave a response of &amp;lsquo;Go private&amp;rsquo;. While partially a joke he went on to elaborate something that many businesses seem to miss on. The main idea is that businesses are very nearsighted in their focus, they look at quarterly goals and in some cases yearly, but not where they want to be in 10 years. When companies become worried that head count is high they simply freeze hiring across the board without thinking of its ramifications. Good people, well great people are truly hard to find, and when a company enforces a blanket hiring freeze they miss out on those few great people that they truly need to grow. Meanwhile when they decide they have bandwidth for 1000 new employees they open the flood gates and let the first 1000 that can spell their name correctly in, because they can. This short term focus in the long run greatly limits the ability of what a company can achieve.&lt;/p>
&lt;p>In contrast a smaller company that is actually much more at risk of dying seems to have a better understanding of what their approach should be. While they may be understaffed and overworked, they firmly understand that they only have so many funds and therefore make wiser decisions when using them. The characteristics of the larger business and their short sighted focus leads to the cyclical performance that many experience over a few years, rather than a very steady growth they would like to maintain, and often leads to their end. A prime example would be IBM that laid off so many of their more talented people to lower their numbers years ago. As a result they lost their best workers and had many unexperienced individuals in there when they began hiring again. They are still working to catch back up to where they once were in the IT industry&amp;hellip;&lt;/p>
&lt;p>In part I wonder if being a private entity is really the only way to have the long term focus and not worry about quarterly earnings. Personally I have never been privy to this insight and may not be for some time, but I don&amp;rsquo;t foresee shareholders being patient enough to not punish a company if earnings are not so hot for a year or even a few quarters. So there may be nothing a large business can do about it, but I am surprised that more do not try.&lt;/p></description></item><item><title>Blurring the lines, the flip side</title><link>/2008/06/04/Blurring-the-lines-the-flip-side/</link><pubDate>Wed, 04 Jun 2008 23:23:33 -0700</pubDate><guid>/2008/06/04/Blurring-the-lines-the-flip-side/</guid><description>&lt;p>So yesterday I posted around blurring the lines around your personal and professional life. Today I&amp;rsquo;d like to discuss a bit of the opposite of when companies blur the lines. Hopefully you don&amp;rsquo;t, but at first you may think how is this possible. Well first let me highlight some of what many feel are negative pieces, such as when an HR Rep who went to the same university as you looks up your facebook profile. You thinking this is private to friends at school may not regularly monitor the content that goes up there. This specific case is a very interesting one, and for the moment I&amp;rsquo;d like to stay clear of it.&lt;/p>
&lt;p>Instead I&amp;rsquo;d like to focus on some of the areas where businesses undoubtedly should improve, and some notable ones that are doing that very well. I first would like to take (as per my usual) an example from twitter. Twitter is many things for many people, but it is extremely common to find people on twitter ranting about a particular service. While I may complain all I want about &lt;!-- raw HTML omitted -->Comcast &lt;!-- raw HTML omitted -->to my friends, they have little ability to do much to counteract this. But when I do it on &lt;!-- raw HTML omitted -->twitter &lt;!-- raw HTML omitted -->they do, and &lt;!-- raw HTML omitted -->Comcast &lt;!-- raw HTML omitted -->is one example of a company that is taking a very pro-active approach to managing their online presence. I take an example of a few months ago, when internet had been out at Michael Arrington&amp;rsquo;s house, who is the founder of &lt;!-- raw HTML omitted -->TechCrunch&lt;!-- raw HTML omitted -->. He twittered about this outage, and had a personal phone call from an executive in Philadelphia a few hours later. Sure, he&amp;rsquo;s a noticeable guy so they responded to him. To me the attention getter was when someone called comcast&amp;rsquo;s bluff they they only follow the important people, and any old average joe doesn&amp;rsquo;t get a response. That particular average old joe did, saying they make the best effort they can to reach out to everyone (&lt;!-- raw HTML omitted -->HR Block&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->Southwest &lt;!-- raw HTML omitted -->are also doing this quite well).&lt;/p>
&lt;p>The other is a little less about blurring the lines, but I still think a great example of a business stepping out of their traditional roles. This one was a story relayed to me by a co-worker. &lt;!-- raw HTML omitted -->Zappos&lt;!-- raw HTML omitted -->, which is an online shoe company primarily, has a great return policy. In any case, if you don&amp;rsquo;t like the shoe after you receive it, just return it, and they&amp;rsquo;ll even pay for the shipping. This specific incident a woman&amp;rsquo;s husband had recently passed away and she was attempting to return the shoes. She gave the reasoning behind it, and the customer service rep proceeded to go an extra step and send flowers to the funeral. While to some this might be offensive, or at the very least outside the bounds of a normal company, it shoes a company actually caring for people, which wasn&amp;rsquo;t their core business. While I won&amp;rsquo;t go into details of how well this turned out for the company, it&amp;rsquo;s a great example of a company blurring the lines.&lt;/p>
&lt;p>In the future I anticipate we will see more and more of companies doing this, actually caring about what someone says/thinks/feels not only about the company, but personally as well. As we get to this it will become less about the buck and more about meeting needs.&lt;/p></description></item><item><title>Mixing personal and professional, Transparency</title><link>/2008/06/04/Mixing-personal-and-professional-Transparency/</link><pubDate>Wed, 04 Jun 2008 02:57:16 -0700</pubDate><guid>/2008/06/04/Mixing-personal-and-professional-Transparency/</guid><description>&lt;p>Someone recently commented on by tweeting after having given my two weeks notice to my company, that it may not have been the best idea. So as a result I&amp;rsquo;d like to post my reasoning and thought why I feel it is actually a great idea. Even a month before my giving two weeks notice many knew it was likely going to happen, and I personally hope that this allowed those that may have needed to, to better plan accordingly. This also I believe allows me to be more evaluated on my actual merit in some terms. You see if I made it clear that I might be looking at another opportunity, and was not wanted I believe there may have been good reason hints would have been given that I should look harder and more. Instead in was a reasonable bit of the opposite.&lt;/p>
&lt;p>However the larger point of what I&amp;rsquo;d like to illustrate is that many of those that I work with I view as more than strictly co-workers. It&amp;rsquo;s not uncommon to meet up with them on a Saturday for drinks or to just hang out. Meanwhile I have many friends who I do not talk to on a daily or even weekly basis, yet still like to keep them informed of what I&amp;rsquo;m up to, just as I look to follow how they are. To me twitter and other social tools are this medium. While some may prefer to keep professional and personal strictly separate entities, I have no problem with the two blurring. In fact I believe it adds to what I bring to the table in both contexts. By no means do I live and breath work, but to me my work is not only a job either. There are times after 5 or 6 o&amp;rsquo;clock that I will spend reading about business and technology, in short because they interest me. Though there are times between 8 and 5, that I will have an IM conversation un-work related, or post tweets available to the rest of the world.&lt;/p>
&lt;p>Hopefully some may value this transparency, though if you do not, dont add me on facebook, dont follow me on twitter. You&amp;rsquo;ll still get the formal good-bye email with the rest of the group, however, I wouldn&amp;rsquo;t expect you to get updates in 5 years, though that may be what you hope for. Personally I like to keep in touch with those that I enjoy working with, but also care to know about how they are doing with regards to their personal life. To me blurring the lines makes the relationships deeper and life more rewarding&lt;/p></description></item><item><title>Adobe came to play</title><link>/2008/06/03/Adobe-came-to-play/</link><pubDate>Tue, 03 Jun 2008 00:30:10 -0700</pubDate><guid>/2008/06/03/Adobe-came-to-play/</guid><description>&lt;p>I&amp;rsquo;m pretty sure I&amp;rsquo;ve said it before, but in case I haven&amp;rsquo;t voiced it on here yet, watch out for Adobe. They look like they&amp;rsquo;re firing on all cylinders lately and don&amp;rsquo;t look to be slowing down. At Adobe MAX 2007, I saw a preview of many things that were coming up for them. Though from already having worked with Adobe Flex was a fan, at least of the Flex and AIR products. Adobe now seems to be doing as much to drive adoption of the products as they expect from developers.&lt;/p>
&lt;p>First came the acquisition of Buzzword, which is a Flex based word application. With additional abilities for users to collaborate, which in my opinion were already slightly superior to Google&amp;rsquo;s word equivalent. Then came Adobe Photoshop Express, this was in a sense a lighter version of Adobe Photoshop, only available online and best of all for &lt;!-- raw HTML omitted -->free&lt;!-- raw HTML omitted -->. While impressive in their own rights, they really just did a great job of showcasing the power of flex.&lt;/p>
&lt;p>Now with acrobat.com adobe seems to have hit a home run. While it may only be a landing place for their in house web applications, it&amp;rsquo;s a landing place that points to a lot of great tools. Namely adobe connect, which at least matches if not passes every virtual meeting tool I&amp;rsquo;ve ever used. With well integrated white-boarding, screen sharing, file sharing, web cams, and dial-in support as well, it will surely be my choice for online meetings in the near future. Once the other tools such as buzzword and potentially other applications others such as google and microsoft will have to very much watch out.&lt;/p></description></item><item><title>Changing etiquette?</title><link>/2008/06/02/Changing-etiquette/</link><pubDate>Mon, 02 Jun 2008 06:16:31 -0700</pubDate><guid>/2008/06/02/Changing-etiquette/</guid><description>&lt;p>A recent conversation of someone that was offended when the were introduced to someone new, then was not greeted first since they were a female brought what follows to mind. The above is a train of thought that came from a 70 year old military wife. I do not believe this is common practice today and is quite rarely found as the common etiquette, but nonetheless I think what is proper etiquette in business is changing quite rapidly. Though I&amp;rsquo;m not sure if &lt;!-- raw HTML omitted -->all&lt;!-- raw HTML omitted --> of the older ideas and principles have gone away.&lt;/p>
&lt;p>I take as a first example zuckerburg, whom is a notoriously difficult interview. Not because he keeps things hidden, or is sealed tight about the company, but rather that his soft skills are not his strength. His strength is building a web product that millions of people find worthwhile to divulge hours of their day into it.&lt;/p>
&lt;p>Even two years ago when you were disgruntled with a company you may have gotten a few drinks in you and talked to a friend about your displeasure. But it certainly was not made fully public for anyone to see. At best you could only hope you were simply privy to things that would be brought to the publics eye from a larger misdoing either legally or that a mass-crowd found a problem with. But for simply being overworked, underpaid, or in some other odd way mistreated there was no politically correct outlet to speak through.&lt;/p>
&lt;p>However in the past years it has become extremely common for those that are still employed, or were employed to voice their complaints and bring to light the details that were once hidden. I think of Zed Shaw&amp;rsquo;s rant on rails which calls out specific companies, or an older blog the diary of a mac genius, who gave detailed behind the scenes information of an apple customer support genius bar. While I&amp;rsquo;ll concede for the mass majority if it&amp;rsquo;s published it&amp;rsquo;s doesn&amp;rsquo;t mean its consumed, so it&amp;rsquo;s not a dramatic effect on any single business, I still find it hard to believe that this overall shift of users freely publishing is not going to be able to be stopped by companies. As we approach web 3.0 and have a better ability to pull in a larger base of information that&amp;rsquo;s more relevant this information may become more and more helpful to users.&lt;/p>
&lt;p>Regardless of the effects, it seems the standard procedures for what is proper etiquette are changing. Whether its talking about your place of employment, or HR checking out you&amp;rsquo;re facebook profile to see if you&amp;rsquo;d be a risk for the company, the lines are being blurred from both sides and the barriers that once existed are now being torn down.&lt;/p></description></item><item><title>Is web 2.0 more utopian?</title><link>/2008/05/29/Is-web-2.0-more-utopian/</link><pubDate>Thu, 29 May 2008 17:36:50 -0700</pubDate><guid>/2008/05/29/Is-web-2.0-more-utopian/</guid><description>&lt;p>I recently read an article on Techcrunch on how web 2.0 had undoubtedly made an impact, but had yet to truly make money. From my stance they is really one way to make money on the web, which is through advertising (paid subscription services are dying). This can either be done through a simple banner ad, or something that can more easily be deemed a qualified lead or referral. Ads will always be there, but if web 2.0 is to start making money it must be on improving the measurement and throughput of qualified leads.&lt;/p>
&lt;p>Without going into too much detail on referrals and qualified leads I&amp;rsquo;d like to mention a great example of this, mint.com. Mint offers a great free service of managing your personal finances. Throwing out security and sharing your data (another time another place), they do a great job of categorizing and monitoring your finances. In exchange they have access to your spending history. So you give them your spending history, in exchange that have hundreds of thousands of peoples data, such as what credit card you use, who your cable provider is. With this mint does what I believe is a good job of generating referrals, but telling you how much you can save by switching from Internet provider A at $60 per month to Internet provider B at $30 per month. They&amp;rsquo;re not just giving ads for the sake of it, they&amp;rsquo;re giving me something that I would actually want.&lt;/p>
&lt;p>Does this lead to higher or lower revenue? We&amp;rsquo;ll this I&amp;rsquo;m not sure of, but with regards to advertising, feel this is a more better fit for a user. I only get things that the service provider thinks &lt;!-- raw HTML omitted -->I want &lt;!-- raw HTML omitted -->not what they &lt;!-- raw HTML omitted -->think they can sell me&lt;!-- raw HTML omitted -->. As we reach more of the semantic understanding of the web I believe this will prevail and make web 2.0 more profitable, but it cannot be done with web 2.0 alone.&lt;/p></description></item><item><title>Consuming versus Publishing</title><link>/2008/05/22/Consuming-versus-Publishing/</link><pubDate>Thu, 22 May 2008 23:16:08 -0700</pubDate><guid>/2008/05/22/Consuming-versus-Publishing/</guid><description>&lt;p>I&amp;rsquo;m finding it a growingly interesting balance in consuming versus producing information. I also feel with the increase in availability of information, the barrier to entry in so many areas are shrinking rapidly. I think of some of the areas where the barriers to entry are typically much higher. 15 years ago we would have never seen a 23 year old as the CEO of a company valued at 15 billion dollars. While my vantage point even within the business market is narrow, as I think in relation to technology I still believe it applies across the board. Now it no longer takes 20 years in business , learning from your experiences and mistakes, to have the knowledge and ability to run a large company. In fact, in some cases that may be a hinderance, because you will expect that your previous experiences have prepared you to handle the situation, which you may not view as different. The difference in today&amp;rsquo;s world is that businesses, the ones that will at least be around in 5, 10, and 20 years are the ones that manage to adapt to change extremely quickly.&lt;/p>
&lt;p>But I digress, I&amp;rsquo;m starting to find it increasingly more difficult to determine what the balance is between creating and consuming content. I read on average 200 blog posts per day, while posting an average of two. I see and read an average of 500 tweets per day, while posting an average of 4. I listen to and watch an average of 3 podcasts per day, and publish none. Meanwhile I find myself having a variety of conversations about all the things I read, yet few of these are web communications, or at best over IM. While there should always be a learning curve in getting familiar with an industry space or domain expertise, and what point should it tip so you can become a publisher of content.&lt;/p>
&lt;p>More specifically I&amp;rsquo;m curious what the current actual positions of those are that consume and those that publish both currently and from a long term perspective. You see because I consume content does it make me more likely to take and readily apply that. Or because I am polishing and publishing content does it mean when I interact with others it will be more polished, perhaps allowing me to sell better.&lt;/p>
&lt;p>Really it&amp;rsquo;d be great to get some sort of focus group stats around this. . .
Technorati Tags: &lt;!-- raw HTML omitted -->content&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->twitter&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->blogs&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->publish&lt;!-- raw HTML omitted -->, &lt;!-- raw HTML omitted -->consume&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>Reduced noise in exchange for transparency</title><link>/2008/05/21/Reduced-noise-in-exchange-for-transparency/</link><pubDate>Wed, 21 May 2008 17:52:52 -0700</pubDate><guid>/2008/05/21/Reduced-noise-in-exchange-for-transparency/</guid><description>&lt;p>As I&amp;rsquo;ve become more or less a web 2.0 whore. I&amp;rsquo;ve also had a great interest in web 3.0 and what it will fortell. Most believe natural language and the semantic web will play a large role in that. And while it will that will not be the end result of web 3.0. While web 2.0 included AJAX and Flex, that really doesn&amp;rsquo;t fully encompass what they are. Web 3.0 to sum it up most simply will be about reducing the noise of the web. While I can take very little credit for this idea as I have heard others say the same or at least similar things, there is an interesting side that I believe most have not thought about.&lt;/p>
&lt;p>You see, in order to reduce the noise of the web you have to know about me and what I consider noise. In order for someone to do this we have to be willing to give up information about ourselves, some of which people consider private. I still recall a conversation which I posted on a few days ago about users not wanting to give out their private information. I believe this attitude is very quickly becoming old hat, while there are individuals that will stay this way for several decades as a collective whole it&amp;rsquo;s a fleeting attitude. I think for example of mint.com which I willingly give all of my financial account information to in order for them to simplify my life. Instead of a massive collection of emails and notifications I get summarized views from them. While there still is the chance for noise as I could receive text messages about every transaction that happens, I have the ability now to filter that noise.&lt;/p>
&lt;p>Noise is something that some people love, take scoble for example who loves having hundreds of twitter messages fly across his screen every few minutes. Though for the vast majority to reduce the noise to allow us to accomplish more in a day, but also have more time to enjoy it will be the key to the future of the web.&lt;/p>
&lt;p>I&amp;rsquo;ve talked with some that believe that government policy will come after people start to become too open with their information. My perspective is that as long as there are safeguards around that information then there will be little barriers to users giving it away freely very soon. But in truth only time will tell at how well companies and products can reduce this noise and truly learn about a user, and if there will be regulation preventing such improvements.&lt;/p></description></item><item><title>Why Twitter matters to you</title><link>/2008/05/18/Why-Twitter-matters-to-you/</link><pubDate>Sun, 18 May 2008 15:57:21 -0700</pubDate><guid>/2008/05/18/Why-Twitter-matters-to-you/</guid><description>&lt;p>Products Company - For me this may the be most obvious and strongest reason for any of the four groups to begin using Twitter. It&amp;rsquo;s quite simple, people use your product or service, people talk about your product or service, people ARE talking about your product or service on Twitter. Regardless of whether you want it or not, people are going to talk and they&amp;rsquo;ll speak their minds. I don&amp;rsquo;t believe I know of a company that wouldn&amp;rsquo;t want to know what it&amp;rsquo;s consumers are saying about them, much less that wouldn&amp;rsquo;t want to be part of that conversation. But if they really do want to, they have the chance to at least be part of it over twitter if they so choose.&lt;/p>
&lt;p>Enterprise - The enterprise has two main reasons why I feel twitter is of importance. Those were highlighted in a little more detail in a previous post, but to sum them up&amp;hellip; Twitter is an asynchronous IM that you could rollout within an enterprise and have control over. You could own the messages, which allows for companies concerned about data security to feel more at ease. It is a convenient medium to convey status to a team and reduce meetings while increasing knowledge flow.&lt;/p>
&lt;p>Additionally twitter starts to become a place for brainstorming and flushing out ideas. On twitter I follow people with similar interests in similar spaces. As I have a fraction of an idea, or a problem I encounter I post to twitter. Others throw in their opinion and a few hours or days later I have hundreds of thoughts around it, and a hopeful solution or flushed out thought.&lt;/p>
&lt;p>Power user - This is an interesting group, because I feel web 3.0 will change in many ways how this group works. Few users like a lot of noise, few users like to see hundreds of messages fly across their screen each hour, and even fewer are truly productive with this. However, for the time being, there are users that want that noise, and that only seem to become more productive and thrive further with the more they have of it. For those users twitter is a gold mine, you can&amp;rsquo;t find a place where you can get much more unfiltered noise, with the exception of the web as a whole. While in its most raw form twitter is extremely noisy, there are a variety of methods to filter this, which is where twitter seems to become most useful to the rest of the population.&lt;/p>
&lt;p>Consumer - If you haven&amp;rsquo;t fit yourself into any of the above categories then this will be where you fall. If you use facebook, email, or IM to communicate with friends, then twitter will be your friend in coming years. I remember a time where it seemed almost a set time at night I would see my buddy list on AIM start to grow as the usual friends sign on. I wouldn&amp;rsquo;t talk to all each day, but over the period of a week would talk to most on there, get updates on their lives and make distant plans to catch up at some point. As the world seems to spin our lives become more hectic and complicated with each passing day. Some nights I sit at my machine and see only a fraction of people that I&amp;rsquo;ve talked to in over a year on AIM. I debate whether to reach out to them to hear their latest and greatest news, or avoid some of the awkwardness. Though I genuinely do care and would like to know, it&amp;rsquo;s not always a simple and relaxed conversation to feel a part of their life.&lt;/p>
&lt;p>Facebook has done a reasonable job of overcoming this, but facebook has hit the tipping point, where you now seem to know more people on there than you actually do. People spend more time, wasting time than actually reconnecting, and at the end of the day it&amp;rsquo;s originally goal has started to seemingly fade.&lt;/p>
&lt;p>Twitter on the other hang allows me to have conversations with friends over a longer period of time. I don&amp;rsquo;t have to sit and wait for my friend to respond, he gets to it when he can. But for me it still maintains that direct communication path feel like AIM. I can also communicate from one to many people much easier, now instead of sending out an email to all my contacts I post a tweet, then all of my friends get the message. All-in-all what twitter really gives you is a way to still feel close and connected to those people. While a facebook status message may work just the same, it somehow seems to get lost amongst all the noise.&lt;/p></description></item><item><title>Web, Scalability, SAAS</title><link>/2008/05/16/Web-Scalability-SAAS/</link><pubDate>Fri, 16 May 2008 19:46:45 -0700</pubDate><guid>/2008/05/16/Web-Scalability-SAAS/</guid><description>&lt;!-- raw HTML omitted -->
&lt;p>At the time one startup that would be a prime example of what I&amp;rsquo;m about to detail did not come to mind. Salesforce, salesforce has a respectable feature list, yet is also one of the web companies that has managed to scale well. The interesting thing about web companies is the best ones are the ones that can truly scale to a mass audience. Many can offer an okay service, but scaling that service is a truly difficult task.&lt;/p>
&lt;p>Many would argue that extensive testing and rigorous QA will help to offer enterprise quality software. But to this note I very strongly disagree, in coming years we are going to see more and more of a facebook model. Facebook as they develop code they test against live data, it will be the individuals that coded and perhaps a few others, but is really not much more than a smoke test to make sure things are still working. They then role out the new code and when things break they are ready to fix them. Why does this work? Why are users okay with the site being down at times? Well personally I will settle for more features at a few inconveniences most days of the week. Seldom is software 100% solid, I have even seen bugs in notepad, so as a result you cannot expect software to be perfect.&lt;/p>
&lt;p>Instead with a SAAS, software as a service, model you do not have to worry about software updates. You simple update the site or service, and then you can role out these features more rapidly. Instead of office being a 2-3 year large product update, you push new features to the site at a weekly basis. You also alleviate some of your burden of supporting a variety of installations and versions of your product.&lt;/p>
&lt;p>Because of these points it&amp;rsquo;s more important that we pay attention to these companies that have gotten scalability right. The facebook&amp;rsquo;s, google&amp;rsquo;s, amazon&amp;rsquo;s of the world that can handle millions of hits per second, once enterprises have a firm understanding of this, they can attempt to them build their feature set within a SAAS model. When we get to this point features will be built in faster and software will begin to grow faster than in previous years.&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>Bearish on mobile</title><link>/2008/05/16/Bearish-on-mobile/</link><pubDate>Fri, 16 May 2008 01:05:00 -0700</pubDate><guid>/2008/05/16/Bearish-on-mobile/</guid><description>&lt;p>I&amp;rsquo;ve heard that mobile devices will be everywhere and will replace computers for what seems like decades, but is probably growing on 6 or 7 years now. The thing is I don&amp;rsquo;t really need a desktop with me every where I go. Seldom am I somewhere and I wish I had access to Microsoft Office or wish I had Eclipse or Visual Studio. While I concede that I occasionally watch youtube on my IPhone, this is far more rare than it is common. Most of the time it&amp;rsquo;s simply for the wow factor that I pull it out and load up the &amp;ldquo;Here comes another bubble&amp;rdquo; video.&lt;/p>
&lt;p>Meanwhile I will admit that I do love certain things about my mobile device. The ability to, within three button clicks, publish a photo to twitter or flickr. Or to quickly to live micro-blogging from an event, or (not I, but others) the ability to stream an interview from my phone and have others text questions to ask. But is this truly what I use on my desktop, yes I have IM and micro-blogging clients, but it&amp;rsquo;s far different. I seem to care more about existing services integrating to support SMS, or mobile applications, than about my mobile device being able to run whatever is on my desktop.&lt;/p>
&lt;p>My primary point here is that I care less about supporting multimedia formats, applications, and power. And more about data and accessibility. Mobile devices are at a point now where I could locate friends, communicate with others, and have access to my small pieces of data I want. We simply need to have the backbone systems support them more.&lt;/p></description></item><item><title>Large corporations versus startups</title><link>/2008/05/15/Large-corporations-versus-startups/</link><pubDate>Thu, 15 May 2008 12:32:00 -0700</pubDate><guid>/2008/05/15/Large-corporations-versus-startups/</guid><description>&lt;p>After a year of living in Silicon Valley it&amp;rsquo;s hard not to be consumed with the excitement around one startup after the next. The hopes of being the next eBay, Google, or Facebook lie within many of individuals in the area. Some pursue it, some write it off as a distant hope, and still others just want to be a part of them at some point.&lt;/p>
&lt;p>But why would someone just want to be a part of Google 5 years ago? The first thing that comes to mind is money, and while thats nice, I don&amp;rsquo;t believe its at the root of it. There&amp;rsquo;s a vastly different atmosphere at a startup. For one you have a say, right now if I left my company, I&amp;rsquo;d get good-byes from 100 people, be missed by maybe 20, and the other 159,900 would move along as if nothing happened. But if I left a startup the entire company notices, so there is a closer sense of belonging. Still I don&amp;rsquo;t believe this is the heart of it.&lt;/p>
&lt;p>In part if you have the ability to make it at a startup you&amp;rsquo;re of a different breed. If a startup excites you, you&amp;rsquo;re of a different breed. You eat, sleep, breath what you do. In a 160,000 person company I don&amp;rsquo;t believe there&amp;rsquo;s any way 100% of the employees decided it was a dream job, or as a 10 year old, or even at 16 it was what they wanted to do with their life. But the kid that was developing at 12 his own first person shooter game, or at 16 was following the markets and getting a summer job to be able to invest, those are of a different breed. For those, it&amp;rsquo;s not a job, its a portion of who they are. You don&amp;rsquo;t do home and unwind, you go home and read more blogs, dive further into your area of expertise, and work on your own projects that allow you to bring more expertise into the workplace.&lt;/p>
&lt;p>Perhaps this same attitude and drive applies in other industries, though I have the greatest insight into tech/web companies. There was a statement made by Paul Graham of Y Combinator at startup school recently. He said that investors are looking for the type of individuals that don&amp;rsquo;t need them, the type that are going to make it regardless of what everyone else says and who supports them. This is succinctly different than the corporate world, where you have to have validation all across the board to be able to move forward.&lt;/p>
&lt;p>As I write this and contemplate more I believe it becomes even more of a chicken and egg problem. Startups require a certain type of individual, but those individuals are the ones best suited for startups.&lt;/p></description></item><item><title>Twitter will be commonplace in the enterprise</title><link>/2008/05/14/Twitter-will-be-commonplace-in-the-enterprise/</link><pubDate>Wed, 14 May 2008 21:38:41 -0700</pubDate><guid>/2008/05/14/Twitter-will-be-commonplace-in-the-enterprise/</guid><description>&lt;p>Twitter is great for a few key reasons, first let me highlight the two &lt;!-- raw HTML omitted -->key&lt;!-- raw HTML omitted --> uses I feel it has in the enterprise.&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>Adobe AIR is a game changer, if people would build for it...</title><link>/2008/05/08/Adobe-AIR-is-a-game-changer-if-people-would-build-for-it.../</link><pubDate>Thu, 08 May 2008 16:46:00 -0700</pubDate><guid>/2008/05/08/Adobe-AIR-is-a-game-changer-if-people-would-build-for-it.../</guid><description>&lt;p>Spend five minutes talking to me about technology or business and you&amp;rsquo;ll quickly realize I&amp;rsquo;m a fan of Adobe AIR. Adobe has done a very good job building a cross-platform runtime, and providing tools that make the transition from the web to the desktop quite minimal.&lt;/p>
&lt;p>First to elaborate why I like AIR. For one I&amp;rsquo;m a fan of web 2.0, the sites feel cleaner, smoother, and drive new capabilities. Versus most desktop applications that are starting to feel old, and much like 1990&amp;rsquo;s Java Applets do on the web. With Flex Builder, which is an IDE for developing for flash and/or AIR, I can develop a sweet website, but then quickly port it to the desktop while maintaining a rich web 2.0 feel.&lt;/p>
&lt;p>Second, did I mention it&amp;rsquo;s cross-platform? Windows, OSX, Linux, the application in AIR will look/feel/function the same. So what? This could have been done other ways right? Well here is where I start to place my bets, no one else has really done anything in this area as well as Adobe so far. Also Adobe has made their long term strategy clear, they want to truly become a cross-platform runtime. If you&amp;rsquo;re thinking what other platforms right now, you&amp;rsquo;re not thinking large enough. They want AIR to support mobile phones, set-top boxes, likely even gaming consoles. This means I can look at one application on multiple mediums with an either identical look, of very similar one, with minimal development efforts. This allows a developer to then focus even further on improving functionality.&lt;/p>
&lt;p>Finally, a bit of a rant. Adobe AIR does not have a true competitor, Silverlight is a competitor to flash (not AIR), Google Gears might be the closest thing to it. But, with regard to gears taking a website and making it available offline isn&amp;rsquo;t all AIR can do. AIR has local file access, local access to some devices, which when you&amp;rsquo;re still within a browser you can&amp;rsquo;t do. Oh, and one feature I personally just like is the auto-update ability of applications.&lt;/p>
&lt;p>So&amp;hellip;.. If it&amp;rsquo;s so great, why haven&amp;rsquo;t you heard of it and why aren&amp;rsquo;t you using it? Well the single problem seems to be people building applications on it. I&amp;rsquo;ve seen very few applications that would appeal to mainstream users. I (being an avid fan of AIR and anything web 2.0), will typically use 2 AIR applications per day. One being twhirl, which I use as my primary twitter client. The other tends to vary by needs. However this is contrasted with about 20 applications that I work in over a given day. Most AIR applications thus far are simple, one-off fun applications. Perhaps to really make some penetration there should be some of the following:&lt;/p>
&lt;!-- raw HTML omitted --></description></item><item><title>Why Google may not exist in 8-10 years</title><link>/2008/05/08/Why-Google-may-not-exist-in-8-10-years/</link><pubDate>Thu, 08 May 2008 03:35:00 -0700</pubDate><guid>/2008/05/08/Why-Google-may-not-exist-in-8-10-years/</guid><description>&lt;p>As I write this, I write only from my vague knowledge of where revenue&amp;rsquo;s come directly from. However, I do hope to back this up in the future with more numeric backing. My title of the post may be quite strong and negative, but I feel it has reasonable ground to stand on, based on one simple principle. A corporation should stick to and focus on it&amp;rsquo;s core business, and exhausting resources outside it&amp;rsquo;s core business could end up costing them their business.&lt;/p>
&lt;p>As it is, Google&amp;rsquo;s primary revenue comes from advertising, they&amp;rsquo;re the primary source for advertising because of their search engine. While some may say their core business is data, I disagree, as how are they making money off of data. Data simply allows them to better target their ads. With Google&amp;rsquo;s attitude of &amp;ldquo;Do no wrong&amp;rdquo; they are unlikely to profit from the consolidation and sales of such data.&lt;/p>
&lt;p>Meanwhile Google is exhausting their resources with little to show for it. Google over the past 5 years has been hiring some of the top talent within Silicon Valley. Paying good salaries for individuals that are supposed to be some of the best software engineers in the industry. I&amp;rsquo;m not suggesting that the individuals are not sharp, but what has Google truly produced from within it&amp;rsquo;s own walls? Google has bought many of it&amp;rsquo;s out lier products, i.e. Google Earth, Google Spreadsheets, Picasa, and others. First if they are to go into these areas they should strictly focus on acquisitions and have a smaller developer base.&lt;/p>
&lt;p>Though from my perspective Google should not be investing in any of the three products mentioned above. While cool and arguably good products, how does Google plan on making money from these? If they are exhausting resources and effort into these products, at the expense of improving both search and ad&amp;rsquo;s they&amp;rsquo;re not focusing on their core business as they should be&lt;/p>
&lt;p>Finally, if Google is not pouring into these two areas, search and ad&amp;rsquo;s, it only takes being beaten by one to be unseated. As soon as a company is able to do search better, or ad&amp;rsquo;s better Google will lose the majority, if not all of their revenue. While they may be able to stay around after someone else has become a dominant player, it will only be as a very small fraction of what they currently are.&lt;/p>
&lt;p>I&amp;rsquo;m not predicting that Google &lt;!-- raw HTML omitted -->will &lt;!-- raw HTML omitted -->be gone in 8 years, but unless they really start to devote to their core business and quit wasting resources on un-needed areas they will have something to worry about.&lt;/p></description></item><item><title>Craig's Disney Food Guide</title><link>/about/disneyworld/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/disneyworld/</guid><description>&lt;p>There&amp;rsquo;s an immense amount of things online about Disney, and especially so about Disney dining. We ourselves have frequented disney world a number of times over the years, and in time have made it to many of the restaurants there with only a few of the fancier ones left on our list. Here&amp;rsquo;s a few of our favorites, what to get, and why:&lt;/p>
&lt;h3 id="food" >
&lt;div>
Food
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Flying Fish&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Le Cellier&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="drinks" >
&lt;div>
Drinks
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;/li>
&lt;/ul></description></item><item><title>Craig's Disneyland Guide</title><link>/about/disneyland/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/disneyland/</guid><description>&lt;!-- raw HTML omitted -->
&lt;p>Disney, and specifically disneyland, is a frequent vacation for us as it can be a convenient long weekend getaway. It doesn&amp;rsquo;t hurt that my wife is a huge disney fan. At the same time there&amp;rsquo;s certain things that can make it more of a relaxing trip than you may realize without screaming children. Rides are purely up to you, but I&amp;rsquo;ll dig into a few favorites for food/drinking.&lt;/p>
&lt;h3 id="food" >
&lt;div>
Food
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.yelp.com/biz/carthay-circle-restaurant-anaheim">Carthay Circle&lt;/a> - This is our most common visit in Disneyland. It&amp;rsquo;s a bit more fine dining, but not too overly high end as well. A few of the favorites are the biscuits, sriracha duck wings as appetizers. For entrees, mostly anything, though the pork chop is a highlight. Their wine list is also quite nice. And if you&amp;rsquo;re lucky enough to be on a corner table there&amp;rsquo;s a nice easter egg of the evil queen.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/flos-v8-cafe-anaheim">Flo&amp;rsquo;s V8 Cafe&lt;/a> - Another common place we visit, though this is what Disney classifies as quick service. This is where it shines that Disney has really stepped up its food quality though. With quick service that includes fresh salads with turkey, fresh and quality sides, or delicious pork loin with BBQ sauce its much better than the microwaved burgers of years ago.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/napa-rose-anaheim">Napa Rose&lt;/a> - On the other end of the spectrum from quick service is Disney&amp;rsquo;s much finer dining. This is an area that has always been quite nice, but has continued to be impressive. Only having the opportunity to dine here a couple times we can&amp;rsquo;t give a huge run down of the menu but will say the chef&amp;rsquo;s tasting and wine pairing is worth the experience.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/blue-bayou-anaheim">Blue Bayou&lt;/a> - Blue bayou is good food and especially filling. Though where it really wins is the ambiance. It exists within the same setting as the Pirates of the Carribean and feels exactly like you&amp;rsquo;re on a bayou at night in Lousiana. Being one of the most sought after places make sure to make reservations early for here.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/little-red-wagon-anaheim">Little Red Wagon&lt;/a> - If you want something quick, but amazing this is the go to. True old fashioned style corn dogs, fresh dipped in batter for hot, greasy deliciousness. Lines can get a little long here, but it moves quickly so don&amp;rsquo;t fret too much.&lt;/li>
&lt;/ul>
&lt;h3 id="drinking" >
&lt;div>
Drinking
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.yelp.com/biz/carthay-circle-restaurant-anaheim">Carthay Circle Lounge&lt;/a> - Carthay Circle is amazing for good, and their lounge is the spot for drinks, though their light dishes are quite nice as well. Their wine list is pretty good, though their cocktails are what you want here. Whether your preference is gin, whiskey, or champagne there&amp;rsquo;s a cocktail that will make all the screaming kids so much more bearable. They also have pretty good small bites here.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/cove-bar-anaheim">Cove Bar&lt;/a> - On a warm day this is a great spot to sit and enjoy the pier area. They&amp;rsquo;ve got a few off menu drinks that make it both an adult but fun disney experience such as the black pearl (a long island with a twist). And if you&amp;rsquo;re hungry their lobster nachos are great.&lt;/li>
&lt;/ul></description></item><item><title>Craig's Huntsville Guide</title><link>/about/huntsville/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/huntsville/</guid><description>&lt;!-- raw HTML omitted -->
&lt;h3 id="food" >
&lt;div>
Food
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://poboyfactory.com/">Po Boy Factory&lt;/a> - This is a regular stop anytime I&amp;rsquo;m back in Huntsville. No pomp and circumstance at all, just great New Orleans food that measures up to much of it actually in New Orleans.&lt;/li>
&lt;li>&lt;a href="http://gibsonsbbq.com/">Gibsons&lt;/a> - A clear staple of the south is BBQ, Gibsons does it quite well. The pulled pork is great, though my favorite is probably hitting up this place for breakfast. A good country ham biscuit which is just not a thing in most other parts of the country. Though if there for lunch or dinner make sure to pick up a slice of lemon icebox.&lt;/li>
&lt;li>&lt;a href="https://plus.google.com/106762386505884740495/about?gl=us&amp;amp;hl=en">Little Paul&amp;rsquo;s&lt;/a> - Within the family of the Gibson&amp;rsquo;s, Little Paul is the little brother. Very similar overall to Gibson&amp;rsquo;s, but in particular their smoked turkey here is amazing. Make sure to use the white barbecue sauce with it.&lt;/li>
&lt;li>&lt;a href="">Mezza Luna&lt;/a>&lt;/li>
&lt;li>&lt;a href="">Bob Baumhauer&amp;rsquo;s Wings&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="drinking" >
&lt;div>
Drinking
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="">Amendment 21&lt;/a>&lt;/li>
&lt;li>&lt;a href="">Below the Radar&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="what-to-do" >
&lt;div>
What to Do
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.earlyworks.com/">Early Works&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://rocketcenter.com/">Space and Rocket Center&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Craig's New Orlenas Guide</title><link>/about/neworleans/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/neworleans/</guid><description>&lt;!-- raw HTML omitted -->
&lt;h3 id="drinking--food" >
&lt;div>
Drinking / Food
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.thethreemuses.com/">Three Muses&lt;/a> - One of the best bars in the area. Great cocktails including orange blossom sazerac. Their food is quite great as well, amazing things had there – lobster spring rolls, crispy pork belly, fish tacos, edamame with toasted sesame oil and star anise&lt;/li>
&lt;li>&lt;a href="http://www.jacksonbrewerybar.com/">Jackson Brewery&lt;/a> - As with many a pretty solid brewery with good food. The few isn&amp;rsquo;t quite traditional bar food, slants more to new orleans cuisine, but definitely have a few good items. The seared tuna salad is quite the helping of tuna and blackened alligator is delcious.&lt;/li>
&lt;li>&lt;a href="http://www.patobriens.com/patobriens/">Pat Obriens&lt;/a> - Well known for creating the hurricane. Their drinks are definitely sweet most and not the place for bargain drinks, but an evening in the courtyard or near the piano bar is a must do experience at least once if not many times in your lifetime.&lt;/li>
&lt;li>&lt;a href="http://abita.com/">Abita&lt;/a> - Its a bit of a drive out of town, but a nice different experience. All of their beers are of course nice and fresh here and a good selection of quality bar food here as well.&lt;/li>
&lt;/ul>
&lt;h3 id="food-only" >
&lt;div>
Food Only
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.saveur.com/article/Travels/saveur-100-crabby-jacks">Crabby Jacks&lt;/a> - The place for a Po Boy. Their King Po Boy is ~ $12 and probably has 2 pounds of perfectly fried shrimp on it. Feels like a New Orleans &lt;a href="http://www.yelp.com/biz/city-cafe-northport">City Cafe&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.cafedumonde.com/">Cafe Du Monde&lt;/a> - Sure its a given, but its still great. Beignets and Cafe Au Lait are a must anytime in new orleans.&lt;/li>
&lt;li>&lt;a href="http://www.meltdownpops.com/">Meltdown popsicles&lt;/a> - In several days I walked by this place many times before even realizing it was there, but what a treat. Gourmet popsicles, i.e. strawberry basil, vietnamese coffee, pineapple cilantro&lt;/li>
&lt;li>&lt;a href="http://www.angelobrocatoicecream.com/">Angelo Brocato Gelato&lt;/a> - As I right this I&amp;rsquo;m returning from Florence Italy. There&amp;rsquo;s not many places I could say even come close to the gelato I consumed this past week, this place though was truly great. Of course still not quite as good, but it does come close.&lt;/li>
&lt;/ul>
&lt;h3 id="shops" >
&lt;div>
Shops
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.fleurdeparis.net/">Fleur de Paris&lt;/a> - Awesome true milinery. No photos allowed. Hats are $$$$ but dresses can be fun and affordable for an amazing quality.&lt;/li>
&lt;li>&lt;a href="http://www.goorin.com/">Goorin Brothers&lt;/a> - With something that has a little more for the men as well here&amp;rsquo;s another hat shop. This has a variety of very style-ish both mens and womens hats if you can find the occasion to wear them.&lt;/li>
&lt;li>&lt;a href="http://www.calicheandpao.com/">Caliche and Pao&lt;/a> - For a city filled with local art and music this studio always jumps out to me. So much so I had to grab his well known set of light posts. The color and emotion within it captures the city so well.&lt;/li>
&lt;/ul></description></item><item><title>Craig's Paso Robles Guide</title><link>/about/pasorobles/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/pasorobles/</guid><description>&lt;!-- raw HTML omitted -->
&lt;h3 id="wineries" >
&lt;div>
Wineries
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.lonemadrone.com">Lone Madrone&lt;/a> - Lone madrone is one of my favorite wineries in that area and possibly period. In particular they focus a bit more on blends and being a little crazier, their winemaker Neil is also the winemaker at Tablas Creek where he makes a slightly more traditional Rhone style. Their new space makes it even better overall, with burgers and music often on weekends. They also do a variety of ciders, which are all very well done and can be a nice change of scenary to all the wine. Though don&amp;rsquo;t be mistaken despite great burgers delicious cider the wines are truly the highlight. A few personal favorites are The Dodd, The Will and the Tannat, though nearly all are delectable. Tasting here is $5, bottles range from $10 for cider $20 for wine up to $60ish.&lt;/li>
&lt;li>&lt;a href="http://www.lcwine.com">Le Cuvier&lt;/a> - Le Cuvier was a rare gem we immediately found in Paso. Their wines are a bit more on the lighter side over all with some acidity coming through, but at the same time very unique. Their pairing is all done with food and the food goes &lt;em>perfectly&lt;/em> with the wine. If you like wines that are meant to be done with food or slightly lighter/acidic overall its well worth the visit. Tasting is complimentary wines range from $30 towards $70 with most in the $50 range.&lt;/li>
&lt;li>&lt;a href="http://www.shaleoakwinery.com">Shale Oak&lt;/a> - Shale oak is newer on the list for me, upon entering it had a much more elaborate feel to many others in Paso Robles. They have a strong focus on sustainability, which is expressed in a nice flair of their tasting menu having seeds made into it which can sprout flowers. Though for all the focus on sustainability its not lost on their wines. Straight down the menu was delicious with their white blend, cab (lighter overall compared to bolder napa ones), and petite sirah all standing out. Tasting is $5, bottles range from $20 to $40.&lt;/li>
&lt;li>&lt;a href="http://www.derbywineestates.com">Derby&lt;/a> - Derby is much more of a grower than wine maker, making wine from only about 10% of the grapes themselves, however what they do make is all equisite. Several were in a bit of a Rhone style and done quite well, overall lighter on the earth in many cases. Their white was a great surprise more interesting than most, as was their sparkling. Tasting is $5, bottles range from $15 to $60.&lt;/li>
&lt;li>&lt;a href="http://www.clayhousewines.com">Clayhouse&lt;/a> - Clayhouse was largely the reason we started heading down to Paso Robles. Looking for something different from the common Sonoma/Napa wines we were drawn to them strictly for their Petite Sirah which is an extremely valuable buy for as delicious as it is. They have several others that I&amp;rsquo;d put within the good every day drinking range, as well as some nicer ones that hold up well to other wineries such as their reserve Petite Sirah and Malbec. Another great convenience is they&amp;rsquo;re located on the square and open later to make it a great end of day stop once you shouldn&amp;rsquo;t be driving. Tasting is $5, bottles range from $10 to $50&lt;/li>
&lt;li>&lt;a href="http://www.tablascreek.com">Tablas Creek&lt;/a> - With the same winemaker as Lone Madrone its not a surprise that many of these are great, it also probably doesn&amp;rsquo;t hurt that many of their grapes came from Chateau de Beaucastel. Tablas Creek focuses especially on Rhone varietals and dry farming as much as they can in similar fashion to many Rhone wineries. Commonly their rated well in wine reviews, and its clear why with certain ones. While all of theirs don&amp;rsquo;t stand out the same on the list, over half of them delight everytime I&amp;rsquo;m there. Tasting is $5, bottles range from $15 to $80&lt;/li>
&lt;li>&lt;a href="http://www.westbergcellars.com">TurtleRock&lt;/a> - Turtle rock was actually one of two labels by the wine maker. The turtle rock wines stood out a bit more, in particular their Rose was the highlight. A dry, but with great floral-ness and strawberry on the nose rose this was probably the favorite of many we&amp;rsquo;ve had down in Paso Robles.&lt;/li>
&lt;li>&lt;a href="http://www.arroyorobles.com/">Arroyo Robles&lt;/a> - Arroyo robles is often hit or miss for us. Often times its been great, such times include when they had their sparkling, their almond sparkling (sweet, but could pair great with a weekend brunch), their grenache which has some awesome spice. Though sometimes when they have a shorter list while still good some its not quite the same. Their Rose is a fun one in that its more orange than pink. Tasting is $5, bottles range from $15 to $50&lt;/li>
&lt;li>&lt;a href="">Assucion Ridge&lt;/a>&lt;/li>
&lt;li>&lt;a href="">Aaron&lt;/a>&lt;/li>
&lt;/ul>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;h3 id="food" >
&lt;div>
Food:
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.berryhillbistro.com">Berry Hill Bistro&lt;/a> - Berry Hill is one of our regular stops when down in the area. Most commonly for lunch, a fairly casual bistro overall their sandwiches and salads are all delicious. Among delicious ones we&amp;rsquo;ve enjoyed were the Ahi Tuna, French Dip, and Swordfish steak, though nothing on the menu is likely to let you down.&lt;/li>
&lt;li>&lt;a href="http://www.thomashillorganics.com">Thomas Hill Organics&lt;/a> -&lt;/li>
&lt;li>&lt;a href="">Yanagi&lt;/a> - A reasonable sushi place overall. There&amp;rsquo;s nothing in particular that stands out about it, their rolls are more creative than traditional. Fish has always been fresh.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/amsterdam-coffee-house-paso-robles">Amsterdam Coffee House&lt;/a> - This is a regular stop for us at least once often more when we visit. Their coffee is great, and the overall feel of the place is even better. Good choices in music, ample couch space, and great breakfast sandwiches make it an easy way to get going for the day.&lt;/li>
&lt;li>&lt;a href="http://www.weolive.com">We Olive&lt;/a> - This was a bit of a surprise find as we were searching for a place to get some good aged balsamic vinegar. The result was leaving with that plus some great olive oil and banana caramel. They&amp;rsquo;ve got nearly everything in the store available for tasting, ranging from olive oils to marinades.&lt;/li>
&lt;/ul></description></item><item><title>Craig's San Francisco Guide</title><link>/about/sf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/sf/</guid><description>&lt;h3 id="drinking" >
&lt;div>
Drinking
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.yelp.com/biz/smugglers-cove-san-francisco#query:smugglers%20cover">Smugglers Cove&lt;/a> - great rum bar. Punch bowls lit on fire.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/83-proof-san-francisco">83 Proof&lt;/a> - Best cocktails in the city, if you go try a basil gimlet if you like basil at all and have not had one before.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/city-beer-store-san-francisco">City Beer Store&lt;/a> - if you go one place for beer it has to be here. Its a beer store that also has about 10 taps, they&amp;rsquo;ve had beers made for them in collaboration with breweries before.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/the-trappist-oakland">The Trappist&lt;/a> - Its in oakland, but convenient off of BART, would be second on my list likely of places to get beers at. I am to get here about once a month if possible, great beers of all varieties.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/21st-amendment-brewery-san-francisco">21st Amendment&lt;/a> - I&amp;rsquo;m personally mixed on 21st amendment they do make some good beers and some people absolutely love the place. Probably the biggest up and coming brewery we have.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/anchor-brewing-company-san-francisco#query:21st%20Amendment%20Brewery">Anchor Brewing Company&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/hangar-one-alameda-3#query:distillery">Hangar One Distillery&lt;/a> if you&amp;rsquo;re willing to take a ferry ride this is a great time, its about $10 to taste nearly 10 different liquors. They make hangar one vodka, lots of gins, some liquers (one with blue bottle coffee), and they were the first place to start making absinthe when it was legal again in the US.&lt;/li>
&lt;/ul>
&lt;h3 id="beer-and-food" >
&lt;div>
Beer and Food:
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.yelp.com/biz/la-trappe-san-francisco-2">La Trappe&lt;/a> - Great beer and food place, mostly of the belgian varietal. The beer selection is a good list, then they have a full binder of whats in bottles that you can order. If you go here the fries are a must and the belgian mayo goes great with them (the have something like 16 different sauces for the fries).&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/suppenk%C3%BCche-san-francisco-2#query:walzwek">Suppenkuche&lt;/a> - german food and boots, theres also the biergarten next door which if weather is nice its a great place to stop.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/the-monks-kettle-san-francisco">Monks Kettle&lt;/a> - great beers, have only have the food once, was good but pricey for quality. Place is small and can get crowded.&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/rogue-ales-public-house-san-francisco#query:21st%20Amendment%20Brewery">Rogue Public Alehouse&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/toronado-san-francisco#query:21st%20Amendment%20Brewery">Toronado&lt;/a> - food is from &lt;a href="(http://rosamundesausagegrill.com/)">a sausages place&lt;/a> thats excellent - this is definitely a very affordable and great food option with enough food to fill you up for &amp;lt; $10 often&lt;/li>
&lt;li>&lt;a href="#">Pyramid Brewery&lt;/a> - Over by us in east bay a bart ride away but doable, standard pub food, but done pretty well.&lt;/li>
&lt;li>&lt;a href="#">Elevation 66&lt;/a> - Over by us as well, a super small microbrewery, they have great food as well.&lt;/li>
&lt;/ul>
&lt;h3 id="food" >
&lt;div>
Food
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.yelp.com/biz/osha-thai-san-francisco-3">OSHA&lt;/a> - great thai food&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/stone-korean-kitchen-san-francisco-2">Stone Korean Kitchen&lt;/a> - korean, the kimchi friend rice is great&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/zero-zero-san-francisco">Zero Zero&lt;/a> - pizza, thin crust style but San Francisco as well as in a bit foodie&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/colosseo-ristorante-and-bar-italiano-san-francisco">Colosseo&lt;/a> - Italian place in north beach have eaten at a few times, quite a few people ate here when out at the wedding and loved it&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/sotto-mare-san-francisco">Sotto Mare&lt;/a> - Smaller italian restaurant, more seafood. Feels like your italian grandmother serving you, when we had to wait 5 minutes they were immediately pouring us wine on the house and chatty/friendly as ever. (small)&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/fish-sausalito">Fish&lt;/a> - best seafood I&amp;rsquo;ve ever had, a laid back place but can be pricier with entrees anywhere from ~ $20 and up&lt;/li>
&lt;li>&lt;a href="http://www.yelp.com/biz/walzwerk-san-francisco#query:walzwek">Walzwerk&lt;/a> - tiny little east german place with well good german beers. Not super pricey, but many entrees ~ $15 range and up&lt;/li>
&lt;li>SOMA Street Food Park - A food truck area that has about 10 trucks for lunch and 10 for dinner. Lots of variety here, heaters, tv&amp;rsquo;s, wifi, picnic benches and beer. Its a very SF take on food trucks.&lt;/li>
&lt;li>&lt;a href="http://www.dynamodonut.com/">Dynamo Donuts&lt;/a> - Must try the bacon maple apple donut.&lt;/li>
&lt;li>&lt;a href="http://www.kijirestaurant.com/">Kiji&lt;/a> - California fusion sushi, really good sushi with some fun twists.&lt;/li>
&lt;/ul>
&lt;h3 id="activities" >
&lt;div>
Activities
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="#">Exploratorium&lt;/a>&lt;/li>
&lt;li>&lt;a href="#">California academy of sciences&lt;/a>&lt;/li>
&lt;li>&lt;a href="#">Golden gate park&lt;/a>&lt;/li>
&lt;li>&lt;a href="#">Dolores park&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Craig's Sonoma and Napa Wine Guide</title><link>/about/wine/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/wine/</guid><description>&lt;p>As a frequent visitor to Sonoma/Napa area and wine drinker I often guide friends and visitors when planning their wine country trip. Even when not playing tour guide I&amp;rsquo;ll give advice to those looking for a wine tasting experience. To simplify this I&amp;rsquo;ve written up some notes on many of the places I&amp;rsquo;ve visited on several occasions and have a a set of recommended agenda over &lt;a href="/about/wine_route/">here&lt;/a> based on your preferences.&lt;/p>
&lt;h3 id="imagery-winery" >
&lt;div>
Imagery Winery
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="http://www.imagerywinery.com/">Website&lt;/a> | &lt;a href="http://www.yelp.com/biz/imagery-estate-winery-glen-ellen">Yelp&lt;/a>&lt;/p>
&lt;p>Large variety, great to expose those newer to wines to some approachable ones as well as having something for the experienced wine drinker. They&amp;rsquo;re often a bit more creative with their wines, sometimes doing grapes that are commonly blended by themselves and other times doing creative blends such as their code blue which is 80% Syrah and 20% blueberry wine (a wine that smells blueberry, tastes like a solid Syrah and finishes like blueberry, but not sweet at any point).&lt;/p>
&lt;ul>
&lt;li>Tasting ranges from $10-$20&lt;/li>
&lt;li>Bottles range from $20-$80&lt;/li>
&lt;/ul>
&lt;h3 id="benziger-winery" >
&lt;div>
Benziger Winery
&lt;/div>
&lt;/h3>
&lt;p>Benziger, sister winery to Imagery, follows a more traditional approach to their wines. Here you&amp;rsquo;ll find great quality Chardonnay, Pinot, Bordeaux Blends and Cabs. They have a large emphasis on bio-dynamic wines (the next step up from organic) and are a great way to experience a variety of wines made in a traditional form. The grounds are also gorgeous providing a great place to picnic or enjoy a brick over pizza from them.&lt;/p>
&lt;ul>
&lt;li>Tasting ranges from $10-$20&lt;/li>
&lt;li>Bottles range from $20-$80&lt;/li>
&lt;/ul>
&lt;h3 id="kaz" >
&lt;div>
Kaz
&lt;/div>
&lt;/h3>
&lt;p>The smallest winery in Sonoma valley, it embodies much of what Sonoma is compared to Napa. The owner and wine maker is often behind the bar guiding you through the menu and he alone is a great experience. As for the wines themselves, their reds are generally good but nothing to write home about typically in the category of a good table wine. However they do have a great selection of Port in particular a white, blush and red port, with the white port most recently tasting like Hazelnut.&lt;/p>
&lt;ul>
&lt;li>Tasting $5&lt;/li>
&lt;li>Bottles range from $15-$40&lt;/li>
&lt;/ul>
&lt;h3 id="gundlasch-bundshu" >
&lt;div>
Gundlasch Bundshu
&lt;/div>
&lt;/h3>
&lt;p>Gundlasch Bundshu is the oldest winery in Sonoma. They make many traditional wines including Chardonnay, Merlot, Pinot Noir. They also have a few that are done a less common way such as their Gewurtzaminer done in an off-dry fashion which is enjoyable for those that like sweet wines but also approachable for those that do not. Its a bit more nestled away than some of the other Sonoma wineries and provides a good experience of being hidden away from it all.&lt;/p>
&lt;ul>
&lt;li>Tasting $10&lt;/li>
&lt;li>Bottles range from $20-$80&lt;/li>
&lt;/ul>
&lt;h3 id="sojourn-cellars" >
&lt;div>
Sojourn Cellars
&lt;/div>
&lt;/h3>
&lt;p>Sojourn is more of the Napa experience within Sonoma, its a private tasting by reservation only. They&amp;rsquo;ll take you through their current releases of Pinot and Cab typically 3 of each. The tasting room is just off of the Sonoma square and feels as if you&amp;rsquo;re sitting around someone&amp;rsquo;s dining room table. For Pinot or Cab lovers both are great here.&lt;/p>
&lt;ul>
&lt;li>Tasting complimentary&lt;/li>
&lt;li>Bottles range from $40 and $70&lt;/li>
&lt;/ul>
&lt;h3 id="cline" >
&lt;div>
Cline
&lt;/div>
&lt;/h3>
&lt;p>Cline is one of the larger producers within Sonoma and is something you can generally find at local markets. The wines are generally approachable to those newer to wine, though there are also some for the more experienced as well. In particular they have a large variety of Zins ranging from fruity to spicy. They also have a variety of birds and animals on the property around their pond making it a good place to entertain kids for a bit.&lt;/p>
&lt;ul>
&lt;li>Tasting from $0 to $5&lt;/li>
&lt;li>Bottles range from $15 to $40&lt;/li>
&lt;/ul>
&lt;h3 id="jacuzzi" >
&lt;div>
Jacuzzi
&lt;/div>
&lt;/h3>
&lt;p>Jacuzzi is the sister winery to Cline with Cline focusing on more French style Jacuzzi focuses on more Italian style. In addition to the traditional Sangiovese which is the primary wine in Chianti you&amp;rsquo;ll find Italian wines that are less common in California including Dolcetto, Nebbiolo, and Sagrantino. If you&amp;rsquo;re a fan of Italian wines this can be a good stop and with a large variety its likely to include something for people newer to wine as well. Also of note is they typically have a large selection of olive oils to taste for the non-drinkers in the party.&lt;/p>
&lt;ul>
&lt;li>Tasting from $0 to $5&lt;/li>
&lt;li>Bottles range from $15 to $40&lt;/li>
&lt;/ul>
&lt;h3 id="viansa" >
&lt;div>
Viansa
&lt;/div>
&lt;/h3>
&lt;p>Falling somewhere between Jacuzzi with a strong selection of Italian wines and other more traditional California wineries with selections such as Cab, Chardonnay, and Zin this winery can have something for most. It also offers great views looking out over part of Sonoma valley. If stopping here try to do it earlier in the day as being one of the first places you encounter its likely to be crowded as the day progresses.&lt;/p>
&lt;ul>
&lt;li>Tasting from $10&lt;/li>
&lt;li>Bottles range from $20 to $60&lt;/li>
&lt;/ul>
&lt;h3 id="gloria-ferrer" >
&lt;div>
Gloria Ferrer
&lt;/div>
&lt;/h3>
&lt;p>One of the few places with a focus on champagne in Sonoma it also offers great views. While many of their champagnes you can find in local markets, the ones sold here are far less available. Their champages are sold by the glass, not the traditional wine tasting method of a sampling of several, this makes the experience a bit easier to enjoy the view from their patio looking out over part of Sonoma Valley.&lt;/p>
&lt;ul>
&lt;li>Glasses from $5-$15&lt;/li>
&lt;li>Bottles from $15-$60&lt;/li>
&lt;/ul>
&lt;h3 id="enkidu" >
&lt;div>
Enkidu
&lt;/div>
&lt;/h3>
&lt;p>Enkidu is a hidden spot in much of Sonoma as its a smaller tasting room that doesn&amp;rsquo;t draw much attention to itself. The people behind the bar will be 1 of a small handful that are very involved with the winery. Their wines can be enjoyed by many, but for more experienced wine drinkers that enjoy more body they have a great selection of Petite Syrah.&lt;/p>
&lt;ul>
&lt;li>Tasting $10&lt;/li>
&lt;li>Bottles from $20-$50&lt;/li>
&lt;/ul>
&lt;h3 id="st-francis" >
&lt;div>
St. Francis
&lt;/div>
&lt;/h3>
&lt;p>St. Francis has a more common selection of California wines including a special focus Zin&amp;rsquo;s and Cab&amp;rsquo;s, offering a great quality of both. In addition to a standard tasting they have some options to do food and wine pairings as well to allow for a bit more of a special experience. The winery itself is reminiscent of a European Castle to a much smaller scale, a winery that while a bit isolated by itself feels like its been pulled right out of Napa.&lt;/p>
&lt;ul>
&lt;li>Tasting $10-$30&lt;/li>
&lt;li>Bottles $20-$80&lt;/li>
&lt;/ul>
&lt;h3 id="chateau-st-jean" >
&lt;div>
Chateau St. Jean
&lt;/div>
&lt;/h3>
&lt;p>Chateau St. Jean is also a more traditional winery though they offer a long list and broad selection. As a winery where you can find many of theirs in stores they go well beyond that at the Winery. With a large grounds area its a great spot for photos and to relax for a bit.&lt;/p>
&lt;ul>
&lt;li>Tasting $5-$20&lt;/li>
&lt;li>Bottles $20-$80&lt;/li>
&lt;/ul>
&lt;h3 id="kenwood" >
&lt;div>
Kenwood
&lt;/div>
&lt;/h3>
&lt;p>Kenwood winery also commonly found in stores has a much broader selection as well. While most of theirs are distributed at stores with about 30 wines on their tasting menu it offers a great chance to try a large variety of theirs. In particular their Reserve and Jack London series offer a variety of Cabs and Merlots at a price much more approachable than many Napa wineries.&lt;/p>
&lt;ul>
&lt;li>Tasting $5&lt;/li>
&lt;li>Bottles $10-$60&lt;/li>
&lt;/ul>
&lt;h3 id="mayo-family" >
&lt;div>
Mayo Family
&lt;/div>
&lt;/h3>
&lt;p>A smaller family winery with its tasting room separate from the vineyard its a nice spot for a variety of wines. Its one of a few places serving champagne and also has a couple of choices for dessert wines for those that prefer it.&lt;/p>
&lt;ul>
&lt;li>Tasting $5&lt;/li>
&lt;li>Bottles $15-$50&lt;/li>
&lt;/ul>
&lt;h3 id="audelessa" >
&lt;div>
Audelessa
&lt;/div>
&lt;/h3>
&lt;p>Audelessa offers a more limited list typically only pouring 5 wines on a given day, though those 5 can be be well worth the trip. For Pinot or Cab lovers this is a great stop though they do venture beyond those as well. Additionally if you&amp;rsquo;re tired from standing at the counter all day they have some comfy seats assuming they&amp;rsquo;re not all full.&lt;/p>
&lt;ul>
&lt;li>Tasting $10&lt;/li>
&lt;li>Bottles $25-$60&lt;/li>
&lt;/ul>
&lt;h3 id="highway-12" >
&lt;div>
Highway 12
&lt;/div>
&lt;/h3>
&lt;p>Located right on the downtown square and sharing space with a store this one thats easy to miss, though its a shame to have that happen. They have a range of wines but focus mostly on their Cab and Bordeaux blends. They have a large range from approachable table wines up to their reserve Bordeaux. In particular their regular Bordeaux blend and Cab are an amazing bang for the buck that make you not feel bad opening one on a weeknight.&lt;/p>
&lt;ul>
&lt;li>Tasting complimentary to $5&lt;/li>
&lt;li>Bottles $10 to $80&lt;/li>
&lt;/ul>
&lt;h3 id="adobe-road" >
&lt;div>
Adobe Road
&lt;/div>
&lt;/h3>
&lt;p>Located on the square with a range from beginner to some big cabs it has something thats pretty approachable for everyone. They can often get crowded so getting their earlier is advisable.&lt;/p>
&lt;ul>
&lt;li>Tasting $10 to $20&lt;/li>
&lt;li>Bottles $10 to $80&lt;/li>
&lt;/ul>
&lt;h3 id="hawkes" >
&lt;div>
Hawkes
&lt;/div>
&lt;/h3>
&lt;p>Just off the square this is slightly more hidden than some, but more discoverable than others. With a short list at a given point in time they have a strong focus on Cabs and is a great spot if you want to enjoy 2-3 within a tasting.&lt;/p>
&lt;ul>
&lt;li>Tasting $10&lt;/li>
&lt;li>Bottles $20-$80&lt;/li>
&lt;/ul>
&lt;h3 id="conn-creek" >
&lt;div>
Conn Creek
&lt;/div>
&lt;/h3>
&lt;p>Hidden off the main road of Napa this place has a more approachable feel than most Napa wineries. Despite not having an ornate entrance they deliver the same quality Cabs that so many other Napa wineries do at a fraction of the price. If you&amp;rsquo;re in Napa strictly for the quality of wines and want a place where you can relax this is a great stop.&lt;/p>
&lt;ul>
&lt;li>Tasting $5-$10&lt;/li>
&lt;li>Bottles $20-$60&lt;/li>
&lt;/ul>
&lt;h3 id="flora-springs" >
&lt;div>
Flora Springs
&lt;/div>
&lt;/h3>
&lt;p>Flora Springs is a pretty typical Napa experience with high ceilings and beautifully decorated their wines match what you&amp;rsquo;d expect. With a great selection of Cabs and other quality wines its a place to come if you want the stereotypical Napa experience. You&amp;rsquo;ll hear a bit more about the region and vineyard than the taste of the wine, but it doesn&amp;rsquo;t mean the wines are lacking.&lt;/p>
&lt;ul>
&lt;li>Tasting $10-$20&lt;/li>
&lt;li>Bottles $25-$100&lt;/li>
&lt;/ul>
&lt;h3 id="frogs-leap" >
&lt;div>
Frogs Leap
&lt;/div>
&lt;/h3>
&lt;p>Frogs Leaps is a pretty common Napa winery, though a bit more laid back than many. With a variety of great wines they&amp;rsquo;ll rotate through what they&amp;rsquo;re pouring pretty frequently. This can range from Rose to Zin to a common Napa Cab. Most wines are great quality and you have the ability to enjoy them in a variety of ways from at a sit down tasting to outdoors while playing Cornhole.&lt;/p>
&lt;ul>
&lt;li>Tasting $10-$30&lt;/li>
&lt;li>Bottles $20-$100&lt;/li>
&lt;/ul>
&lt;h3 id="pina" >
&lt;div>
Pina
&lt;/div>
&lt;/h3>
&lt;p>Pina is what you expect in quality when it comes to great Napa cabs, but without so much of the pomp and circumstance. You taste in what is essentially a large warehouse that has a bit of a Kaz feel to it. The people behind the counter are usually older and simply there to pour and let you enjoy. Colors of their cab go from dark ink, to dark ink died with dark ink. Selection is mostly cabs, though they have a Chardonnay and late harvest as well.&lt;/p>
&lt;ul>
&lt;li>Tasting ~ $15&lt;/li>
&lt;li>Bottles $50 - $100&lt;/li>
&lt;/ul>
&lt;h3 id="vjb" >
&lt;div>
VJB
&lt;/div>
&lt;/h3>
&lt;p>For sometime I&amp;rsquo;d passed VJB up as it seemed very touristy, though sad it took so long to visit. They have several italian varietals, but of the ones on my list doing that style very possibly the best. They don&amp;rsquo;t have anything quite in the range of Super Tuscan or Brunellos, more on the softer side of Italian wines but they do them very well. Also a great area for ordering a pizza or from their cafe and enjoying the area&lt;/p>
&lt;ul>
&lt;li>Tasting ~ $10&lt;/li>
&lt;li>Bottles $20 - $50&lt;/li>
&lt;/ul>
&lt;h3 id="iron-horse" >
&lt;div>
Iron Horse
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="http://www.ironhorsevineyards.com/">Website&lt;/a> - &lt;a href="http://www.yelp.com/biz/iron-horse-vineyards-sebastopol">Yelp&lt;/a>&lt;/p>
&lt;p>Among Gloria Ferrer, Domaine Carneros, and Chandon Iron Horse is hands down my favorite. They do both still and sparkling wines, though I can only comment about their sparkling. In getting there you feel as if you&amp;rsquo;re entirely off the beaten path. The tasting area is outside and overlooks the valley with gorgeous views. Their champagnes are great quality and many that may be harder to find in stores, including one commissioned especially by Disney for distribution in their parks which is quite great.&lt;/p>
&lt;ul>
&lt;li>Tasting ~ $10&lt;/li>
&lt;li>Bottles $30 - $80&lt;/li>
&lt;/ul>
&lt;h3 id="morlet" >
&lt;div>
Morlet
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="http://www.morletwine.com/">Website&lt;/a> | &lt;a href="http://www.yelp.com/biz/morlet-family-vineyards-st-helena">Yelp&lt;/a>&lt;/p>
&lt;p>This is the most impressive wine experience I&amp;rsquo;ve ever had, and at the same time an extremely relaxed one. Their tasting is by appointment only and you should plan a few weeks out. The wine maker is a 4th generation wine maker and grower from France. He&amp;rsquo;s the wine maker for several other great quality wineries in the area as well. Easily some of the best wine I&amp;rsquo;ve tasted in my life, though it also comes with a price to match. Some wines of particular note include his White Bordeaux, his Syrah which smells just like fresh craked black pepper, and every single one of his cabs. A final note, the wine tasting is always conducted by him or his wife, both of whom are a wonderful experience and very different from each other.&lt;/p>
&lt;ul>
&lt;li>Tasting ~ $100&lt;/li>
&lt;li>Bottles $65-$300&lt;/li>
&lt;/ul>
&lt;h3 id="salvestrin" >
&lt;div>
Salvestrin
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="http://www.salvestrinwinery.com/">Website&lt;/a> | &lt;a href="http://www.yelp.com/biz/salvestrin-saint-helena">Yelp&lt;/a>&lt;/p>
&lt;p>This was an impromptu visit for us, they generally encourage a reservation though it seems easy enough to just stop in. Their environment was very relaxed as nice break from so much of Napa. Their lower end wines were definitely the ones that seemed to excel. The higher end into cab and estate wines were of good quality but didn&amp;rsquo;t quite hold up to some of the outstanding others in the Napa area. The great thing was their lower end ones stood out as great compared to so many surrounding wineries.&lt;/p>
&lt;ul>
&lt;li>Tasting ~ $20&lt;/li>
&lt;li>Bottles $25-$100&lt;/li>
&lt;/ul>
&lt;h3 id="lasseter" >
&lt;div>
Lasseter
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="http://www.lasseterfamilywinery.com/">Website&lt;/a> | &lt;a href="http://www.yelp.com/biz/lasseter-family-winery-glen-ellen">Yelp&lt;/a>&lt;/p>
&lt;p>If you love anything about Disney or Pixar whats not to love about a winery by John Lasseter himself. In truth the winery is actually mostly a labor of love by his wife, or as he describes it &amp;ldquo;her movie&amp;rdquo;. Appointment only here definitely holds true, but as with most places that require an appointment it&amp;rsquo;s worth the coordination. Their tasting experience includes a quick walk through the grounds and barrel room, followed by a great tasting experience paired with cheeses and chocolates. They focus exclusively on Rhone style blends, all of which are quite excellent.&lt;/p>
&lt;ul>
&lt;li>Tasting ~ $25&lt;/li>
&lt;li>Bottles $25-$60&lt;/li>
&lt;/ul></description></item><item><title>Craig's Wine Tasting Routes</title><link>/about/wine_route/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/wine_route/</guid><description>&lt;p>For those interested in tasting in Wine Country, but don&amp;rsquo;t want to read through the &lt;a href="/about/wine.html">full list&lt;/a> and determine you&amp;rsquo;re own agenda here&amp;rsquo;s a few pre-set ones that can help you:&lt;/p>
&lt;h2 id="personal-favorites" >
&lt;div>
Personal Favorites
&lt;/div>
&lt;/h2>
&lt;ul>
&lt;li>Imagery&lt;/li>
&lt;li>Enkidu&lt;/li>
&lt;li>Benziger&lt;/li>
&lt;li>Sojourn&lt;/li>
&lt;/ul>
&lt;h2 id="by-taste" >
&lt;div>
By Taste
&lt;/div>
&lt;/h2>
&lt;h3 id="wine-beginner" >
&lt;div>
Wine Beginner
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Cline&lt;/li>
&lt;li>Jacuzzi&lt;/li>
&lt;li>Gloria Ferrer&lt;/li>
&lt;li>Imagery&lt;/li>
&lt;/ul>
&lt;h3 id="zin" >
&lt;div>
Zin
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Cline&lt;/li>
&lt;li>Kenwood&lt;/li>
&lt;li>St. Francis&lt;/li>
&lt;/ul>
&lt;h3 id="cabsbordeaux" >
&lt;div>
Cabs/Bordeaux
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Benziger&lt;/li>
&lt;li>Hawkes&lt;/li>
&lt;li>Highway 12&lt;/li>
&lt;li>Sojourn&lt;/li>
&lt;/ul>
&lt;h3 id="petite-sirah" >
&lt;div>
Petite Sirah
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Imagery&lt;/li>
&lt;li>Enkidu&lt;/li>
&lt;/ul>
&lt;h3 id="sweet-wines" >
&lt;div>
Sweet Wines
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Kaz (Port)&lt;/li>
&lt;li>Imagery (Port and Moscato)&lt;/li>
&lt;li>Mayo Family (Port and Late Harvest)&lt;/li>
&lt;li>Cline (Late Harvest)&lt;/li>
&lt;/ul>
&lt;h3 id="champagne" >
&lt;div>
Champagne
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Cline&lt;/li>
&lt;li>Jacuzzi&lt;/li>
&lt;li>Gloria Ferrer&lt;/li>
&lt;li>Kenwood&lt;/li>
&lt;/ul>
&lt;h2 id="location" >
&lt;div>
Location
&lt;/div>
&lt;/h2>
&lt;h3 id="glen-ellen" >
&lt;div>
Glen Ellen
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Mayo Family&lt;/li>
&lt;li>Benziger&lt;/li>
&lt;li>Audulessa&lt;/li>
&lt;li>Imagery&lt;/li>
&lt;/ul>
&lt;h3 id="highway-12" >
&lt;div>
Highway 12
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Imagery&lt;/li>
&lt;li>Enkidu&lt;/li>
&lt;li>Kenwood&lt;/li>
&lt;li>Chateau St. Jean&lt;/li>
&lt;li>Kaz&lt;/li>
&lt;/ul>
&lt;h3 id="sonoma-downtown" >
&lt;div>
Sonoma Downtown
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Highway 12&lt;/li>
&lt;li>Hawkes&lt;/li>
&lt;li>Sojourn&lt;/li>
&lt;li>Gundlasch Bundshu&lt;/li>
&lt;/ul>
&lt;h3 id="napa" >
&lt;div>
Napa
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Frogs Leap&lt;/li>
&lt;li>Conn Creek&lt;/li>
&lt;li>Flora Springs&lt;/li>
&lt;/ul></description></item><item><title>Past top content</title><link>/content/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/content/</guid><description>&lt;ol>
&lt;li>&lt;a href="/2022/05/18/Unfinished-Business-with-Postgres/">Unfinished business with Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.craigkerstiens.com/2019/03/13/give-me-back-my-monolith/">Give me back my monolith&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2013/03/31/why-i-blog/">Why I Blog&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2013/08/13/the-rule-of-thirds-followup/">Rule of thirds - roadmap planning&lt;/a>&lt;/li>
&lt;/ol>
&lt;h1 id="popular-postgres-posts" >
&lt;div>
Popular Postgres Posts
&lt;/div>
&lt;/h1>
&lt;ol>
&lt;li>&lt;a href="/2012/04/30/why-postgres/">Why Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2012/05/07/why-postgres-part-2/">Why Postgres Part 2&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2013/01/10/more-on-postgres-performance/">More on Postgres Performance&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2012/10/01/understanding-postgres-performance/">Understanding Postgres Performance&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2014/02/02/Examining-PostgreSQL-9.4/">Examining Postgres 9.4 - A first look&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2013/02/13/How-I-Work-With-Postgres/">How I Work with Postgres&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2013/11/18/best-postgres-feature-youre-not-using/">The best Postgres feature you&amp;rsquo;re not using - CTEs&lt;/a>&lt;/li>
&lt;/ol>
&lt;h1 id="popular-marketing-posts" >
&lt;div>
Popular Marketing Posts
&lt;/div>
&lt;/h1>
&lt;ol>
&lt;li>&lt;a href="/2014/01/28/where-to-go-developer-content/">Where to go with developer content&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2013/04/12/perspective-on-developer-marketing/">Doing Marketing (for developers) Differently&lt;/a>&lt;/li>
&lt;li>&lt;a href="/startupbootstrapped-marketing-recap/">Startup/Bootstrapped Marketing Recap&lt;/a>&lt;/li>
&lt;/ol>
&lt;h1 id="popular-heroku-posts" >
&lt;div>
Popular Heroku Posts
&lt;/div>
&lt;/h1>
&lt;ol>
&lt;li>&lt;a href="/2011/11/07/how-heroku-works-maker-day/">How Heroku Works - Maker&amp;rsquo;s Day&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2011/11/02/how-heroku-works-teams-tools/">How Heroku Works - Teams and Tools&lt;/a>&lt;/li>
&lt;li>&lt;a href="/2011/12/02/how-heroku-works-hiring/">How Heroku Works - Hiring&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>Speaking</title><link>/about/speaking/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/speaking/</guid><description>&lt;p>I frequently give talks at various Tech conferences and meetups. I&amp;rsquo;ve given talks about Postgres/Databases, Python/Django, and cultural talks around effective engineering and product teams. Currently I&amp;rsquo;m interested on speaking related to Postgres, product management, and marketing for developer focused companies. If you&amp;rsquo;re interested in having me speak at a meetup or upcoming conference please reach out to me at craig.kerstiens at gmail.com.&lt;/p>
&lt;h3 id="upcoming-talks" >
&lt;div>
Upcoming Talks
&lt;/div>
&lt;/h3>
&lt;h3 id="past-talks" >
&lt;div>
Past Talks
&lt;/div>
&lt;/h3>
&lt;p>2013-04-02 - &lt;a href="http://greatwideopen.org/">Great Wide Open&lt;/a>&lt;/p>
&lt;p>2013-04-04 - &lt;a href="www.ancientcityruby.com">Ancient City Ruby&lt;/a>&lt;/p>
&lt;p>2013-04-15 - &lt;a href="https://us.pycon.org/2014/">PyCon&lt;/a>&lt;/p>
&lt;p>2014-02-23 - &lt;a href="http://pytennessee.org">PyTennessee&lt;/a> - Going beyond limits of Django ORM with Postgres&lt;/p>
&lt;p>2014-02-01 - &lt;a href="https://fosdem.org/2014/">FOSDEM&lt;/a> - Postgres Performance for Humans&lt;/p>
&lt;p>2013-11-13 - &lt;a href="http://www.salesforce.com/dreamforce/DF13/">Dreamforce&lt;/a>&lt;/p>
&lt;p>2013-10-29 - &lt;a href="http://2013.pgconf.eu/">PgConf EU&lt;/a>&lt;/p>
&lt;p>2013-09-17 - &lt;a href="http://postgresopen.org/2013/home/">Postgres Open&lt;/a>&lt;/p>
&lt;p>2013-07-03 - &lt;a href="https://ep2014.europython.eu/en/">EuroPython&lt;/a>&lt;/p>
&lt;p>2013-05-15 - &lt;a href="http://2013.djangocon.eu/">DjangoCon EU&lt;/a>&lt;/p>
&lt;p>2013-04-04 - &lt;a href="http://mtnwestrubyconf.org/2013">Mountain West Ruby Conf&lt;/a> - Postgres Demystified&lt;/p>
&lt;p>2013-03-18 - &lt;a href="http://us.pycon.org/2013/">PyCon US&lt;/a> - Going beyond the Django ORM limitations with Postgres&lt;/p>
&lt;p>2013-02-02 - &lt;a href="http://fosdem.org/">Fosdem&lt;/a> - &lt;a href="https://speakerdeck.com/craigkerstiens/postgres-demystified">Postgres Demystified&lt;/a>&lt;/p>
&lt;p>2013-01-31 - &lt;a href="http://monkigras.com/">Monkigras&lt;/a> - &lt;a href="https://speakerdeck.com/craigkerstiens/coffee-as-collaboration">Coffee as Collaboration&lt;/a>&lt;/p>
&lt;p>2012-11-23 - &lt;a href="http://allyourbaseconf.com">All Your Base Conf&lt;/a> - &lt;a href="https://speakerdeck.com/craigkerstiens/postgres-demystified">Postgres Demystified&lt;/a> &lt;a href="http://vimeo.com/56682925">Video&lt;/a>&lt;/p>
&lt;p>2012-11-15 - PyCon Argentina - &lt;a href="https://speakerdeck.com/craigkerstiens/django-apps-to-services">Django Apps to Services&lt;/a>&lt;/p>
&lt;p>2012-11-13 - PgDay Argentina - &lt;a href="https://speakerdeck.com/craigkerstiens/postgres-demystified">Postgres Demystified&lt;/a>&lt;/p>
&lt;p>2012-07-16 - OSCON - &lt;a href="https://speakerdeck.com/craigkerstiens/django-apps-to-services">Django Apps to Services&lt;/a> &lt;a href="www.infoq.com/presentations/Postgres-Introduction">Video&lt;/a>&lt;/p>
&lt;p>2012-06-28 - CloudEast - &lt;a href="https://speakerdeck.com/craigkerstiens/12-factor-for-python">12 Factor App&lt;/a>&lt;/p>
&lt;p>2012-06-06 - DjangoCon EU - &lt;a href="https://speakerdeck.com/craigkerstiens/how-heroku-uses-heroku-to-build-heroku">How Heroku Uses Heroku to Build Heroku&lt;/a>&lt;/p>
&lt;p>2012-04-15 - DjangoCong - &lt;a href="https://speakerdeck.com/craigkerstiens/djangocong-apps-to-services">Django Apps to Services&lt;/a>&lt;/p></description></item><item><title>Tahoe Donner</title><link>/about/davos/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/davos/</guid><description>&lt;p>Wifi: ToC&lt;/p>
&lt;p>Password: RollTide&lt;/p>
&lt;p>&lt;em>The wifi is an Eero setup near the TV with an extender plugged in upstairs in the loft.&lt;/em>&lt;/p>
&lt;p>&lt;strong>Upon Arrival&lt;/strong>:&lt;/p>
&lt;p>&lt;em>In winter&lt;/em>&lt;/p>
&lt;p>Water will be off. In the mudroom in the wooden box is the water. You may be able to turn with hands only, though may need to use the wrench (laying right there on top) on the lower portion for extra leverage.&lt;/p>
&lt;p>&lt;strong>Before departing&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Run dishes on rinse cycle - no need to run for a full cycle as we know coordinating turning the water off can be a pain&lt;/li>
&lt;li>Strip beds and leave dirty sheets in the laundry basket&lt;/li>
&lt;li>Lock back door (with foot lock)&lt;/li>
&lt;li>Lock front door&lt;/li>
&lt;li>Set thermostat to 55&lt;/li>
&lt;li>Open cabinets below the sinks&lt;/li>
&lt;li>Turn on sink to drain pipes&lt;/li>
&lt;li>Turn off water&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Water&lt;/strong>:&lt;/p>
&lt;p>Main water shutdown is located in the wooden bench inside the mudroom.&lt;/p>
&lt;p>&lt;img src="https://p197.p4.n0.cdn.getcloudapp.com/items/mXupdW75/4970fcad-b0f7-4ce5-9c20-5575dce7f136.jpeg?v=58e8e04d017d7179119738f3d38f1408" alt="">&lt;/p>
&lt;p>If you have trouble turning use the wrench on the lower half for extra leverage.&lt;/p>
&lt;p>&lt;strong>Fireplace&lt;/strong>:&lt;/p></description></item><item><title>Travel/Wine</title><link>/about/travel_wine/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/travel_wine/</guid><description>&lt;p>Among my hobbies include food/wine/travel. Yes, wine is a hobby. As I know frequently enough get asked for recommendations on wine or when traveling I&amp;rsquo;ve started to condense this into various simple lists.&lt;/p>
&lt;h3 id="city-guides" >
&lt;div>
City Guides
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="/about/huntsville/">Huntsville, AL&lt;/a> - The place I still consider home, Rocket City, because well literally its where the rockets happen. Aside from the obvious space and rocket center there&amp;rsquo;s plenty of great southern food and times to be had.&lt;/p>
&lt;p>&lt;a href="/about/neworleans/">New Orleans&lt;/a> - Theres possibly no greater city in the world for the trio of food, alcohol, and best of all music.&lt;/p>
&lt;p>&lt;a href="/about/pasorobles/">Paso Robles&lt;/a> - A lesser visited wine region, though thats gradually changing with it winning wine region of the year in 2013. Much more relaxed than Napa or even Sonoma, yet great wine.&lt;/p>
&lt;p>&lt;a href="/about/sf/">San Francisco&lt;/a> - Hopefully not much needs to be said about the city by the bay. A foodie city with lots of activities, and a woefully out of date list because the pace at which things change around here is exhausting.&lt;/p>
&lt;p>&lt;a href="/about/disneyland/">Disneyland&lt;/a> - As my wife is a large Disney fan and now with a toddler, we frequent Disney. As we frequent it we tend to hit up a few of the extra things such as food and alcohol of course, here&amp;rsquo;s some of our faves.&lt;/p>
&lt;h3 id="wine-guides" >
&lt;div>
Wine Guides
&lt;/div>
&lt;/h3>
&lt;p>&lt;a href="/about/wine/">Wine reviews&lt;/a> - Reviews of various wineries I&amp;rsquo;ve attended. Each winery has been attended more than once to have some comparisson between visits. Most are in the Sonoma region, though some outside.&lt;/p>
&lt;p>&lt;a href="/about/wine_route/">Wine routes&lt;/a> - For many reading through lists and lists of reviews and creating your own trip to wine country can be tiring. Here&amp;rsquo;s a few pre-canned recommendations based on taste preference or location to make a visit to wine country easier.&lt;/p>
&lt;p>&lt;a href="/about/memberships/">My Memberships&lt;/a> - Occasionally I&amp;rsquo;m asked where I&amp;rsquo;m a member at and where I frequent.&lt;/p></description></item><item><title>Wine Club Memberships</title><link>/about/memberships/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>/about/memberships/</guid><description>&lt;h3 id="sonomanapa" >
&lt;div>
Sonoma/Napa
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Benziger Winery - Good value, standard California varietals/blends&lt;/li>
&lt;li>Sojourn Cellars - Great pinots and cabs&lt;/li>
&lt;li>Iron Horse - Champagne, and great Pinot&lt;/li>
&lt;li>Piña - Grower in Napa, make great Napa cab at a better price point than much of Napa ($85 a bottle typically)&lt;/li>
&lt;/ul>
&lt;h3 id="paso-robles" >
&lt;div>
Paso Robles
&lt;/div>
&lt;/h3>
&lt;ul>
&lt;li>Lone Madrone - Really fun set of blends here&lt;/li>
&lt;li>Tablas Creek - Classic Rhone style wines, good price point&lt;/li>
&lt;/ul></description></item></channel></rss>