<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:carvers="http://paddy.carvers.com/extendedRSS">
  <channel>
    <title>Baking With Neurospice on Paddy’s Blog</title>
    <link>https://paddy.carvers.com/</link>
    <description>Recent content in Baking With Neurospice on Paddy’s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Fri, 03 Apr 2026 18:00:00 -0700</lastBuildDate><atom:link href="https://paddy.carvers.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Harry Potter</title>
      <link>https://paddy.carvers.com/posts/2026/04/harry-potter/</link>
      <pubDate>Fri, 03 Apr 2026 18:00:00 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2026/04/harry-potter/</guid>
      <description>&lt;p&gt;When I was a teenager&lt;sup&gt;&lt;a href=&#34;#fnote1&#34; id=&#34;ref1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I loved Orson Scott Card&amp;rsquo;s &lt;a href=&#34;https://en.wikipedia.org/wiki/Ender%27s_Game_(novel_series)&#34;&gt;&lt;em&gt;Enderverse&lt;/em&gt;&lt;/a&gt;&lt;sup&gt;&lt;a href=&#34;#fnote2&#34; id=&#34;ref2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.
A particularly formative moment for me was when Ender, the protagonist, finally verbalized something he had been realizing over the duration of the novel: that it was impossible to truly know someone and not love them as they love themselves.&lt;/p&gt;
&lt;p&gt;This provided useful clarity on empathy for me.
That everyone had their own rich, interior lives and an understanding of the world that allowed them to view themselves as the hero was perhaps overdue in arriving, but &lt;em&gt;Ender&amp;rsquo;s Game&lt;/em&gt; finally helped me grasp it.&lt;/p&gt;
&lt;p&gt;I picked up Orson Scott Card&amp;rsquo;s &lt;em&gt;Characters &amp;amp; Viewpoint&lt;/em&gt; to learn how he built these characters and worlds I cared about.
I hung out on his Hatrack River website&amp;rsquo;s forums, learning writing techniques from other fans of his writing.&lt;/p&gt;
&lt;p&gt;So you can imagine my surprise and discomfort when I learned that he was a vocal activist &lt;em&gt;against&lt;/em&gt; gay marriage.
Against &lt;em&gt;my&lt;/em&gt; ability to get married.
And, until the Supreme Court ruled against it in 2003, he was a big proponent of making being gay illegal.&lt;/p&gt;
&lt;p&gt;What a wild source to learn empathy from.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I was given the first &lt;em&gt;Harry Potter&lt;/em&gt; book for my birthday when I was in second grade.
I started reading it the day I got it, and the first chapter put me off, so it sat on a shelf in my room for months.
But I was a voracious reader, and no book could survive proximity with me for long before getting read, no matter how disinterested I was in it.
So one day, lacking other things to read, I picked it up and read it.
And I liked it.&lt;/p&gt;
&lt;p&gt;A new book in the series released every July, right around my birthday.
It became tradition that I&amp;rsquo;d receive the latest book for my birthday, and within days would have finished it and flipped back to the beginning to start again.&lt;/p&gt;
&lt;p&gt;But more than that, my younger brother read it, too, and liked it.
That was new for me.
And kids at school had read it.
Family friends had read it.
I vividly remember a family friend telling me her son was so proud that he read the latest book faster than I did, and asking me not to tell him that I was on my seventh read-through at that point.
I remember, on a family vacation to Maine with those family friends, going to the midnight release party at the bookstore for the book that released that summer.&lt;/p&gt;
&lt;p&gt;I remember opening the book on the ride home.
I remember being shocked that my parents let me stay up until midnight, and brought me and my siblings and our family friends out to a bookstore at midnight just to get a new book.&lt;/p&gt;
&lt;p&gt;That was not my experience for any other book.
I read and loved lots of books, lots of series.
But that was the only book event I ever went to.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Harry Potter&lt;/em&gt; was, at a certain point, popular for being popular.
That it was the zeitgeist is, I think, no small thing.
It made my weird hobby legible to people who didn&amp;rsquo;t normally understand it.
And so loving books and loving &lt;em&gt;Harry Potter&lt;/em&gt; became, if not the same thing, useful proxies for each other.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I honestly don&amp;rsquo;t remember when I learned that JK Rowling is a committed transphobe.
Probably later than I should have.&lt;/p&gt;
&lt;p&gt;I do know at some point the conclusion became unavoidable that I could no longer support her work.
Not only could I no longer give her money, I couldn&amp;rsquo;t give her cultural power.
I couldn&amp;rsquo;t help &lt;em&gt;Harry Potter&lt;/em&gt; be synonymous with a love of reading anymore.
There was no logical knot I could tie myself into to justify continuing to engage with it.&lt;/p&gt;
&lt;p&gt;Our friends&amp;rsquo; kids were reading &lt;em&gt;Harry Potter&lt;/em&gt; as their bedtime story at the time.
We had been asking their parents for years when they would be old enough to start.
When they were our ringbearer and flower girl in our wedding, we thanked them with replica wands from the movies.&lt;/p&gt;
&lt;p&gt;We stopped talking about it with them, and stopped inviting them over to watch the movie when they finished the book.
I honestly have no idea if they ever finished the series or not.
Instead we talk with them about &lt;em&gt;Discworld&lt;/em&gt; and Pratchett.
We didn&amp;rsquo;t lose the people, we didn&amp;rsquo;t lose what &lt;em&gt;Harry Potter&lt;/em&gt; meant for us in those interactions—the joy of reading, the excitement of sharing something you love with people you care about, our desire to be part of their family&amp;rsquo;s lives—but we needed to find a new medium for it.
&lt;em&gt;Harry Potter&lt;/em&gt; just couldn&amp;rsquo;t mean the same thing to us anymore.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I came to Neil Gaiman&amp;rsquo;s writing in adulthood.
I had read Good Omens as a teenager, and Neverwhere at a friend&amp;rsquo;s behest, but that was the extent of my exposure.&lt;/p&gt;
&lt;p&gt;But I enjoyed the way he talked about reading.
I enjoyed the way he talked about stories.
I picked up more of his books, and read them, and liked them.
When my therapist suggested I try listening to audiobooks to help regulate my sleep schedule, I used Neil Gaiman reading his own books to fall asleep.
When my husband and I needed to drive halfway across the country, we listened to &lt;em&gt;American Gods&lt;/em&gt;, Gaiman&amp;rsquo;s love letter to the American roadtrip.&lt;/p&gt;
&lt;p&gt;When credible allegations of sexual assault were made against Gaiman, a lot of people wanted to claim that his work had never been that good to begin with.
I understand the impulse; we want good art to be made by good people who do good things.
It feels offensive to know that people who make something beautiful, or true, or meaningful can do monstrous things.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m not a fan of that line of thinking.
Two things can be true:
Neil Gaiman can be a talented writer, with a deep and powerful understanding of stories and how they affect us, and he can be credibly accused of sexual assault.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Harry Potter&lt;/em&gt; offers a harder example to view this through.
&amp;ldquo;Read any other book&amp;rdquo;, you&amp;rsquo;ll be exhorted.
&amp;ldquo;They make books for adults now, you know&amp;rdquo;, you&amp;rsquo;ll be told.
&amp;ldquo;It&amp;rsquo;s not even that good.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;And to an extent, that&amp;rsquo;s&amp;hellip; true.
It&amp;rsquo;s deeply mid writing that, at times, relies on some shameful stereotypes and doesn&amp;rsquo;t do nearly enough self-examination to grapple with what it&amp;rsquo;s implying or outright stating.&lt;/p&gt;
&lt;p&gt;But that doesn&amp;rsquo;t mean it wasn&amp;rsquo;t good &lt;em&gt;to you&lt;/em&gt;.
It doesn&amp;rsquo;t mean you can&amp;rsquo;t have enjoyed it, or were wrong to.
It may reveal some blind spots you have where you&amp;rsquo;re susceptible to harmful narratives (it certainly revealed some to me) but perhaps it&amp;rsquo;s okay for you to be an imperfect person learning and growing.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;HBO has released a trailer for their new show (movie? I&amp;rsquo;m not sure) remaking the incredibly-successful series of movies from my childhood and early adulthood.
One take I&amp;rsquo;ve heard is that part of what&amp;rsquo;s prompting this is too many of the original cast have come out against Rowling&amp;rsquo;s transphobia.
And maybe that&amp;rsquo;s why this is happening.
Maybe HBO and Rowling just like money.
Who knows.&lt;/p&gt;
&lt;p&gt;We will not be watching it.
The trailer, or the show (&amp;hellip; movie?)&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t tell you whether you should watch it or not.
I &lt;em&gt;will&lt;/em&gt; tell you that whether you watch it or not is taking a side.
You&amp;rsquo;re either okay with hurting trans people or you&amp;rsquo;re not.&lt;/p&gt;
&lt;p&gt;Someone once said Rowling could have kept her transphobia to herself and periodically tweeted things like &amp;ldquo;Happy Sorting Hat Day!&amp;rdquo; and gone down in history as the 21&lt;sup&gt;st&lt;/sup&gt; century&amp;rsquo;s most beloved, successful, and rich author.
But she didn&amp;rsquo;t.
She instead said that people must agree with her transphobia because they keep buying &lt;em&gt;Harry Potter&lt;/em&gt; and its merch.
So here we are, JK Rowling is making you choose: &lt;em&gt;Harry Potter&lt;/em&gt; or trans people?&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s okay to have loved &lt;em&gt;Harry Potter&lt;/em&gt;.
It&amp;rsquo;s okay for it to have been formative for you.
It&amp;rsquo;s okay for you to have found community and yourself through it.
It&amp;rsquo;s okay for it to have meant something to you, and for you to continue to honor it for what it meant to you.&lt;/p&gt;
&lt;p&gt;I do not think it&amp;rsquo;s escapable that continuing to engage with it, monetarily or not, makes you complicit in violence against trans people.
I wish that weren&amp;rsquo;t the case.
I think it&amp;rsquo;s entirely JK Rowling&amp;rsquo;s intent and doing that it is the case.&lt;/p&gt;
&lt;p&gt;I think this is where separating the art from the artist becomes impossible: when the artist is wielding that art as a cudgel.&lt;/p&gt;
&lt;p&gt;If you still engage with &lt;em&gt;Harry Potter&lt;/em&gt; but have nothing against trans people, I think it&amp;rsquo;s time to thank it for what it has meant to you, put it down, and pick up something else.
I promise you, there are other series and other communities that will welcome you with open arms.
That have so much to offer you, and that will help you find community and yourself.
There are so many other things out there that can be meaningful to you.&lt;/p&gt;
&lt;p&gt;And supporting them won&amp;rsquo;t hurt anybody.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;footnotes&#34;&gt;Footnotes&lt;/h3&gt;
&lt;ul class=&#34;footnotes&#34;&gt;
	
&lt;li id=&#34;fnote1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt; An affliction I recommend against catching.&amp;nbsp;&lt;a href=&#34;#ref1&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt; That I&#39;m typing this post within ten or fifteen miles of where Orson Scott Card was born is an odd coincidence.&amp;nbsp;&lt;a href=&#34;#ref2&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;

</description>
      <carvers:summary>Some reflections on Harry Potter, JK Rowling, and separating the art from the artist.</carvers:summary>
    </item>
    
    <item>
      <title>Introducing temple</title>
      <link>https://paddy.carvers.com/posts/2026/01/temple/</link>
      <pubDate>Thu, 22 Jan 2026 17:17:46 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2026/01/temple/</guid>
      <description>&lt;p&gt;I actually wrote this post almost a month ago.
Then I sent it out to a friend to review, and woke up in the morning to find we needed to say goodbye to our dog.
Then the next time I went to publish it, my country bombed Venezuela.&lt;/p&gt;
&lt;p&gt;So here it is now, instead.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Twenty years ago, servers used to send HTML to browsers, not just JavaScript.&lt;sup&gt;&lt;a href=&#34;#fnote1&#34; id=&#34;ref1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;
We wrote CSS and HTML and a sprinkling of JavaScript but the HTML was really the basis of the whole thing.
And it’s possible I’m just an old fogey, but I miss it.&lt;sup&gt;&lt;a href=&#34;#fnote2&#34; id=&#34;ref2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Also, the idea of keeping up with whatever the JavaScript-first stack of the day is just feels exhausting to me, so I’m not going to be doing that.&lt;/p&gt;
&lt;p&gt;But I still like to build things, and I still like to build things for the web.
So I had been using Go’s &lt;a href=&#34;https://pkg.go.dev/html/template&#34;&gt;&lt;code&gt;html/template&lt;/code&gt;&lt;/a&gt; package to render HTML, like it was 2006 again.&lt;/p&gt;
&lt;p&gt;I miss 2006.&lt;/p&gt;
&lt;p&gt;But I found some things hard to use and lacking.
I tried out other templating languages and packages for Go, and never really found one that I liked.
I always ended up gravitating back to &lt;code&gt;html/template&lt;/code&gt;, despite the problems I had using it.
I liked the way it approached the problem, it made sense to me.&lt;sup&gt;&lt;a href=&#34;#fnote3&#34; id=&#34;ref3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;
The whole thing hinges on there being a template with a bundle of data, a bundle of functions, and a bundle of other templates.
The template gets to use the data, the functions, and the other templates to construct some HTML.&lt;/p&gt;
&lt;p&gt;But there’s a catch.
The package isn’t so much a templating framework as much as it is a tool.
Managing those bundles and making sure the template literal has the same bundles available to it every time it’s used and otherwise keeping track of all these things is outside its scope.
It lets you handle them however you want.&lt;/p&gt;
&lt;p&gt;Handling them turns out to be a pain if you don’t have some structure to it.
So I made some structure for it, and I called it &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple&#34;&gt;&lt;code&gt;temple&lt;/code&gt;&lt;/a&gt;.&lt;sup&gt;&lt;a href=&#34;#fnote4&#34; id=&#34;ref4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&#34;components-for-html--go&#34;&gt;Components for HTML &amp;amp; Go&lt;/h2&gt;
&lt;p&gt;temple attempts to bundle all these things up into components.
A component, or, I guess, a &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#Component&#34;&gt;&lt;code&gt;Component&lt;/code&gt;&lt;/a&gt;, is at its core just a template literal.
But you can also &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#FuncMapExtender&#34;&gt;make some functions available to it&lt;/a&gt; and whatever you implement the &lt;code&gt;Component&lt;/code&gt; interface on will be available as the bundle of data.
Rather than tracking which templates a &lt;code&gt;Component&lt;/code&gt; needs, it can declare that it &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#ComponentUser&#34;&gt;uses other &lt;code&gt;Components&lt;/code&gt;&lt;/a&gt; and their data and templates and functions will all be included, too.&lt;/p&gt;
&lt;p&gt;Everything gets bundled up into a reusable &lt;code&gt;Component&lt;/code&gt;, with the same functions and data being available to the same template literal, all accessed through a straightforward interface.
The data the template expects to receive is documented through the type implementing the &lt;code&gt;Component&lt;/code&gt; interface, which is usually a struct of the data you want to use in the template.&lt;/p&gt;
&lt;h2 id=&#34;javascript-and-css&#34;&gt;JavaScript and CSS&lt;/h2&gt;
&lt;p&gt;A component often needs some CSS or JavaScript to function properly, so a &lt;code&gt;Component&lt;/code&gt; has some affordances for that.&lt;sup&gt;&lt;a href=&#34;#fnote5&#34; id=&#34;ref5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;
You can declare that a &lt;code&gt;Component&lt;/code&gt; needs to embed some &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#CSSEmbedder&#34;&gt;CSS&lt;/a&gt; or &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#JSEmbedder&#34;&gt;JavaScript&lt;/a&gt; directly into the HTML output, so it’s included in the initial response from the server.
Or you can link to the &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#CSSLinker&#34;&gt;CSS&lt;/a&gt; or &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#JSLinker&#34;&gt;JavaScript&lt;/a&gt;, instead, having the browser fetch them.
(Browsers are pretty cool technology, we should let them do more things for us.)&lt;/p&gt;
&lt;h2 id=&#34;pages&#34;&gt;Pages&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#Page&#34;&gt;&lt;code&gt;Page&lt;/code&gt;s&lt;/a&gt; are just special &lt;code&gt;Component&lt;/code&gt;s.
They tell temple which template to execute when rendering them and are meant to be rendered as whole documents instead of as a piece of a document.
Other than that, they’re essentially just &lt;code&gt;Component&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;When they get rendered, they get &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#RenderData&#34;&gt;the full bundle of information&lt;/a&gt; they need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$.Page&lt;/code&gt; is set to the &lt;code&gt;Page&lt;/code&gt; implementation being rendered.
This is usually a struct, and any &lt;code&gt;Component&lt;/code&gt;s it uses are usually set as properties on the struct.
It’s the &lt;code&gt;Page&lt;/code&gt;’s template’s job to actually include its &lt;code&gt;Component&lt;/code&gt;s’ templates, though.
Usually through the declaration of &lt;a href=&#34;https://pkg.go.dev/html/template#example-Template-Block&#34;&gt;&lt;code&gt;block&lt;/code&gt;s&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$.Site&lt;/code&gt; is… you know what, we’ll come back to this one.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$.CSS&lt;/code&gt; holds the HTML to include all the CSS (both linked and embedded) needed by the &lt;code&gt;Component&lt;/code&gt;s on the page.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$.HeaderJS&lt;/code&gt; holds the HTML to include all the JavaScript (both linked and embedded) needed by the &lt;code&gt;Component&lt;/code&gt;s on the page but that doesn’t need to run after the rest of the document has loaded.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$.FooterJS&lt;/code&gt; holds the HTML to include all the JavaScript (both linked and embedded) needed by the &lt;code&gt;Component&lt;/code&gt;s on the page that needs to run after the rest of the document has loaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Technically your &lt;code&gt;Page&lt;/code&gt; gets to decide where the &lt;code&gt;$.HeaderJS&lt;/code&gt; and &lt;code&gt;$.FooterJS&lt;/code&gt; are rendered (or &lt;em&gt;if&lt;/em&gt; they’re rendered!) but the spirit is that the &lt;code&gt;$.HeaderJS&lt;/code&gt; will be included in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your HTML and the &lt;code&gt;$.FooterJS&lt;/code&gt; will be included as the last thing before the closing &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; of your HTML.
&lt;code&gt;Component&lt;/code&gt;s control which one they land in by setting &lt;code&gt;PlaceInFooter&lt;/code&gt; in &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#JSLink&#34;&gt;&lt;code&gt;JSLink&lt;/code&gt;&lt;/a&gt; or &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#JSInline&#34;&gt;&lt;code&gt;JSInline&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;true&lt;/code&gt; (will be included in &lt;code&gt;$.FooterJS&lt;/code&gt;) or &lt;code&gt;false&lt;/code&gt; (will be included in &lt;code&gt;$.HeaderJS&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;For each of the CSS, HeaderJS, and FooterJS blocks, temple builds a &lt;a href=&#34;https://en.wikipedia.org/wiki/Directed_acyclic_graph&#34;&gt;DAG&lt;/a&gt; and walks it, deduplicating as it goes.
This allows &lt;code&gt;Component&lt;/code&gt;s to influence where their CSS and JavaScript get rendered in relation to other CSS or JavaScript.
The properties of &lt;code&gt;JSLink&lt;/code&gt;, &lt;code&gt;JSInline&lt;/code&gt;, &lt;code&gt;CSSLink&lt;/code&gt;, and &lt;code&gt;CSSInline&lt;/code&gt; have some more information on the knobs you can turn there.&lt;/p&gt;
&lt;h2 id=&#34;sites&#34;&gt;Sites&lt;/h2&gt;
&lt;p&gt;Passing absolutely everything around from &lt;code&gt;Page&lt;/code&gt; to &lt;code&gt;Component&lt;/code&gt; seems like a lot of busywork, so temple has an affordance called the &lt;a href=&#34;https://pkg.go.dev/impractical.co/temple#Site&#34;&gt;&lt;code&gt;Site&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Technically, a &lt;code&gt;Site&lt;/code&gt; is anything that can tell temple where to find the templates the &lt;code&gt;Component&lt;/code&gt;s are referencing.
But because it’s an interface, and because it’s passed to every &lt;code&gt;Page&lt;/code&gt; as &lt;code&gt;$.Site&lt;/code&gt;&lt;sup&gt;&lt;a href=&#34;#fnote6&#34; id=&#34;ref6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;, its main utility is to store the functions and data that every page should have access to.
It can hold your common configuration data, your utility functions, whatever you think you’ll need on every page.&lt;/p&gt;
&lt;h2 id=&#34;try-it-out&#34;&gt;Try It Out&lt;/h2&gt;
&lt;p&gt;temple is released today with version v0.4.0.
That pre-v1.0.0 version is very intentional.
I might have gotten quite a bit of this wrong, and reserve the right to fiddle with the design as much as I want.&lt;/p&gt;
&lt;p&gt;It’s available under the MIT license.&lt;/p&gt;
&lt;p&gt;If you think it may scratch an itch you’ve got, feel free to try it out, and I’d love to hear from you.
But I have a job, and I’m not looking for an unpaid one.
So I reserve the right to only do things with it when I feel like it, and discard any feedback that doesn’t resonate with me.
This is, first and foremost, solving a problem I have.
If you have the same problem, I’m happy to share the solution I’ve come up with.
But if you have a problem that looks similar if you squint and want me to change the solution to be for that problem instead, I’m going to politely decline and wish you great success with your fork.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;footnotes&#34;&gt;Footnotes&lt;/h3&gt;
&lt;ul class=&#34;footnotes&#34;&gt;
	
&lt;li id=&#34;fnote1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;em&gt;Back in my day…&lt;/em&gt;&amp;nbsp;&lt;a href=&#34;#ref1&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt; &lt;em&gt;Back in my day…&lt;/em&gt; intensifies.&amp;nbsp;&lt;a href=&#34;#ref2&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt; Eventually. After like a decade of using it. Look, nobody has ever described me as a man of taste.&amp;nbsp;&lt;a href=&#34;#ref3&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote4&#34;&gt;&lt;sup&gt;4&lt;/sup&gt; If you’re wondering why I named this “temple” instead of, say, “template” or “tmpl”, I need you to stop reading this post &lt;em&gt;right now&lt;/em&gt; and go rename every Go package you’ve given the same name as a package in the standard library or a commonly-used identifier. Nobody should be making a package named &lt;code&gt;err&lt;/code&gt; or &lt;code&gt;errors&lt;/code&gt;, stop it.&amp;nbsp;&lt;a href=&#34;#ref4&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote5&#34;&gt;&lt;sup&gt;5&lt;/sup&gt; It does not involve reinventing CSS and JavaScript to be Go code, no.&amp;nbsp;&lt;a href=&#34;#ref5&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote6&#34;&gt;&lt;sup&gt;6&lt;/sup&gt; Told you we’d get back to this.&amp;nbsp;&lt;a href=&#34;#ref6&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;

</description>
      <carvers:summary>I wrote a server-side component-based templating library in Go.</carvers:summary>
    </item>
    
    <item>
      <title>You Might Not Need a Pointer</title>
      <link>https://paddy.carvers.com/posts/2025/09/go-pointers/</link>
      <pubDate>Thu, 25 Sep 2025 08:55:58 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2025/09/go-pointers/</guid>
      <description>&lt;p&gt;I spent like an hour last night explaining this in a group chat and I need to justify my husband&amp;rsquo;s suffering, so I&amp;rsquo;m going to share my rules of thumb when it comes to pointers in Go.&lt;/p&gt;
&lt;h2 id=&#34;when-to-use-pointers&#34;&gt;When to use pointers&lt;/h2&gt;
&lt;p&gt;There are four things pointers are useful for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Accepting &lt;code&gt;nil&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;Mutating data across functions.&lt;/li&gt;
&lt;li&gt;Avoiding copying data.&lt;/li&gt;
&lt;li&gt;Fulfilling an interface.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;accepting-nil-values&#34;&gt;Accepting &lt;code&gt;nil&lt;/code&gt; values.&lt;/h3&gt;
&lt;p&gt;A fairly straightforward use case.
If you need to be able to distinguish between the zero value (&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, whatever) and &lt;em&gt;not there at all&lt;/em&gt;, a pointer is a good way to do that.
A &lt;code&gt;nil&lt;/code&gt; value is the absence of data, a pointer to the zero value is the zero value.
If a boolean is optional and you want to know if it was specified as &lt;code&gt;false&lt;/code&gt; or just not specified, a pointer to a boolean helps you make that distinction.&lt;/p&gt;
&lt;h3 id=&#34;mutating-data-across-functions&#34;&gt;Mutating data across functions.&lt;/h3&gt;
&lt;p&gt;Go is a pass-by-value language, meaning when you pass an argument to a function, the runtime copies that argument to a whole new chunk of memory and gives the copy to the function.
So if you change that parameter&amp;rsquo;s contents inside the function the caller won&amp;rsquo;t see those changes, unless the parameter is itself a reference type, like a pointer.
Because the data a pointer holds is a location in memory, copying that pointer to pass to the function means it still points to the same location in memory, there are just now two pointers pointing to that location in memory.&lt;/p&gt;
&lt;p&gt;So if you want to be able to modify data in place, a pointer is a great way to do that.&lt;/p&gt;
&lt;h3 id=&#34;avoiding-copying-data&#34;&gt;Avoiding copying data.&lt;/h3&gt;
&lt;p&gt;Because Go is a pass-by-value language, every time you pass a variable to a function the variable gets copied to a new location in memory.
Writing to memory is fast, but not &lt;em&gt;free&lt;/em&gt;, and for some very performance-sensitive things it can be considered &amp;ldquo;slow&amp;rdquo;.
And everything you write to memory the garbage collector eventually needs to clean up, and the more garbage there is the more resources it&amp;rsquo;s using and the more resources cleaning up after everything takes.&lt;/p&gt;
&lt;p&gt;So if you have a really, really big variable or are passing it to an exorbitant number of functions, you can save some resources by passing a pointer.
A pointer is a fixed width, usually 4 or 8 bytes (depending on the system the program is running on), and usually much smaller than the data it&amp;rsquo;s describing.
That means less time copying data and less garbage to clean up.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using pointers for this benefit, you should have a really compelling case that the copying or the garbage collection are actively causing you problems.
Most things will never even notice the difference this brings.&lt;/p&gt;
&lt;h3 id=&#34;fulfilling-an-interface&#34;&gt;Fulfilling an interface.&lt;/h3&gt;
&lt;p&gt;If a type is filling an interface, and &lt;em&gt;any&lt;/em&gt; of the methods implementing that interface use a pointer receiver, you can &lt;em&gt;only&lt;/em&gt; use a pointer as that interface type.
Trying to use a non-pointer will throw a compiler error.
It&amp;rsquo;s often best to just be consistent within the methods implementing an interface whether you&amp;rsquo;re using a pointer or not as the receiver.
And you should only use a pointer as the receiver for any of them if you need to for one of the other three reasons.&lt;/p&gt;
&lt;h2 id=&#34;when-not-to-use-pointers&#34;&gt;When not to use pointers&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve seen a lot of code (professionally, in the wild, that I&amp;rsquo;ve written, whatever) where a pointer is being used, either as a property on a struct or as the return type from a function, for reasons I can only describe as &amp;ldquo;vibes&amp;rdquo;.
The &lt;code&gt;nil&lt;/code&gt; value has no semantic meaning that ever gets used.
The value is never mutated.
The amount of data being conveyed is barely bigger than the pointer itself.&lt;/p&gt;
&lt;p&gt;The most common thing I hear about using a pointer as a function return is &amp;ldquo;so I can &lt;code&gt;return nil, err&lt;/code&gt; when there&amp;rsquo;s an error&amp;rdquo;.
But you don&amp;rsquo;t need to do that.
The error is already conveying the meaning that something happened and the other return value is garbage.
Just &lt;code&gt;return myType{}, err&lt;/code&gt;, it&amp;rsquo;s fine.
And callers won&amp;rsquo;t need to check if the return value is &lt;code&gt;nil&lt;/code&gt;, or wonder if their modifications are going to have impacts somewhere else.&lt;/p&gt;
&lt;p&gt;For structs with pointers as properties, I think it&amp;rsquo;s usually an attempt to avoid copying too much data around.
I think people internalized that advice really prematurely, and just default to pointers when using another struct type as a property in a struct.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t do that.
Default to non-pointer types, and only reach for the pointers when you provably need one of the four benefits of pointers.
Trying to figure out if a struct property is ever going to be &lt;code&gt;nil&lt;/code&gt; and where it was set is a nightmare if the struct property is a pointer.
Embrace pointers as communicating an absence of guarantees around a bit of data, and make as many guarantees as you can.
Your code will be easier to read, navigate, and extend, and when you see a pointer you&amp;rsquo;ll know it means something.&lt;/p&gt;
</description>
      <carvers:summary>A rule of thumb for when to (and not to) use pointers in Go.</carvers:summary>
    </item>
    
    <item>
      <title>I’m Tired of Talking About AI</title>
      <link>https://paddy.carvers.com/posts/2025/07/ai/</link>
      <pubDate>Sat, 19 Jul 2025 13:00:00 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2025/07/ai/</guid>
      <description>&lt;p&gt;I feel like the ground is shifting beneath my feet.
Several times in the last few weeks I’ve seen people I respect talk about how they use a generative AI assistant when coding, or criticize those that are critical of generative AI.
People who were, themselves, critical of generative AI in recent memory.&lt;/p&gt;
&lt;p&gt;I’m tired.&lt;/p&gt;
&lt;p&gt;I am, deep in my bones, tired of talking about this.
The first time I mentioned AI (that I can find) on Mastodon was in May, 2023.
The post was about how tired I was of hearing about it.
In over two years, I have not become less tired of it.&lt;/p&gt;
&lt;p&gt;I have considered that these people I respect whose opinions have changed should prompt me to reexamine my opinions.
I have done so.
I&amp;rsquo;ve taken a look at why I don&amp;rsquo;t use genAI, and checked in on whether those are still good reasons.
I can&amp;rsquo;t find the change in circumstances or information that led to these changes in opinion.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t honestly even know that I consider these people wrong.
They&amp;rsquo;re smart people.
Maybe they&amp;rsquo;re right.
I&amp;rsquo;m a big fan of people changing their opinions in light of new information.
I don&amp;rsquo;t know that those people think &lt;em&gt;I&lt;/em&gt; should use the tool.
There&amp;rsquo;s room for nuance here, as much as the discourse pretends there isn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;But I just can&amp;rsquo;t get there.
I can&amp;rsquo;t look at this situation and say &amp;ldquo;yeah, I should use that tool&amp;rdquo; for any reason other than &amp;ldquo;people I respect find some value in it&amp;rdquo;.
And that&amp;rsquo;s just not a good enough reason for me.
It&amp;rsquo;s indicative, it&amp;rsquo;s enough to make me consider it, but it&amp;rsquo;s not enough to overrule my own judgment.
What is my judgment for, if I&amp;rsquo;m just going to blindly follow people I respect?&lt;/p&gt;
&lt;p&gt;Besides, other people I respect agree with my judgment.
A quandary.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sad.
I&amp;rsquo;m tired.
I don&amp;rsquo;t want to talk to people about computers anymore.
Like &lt;a href=&#34;https://blog.glyph.im/2025/06/i-think-im-done-thinking-about-genai-for-now.html&#34;&gt;Glyph&lt;/a&gt;, I have found that the constant checking in, the constant trying to turn the problem over in my brain to make it make sense to me the way it seems to make sense to other people, has worn me down.
It&amp;rsquo;s exhausting.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;m done talking about AI.
Y&amp;rsquo;all can keep talking about it, if you want.
I&amp;rsquo;m a grown adult and can set my own mutes and filters on social media.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve given this idea its due, and with this post I am absolving myself of having to think about it any more.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve never actually written about AI on my blog before, though I have some unpublished drafts if you know how to find them.
So I&amp;rsquo;m going to leave this conversation with a list of my objections to coding with AI.
If I&amp;rsquo;m wrong about it, let this be a record of my wrongness.
If I&amp;rsquo;m right about it, let this be a record of my argument.&lt;/p&gt;
&lt;h2 id=&#34;llms-have-no-theory-of-the-system-and-cannot-form-one&#34;&gt;LLMs have no theory of the system, and cannot form one.&lt;/h2&gt;
&lt;p&gt;The core of programming, to me, is to develop a &lt;a href=&#34;https://blog.ceejbot.com/posts/programming-as-theory-building/&#34;&gt;theory of the system&lt;/a&gt;.
As Naur says (as quoted by Ceej), a programmer with theory can &amp;ldquo;[e]xplain how the solution relates to the affairs of the world that it helps to handle.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;When talking about this with people, I often describe it as a perspective.
Every problem space looks different depending on where you&amp;rsquo;re viewing it from.
Where you view the problem from is your business&amp;rsquo; thesis on that problem.
Some vantage points are better than others.
Some vantage points are more suited for certain customers than others.
A firm understanding of your vantage point and its limitations and strengths is core to good system design.&lt;/p&gt;
&lt;p&gt;This is, I believe, a solid core of my job, and the LLM is incapable of performing it.
It cannot do it for me.
It cannot help me do it.
There is no shortcut here, I cannot use the forklift to lift the weights for me at the gym.
I need to do my own thinking, build the understanding in my own brain.&lt;/p&gt;
&lt;h2 id=&#34;if-you-dont-start-now-you-wont-be-able-to-find-work-soon&#34;&gt;&amp;ldquo;If you don&amp;rsquo;t start now, you won&amp;rsquo;t be able to find work soon.&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;I find this argument so tedious.&lt;/p&gt;
&lt;p&gt;This is not a logical argument, it&amp;rsquo;s just an appeal to fear.&lt;/p&gt;
&lt;p&gt;You cannot scare me into believing something against my better judgment, I need to understand why my judgment is wrong.&lt;/p&gt;
&lt;p&gt;Worse, this argument pairs particularly poorly with &amp;ldquo;it democratizes software engineering&amp;rdquo; and &amp;ldquo;vibe coding&amp;rdquo;.
If it&amp;rsquo;s so easy now that anyone can do it, why can&amp;rsquo;t I pick up the skills later, when I actually need them for employment?
Is it so easy that anyone can do it, or so hard that if I don&amp;rsquo;t upskill I&amp;rsquo;ll be left behind?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been professionally employed writing software for thirteen years now.
I have navigated the advent of the cloud, and Docker, and web3.
I&amp;rsquo;ve seen Rails&amp;rsquo; ascendancy and NodeJS.
I&amp;rsquo;ve seen Kubernetes and I&amp;rsquo;ve seen CDKs.
I&amp;rsquo;ve seen conversational interfaces and I&amp;rsquo;ve seen voice assistants.
I&amp;rsquo;ve seen smartphones and apps.
I&amp;rsquo;ve seen technologies I&amp;rsquo;ve forgotten about already that the industry lost its damn mind over and was convinced they were the future of software.
For a time.&lt;/p&gt;
&lt;p&gt;I feel reasonably confident in my ability to navigate this bubble, too.&lt;/p&gt;
&lt;h2 id=&#34;why-not-at-least-keep-one-foot-in-the-pool-in-case-it-is-the-future&#34;&gt;&amp;ldquo;Why not at least keep one foot in the pool, in case it &lt;em&gt;is&lt;/em&gt; the future?&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m busy, I&amp;rsquo;m tired, and I have better uses of my time and energy.&lt;/p&gt;
&lt;p&gt;If I were going to invest time in my career, learning Rust and TypeScript are much lower hanging fruit that I&amp;rsquo;m much more confident would yield dividends.
I&amp;rsquo;m not doing either of those things because I&amp;rsquo;ve glanced at them enough to know I won&amp;rsquo;t &lt;em&gt;enjoy&lt;/em&gt; using them as much as I like using Go, and so it hasn&amp;rsquo;t been important enough to me yet.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m certainly not going to enjoy using LLMs.&lt;/p&gt;
&lt;h2 id=&#34;you-wouldve-argued-against-smartphones-or-the-internet&#34;&gt;&amp;ldquo;You would&amp;rsquo;ve argued against smartphones or the internet.&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;Would I have?
I was there for smartphones, and I have no recollection of being skeptical of them.&lt;/p&gt;
&lt;p&gt;But this isn&amp;rsquo;t a real argument.
I argued against web3 and I made fun of Quibi, too.
How are they doing?
There are plenty of technologies I didn&amp;rsquo;t argue against.
I was pretty on board with infrastructure as code.
I don&amp;rsquo;t recall being skeptical of containers or the cloud.&lt;/p&gt;
&lt;p&gt;Maybe I&amp;rsquo;m skeptical of some technologies but not others, and use my judgment to differentiate between those two groups.&lt;/p&gt;
&lt;h2 id=&#34;llms-arent-useless-they-did-this-thing-for-me&#34;&gt;&amp;ldquo;LLMs aren&amp;rsquo;t useless. They did this thing for me.&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;Of course they aren&amp;rsquo;t.
But they aren&amp;rsquo;t a trillion dollar industry, and I just don&amp;rsquo;t buy that they&amp;rsquo;re the future of software development.&lt;/p&gt;
&lt;p&gt;Maybe they&amp;rsquo;ll be a tool software engineers &lt;em&gt;can&lt;/em&gt; use &lt;em&gt;in certain situations&lt;/em&gt;.
Maybe I&amp;rsquo;ll come across a situation where it makes sense to me to reach for an LLM.
I haven&amp;rsquo;t yet, but hey, I won&amp;rsquo;t say never.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m glad you&amp;rsquo;re finding them useful.
Please leave me alone about them.&lt;/p&gt;
&lt;h2 id=&#34;the-energy-cost&#34;&gt;The energy cost&lt;/h2&gt;
&lt;p&gt;Look, a lot of people are disdainfully skeptical about environmental and energy use claims about AI.
I don&amp;rsquo;t have the specifics.
I gather it&amp;rsquo;s because the companies involved don&amp;rsquo;t want us to have the specifics.&lt;/p&gt;
&lt;p&gt;I do know that the companies involved are all sinking an unthinkable amount of money into compute, and building new data centers and power stations to handle the load.
Where&amp;rsquo;s the money going?
What are the new data centers for and why do they need more power, if the energy cost is overstated?&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;t seen anything that will square that circle for me.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Oh, that&amp;rsquo;s just for training, actually &lt;em&gt;using&lt;/em&gt; the thing has much lower energy use.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If you buy a car for $100,000 and then it only costs $50 a month in gas, is that a &lt;em&gt;cheap&lt;/em&gt; car?
No, you still spent $100,000 on it.&lt;/p&gt;
&lt;p&gt;The bottom line is:
if the energy we can currently supply isn&amp;rsquo;t enough, if new data centers need to be built for it, yeah, it&amp;rsquo;s using more energy.
That seems pretty inescapable.&lt;/p&gt;
&lt;h2 id=&#34;the-ethics-of-it&#34;&gt;The ethics of it&lt;/h2&gt;
&lt;p&gt;People turn up their nose at &amp;ldquo;this is trained on stolen IP&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Since when do you care about IP?&amp;rdquo; they say.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s fair.
I&amp;rsquo;m not the world&amp;rsquo;s biggest fan of IP.
I think it&amp;rsquo;s a dirty hack on a dirty hack that has stuck around for centuries and is an awkward solution to the problem it&amp;rsquo;s addressing, and the cracks are showing through it in a pretty big way.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d be very happy with some very aggressive reform of IP and copyright law.&lt;/p&gt;
&lt;p&gt;This is not an intellectually or ethically inconsistent stance with being displeased that it&amp;rsquo;s not being reformed, but you can ignore it if you&amp;rsquo;re wealthy enough.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s just another indication to me that AI is a tool of capital.
Between the &amp;ldquo;public domain for thee, copyright for me&amp;rdquo; approach and the push from executives and VCs for its adoption, I&amp;rsquo;m wary.
When you add in the open desire from executives to use it to replace labor, I&amp;rsquo;m alarmed.&lt;/p&gt;
&lt;p&gt;GenAI, as it exists, is fundamentally a tool for undercutting labor.
And it&amp;rsquo;s using stolen labor to achieve it, and mandating that labor implement their own replacement.&lt;/p&gt;
&lt;p&gt;But I don&amp;rsquo;t believe it&amp;rsquo;s a suitable replacement.
I believe that what&amp;rsquo;s way more likely is that it won&amp;rsquo;t supplant labor, but will turn us into professional AI output editors, while devaluing our skills and driving our wages and working conditions lower.&lt;/p&gt;
&lt;p&gt;This is about the point in the story where unions start being important.&lt;/p&gt;
&lt;h2 id=&#34;the-bubble&#34;&gt;The bubble&lt;/h2&gt;
&lt;p&gt;Look, the economics of this &lt;a href=&#34;https://www.wheresyoured.at/pop-culture/&#34;&gt;just don&amp;rsquo;t make sense&lt;/a&gt; and the &amp;ldquo;what trillion dollar problem will AI solve?&amp;rdquo; question takes up a lot of space in my brain.
I see people talking about the limited ways in which they work with it now, and wonder what happens when the bill comes due.
We wouldn&amp;rsquo;t, as a society, pay a trillion dollars to solve those problems.
Not even close.&lt;/p&gt;
&lt;p&gt;Where&amp;rsquo;s the money coming from?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m suspicious it&amp;rsquo;s not.
I believe that at some point the music will stop and the funding will dry up.
And at that point, what happens to these tools?
What happens to the people using them?
What happens to the executives they&amp;rsquo;ve misled about how much productivity they can expect per dollar?&lt;/p&gt;
&lt;p&gt;What future exists where we continue on &lt;em&gt;even as we are&lt;/em&gt;, let alone with more advanced capabilities?&lt;/p&gt;
&lt;p&gt;Where&amp;rsquo;s the money coming from?&lt;/p&gt;
&lt;h2 id=&#34;even-in-the-best-case-scenario-im-not-sure-this-is-the-job-i-want&#34;&gt;Even in the best case scenario, I&amp;rsquo;m not sure this is the job I want&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s assume the best case scenario.
Generously, let&amp;rsquo;s assume coding agents can solve any problem if I describe what I want them to do.
Let&amp;rsquo;s assume I&amp;rsquo;m sipping rocket fuel.&lt;/p&gt;
&lt;p&gt;What does my job look like?&lt;/p&gt;
&lt;p&gt;It looks like prompting an agent to do a thing, then skipping over to another agent to review its answer to a different problem.
Jumping between different attempts by agents to do what I asked all day, juggling a dozen or more projects so I don&amp;rsquo;t waste any time.
Reviewing code for something that can&amp;rsquo;t learn from the time I invested, catching the same mistakes over and over.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m neurospicy.
Switching between tasks is expensive for me.&lt;/p&gt;
&lt;p&gt;Is this a job I would &lt;em&gt;want&lt;/em&gt;?
Would I have gotten into this career if this was the work?
Would I still be here?&lt;/p&gt;
&lt;p&gt;Set aside wishy-washy arguments about &lt;em&gt;craft&lt;/em&gt; or &lt;em&gt;fun&lt;/em&gt;.
Let&amp;rsquo;s accept that people have strengths and weaknesses.
Right now, my job optimizes fairly well for my strengths.
If that job changes to one that targets all my weaknesses, is that a career I should stay in?&lt;/p&gt;
&lt;p&gt;What a bleak future.&lt;/p&gt;
</description>
      <carvers:summary>I don’t want to talk about LLMs anymore.</carvers:summary>
    </item>
    
    <item>
      <title>Well, That Didn’t Go As I Expected</title>
      <link>https://paddy.carvers.com/posts/2025/06/clerk/</link>
      <pubDate>Mon, 16 Jun 2025 16:02:25 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2025/06/clerk/</guid>
      <description>&lt;p&gt;Look, when I &lt;a href=&#34;https://paddy.carvers.com/posts/2025/05/next/&#34;&gt;left my last job&lt;/a&gt; I didn’t really know what to expect or have any plans, but I knew what I had to be prepared for.
I was voluntarily leaving my job in a notably poor job market, and I had to be prepared to be unemployed for a while, take a pay cut, or both.&lt;/p&gt;
&lt;p&gt;So when I wrote that post, what I &lt;em&gt;expected&lt;/em&gt; to happen was for me to take like six weeks and just chill, not really doing much of anything.
I’d play with my kid, take care of side projects, spend time with family, play some video games, read some books, cook and bake, and just generally relax.&lt;/p&gt;
&lt;p&gt;When I &lt;a href=&#34;https://paddy.carvers.com/posts/hashicorp-last-day/&#34;&gt;left HashiCorp&lt;/a&gt;, I didn’t take much time at all between jobs.
We were in the process of adopting, and the agency had some misgivings about me being unemployed for any length of time.
I needed the next thing lined up when I told them I was quitting.
So I ended up leaving HashiCorp during the winter break, while I was off work anyways.
And I joined up with LaunchDarkly first thing in January, when I would’ve come back from break.
There wasn’t really any rest or decompression time there, just the normal&lt;sup&gt;&lt;a href=&#34;#fnote1&#34; id=&#34;ref1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; PTO.&lt;/p&gt;
&lt;p&gt;This was a mistake, and not one I was keen to repeat.
And we had already planned to visit &lt;a href=&#34;http://lanestaples.com&#34;&gt;our friend&lt;/a&gt; for Lucas’ second birthday.
So I thought: cool.
I’ll just chill until that trip, come back from it, and start applying for jobs then, knowing I may not even get one this &lt;em&gt;year&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&#34;welp&#34;&gt;Welp.&lt;/h2&gt;
&lt;p&gt;That is not, in fact, what happened.
I published that post at 5pm on a Friday, Pacific time.
10am on Monday morning, Pacific time, &lt;a href=&#34;https://dstaley.com&#34;&gt;my friend&lt;/a&gt;’s &lt;a href=&#34;https://clerk.com&#34;&gt;employer&lt;/a&gt; was in my inbox asking if we could talk.
That Thursday we talked for an hour, and I realized I had a problem.
I like to remain uninvested in companies while interviewing.
I need to see what I &lt;em&gt;could&lt;/em&gt; get invested in, but I like to not be invested until the contract is signed.
It lets me retain some objectivity during the process about whether it’s actually the right fit or not.&lt;/p&gt;
&lt;p&gt;But our hour-long phone call had ruined that for me.
I was emotionally invested now.
I believe the direct quote was “[i]t, unfortunately, sounds like it could be an opportunity to do the best work of my career”.&lt;/p&gt;
&lt;p&gt;The rest of my interview experience was short, to the point, and pain-free.
We actually verbally agreed a month ago, I’m just a problem child and some of my questions required them do some stuff with legal about contracts.&lt;sup&gt;&lt;a href=&#34;#fnote2&#34; id=&#34;ref2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;
This actually sets a new record for how early in my employment I can be a problem.&lt;sup&gt;&lt;a href=&#34;#fnote3&#34; id=&#34;ref3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&#34;so-much-for-that-plan&#34;&gt;So much for that plan.&lt;/h2&gt;
&lt;p&gt;And so that vague plan of screwing around for a bit over a month and then searching for a new job until I find one is blown almost immediately.
Instead, I start with Clerk at the end of July as a Staff Software Engineer.
They were nice enough to be patient and still give me plenty of time with my family and to rest up between jobs.&lt;/p&gt;
&lt;p&gt;And I’m pretty excited to get started.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;footnotes&#34;&gt;Footnotes&lt;/h3&gt;
&lt;ul class=&#34;footnotes&#34;&gt;
	
&lt;li id=&#34;fnote1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt; Yes, I know my “normal” is wildly luxurious for most salaried workers, and I know retail workers are struck mute with rage that I would characterize any sort of time off over the holidays as “normal”. I’m going to hold my ground on this one: it &lt;em&gt;is&lt;/em&gt; normal, you’re being exploited.&amp;nbsp;&lt;a href=&#34;#ref1&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt; Pay attention to what you’re signing and ask questions about your contract, kids. Any employer you want to work for won’t be mad about it.&amp;nbsp;&lt;a href=&#34;#ref2&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt; My previous record was set in 2016, when I had to ask HashiCorp to change the name on my offer because I neglected to tell them that my legal name was not the name they had been calling me. This was so mortifying I went to court to make sure I would never need to have that conversation again.&amp;nbsp;&lt;a href=&#34;#ref3&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;

</description>
      <carvers:summary>I’m joining Clerk at the end of July.</carvers:summary>
    </item>
    
    <item>
      <title>Push to Deploy</title>
      <link>https://paddy.carvers.com/posts/2025/05/push-to-deploy/</link>
      <pubDate>Fri, 30 May 2025 15:39:35 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2025/05/push-to-deploy/</guid>
      <description>&lt;p&gt;Now that I’m &lt;a href=&#34;https://paddy.carvers.com/posts/2025/05/next/&#34;&gt;funemployed&lt;/a&gt; and have some time on my hands&lt;sup&gt;&lt;a href=&#34;#fnote1&#34; id=&#34;ref1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I decided to solve a problem that has been bothering me.&lt;/p&gt;
&lt;p&gt;See, historically I have published my blog in the following way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a post in &lt;a href=&#34;https://neovim.io&#34;&gt;NeoVim&lt;/a&gt; over SSH on our home server.&lt;/li&gt;
&lt;li&gt;Run &lt;a href=&#34;https://gohugo.io&#34;&gt;Hugo&lt;/a&gt; on that home server, overriding the base URL to point to the home server’s domain.&lt;/li&gt;
&lt;li&gt;Preview the blog post by navigating to the home server’s domain.&lt;/li&gt;
&lt;li&gt;Re-run Hugo with the actual domain name as the base URL.&lt;/li&gt;
&lt;li&gt;Run &lt;a href=&#34;https://packer.io&#34;&gt;Packer&lt;/a&gt;, which installs &lt;a href=&#34;https://nginx.org&#34;&gt;Nginx&lt;/a&gt; into a Google Cloud Platform VM, puts all the files generated by Hugo in the right places, and bakes the whole thing into a VM.&lt;sup&gt;&lt;a href=&#34;#fnote2&#34; id=&#34;ref2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;a href=&#34;https://terraform.io&#34;&gt;Terraform&lt;/a&gt;, which notices the new image, generates a new instance template, and updates the managed instance group running my blog to roll out the new images.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This approach has the wonderful property of never waking me up in the middle of the night and I never forget how to do it just because I haven’t published a blog post in like a year. And if I managed to break anything, I could just delete the new image and roll out the previous one to get things back the way they were, no sweat. But on the other hand, I sometimes forgot to run step 4&lt;sup&gt;&lt;a href=&#34;#fnote3&#34; id=&#34;ref3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; and broke the assets and links horribly. And steps 5 and 6 took fifteen minutes to run by themselves. And that was annoying.&lt;/p&gt;
&lt;p&gt;I started wondering if there was a better way.&lt;/p&gt;
&lt;p&gt;And I don’t know that it’s “better”, but I did land on a very cursed way to keep some of those properties that doesn’t involve pushing to prod from my laptop.&lt;/p&gt;
&lt;p&gt;Here’s the new system:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a post in NeoVim over SSH on our home server.&lt;/li&gt;
&lt;li&gt;Commit that post with git and push it to the git repo.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/build/&#34;&gt;Google Cloud Build&lt;/a&gt; runs Hugo for me and builds a &lt;a href=&#34;https://docker.com&#34;&gt;Docker&lt;/a&gt; image of the Nginx server and the files for my blog.&lt;sup&gt;&lt;a href=&#34;#fnote4&#34; id=&#34;ref4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;That image gets pushed to &lt;a href=&#34;https://cloud.google.com/artifact-registry/&#34;&gt;Google Cloud Artifact Registry&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The instances in my managed instance group notice that a new Docker image is available and pull it down, then spin up new containers with that image, register them with &lt;a href=&#34;https://haproxy.org&#34;&gt;HAProxy&lt;/a&gt;, drain traffic from the existing containers in HAProxy, and kill the existing containers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This whole process&lt;sup&gt;&lt;a href=&#34;#fnote5&#34; id=&#34;ref5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt; takes between one and five minutes, total, and is all kicked off by the git push.&lt;/p&gt;
&lt;p&gt;The interesting thing here is step 5. I kinda glossed over how that happens, because the answer is “I wrote cursed software that does it”. I built a Go binary that, every minute, uses the &lt;a href=&#34;https://github.com/haproxytech/client-native&#34;&gt;HAProxy native client&lt;/a&gt; and the &lt;a href=&#34;https://pkg.go.dev/github.com/docker/docker/client&#34;&gt;Docker SDK&lt;/a&gt; to compare the running Docker containers to the registered HAProxy servers. Any server without an associated running container gets removed from the backend. Any container missing a server gets added to the backend. And every minute, it pulls all the images associated with the running container using the image ref that was used to start the container. If the image version doesn’t match the one the container is running, it spins up a new container, adds it to HAProxy, sets the old container to drain connections in HAProxy, removes the old container from HAProxy, and kills the old container.&lt;/p&gt;
&lt;p&gt;It’s a truly cursed piece of software.&lt;/p&gt;
&lt;p&gt;Because I’m me, there are several pieces of this that I’m unhappy with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Because I’m insistent on not making a config file or database to hold state, the only way to change the number of containers or the image refs they point to is to do a whole new Packer build and Terraform rollout, like the old system. Because the running containers are considered to be the definition of what’s supposed to be running.&lt;/li&gt;
&lt;li&gt;If a new image rollout fails halfway through, I could accidentally increase the number of containers running; the program has no idea how many containers are supposed to be running, so if the new one starts up and the program gets interrupted before it brings the old one down, it will stand up &lt;em&gt;another&lt;/em&gt; new container for the old one on the next run.&lt;/li&gt;
&lt;li&gt;If containers die and Docker’s restart policy fails me somehow, the program doesn’t know to start more containers because it doesn’t know how many should be run.&lt;/li&gt;
&lt;li&gt;There’s a very delicate mapping of the Docker image ref and the port exposed inside the container to a HAProxy backend name that ties the running container to the HAProxy backend they should be added to. This is fragile and annoying but necessary because no other state contains that information.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But it’s good enough to publish this post, and that was the spec! I think the next part of this is investigating having the instance group manager in GCP automatically roll the instances every day or something, just to hide any sins that creep in while this lurching horror runs over time.&lt;/p&gt;
&lt;p&gt;Some day I may make the version of this that stores state outside of “whatever containers are running right now”, but that is a whole project, and I have enough projects for the moment.&lt;/p&gt;
&lt;p&gt;You may be expecting this blog post to end with a link to a GitHub repo for this cursed program. It will not be. I generally do like to open source the code I write, so nobody needs to write the same code twice. I like having nice things, and think we deserve nice things, and if I take the time to make a nice thing I want as many people as possible to benefit from that nice thing.&lt;/p&gt;
&lt;p&gt;But this is not a nice thing. This is A Mistake™. And if you want to make this particular mistake, I think it’s probably good for you to go through the steps of making it yourself, instead of just downloading my mistake.&lt;/p&gt;
&lt;p&gt;Let’s see if this works. 🤞&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;footnotes&#34;&gt;Footnotes&lt;/h3&gt;
&lt;ul class=&#34;footnotes&#34;&gt;
	
&lt;li id=&#34;fnote1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt; I do not, in fact, have some time on my hands, everything I say in this post notwithstanding. Toddlers, man.&amp;nbsp;&lt;a href=&#34;#ref1&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt; It actually does a lot of other things, too, mostly grabbing other HTML files for other sites and grabbing some binaries. I host a lot of sites on a single VM because I&amp;rsquo;m cheap.&amp;nbsp;&lt;a href=&#34;#ref2&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt; I eventually wrote a shell script to detect when I had done this and fail the Packer build after, and this is true, my interviewer brought up my broken site while I was in an interview.&amp;nbsp;&lt;a href=&#34;#ref3&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote4&#34;&gt;&lt;sup&gt;4&lt;/sup&gt; Notably, there are no other sites hosted in that image. Each site can have its own Docker image.&amp;nbsp;&lt;a href=&#34;#ref4&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote5&#34;&gt;&lt;sup&gt;5&lt;/sup&gt; Except for the blog post writing part. That part takes longer than I care to think about.&amp;nbsp;&lt;a href=&#34;#ref5&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;

</description>
      <carvers:summary>I built a completely cursed new way to deploy my sites.</carvers:summary>
    </item>
    
    <item>
      <title>What’s Next?</title>
      <link>https://paddy.carvers.com/posts/2025/05/next/</link>
      <pubDate>Fri, 02 May 2025 17:00:00 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2025/05/next/</guid>
      <description>&lt;p&gt;Three years and just under five months ago, I &lt;a href=&#34;https://paddy.carvers.com/posts/hey-launchdarkly&#34;&gt;joined LaunchDarkly&lt;/a&gt;. Today, as of 5pm PDT, I no longer work for LaunchDarkly.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d love to be really clear about why not. To explain the choice in full and outline my reasons. But I’m not confident I know why not. I have a lot of reasons, but those reasons were true six months ago, too. Why now? Well, because.&lt;/p&gt;
&lt;p&gt;The truth is, I don’t know. I woke up, looked around, said “It’s time to be doing something else.” and gave notice.&lt;/p&gt;
&lt;p&gt;I’ve never done that before. I’ve never been able to do that before. This is the first time in my career I’ve gotten to the last day of employment at one company and not known where I was going to be working next.&lt;/p&gt;
&lt;p&gt;It’s scary, and that makes me suspicious it’s the right thing to be doing.&lt;/p&gt;
&lt;p&gt;Tonight, I’m hanging out with my husband and our toddler. As I told the HR professional who conducted my exit interview, my next job title is “dad”. I have a very patient husband who would love to be able to do anything at all between 9 and 5 without a toddler being involved, and a toddler on the cusp of talking who wants his Other Dad’s attention and to maybe play with that keyboard Other Dad gets to spend all day playing with. For now, what’s next is them.&lt;/p&gt;
&lt;p&gt;We aren’t in a financial position where that can be forever, though, and I don’t know how long it’ll be for or what comes after it. What’s wild is it will only be the third time in almost fifteen years that I’ve been publicly available to hire.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;If you’d like what comes next after “dad” to be working for your company, shoot an email to &lt;a href=&#34;mailto:hire@paddy.dev&#34;&gt;hire@paddy.dev&lt;/a&gt;. Tell me about what you’re doing, and what you hope I’d help you with.&lt;/del&gt; (Update: &lt;a href=&#34;https://paddy.carvers.com/posts/2025/06/clerk/&#34;&gt;nevermind&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Here are the things I’m looking for in a job, to save you some time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I won’t come into your office. Don’t ask. An occasional (max like four a year) offsite with a team or annual company gathering? Sure. Anything you’re tempted to categorize as hybrid? I’m not doing it.&lt;/li&gt;
&lt;li&gt;I have a lot of deep expertise in Go. I have a strong preference for working in Go, but for the right company am willing to use other languages. “What you hope I’d help you with” should probably be engineering leadership things that emphasize leveling up teammates, in that case. Accept that I would be navigating a new-to-me situation if you hired me, but one I’m confident in my ability to navigate.&lt;/li&gt;
&lt;li&gt;I don’t want to be a manager. I am happy to be in a &lt;a href=&#34;https://paddy.carvers.com/posts/engineering-leadership&#34;&gt;leadership role&lt;/a&gt; but I do not want that leadership to be conducted under the shadow of institutional authority.&lt;/li&gt;
&lt;li&gt;I don’t want to work on blockchains or AI. I have some tolerance for you making an AI play, because every tech company in existence is having to explain to investors what their AI strategy is. But if you don’t think someone skeptical of the long-term value prop of LLMs is a good fit for your company, that’s me.&lt;/li&gt;
&lt;li&gt;I want to work in a high-trust environment. I want to be given hard problems and work collaboratively to solve them. I want my experience to be valued and I want to learn from others’ experience. I want to work with people who care about understanding a problem space and making choices about navigating it. I want to work on a team that’s trying to build both software and also a team that will provide a solid foundation for the next ten years. I want to work with people who understand that the team is a system for building systems, and tuning that meta-system yields disproportionate rewards.&lt;/li&gt;
&lt;li&gt;I want to solve problems. I don’t want to not be able to solve problems because people don’t believe they can be solved.&lt;/li&gt;
&lt;li&gt;I want to view my coworkers (not just my teammates) as allies trying to solve the same or similar problems. I do not want to jockey against them for power. I do not want to deal with them jockeying against me for power. I understand there’s some amount of this in every job, but know that I care about showing up at work to work on problems, not to play status games, and if status games are required for every problem, I’m not going to be happy or last very long.&lt;/li&gt;
&lt;li&gt;I want asynchronous work to be valued. I actually really like meetings, but I need them to be a tool used in the proper way, not the hammer that’s deployed on every problem that could be a nail if you squint. Either have or have an appetite for a work culture that values writing and reading, and deploys meetings for specific value that couldn’t be obtained through writing and reading.&lt;/li&gt;
&lt;li&gt;I’ve spent most my career in developer tooling and that’s where I feel most at home, but I am very open to branching out into other areas.&lt;/li&gt;
&lt;li&gt;I have a lot of thoughts and opinions on billing, authentication, infrastructure management, and APIs. I am very open to branching out into other areas.&lt;/li&gt;
&lt;li&gt;I do love open source and community stewardship, but that is definitely not a requirement.&lt;/li&gt;
&lt;li&gt;I’m not really interested in non-senior roles. A lot of the value I bring to an org is I’m pretty good at leveling up my coworkers. If you’re not looking for that, you’re wasting your money on me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s a long list, it’s not exhaustive, and it’s not like my eventual next thing will tick every box. But hopefully it gives people enough to get a feel for me as an employee.&lt;/p&gt;
&lt;p&gt;I am not actively trying to get hired today. I will probably be really hesitant to start a new job until at least mid-June, and I’m not convinced I’ll have a job this year. But for the right opportunity, &lt;del&gt;I’m available&lt;/del&gt; (update: &lt;a href=&#34;https://paddy.carvers.com/posts/2025/06/clerk/&#34;&gt;nevermind&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For now, I’m gonna go play with my kid.&lt;/p&gt;
</description>
      <carvers:summary>Today was my last day at LaunchDarkly and I don’t know what’s next.</carvers:summary>
    </item>
    
    <item>
      <title>Errors in Go</title>
      <link>https://paddy.carvers.com/posts/go-errors/</link>
      <pubDate>Fri, 05 Jul 2024 12:00:00 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/go-errors/</guid>
      <description>&lt;p&gt;Errors in Go are a contentious topic.
Everyone has an opinion on them.
I’m not going to share mine here, nor am I really going to engage with the controversy of them.
Instead, I’m going to accept that the tree grew in the way it did, and explore how to best cut with the grain, rather than fighting against it.&lt;/p&gt;
&lt;p&gt;I was discussing error handling in Go with some coworkers, and the discussion prompted me to break the problem down in ways I found useful.
So I’m writing them down, both so I remember my conclusions and so I can more easily share them with people I collaborate with.&lt;/p&gt;
&lt;h2 id=&#34;the-setting&#34;&gt;The Setting&lt;/h2&gt;
&lt;p&gt;Stop me if you’ve heard this one.
You’re working on a Go service, and it’s time to bring it past a prototype.
You need to surface proper HTTP responses when you encounter an error.
You need to log them, ideally with a stack trace, in your logging service, your error reporting tool, or ideally, both.
And when writing your HTTP handlers, you need to know if an error occurred, so you can stop processing.
Sometimes, you need to know &lt;em&gt;which&lt;/em&gt; error occurred, so you can recover or customize your response appropriately.&lt;/p&gt;
&lt;p&gt;Fortunately, Go’s &lt;code&gt;error&lt;/code&gt; type is an interface, and you can implement your own errors in your application.
So you build a type that holds an HTTP status code, maybe a message to display to the end user as part of the HTTP response, and a stacktrace.
You start using this custom error type everywhere in your application, and set up a linter to make sure people don’t accidentally use another error.
Maybe you write a helper for converting other errors into your custom error.&lt;/p&gt;
&lt;p&gt;Suddenly, you have headaches.
You want to wrap errors coming back from helper functions, but oops, some of those errors were already your custom error type, and you just overrode their HTTP status code and have the wrong stacktrace and it’s a mess.
Okay, you build a check into your wrapper to just return without wrapping the variables that are already your custom error type.
Except whoops, now you’re missing the added context of the message that was passed in to wrap with.
Worse, you’re now seeing some mistakes that are arguably security problems.
It seemed like a good idea to return a custom error with a 404 status code from the helper for looking up an account if that account couldn’t be found, but it turns out that’s a problem in auth code and you really want a 401.&lt;/p&gt;
&lt;p&gt;This isn’t working.
We keep needing to be careful, and there are some mistakes it’s really easy to make that reduce the quality of our errors and make it harder to figure out what’s happening in our program.&lt;/p&gt;
&lt;p&gt;Something’s wrong with our design.&lt;/p&gt;
&lt;h2 id=&#34;who-is-an-error-for&#34;&gt;Who Is An Error For?&lt;/h2&gt;
&lt;p&gt;One of the first things I think about when designing software is who my audiences are and what they want.
Errors have two responsibilities: indicating what went wrong, and indicating the context it went wrong in.
Who the error is for, and what they plan to do with it, informs what context we want to associate with the error.&lt;/p&gt;
&lt;h3 id=&#34;errors-are-for-operators&#34;&gt;Errors Are For Operators&lt;/h3&gt;
&lt;p&gt;Operators are who we generally think of when thinking about the audience for an error.
The people who interact with a program from outside the process boundary, generally tasked with keeping it running and working well.&lt;/p&gt;
&lt;p&gt;Operators want errors because they want to know what broke, how it broke, and ideally, what made it break.
The context an operator wants, therefore, is very zoomed in.
They want to know the stack trace, the state of the program when the error occurred, and what it was trying to do.&lt;/p&gt;
&lt;h3 id=&#34;errors-are-for-end-users&#34;&gt;Errors Are For End Users&lt;/h3&gt;
&lt;p&gt;End users care about errors, because end users want to know what to do next.
Sometimes that means correcting the information they entered in a form.
Sometimes it means checking an online archive of the site.
Sometimes it means just waiting until whoever got paged can fix things.&lt;/p&gt;
&lt;p&gt;Letting an end user know what’s going on means they can adjust their expectations and behaviors accordingly.&lt;/p&gt;
&lt;p&gt;End users want the wider context, to put the error in perspective.
They don’t care about stack traces and state.
They don’t care about whatever a database constraint violation is.
They just want to know the username is already taken.&lt;/p&gt;
&lt;p&gt;End users care about what an error &lt;em&gt;means&lt;/em&gt;, not what caused it.&lt;/p&gt;
&lt;h3 id=&#34;errors-are-for-callers&#34;&gt;Errors Are For Callers&lt;/h3&gt;
&lt;p&gt;The caller of a function has a vested interest in whether the function succeeded and, if not, the specific way in which it failed.
But the callers of a function have more responsibilities than that.
They’re responsible for ferrying errors to end users or operators, as well as to any callers of their own.&lt;/p&gt;
&lt;p&gt;This is where things start to get dicey.
Because an operator wants the zoomed-in &lt;em&gt;what&lt;/em&gt; of an error.
An end user wants the zoomed-out &lt;em&gt;so what&lt;/em&gt; of an error.
Callers want &lt;em&gt;neither&lt;/em&gt;, they just want to know what state they’re in and whatever information they need to attempt an automated recovery, if possible.&lt;/p&gt;
&lt;p&gt;A single error type can’t meet all those concerns all at once.&lt;/p&gt;
&lt;p&gt;Error wrapping helps.
You can wrap an error in the context that an operator will want, and callers can strip it away to get to the bare state.
But that frustrates attempts to put the error in the wider perspective for the end user, because any callers are going to attempt to bring the error back to the zoomed-in context, for the operators.
Worse, you’re attempting to put things in the wider context of, say, an HTTP status code while deep within the call stack, where that context just isn’t available to you.
You can make an educated guess, at best.&lt;/p&gt;
&lt;p&gt;Stack traces, likewise, get messy.
You’re passing around a variable with a stack trace in it, and it’s invariably getting &lt;em&gt;actually reported&lt;/em&gt; from somewhere different from where the error actually occurred.
You haven’t tricked Go into having exceptions, you’ve just taught your log line numbers to lie to you.
God help you if you end up with multiple stack traces because of wrapping.&lt;/p&gt;
&lt;h2 id=&#34;why-an-error-though&#34;&gt;Why An &lt;code&gt;error&lt;/code&gt;, Though?&lt;/h2&gt;
&lt;p&gt;At this point, I like to go back and revisit my assumptions.
Is an &lt;code&gt;error&lt;/code&gt; even the right way to communicate this information?&lt;/p&gt;
&lt;p&gt;Why are we using an &lt;code&gt;error&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt;s, in Go, are just values.
Why do operators and end users need values in the runtime?&lt;/p&gt;
&lt;p&gt;They don’t.&lt;/p&gt;
&lt;h3 id=&#34;errors-arent-for-operators&#34;&gt;&lt;code&gt;error&lt;/code&gt;s Aren’t For Operators&lt;/h3&gt;
&lt;p&gt;What an operator wants is an error report, not an error value.&lt;/p&gt;
&lt;p&gt;They’re not going to handle it at runtime.
They don’t need it stored in memory.
They don’t want it passed around the call stack.&lt;/p&gt;
&lt;p&gt;What they actually want, at the root of it, is for an error condition to trigger a log line or an error report, with a bunch of context at that point in time.&lt;/p&gt;
&lt;p&gt;That sounds like a function call to me.&lt;/p&gt;
&lt;p&gt;That sounds, honestly, like &lt;a href=&#34;https://pkg.go.dev/log/slog&#34;&gt;&lt;code&gt;slog&lt;/code&gt;&lt;/a&gt; to me: a function call that reports a message, some caller-defined context, and a stack trace.&lt;/p&gt;
&lt;p&gt;Operators don’t want stack traces in your error variables, they want function calls at the point errors actually happened.&lt;/p&gt;
&lt;p&gt;Everyone will hate this take because the much-reviled&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;gets even more verbose, turning into&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;slog&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrorContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed to get account&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;account.id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;123&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;but I call ’em like I see ’em, and the thing operators &lt;em&gt;actually want&lt;/em&gt; here is best served by a function call at the point in the stack where it happens, not passing around a variable.&lt;/p&gt;
&lt;p&gt;It’s probably worth being explicit here that I’m using &lt;code&gt;slog.ErrorContext&lt;/code&gt; as an example, because it already has the function signature I want.
You could have a &lt;code&gt;slog.Handler&lt;/code&gt; that surfaces the error however your operators want it, or you could use your own function.
The key point here is it’s a function, not an &lt;code&gt;error&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It’s also fair to note that people need to remember to actually call these functions in error states.
A counterpoint to that, though, is that people need to remember to inject the stack trace into the error when returning it.
If you can have a linter for one, you can have a linter for the other.&lt;/p&gt;
&lt;p&gt;Likewise, it’s fair to note that you’ll get multiple error reports for the same error condition, as the error travels back up the call stack.
But that’s easily solvable, without any real compromises the way trying to deduplicate stack traces has compromises:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reportedError&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;report&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;alreadyReported&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reportedError&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;As&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;alreadyReported&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; = append([]&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;}, &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;slog&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrorContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getAccount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;accountID&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;queryDatabase&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;accountID&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;report&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed to get account&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;account.id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;accountID&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reportedError&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As long as after each call to &lt;code&gt;report&lt;/code&gt; the &lt;code&gt;error&lt;/code&gt; is turned into a &lt;code&gt;reportedError&lt;/code&gt;, you’ll only report it once, no matter how deep in the stack you are.
Again, people need to remember to do it, but if you can lint for only constructing errors a certain way, you can lint for only returning them a certain way.
If you get clever enough with the code, and do enough magic, you can probably have &lt;code&gt;report&lt;/code&gt; do the wrapping itself.&lt;/p&gt;
&lt;p&gt;Or, heck, you could take the easy way out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;report&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;alreadyReported&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reportedError&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;As&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;alreadyReported&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; = append([]&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;}, &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;slog&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrorContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;msg&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reportedError&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getAccount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;accountID&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;queryDatabase&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;accountID&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;report&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed to get account&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;account.id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;accountID&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;errors-arent-for-end-users&#34;&gt;&lt;code&gt;error&lt;/code&gt;s Aren’t For End Users&lt;/h3&gt;
&lt;p&gt;An end user doesn’t actually want an &lt;code&gt;error&lt;/code&gt; value either.
Like an operator, they also want an error report—just the opposite kind of error report.&lt;/p&gt;
&lt;p&gt;An end user doesn’t want the error report authored at the point in the call stack the error occurred, the end user wants the error report authored at the point in the call stack that understands their request.
They want the handler to write the error report, because the handler has the relevant information to guide them to next steps and to indicate precisely what about their request went wrong.&lt;/p&gt;
&lt;p&gt;The end user wants the handler to detect specific error states, and translate them into something they can understand.&lt;/p&gt;
&lt;p&gt;My preferred way to do this is with a small package I wrote called &lt;a href=&#34;https://pkg.go.dev/impractical.co/apidiags&#34;&gt;&lt;code&gt;apidiags&lt;/code&gt;&lt;/a&gt;, which is really just a struct definition and some helpers.
It’s based incredibly heavily off of the &lt;a href=&#34;https://pkg.go.dev/github.com/zclconf/go-zcl/zcl#Diagnostic&#34;&gt;&lt;code&gt;zcl.Diagnostic&lt;/code&gt;&lt;/a&gt; type that &lt;a href=&#34;https://martin.atkins.me.uk&#34;&gt;Martin Atkins&lt;/a&gt; wrote for ZCL.
But honestly, whatever your scheme for communicating an error to the end user is, it doesn’t belong wrapped in an &lt;code&gt;error&lt;/code&gt; type.
It’s probably a function call that, e.g., writes a set of bytes over a wire, or renders text to standard error, or whatever.
Or it’s setting a value on some response state that will be written to the user later.
But importantly, that value on the response state is not an &lt;code&gt;error&lt;/code&gt;, and nobody expects to be able to interact with it like one.&lt;/p&gt;
&lt;h3 id=&#34;what-is-error-for&#34;&gt;What Is &lt;code&gt;error&lt;/code&gt; For?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt;s do one thing really, really well.
And that’s indicating an error state of a program, and communicating with callers around it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt;s are for callers, and nobody else.&lt;/p&gt;
&lt;p&gt;What’s up with wrapping, then?
Why can we add context to an error, if the caller doesn’t care about or want the context?&lt;/p&gt;
&lt;p&gt;A weaselly answer is that sometimes callers &lt;em&gt;do&lt;/em&gt; want more context.
The ability to wrap one strongly typed error inside another strongly typed error and let callers pick the level that they want to detect is pretty neat.
But that’s weaselly, because most people just &lt;code&gt;fmt.Errorf&lt;/code&gt; their way into a new error, adding context a caller can’t reliably read.
If the &lt;code&gt;error&lt;/code&gt; is for the caller, why is that so popular?&lt;/p&gt;
&lt;p&gt;Because third party libraries exist.&lt;/p&gt;
&lt;p&gt;Suppose you have a third party library for some SaaS API.
It needs to communicate to you that the endpoint you requested wasn’t found.&lt;/p&gt;
&lt;p&gt;The caller wants to know that the endpoint wasn’t found (and a retry is unlikely to fix it).
The operator wants to know &lt;em&gt;what the endpoint was&lt;/em&gt;, to aid in debugging.
The third party library knows what the endpoint was, the caller does not.
The caller knows how to communicate to the operator, the third party library does not.&lt;/p&gt;
&lt;p&gt;In this case, the third party library wraps the “endpoint not found” error in some context that isn’t for the caller, but for the operator: the endpoint that couldn’t be found.
It returns that to the caller, to surface to the operator.
The caller can unwrap to get what &lt;em&gt;they&lt;/em&gt; want, which is the error state they’re in.
The caller can report the error to the operator, giving them what &lt;em&gt;they&lt;/em&gt; want: the context around that error state, and where in the call stack the third party client was called.
The deepest point within the application that the error state occurred in.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;These are my beliefs on errors, and on &lt;code&gt;error&lt;/code&gt;s.
I think my conclusion is that the &lt;code&gt;error&lt;/code&gt; type is &lt;em&gt;only&lt;/em&gt; for information that you think the caller needs, or need to give the caller so they can report it to the operator because &lt;em&gt;you don’t know how&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Everything else doesn’t really benefit from being an &lt;code&gt;error&lt;/code&gt;, but it does suffer for it.&lt;/p&gt;
</description>
      <carvers:summary>A look at the different audiences for Go’s errors and a recommendation on how to stop passing around stack traces.</carvers:summary>
    </item>
    
    <item>
      <title>Hey, Lucas</title>
      <link>https://paddy.carvers.com/posts/lucas/</link>
      <pubDate>Fri, 15 Dec 2023 08:40:00 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/lucas/</guid>
      <description>&lt;p&gt;Today we got the email that a judge in Texas has ruled that Lucas is now legally our child.&lt;/p&gt;
&lt;p&gt;Let’s back up a bit.&lt;/p&gt;
&lt;h2 id=&#34;the-call&#34;&gt;The Call&lt;/h2&gt;
&lt;p&gt;On the afternoon of Saturday, June &lt;nobr&gt;10&lt;sup&gt;th&lt;/sup&gt;,&lt;/nobr&gt; our &lt;a href=&#34;https://www.americanadoptions.com&#34;&gt;adoption agency&lt;/a&gt; called and told us a woman was actively in labor, and asked if we wanted to adopt the baby.&lt;/p&gt;
&lt;p&gt;We said yes, dropped everything, and got on the next flight to Texas&lt;sup&gt;&lt;a href=&#34;#fnote1&#34; id=&#34;ref1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;We sat on the plane, knowing very little.
We didn’t know the baby’s expected gender&lt;sup&gt;&lt;a href=&#34;#fnote2&#34; id=&#34;ref2&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, we didn’t know if the baby had been born, we didn’t know if we were going to land and get told to turn around and go home, she decided not to place the baby for adoption, after all.
We didn’t know anything other than “a woman is in labor” and that she’s Mexican-American and the father was believed to be white.
Neither of us slept on the flight.
I, personally, spent it mentally chanting “the baby is born, the baby is healthy, come get the baby.”, trying to manifest it.&lt;/p&gt;
&lt;p&gt;When we landed, around 6am Central&lt;sup&gt;&lt;a href=&#34;#fnote3&#34; id=&#34;ref3&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, after pestering the agency a little, they called while we were heading to baggage claim.
My heart sank, I almost cried.
I was sure they were calling to tell us to turn around and go home.
They were not.
The baby was born, the baby was healthy, come get the baby.&lt;/p&gt;
&lt;p&gt;We got our bags, got our rental car, and drove an hour and a half from DFW to the hospital.&lt;/p&gt;
&lt;h2 id=&#34;the-hospital&#34;&gt;The Hospital&lt;/h2&gt;
&lt;p&gt;I spent much of this process &lt;em&gt;very sure&lt;/em&gt; that the agency, who had done this kind of thing before, would start proactively guiding us any minute now.
I was perhaps unprepared for how little guidance I’d be getting.&lt;/p&gt;
&lt;p&gt;Which is how I found myself sitting in a rented minivan&lt;sup&gt;&lt;a href=&#34;#fnote4&#34; id=&#34;ref4&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, calling the agency and asking “so… now what?”&lt;/p&gt;
&lt;p&gt;The told us to go inside, and ask for “Baby Boy X&lt;sup&gt;&lt;a href=&#34;#fnote5&#34; id=&#34;ref5&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;”.
It took a little (possibly hysterical&lt;sup&gt;&lt;a href=&#34;#fnote6&#34; id=&#34;ref6&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;) coaxing before they told me I wouldn’t be meeting the person giving birth, and would only be interacting with the baby.&lt;/p&gt;
&lt;p&gt;So we went inside, Ethan went to the bathroom, and I went up to the reception to ask for “Baby Boy X”.
The person working the desk looked at me like I had a third eye and asked what I was talking about.
Suboptimal.&lt;/p&gt;
&lt;p&gt;After a fair bit of explaining, they told me I needed to go up to the maternity floor and ask there.
I collected Ethan, and we rode the elevator up, looking for reception.
There wasn’t a reception area.
But we found a closed and locked door with an doorbell and intercom next to it, with painting on the wall indicating it might be the maternity ward.
So we rang the doorbell.&lt;/p&gt;
&lt;p&gt;Someone came to the door and, through the intercom, politely inquired as to why two random guys who looked like they traveled for 6-ish hours were trying to get into the maternity ward.
We explained we were there to see Baby Boy X and were hopefully the adoptive parents.&lt;/p&gt;
&lt;p&gt;They had no idea what we were talking about, either.&lt;/p&gt;
&lt;p&gt;At this point, our luck turned, and a nurse &lt;em&gt;happened to be walking by&lt;/em&gt; who knew what we were talking about and took us under her wing.
She led us to the NICU while explaining that there was nothing wrong with the baby, but he was in the NICU because the hospital didn’t have a standalone nursery; babies generally just stayed with mom, which mom did not want in this case&lt;sup&gt;&lt;a href=&#34;#fnote7&#34; id=&#34;ref7&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;.
This created some confusion for the hospital, so the NICU took custody of the baby but it was administratively weird for them.&lt;/p&gt;
&lt;p&gt;We scrubbed in, and were shown to his bassinet, where we held him for the first time.
The NICU nurses wanted to get us our own room, but the supervisor that needed to sign off on it was in a meeting or a surgery or something.
So we sat in the NICU, rocked the baby, and fell helplessly in love.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;picture&gt;
		
&lt;source srcset=&#34;https://paddy.carvers.com/img/posts/lucas/bassinet.avif&#34; type=&#34;image/avif&#34;&gt;


		&lt;img src=&#34;https://paddy.carvers.com/img/posts/lucas/bassinet.jpg&#34; alt=&#34;A baby asleep in a bassinet, swaddled in a white blanket with different colored footprints on it.&#34;&gt;
&lt;/picture&gt;
&lt;/div&gt;

&lt;p&gt;An hour later, they got us situated in a room where we could finally, finally, get some sleep&lt;sup&gt;&lt;a href=&#34;#fnote8&#34; id=&#34;ref8&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;.
We each laid in a hospital bed, with Lucas in a bassinet between us, and passed out.
Nurses came and fed and changed him, and we were dead to the world for a bit.&lt;/p&gt;
&lt;p&gt;After we woke up, we got some baby training.
We learned to swaddle and change diapers and feed him.
A social worker working with the agency came and did all the paperwork with us.
We signed so many things, taking custody&lt;sup&gt;&lt;a href=&#34;#fnote9&#34; id=&#34;ref9&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; of him and agreeing to the placement.
The hospital told us we could discharge basically whenever, because the baby was healthy and the papers were all signed.
We asked if it was okay to stay for a bit longer, to try and practice parenting with a safety net with more than a handful of hours of sleep under our belt.
They generously allowed us to, on the condition that they continue to not need the room.&lt;/p&gt;
&lt;p&gt;Texas law says that you need to wait 48 hours after a child is born to voluntarily relinquish your parental rights to that child.
The mother had already discharged, and our agency told us when the social worker’s appointment with her to sign those papers was.
We decided to time our discharge from the hospital so we were in the hotel when that happened.
The thought process was that if she declined to sign the paperwork and decided to parent instead, we didn’t want to have an audience for receiving that news, and didn’t want to be packing up the hospital room after we had no reason to be in it anymore.
So Monday afternoon we packed up and left for a hotel.&lt;/p&gt;
&lt;h2 id=&#34;the-hotel&#34;&gt;The Hotel&lt;/h2&gt;
&lt;p&gt;The hotel was a mistake.&lt;/p&gt;
&lt;p&gt;While we were in the hospital, we planned ahead a bit.
I ordered a drive-up order from Target with bottles, diapers, wipes, formula, and the other things we’d need for our days-old infant.
What I neglected to do was figure out how we were going to clean those bottles, which needed to be cleaned before they could be used.
Worse, I neglected to figure out how we were going to &lt;em&gt;sanitize&lt;/em&gt; those bottles, which &lt;em&gt;also&lt;/em&gt; had to happen before they were used.&lt;/p&gt;
&lt;p&gt;Our hotel room, you see, did not have a kitchen.
It had a bathroom sink and a microwave.&lt;/p&gt;
&lt;p&gt;So we checked into the hotel room, and Lucas started screaming.
Newborns take small amounts of food every hour or two.
Tiny little tummies.
It had been an hour or two since we left the hospital.&lt;/p&gt;
&lt;p&gt;We had bottles to feed him with, but no way to get them clean or sanitized.&lt;/p&gt;
&lt;p&gt;I made a frantic run to the Walmart five minutes from our hotel and grabbed sponges and dish soap.
I must’ve walked the entire store before I found the two (2) kinds of bottle sanitizers they had, tucked away on the bottom shelf.
I bought both.&lt;/p&gt;
&lt;p&gt;I got back to the hotel, washed the bottles and sanitizer in the bathroom sink, and sanitized the bottles in the microwave.
We poured some pre-mixed formula into the bottle, and started feeding Lucas.&lt;/p&gt;
&lt;p&gt;Or, we tried to.
It was his first time drinking out of those bottles.&lt;/p&gt;
&lt;p&gt;He couldn’t get milk out of the nipples.&lt;/p&gt;
&lt;p&gt;The hours since he’s eaten are ticking by.
He is unhappy.
We are unhappy and getting tired.&lt;/p&gt;
&lt;p&gt;Ethan, fortunately, is a genius and remembered that we had a bag of samples from Target because we started a baby registry there.
And that bag had a couple different sample bottles in it.&lt;/p&gt;
&lt;p&gt;I washed and sanitized all the sample bottles, and Ethan poured the formula into the one most similar to what they were using in the hospital.
Finally, Lucas was drinking.&lt;/p&gt;
&lt;p&gt;On to the next problem: we had one bottle he could drink from, it’s after 10pm, and we need to feed him throughout the night.
Every time he gets fed, we need to wash the bottle in the bathroom sink after and sanitize it.
Every time we use the sanitizer it needs to be washed first in the bathroom sink.&lt;/p&gt;
&lt;p&gt;This wasn’t working.&lt;/p&gt;
&lt;p&gt;I got on my phone and looked for an Airbnb with an instant book option.
I found one nearby, booked it for the week, and pleaded with the owner to let us in that night.
The owner agreed.&lt;/p&gt;
&lt;p&gt;We grabbed our bags, loaded the van up, stopped at Walmart to grab a bunch more of the bottles he could drink from, and got into the Airbnb around midnight.&lt;/p&gt;
&lt;h2 id=&#34;the-airbnb&#34;&gt;The Airbnb&lt;/h2&gt;
&lt;p&gt;After checking in, Ethan took care of Lucas while I washed all the bottles we just bought.
In a sink.
A real, glorious, big-enough sink.
When they were all washed and dried, I started running them through the microwave in the sanitizer in groups of four.
By around 2am, we had enough bottles to get us to tomorrow afternoon without washing any.
I passed out.&lt;/p&gt;
&lt;p&gt;The next day, we went to Target and set ourselves up for a stay.&lt;/p&gt;
&lt;p&gt;The funny thing about adoption is it’s a matter of state law.
Every state has its own laws and requirements around it.
Fortunately, this thing called &lt;a href=&#34;https://en.wikipedia.org/wiki/Interstate_Compact_on_the_Placement_of_Children&#34;&gt;the Interstate Compact on the Placement of Children&lt;/a&gt; exists to make this all work when the people adopting the child don’t live in the same state the child was born in.
It’s a whole thing about making sure rights are honored.&lt;/p&gt;
&lt;p&gt;But basically, the adoption agency files with a state agency that coordinates with Texas and Washington courts to give us permission to leave the state with the baby.
This is supposed to take “around two weeks”, but it’s stressed that it could be longer, it could be shorter, nobody has any insight into it, the state agencies don’t like when you ask, just parent your baby and be patient.&lt;/p&gt;
&lt;p&gt;So we weren’t really sure how long we’d be in this Airbnb.
So we prepared ourselves to hunker down for a few weeks, and were just renting it a week at a time.
But we started setting our systems up: how would we make sure we always had clean bottles?
What’s the laundry schedule and rotation look like?
What are we eating, and when, and how?&lt;/p&gt;
&lt;p&gt;We established our rhythm.
I started trying to get him on our health insurance, applied for &lt;a href=&#34;https://paidleave.wa.gov&#34;&gt;Washington’s paid leave&lt;/a&gt; program, and updated my employer.&lt;/p&gt;
&lt;p&gt;Wednesday we went to the follow-up appointment with the pediatrician that saw him in the hospital.
They wanted to schedule a two week follow-up.
We told them we didn’t know if we’d even be in the state in two weeks.
They told us we could do the two week follow-up as soon as one week after birth.
We found this perplexing, but scheduled an appointment for Saturday.&lt;/p&gt;
&lt;p&gt;A couple hours later, the agency called.
Texas had cleared ICPC for us in less than 24 hours.
We were just waiting on Washington.&lt;/p&gt;
&lt;p&gt;We got another call Thursday afternoon.
Washington cleared ICPC.
We could go home.&lt;/p&gt;
&lt;p&gt;But how?
We have an infant who is less than a week old.
He has no immune system, he can’t be vaccinated against COVID-19.&lt;/p&gt;
&lt;h2 id=&#34;getting-home&#34;&gt;Getting home&lt;/h2&gt;
&lt;p&gt;We could fly, but it’s a 1½ hour drive to the airport, a 3-4 hour flight, then a 3½ drive home.
With an infant who needs fed at least every 2 hours.
Also, if there are any delays, we’re stuck.
So we need to travel with enough formula and diapers, and something he can safely sleep in.&lt;/p&gt;
&lt;p&gt;But we flew to Texas with two checked bags, two carry ons, and two personal items.
And that didn’t have any baby stuff in it.
And while we could just buy more bags and figure out what to check, how were we physically going to move the bags &lt;em&gt;and him&lt;/em&gt; through the airport?&lt;/p&gt;
&lt;p&gt;Also, we can call and ask what they’ll let us do (bring the carseat on the plane, bring however many ounces of pre-mixed formula, etc) but if &lt;em&gt;anyone&lt;/em&gt;, from the person checking boarding passes at the security line to the flight attendant, says anything different at any point, we’re stuck with whatever they say.&lt;/p&gt;
&lt;p&gt;This sounds like a nightmare.&lt;/p&gt;
&lt;p&gt;But driving isn’t much better.
It’s a 28 hour drive, neither of us is getting much sleep, and a car accident doesn’t sound like a good time right now.
Committing to 28 hours of driving seems untenable.&lt;/p&gt;
&lt;p&gt;Fortunately, I married a genius, and Ethan realized something: if we drive, we’re driving through two different cities that have direct flights to the airport five minutes from our house.&lt;/p&gt;
&lt;p&gt;We could commit to driving 8 hours, then make a decision about flying.
And at that point, it was a 2 hour direct flight with no driving on either end.
Way more manageable.&lt;/p&gt;
&lt;p&gt;And then 8 hours later, we’d get to make the same decision again.&lt;/p&gt;
&lt;p&gt;So we stayed in Texas until the pediatrician appointment on Saturday, and after leaving it, packed the Airbnb up and got on the road.
We set up our route so that one of us could drive for two hours while the other sat in the back keeping an eye on Lucas (he was in a car seat, but we were anxious).
Then we’d stop, get food, feed Lucas, and switch drivers.
The other person would drive to the Airbnb we were staying in that night.
We only booked Airbnbs that had dishwashers, so once we got there, we’d unload what we needed for the night, feed Lucas, run the day’s bottles through the wash and sanitize functions on the dishwasher, eat dinner, decide whether to fly (when we were in a city that had an airport), and book the next day’s Airbnb.&lt;/p&gt;
&lt;p&gt;It took us six days, but we drove all 28 hours home.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;picture&gt;
		
&lt;source srcset=&#34;https://paddy.carvers.com/img/posts/lucas/car.avif&#34; type=&#34;image/avif&#34;&gt;


		&lt;img src=&#34;https://paddy.carvers.com/img/posts/lucas/car.jpg&#34; alt=&#34;Paddy taking a selfie in the bucket seat in the back of a minivan. A baby is sleeping in a carseat in the other bucket seat. Ethan is driving in the front seat. The back of the minivan is littered with bags and drinks.&#34;&gt;
&lt;/picture&gt;
&lt;/div&gt;

&lt;h2 id=&#34;parenting&#34;&gt;Parenting&lt;/h2&gt;
&lt;p&gt;Ever since, we’ve been doing the parenting thing.
There’s some more in there about terminating dad’s parental rights, arguing with health insurance, our A/C dying, our dishwasher leaking, arguing with our car’s manufacturer, selling a car back to the manufacturer, buying a new car, mice invading our kitchen…
But honestly, it’s all not very interesting.&lt;/p&gt;
&lt;p&gt;That parenting thing, though, that’s some complicated stuff.&lt;/p&gt;
&lt;h3 id=&#34;the-general-framework&#34;&gt;The General Framework&lt;/h3&gt;
&lt;p&gt;We thought for a long time about what parenting means to us.
We started the process of adopting back in July of 2020, after all, so we’ve known this was coming.&lt;/p&gt;
&lt;p&gt;And at the end of the day, there’s two things I keep coming back to about parenting.&lt;/p&gt;
&lt;p&gt;First, he’s his own, whole person.
He’s not property, he’s not mine to mould or shape or whatever.
It’s my job to help him be healthy and happy, and give him the tools to learn about himself and make his own choices about who to be.&lt;/p&gt;
&lt;p&gt;Second, he can’t make choices yet.
He doesn’t have the capacity to choose for himself yet, not because he’ll make choices I think are bad, but because he is developmentally incapable of even understanding the question or that you’re asking it.
So my job as his parent is to make some reasonable default choices for him to start from.&lt;/p&gt;
&lt;h3 id=&#34;gender-and-name&#34;&gt;Gender and Name&lt;/h3&gt;
&lt;p&gt;The first way you see this framework in action is with gender&lt;sup&gt;&lt;a href=&#34;#fnote10&#34; id=&#34;ref10&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;.
My fundamental belief about gender is that it is a social construct, not a phsyical property of a person.
So, basically, a person’s gender is whatever they say it is.
Which is a problem when the person in question doesn’t understand what a gender is&lt;sup&gt;&lt;a href=&#34;#fnote11&#34; id=&#34;ref11&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;, let alone have the ability to vocalize it.&lt;/p&gt;
&lt;p&gt;My default answer to this is that person does not have a gender.
If your gender is whatever you say it is, but you don’t even understand the concept of gender or self, you don’t have a gender, because having a gender requires a concept of self or identity.&lt;/p&gt;
&lt;p&gt;And this is fine, in a world where we don’t gender everything.
Sadly, we are in a world where we do gender everything, and not having a gender is Breaking The System.&lt;/p&gt;
&lt;p&gt;This means that not having a gender is signing up for friction in most of your life.&lt;/p&gt;
&lt;p&gt;So what are we supposed to do?
If we gender him, we’re assigning a gender that he can’t possibly have.
If we don’t gender him, we’re making his life harder when he doesn’t have a say in it.&lt;/p&gt;
&lt;p&gt;In this case, we chose to not sign him up for the struggle, and to just go with the gender people were going to assume, but to make sure he had the tools to understand and explore gender as he grows.&lt;/p&gt;
&lt;p&gt;Likewise, naming him was rough.
Names are an important marker of identity, and we believe your name is what you say it is, but he couldn’t tell us what his name was.
How were we supposed to pick his name before we knew who he was?&lt;/p&gt;
&lt;p&gt;It helped to reframe it, from picking his name to picking what we were going to call him.
If he doesn’t like it, he can change it.
No big deal.&lt;/p&gt;
&lt;p&gt;We talked a lot about going with a gender-neutral name.
We really liked Sage.
We talked with some of our non-binary friends about names, and someone told us they really liked having a gendered first name and neutral middle name, so they could choose when to fly under the radar but had a name ready for when they didn’t want to be gendered.
They appreciated having the choice to take on the friction or not.&lt;/p&gt;
&lt;p&gt;So Lucas Sage it was.
Until he tells us it’s something different.&lt;/p&gt;
&lt;h3 id=&#34;privacy&#34;&gt;Privacy&lt;/h3&gt;
&lt;p&gt;Another place we needed this framework was in deciding how much about him to share, where, and with whom.&lt;/p&gt;
&lt;p&gt;We believe, if he’s his own person, he gets to choose what about him gets shared and what is private.
Just because we’re his parents doesn’t mean his life is ours to publish on the internet for all eternity.
He should get to make that decision.&lt;/p&gt;
&lt;p&gt;But he can’t make that decision yet.
And his extended family, and the people who care about him, are spread all over the world.
Not building those familial ties by refusing to share information about him was depriving him of growing up with family and connections, without input from him.
Which also doesn’t seem ideal.&lt;/p&gt;
&lt;p&gt;My default (“if I don’t tell everyone everything about me all the time I’ll explode”) is fine to apply when it’s &lt;em&gt;my&lt;/em&gt; privacy I’m voiding, but it’s probably not appropriate for someone who can’t make an informed choice about it.&lt;/p&gt;
&lt;p&gt;The hard opposite end of the spectrum (“nothing about him gets put on the internet until he can make an informed decision”) is also making a choice without his input, and signing him up for some consequences.
There are plenty of articles written by people who have tried to do this; it’s only partially successful, and cuts you off from a lot of modern life.&lt;/p&gt;
&lt;p&gt;We resolved this problem through some threat-modeling.
Why did we care about his information not being on the public internet?
What negative things were we trying to control?
The appropriate, proportionate measures to take could be informed by understanding our goals.&lt;/p&gt;
&lt;p&gt;What it came down to is that we didn’t want him to feel like his life was already on the internet.
We didn’t want him to grow up knowing friends could look up embarrassing things he did as an infant or toddler on the internet, or feeling like his life was fodder for clout.&lt;/p&gt;
&lt;p&gt;It would be nice if Meta and Google didn’t know a bunch about him, couldn’t train deep learning models against his likeness, but we concluded that was going to happen whether we wanted it to or not.
And while we could probably bully family and friends into not putting pictures of him on Facebook, it would be hard.
And how long are we going to do that?
If he goes to a family wedding with us, are we going to refuse to have his picture taken?
Or ask the newly-married couple not to share any pictures of their wedding that include him?&lt;/p&gt;
&lt;p&gt;That seems untenable.&lt;/p&gt;
&lt;p&gt;So we’re doing our best to make some default choices as to how much of his privacy has been given up, trying to make sure he’s not &lt;em&gt;more&lt;/em&gt; exposed than his peers, but also trying to make sure he doesn’t grow up isolated and unknown to his family and friends.&lt;sup&gt;&lt;a href=&#34;#fnote12&#34; id=&#34;ref12&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We’ve been parents for six months, and we’re exhausted, but it’s everything we hoped it would be.
It was hard getting here, and absolutely worth it.&lt;/p&gt;
&lt;p&gt;Lucas is amazing, and we can’t wait to find out who he is, as he finds out himself.&lt;/p&gt;
&lt;p&gt;We have a lot of data on development and milestones, but the short version is: he seems healthy, and he seems happy.
And we’re going to do what we can to keep it that way.&lt;/p&gt;
&lt;p&gt;I know you’re all just here for the photos, so I’ll end this super-long post with just a few of our favorites.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;picture&gt;
		
&lt;source srcset=&#34;https://paddy.carvers.com/img/posts/lucas/roxy.avif&#34; type=&#34;image/avif&#34;&gt;


		&lt;img src=&#34;https://paddy.carvers.com/img/posts/lucas/roxy.jpg&#34; alt=&#34;A baby laying on a blanket, with a dog laying up against him.&#34;&gt;
&lt;/picture&gt;
&lt;/div&gt;

&lt;div class=&#34;bigimage&#34;&gt;
&lt;picture&gt;
		
&lt;source srcset=&#34;https://paddy.carvers.com/img/posts/lucas/halloween.avif&#34; type=&#34;image/avif&#34;&gt;


		&lt;img src=&#34;https://paddy.carvers.com/img/posts/lucas/halloween.jpg&#34; alt=&#34;A baby wearing black pajamas, with dogs dressed as ghosts on it, looking at the camera with a goofy grin.&#34;&gt;
&lt;/picture&gt;
&lt;/div&gt;

&lt;div class=&#34;bigimage&#34;&gt;
&lt;picture&gt;
		
&lt;source srcset=&#34;https://paddy.carvers.com/img/posts/lucas/controller.avif&#34; type=&#34;image/avif&#34;&gt;


		&lt;img src=&#34;https://paddy.carvers.com/img/posts/lucas/controller.jpg&#34; alt=&#34;A baby looking at the camera, laying on its back. It has a teether toy shaped like a controller that it&amp;#39;s holding in its mouth.&#34;&gt;
&lt;/picture&gt;
&lt;/div&gt;

&lt;div class=&#34;bigimage&#34;&gt;
&lt;picture&gt;
		
&lt;source srcset=&#34;https://paddy.carvers.com/img/posts/lucas/goofy.avif&#34; type=&#34;image/avif&#34;&gt;


		&lt;img src=&#34;https://paddy.carvers.com/img/posts/lucas/goofy.jpg&#34; alt=&#34;A baby laying on a quilt, looking at the camera with a goofy grin.&#34;&gt;
&lt;/picture&gt;
&lt;/div&gt;

&lt;hr&gt;
&lt;h3 id=&#34;footnotes&#34;&gt;Footnotes&lt;/h3&gt;
&lt;ul class=&#34;footnotes&#34;&gt;
	
&lt;li id=&#34;fnote1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt; This is a bit of an underwhelming way to express &amp;ldquo;we booked the next available flight that we thought we could make after a 3&amp;half; hour drive to SeaTac, reserved a car and hotel room, frantically packed everything we&amp;rsquo;d need to stay an indeterminate amount of time in Texas with a newborn in like an hour, told my job I wouldn&amp;rsquo;t be in on Monday and I&amp;rsquo;d follow up when I knew more, asked our friends to take care of our house and dog for us, drove to SeaTac, begged and pleaded with a baggage claim agent to take our bags even though we were like 3 minutes past the cut-off after waiting in line, sprinted through a concourse, and slid through the doors as they were closing, narrowly avoiding missing the last flight from SeaTac that night and needing to wait like 6-8 hours while a baby was actively being born&amp;rdquo;, but that&amp;rsquo;s a very long sentence to embed in the middle of this story.&amp;nbsp;&lt;a href=&#34;#ref1&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt; We&amp;rsquo;ll come back to gender later, I promise.&amp;nbsp;&lt;a href=&#34;#ref2&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt; Sleep tracker: awake for roughly 18 hours at this point.&amp;nbsp;&lt;a href=&#34;#ref3&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote4&#34;&gt;&lt;sup&gt;4&lt;/sup&gt; Technically, &amp;ldquo;laying in the back of a rented minivan, debating whether I could nap for ten minutes while I waited for guidance.&amp;rdquo;&amp;nbsp;&lt;a href=&#34;#ref4&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote5&#34;&gt;&lt;sup&gt;5&lt;/sup&gt; Because the person giving birth wanted a closed adoption, we were not given her last name. She did not want to name the baby, so his name was &amp;ldquo;Baby Boy&amp;rdquo;. So the hospital referred to him as &amp;ldquo;Baby Boy (the first letter of her last name)&amp;rdquo; on everything. Because y&amp;rsquo;all have no need to know her last initial, I have substituted X.&amp;nbsp;&lt;a href=&#34;#ref5&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote6&#34;&gt;&lt;sup&gt;6&lt;/sup&gt; Sleep tracker: awake for roughly 20 hours at this point.&amp;nbsp;&lt;a href=&#34;#ref6&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote7&#34;&gt;&lt;sup&gt;7&lt;/sup&gt; It is a hard thing to give birth, and a hard thing to choose adoption for the child you just gave birth to. We don&amp;rsquo;t know any of this person&amp;rsquo;s circumstances, because she did not want us to know. But we respect her decisions. We require those who wish to be social with us to respect her and her decisions. And Lucas, if you&amp;rsquo;re reading this years from now, remember what your dad and I told you about this.&amp;nbsp;&lt;a href=&#34;#ref7&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote8&#34;&gt;&lt;sup&gt;8&lt;/sup&gt; Sleep tracker: awake for roughly 24 hours at this point.&amp;nbsp;&lt;a href=&#34;#ref8&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote9&#34;&gt;&lt;sup&gt;9&lt;/sup&gt; Custody is wild in adoption. I learned there are a bunch of different phrases with a bunch of different legal meanings. A helpful framework I found is to look at it in terms of rights and responsibilities. What we did is technically take &amp;ldquo;placement&amp;rdquo; of him, which gives us the right and responsibility to care for him, make medical decisions, and do the day-to-day parenting stuff. It also meant taking legal and financial liability for him, I believe. It did not, however, confer on us any permanent rights. The birth parents still had their rights and could assert them at any point. The agency, I believe, had taken &amp;ldquo;custody&amp;rdquo;, which gave them the right to some information and to do legal maneuvering? Something like that. We answered to the agency, the agency answered to mom. We were, essentially, very empowered babysitters.&amp;nbsp;&lt;a href=&#34;#ref9&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote10&#34;&gt;&lt;sup&gt;10&lt;/sup&gt; Told you we&amp;rsquo;d get to gender.&amp;nbsp;&lt;a href=&#34;#ref10&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote11&#34;&gt;&lt;sup&gt;11&lt;/sup&gt; My understanding is he is only now starting to understand that he is a separate entity from me or Ethan. Which is a really neat way to look at the world!&amp;nbsp;&lt;a href=&#34;#ref11&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;

&lt;li id=&#34;fnote12&#34;&gt;&lt;sup&gt;12&lt;/sup&gt; If you&amp;rsquo;re a friend&amp;mdash;we&amp;rsquo;ve met, or you think I would know your name&amp;mdash;or family member and don&amp;rsquo;t know how to get pictures of and updates about Lucas, please reach out, and we&amp;rsquo;ll get you set up.&amp;nbsp;&lt;a href=&#34;#ref12&#34; class=&#34;backref&#34;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;

</description>
      <carvers:summary>The story of how we became parents, to celebrate the legal finalization of our adoption today.</carvers:summary>
    </item>
    
    <item>
      <title>2022</title>
      <link>https://paddy.carvers.com/posts/2022/</link>
      <pubDate>Sat, 31 Dec 2022 19:56:51 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2022/</guid>
      <description>&lt;p&gt;I can&amp;rsquo;t quite believe it, but the year&amp;rsquo;s over. Again. I can&amp;rsquo;t quite figure out where it went. We&amp;rsquo;ve grown fond of saying &amp;ldquo;time is fake and homophobic&amp;rdquo; around our house.&lt;/p&gt;
&lt;p&gt;This means it&amp;rsquo;s time to update my blog again, because I can&amp;rsquo;t be relied upon to write about things as they&amp;rsquo;re happening, clearly. Let&amp;rsquo;s take things one at a time.&lt;/p&gt;
&lt;h2 id=&#34;launchdarkly&#34;&gt;LaunchDarkly&lt;/h2&gt;
&lt;p&gt;As I &lt;a href=&#34;https://paddy.carvers.com/posts/hey-launchdarkly&#34;&gt;wrote about&lt;/a&gt;, I started a new job working on the Internal Tools team at LaunchDarkly in January.
As I predicted, there was a bit of culture shock and adjustment to be done, and I&amp;rsquo;m learning a lot.
I&amp;rsquo;m spending a lot of time working on automation, but I&amp;rsquo;m also spending an appreciable amount of time working on process and structure.
The team is relatively new, and was small before I joined, and has grown considerably since then.
We found we needed to iterate on how we work, and it has been interesting trying to help with that iteration, sharing things I&amp;rsquo;ve learned in my career, while remaining open to there being other ways to do things than how I&amp;rsquo;ve seen them work before.&lt;/p&gt;
&lt;p&gt;In the last couple of months, we&amp;rsquo;ve hired my friend &lt;a href=&#34;https://www.margaretstaples.com&#34;&gt;Margaret&lt;/a&gt; to be the team&amp;rsquo;s manager, which I&amp;rsquo;m &lt;em&gt;very&lt;/em&gt; excited about.&lt;/p&gt;
&lt;h2 id=&#34;pride&#34;&gt;Pride&lt;/h2&gt;
&lt;p&gt;At the start of 2022, I got involved with the group of people organizing our local Pride celebration, to put on the first in-person Pride since 2019.
Shortly after I joined up, my husband Ethan joined as well.
We were operating under a fiscal sponsor 501(c)(3) organization, but were largely just a random assortment of people without much structure.
We managed to pull together a week of events, and I&amp;rsquo;m really proud of what we achieved. I thought with more structure and planning, we could pull off something even better in 2023.
People seemed amenable to this, so I started working on it.&lt;/p&gt;
&lt;p&gt;Long story short (&lt;em&gt;very&lt;/em&gt; long. State/federal/local corporation/non-profit stuff is &lt;em&gt;wild&lt;/em&gt;.) with the help of a bunch of the other organizers and the pro-bono support of a local law firm, I managed to get us set up as a standalone 501(c)(3) organization.&lt;/p&gt;
&lt;p&gt;Sadly, for a variety of reasons, Ethan and I had to resign our board positions.
We&amp;rsquo;re still rooting for the organization, though, and are excited to see what they achieve in 2023.&lt;/p&gt;
&lt;h2 id=&#34;reading&#34;&gt;Reading&lt;/h2&gt;
&lt;p&gt;According to my notes, I&amp;rsquo;ve read 40 books in 2022, all of them fiction.
This is slightly below my goal of 52 books, but I&amp;rsquo;m giving myself grace about that.&lt;/p&gt;
&lt;p&gt;I mostly chose 52 as a nice, easy-to-track pace (1 book a week) that felt like it approximated my goal: investing in myself.
I realized I hadn&amp;rsquo;t been saving a whole lot of &lt;a href=&#34;https://en.wikipedia.org/wiki/Spoon_theory&#34;&gt;spoons&lt;/a&gt; for my own enjoyment in recent years.
Side projects languished and there was always an awkward pause when people asked about my hobbies.
It turns out, I was largely giving all my spoons to work, so after work I just&amp;hellip; watched TV or a movie, or just endlessly scrolled.
I could and did invest in things I enjoyed, but largely as a focused burst.
I&amp;rsquo;d bake pies for special holidays or occasions, or read and bake on a vacation.
But I couldn&amp;rsquo;t keep it up as a practice of making space in my life for hobbies.&lt;/p&gt;
&lt;p&gt;So I decided I was going to try and read 52 books in 2022, with an explicit rule that they &lt;em&gt;couldn&amp;rsquo;t&lt;/em&gt; serve double duty.
No reading about work topics, no self-improvement.
Just reading like I did as a kid, when I could devour a book in a sitting, for the joy of getting caught up in a story.&lt;/p&gt;
&lt;p&gt;Counting books turns out to be a fuzzy metric.
I read a lot of fanfiction I&amp;rsquo;m not counting, not because it&amp;rsquo;s not &amp;ldquo;real&amp;rdquo; or is somehow lesser than a book, but because most of it wasn&amp;rsquo;t book-length.
(Some of it, surprisingly, was!)
A couple of books I &lt;em&gt;am&lt;/em&gt; counting, however, were basically novella length, which feels a bit like cheating.
On the other hand, some of the books I&amp;rsquo;m counting as one are actually anthologies of stories.&lt;/p&gt;
&lt;p&gt;Look, it&amp;rsquo;s fuzzy math, and I&amp;rsquo;m trying not to get caught up in the math here.
The key part, for me, was &amp;ldquo;does it feel like I&amp;rsquo;m regularly holding space and spoons for my hobbies?&amp;rdquo;
And I think the answer was &amp;ldquo;mostly yes&amp;rdquo;.
Some months I didn&amp;rsquo;t read much as capitalism-work or life-work ate through my spoons.
Some months I read a lot more as capitalism-work and life-work didn&amp;rsquo;t require as many spoons from me.&lt;/p&gt;
&lt;p&gt;But in general, I felt like I could say reading was a hobby without feeling like I was lying.
Good enough.&lt;/p&gt;
&lt;p&gt;What did I read?
Mostly queer stories of every stripe: science fiction, fantasy, mystery, romance.
Young adult and adult.
I don&amp;rsquo;t think I read a single book all year that didn&amp;rsquo;t feature a character that was explicitly queer in the text.
Shoutout to the fine folks at &lt;a href=&#34;https://www.readsrainbow.com&#34;&gt;readsrainbow.com&lt;/a&gt; who have filled my backlog for years to come.&lt;/p&gt;
&lt;p&gt;If I had to pick specific books I read this year to recommend others read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.speculativelyqueer.com/products/xenocultivars-stories-of-queer-growth-paperback&#34;&gt;Xenocultivars&lt;/a&gt; was the perfect plantpunk queer anthology that I needed to start the year with.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.caseymcquiston.com/red-white-royal-blue&#34;&gt;Red, White, &amp;amp; Royal Blue&lt;/a&gt; is a well-done love story about the son of the President and the Prince of England.
It&amp;rsquo;s being adapted into a TV show, I believe.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://us.macmillan.com/books/9781250789068&#34;&gt;Light From Uncommon Stars&lt;/a&gt; was&amp;hellip; impossible to describe, but an amazing book.
Music and aliens and deals with the devil and queerness and a love story somehow?&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.erikjbrown.com/allthatsleftintheworld&#34;&gt;All That&amp;rsquo;s Left In The World&lt;/a&gt; was a great love story about the apocalypse and community.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.otherscribbles.com/a-psalm-for-the-wild-built/&#34;&gt;A Psalm For The Wild-Built&lt;/a&gt; (and its sequel, &lt;a href=&#34;https://www.otherscribbles.com/a-prayer-for-the-crown-shy/&#34;&gt;A Prayer For The Crown-Shy&lt;/a&gt;) are short but easy contenders for my books of the year.
Honestly, if you haven&amp;rsquo;t read them, stop reading this blog and go read them.
Solarpunk queer cozy stories about trying to find meaning in life?
What more can you ask for?
I want fanart of these stories on my walls &lt;em&gt;so badly&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://philstamper.com/gravity-2/&#34;&gt;The Gravity Of Us&lt;/a&gt; was a neat love story with the space program as a background.&lt;/li&gt;
&lt;li&gt;I was late to reading &lt;a href=&#34;https://www.adamsilvera.com/they-both-die-at-the-end&#34;&gt;They Both Die At The End&lt;/a&gt;, but even with that title, I wasn&amp;rsquo;t expecting to be punched in the face as frequently as I was.
It turns out if you&amp;rsquo;re already Feeling Things about whether you&amp;rsquo;ll get to raise kids, hearing two teenagers fantasize about the lives they may have led if they weren&amp;rsquo;t dying that day is gonna make you Feel Some Things.
But honestly, a really well-written love story with a neat premise.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://us.macmillan.com/series/thelockedtombseries&#34;&gt;The Locked Tomb series&lt;/a&gt; I&amp;hellip; have a lot of feelings about it.
Look, Lesbian Space Witches is already in &amp;ldquo;shut up and take my money&amp;rdquo; territory on its own.
But I didn&amp;rsquo;t love the books as much as I was expecting to.
They&amp;rsquo;re still a rec, still some of the better books I read this year, I keep talking about them with people.
But they fell short of my (possibly unrealistic) expectations because they all follow the same pattern: lead you through 80% of the book from the perspective of someone who doesn&amp;rsquo;t understand what&amp;rsquo;s going on, and then explain everything you just read in the last few chapters as one torrent of information.
And I don&amp;rsquo;t even think that&amp;rsquo;s a bad or invalid way to tell a story!
I just really struggle with not knowing what&amp;rsquo;s going on for so long.
You should read these, but you should read them knowing that unreliable narrators are going to be a big part of it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kellylink.net/books/monstrous-affections&#34;&gt;Monstrous Affections&lt;/a&gt; is an anthology of short stories about monsters and affection.
I mostly picked it up for Wings in the Morning, the short story that spawned &lt;a href=&#34;https://www.sarahreesbrennan.com/book/in-other-lands/&#34;&gt;my favorite book&lt;/a&gt;, but I frequently find myself thinking about a lot of the other stories in it.
A solid collection, honestly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I learned that my ability to sustain my reading pace is pretty predictable based on the pacing of the plot and how clear it is.
A plot that is unclear (told through unreliable narrators, for example) is hard for me to sustain my pace through, and it takes me a while to get through the book.
A plot that is clear but slow (doing lots of world-building) also is going to take me a while to get through.
A fragmented plot (anthologies!) are also going to take me a while to get through.
I think it&amp;rsquo;s something about my brain being able to disengage (because it doesn&amp;rsquo;t understand what&amp;rsquo;s happening, or there isn&amp;rsquo;t enough happening to hold my attention without expending effort, or there are reset points where my momentum is lost) that means I need to continuously be investing spoons to stay focused.
I don&amp;rsquo;t think that&amp;rsquo;s a bad thing, nor do I think it means those books aren&amp;rsquo;t for me or aren&amp;rsquo;t enjoyable.
It&amp;rsquo;s just an interesting (to me) observation.&lt;/p&gt;
&lt;h2 id=&#34;the-death-of-twitter&#34;&gt;The Death of Twitter&lt;/h2&gt;
&lt;p&gt;Sometimes I can still hear its voice.&lt;/p&gt;
&lt;p&gt;Look, a billionaire bought a thing because he thought it would make him cool and instead he killed the thing.
This isn&amp;rsquo;t a surprising or even novel story, and honestly the only reason I bring it up is because I spent like 14 years there, so it&amp;rsquo;s an impactful loss to me.
I&amp;rsquo;ve got my tweets archived and backed up, and some day I&amp;rsquo;ll probably get them up on this site for posterity.
You can relive me fumbling around as an awful 18 year old getting traumatized at college, or the cringey early-twenties period of my life.
It captures my whole career, the entire time I&amp;rsquo;ve known my husband.
It captures the beginning of my friendship with &lt;a href=&#34;https://dstaley.com&#34;&gt;Dylan&lt;/a&gt;, when he replied to a tweet I made.&lt;/p&gt;
&lt;p&gt;Some day I&amp;rsquo;ll get it all online here.
Some day I&amp;rsquo;ll run an analysis of when I tweeted and how much, how much was retweets vs. replies vs. quotetweets vs. tweets.
If I find a chunk of time to read through and categorize 57,000 tweets, I may even do an analysis of what I tweeted about.&lt;/p&gt;
&lt;p&gt;Not today.
Today, I&amp;rsquo;m just sad I lost a thing, and curious about what thing(s) will fill the holes it leaves behind.&lt;/p&gt;
&lt;p&gt;Where will I shitpost and opine at you all now?&lt;/p&gt;
&lt;h2 id=&#34;home-improvement&#34;&gt;Home Improvement&lt;/h2&gt;
&lt;p&gt;We finally spent some time and energy fixing up our house, after buying it in 2019.
It turns out a previous owner installed a fence himself, and did not know how to install fences.
It also turns out he didn&amp;rsquo;t take into account sprinkler positioning when doing so, meaning our lawn was pretty patchy.&lt;/p&gt;
&lt;p&gt;We had the old fence torn down and replaced with a new fence installed by professionals, much to the delight of our neighbors.
We also pulled down a tree (technically, a tree-shaped bush, Ethan insists) in our front yard that the wind was uprooting.
After the fence was in, we had the contractors rerun the sprinklers so the whole yard would actually be hit, then do some reseeding and sodding.
Now we&amp;rsquo;ve got a yard we actually enjoy being in, even if it&amp;rsquo;s still a work in progress.&lt;/p&gt;
&lt;h2 id=&#34;other-stuff&#34;&gt;Other Stuff&lt;/h2&gt;
&lt;p&gt;This is mostly skimming the surface of the year.
There were some major health things for people I love that happened throughout the year.
Some loved ones celebrated major milestones, some loved ones experienced hardship.
Some of this touched my life directly, some of I was just a bystander to.
But this post is way too long already, and most of these things aren&amp;rsquo;t mine to talk about, no matter how much they colored my year.
So&amp;hellip; mind your own business. 😂&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;With 2022 in the rearview mirror (I fall back on my yearly taunt: &amp;ldquo;eat your heart out, 2022, I&amp;rsquo;m still here and you&amp;rsquo;re not&amp;rdquo;), here are some of my hopes and dreams for 2023.&lt;/p&gt;
&lt;h2 id=&#34;baby-news&#34;&gt;Baby News&lt;/h2&gt;
&lt;p&gt;We passed 2 years as an active family with &lt;a href=&#34;https://americanadoptions.com&#34;&gt;American Adoptions&lt;/a&gt; in 2022.
We&amp;rsquo;re hoping 2023 is the year our family gets a little bit bigger.&lt;/p&gt;
&lt;h2 id=&#34;writing-more&#34;&gt;Writing More&lt;/h2&gt;
&lt;p&gt;How great would it be if I went to do a 2023 recap post, and my last post on my blog was from a few weeks ago, not 11 months ago?
What if instead of posting on Twitter or Mastodon or whatever, I wrote things where I own the links and can keep things online as long as I care to?&lt;/p&gt;
&lt;p&gt;In a similar-but-unrelated vein, I haven&amp;rsquo;t actually written any fiction since, I believe, the pandemic began.
I&amp;rsquo;ve got notes for a few different stories bouncing around in my brain, but haven&amp;rsquo;t made any attempt to flesh them out.&lt;/p&gt;
&lt;p&gt;I used to write all the time when I was younger.
It would be nice if I could get back into practice.
I&amp;rsquo;d also like to get better at it, and the only way to get better at it is to practice, lots and lots and lots.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve got a list of blog posts I want to write, and notes on stories I&amp;rsquo;d like to tell.
It would be neat if I could make some progress on that in 2023.&lt;/p&gt;
&lt;h2 id=&#34;shipping-lockbox&#34;&gt;Shipping Lockbox&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve had an authentication system evolving in my brain since 2014, slowly building up understanding and opinions of the design space.
I&amp;rsquo;ve written lots and lots of iterations of the software to various states of completion, and think I&amp;rsquo;ve finally landed on one I&amp;rsquo;m happy with.
I&amp;rsquo;d really like it if I could actually ship a release of it in 2023.&lt;/p&gt;
&lt;p&gt;It would be nice to have something to show for all that thinking and experimenting, but it would also unblock a lot of other projects that I want to do.
Turns out almost everything needs authentication, so every project ends up scheduled into the imaginary &amp;ldquo;when I finish the auth system&amp;rdquo; part of the roadmap.&lt;/p&gt;
&lt;h2 id=&#34;finding-another-way-to-support-our-local-queer-community&#34;&gt;Finding Another Way To Support Our Local Queer Community&lt;/h2&gt;
&lt;p&gt;With our departure from the local Pride non-profit, I&amp;rsquo;m back to feeling like I&amp;rsquo;m not doing enough for our local queer community.
I have some thoughts on what it may look like that I&amp;rsquo;m not ready to share yet, but whatever form it takes, I&amp;rsquo;d like to find another way to support that community.&lt;/p&gt;
&lt;h2 id=&#34;more-home-improvement&#34;&gt;More Home Improvement&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve stared into the abyss and am now the abyss domain expert.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve got a long list of home improvement projects we&amp;rsquo;d like to do.
I think gutters and a paint job are the big ones on this year&amp;rsquo;s todo list, but who knows.&lt;/p&gt;
&lt;p&gt;Houses, man.
They&amp;rsquo;re as bad at being done as software is, I gotta tell you.
They have fewer bugs if you do it right, though.&lt;/p&gt;
&lt;h2 id=&#34;continue-to-grow-into-my-role-at-launchdarkly&#34;&gt;Continue To Grow Into My Role At LaunchDarkly&lt;/h2&gt;
&lt;p&gt;With a year of foundation-building behind us, I&amp;rsquo;m really hopeful about this next year at LaunchDarkly.
I&amp;rsquo;m hoping I can start to feel more like a force-multiplier.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t get me wrong, I feel like I&amp;rsquo;m doing good work, and I even feel like I&amp;rsquo;m helping those around me.
But with more domain knowledge and more confidence, I feel like I can do even more.
Almost like I&amp;rsquo;ve got my own oxygen mask on now; I&amp;rsquo;m excited to see what it looks like when I can help others with theirs.&lt;/p&gt;
&lt;p&gt;Feels like some cool stuff is in our future.&lt;/p&gt;
</description>
      <carvers:summary>Looking back at 2022, looking forward at 2023. And some bonus book recommendations.</carvers:summary>
    </item>
    
    <item>
      <title>Good-bye, carvers.co</title>
      <link>https://paddy.carvers.com/posts/carvers-co/</link>
      <pubDate>Sat, 19 Feb 2022 03:16:40 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/carvers-co/</guid>
      <description>&lt;div class=&#34;disclaimer&#34;&gt;
	This post was written on February 19th, 2022. I then proceeded to fail to publish it. I&amp;rsquo;m very good at blogging. For lack of a better answer, it&amp;rsquo;s dated the date it was originally written, and being published on December 31st, 2022. Which is when I noticed it was never published.
&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s &lt;a href=&#34;https://paddy.carvers.com/posts/paddy-io&#34;&gt;been a while&lt;/a&gt; since I switched up my domain name, so I felt like it was time for a new one. 😄&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a long and uninteresting story about how we came to be in possession of carvers.com. (Ethan has learned lessons about agreeing to things because he thinks they won&amp;rsquo;t happen. Also, did you know that &lt;a href=&#34;https://www.sedo.com&#34;&gt;Sedo&lt;/a&gt; will absolutely happily broker the sale of a domain from someone who doesn&amp;rsquo;t actually own it and only checks when they list the domain, no matter how long ago that was? Let&amp;rsquo;s not talk about how I know this.) But the story largely begins and ends with &amp;ldquo;I was very tired of our emails being &amp;lsquo;at carvers.co, not .com, there is no m, yes I am very sure&amp;rsquo;&amp;rdquo; and so we decided to do something about that. By just making there be an m.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s conveniently timed to be just after a decade after I started this iteration of this blog. (You&amp;rsquo;ll notice there are posts older than that; they&amp;rsquo;re ported from a previous iteration, and not all the content made the jump. Only the least cringe-worthy bits, which is hard to believe with how cringe-worthy those early posts are. Ah, to be twenty again.)&lt;/p&gt;
&lt;p&gt;There isn&amp;rsquo;t as much written here as I&amp;rsquo;d like, for a decade. I would&amp;rsquo;ve hoped to have written at least a hundred posts on my own blog in that time, but it seems I&amp;rsquo;m way more likely to shitpost on Twitter. I should do something about that one of these days.&lt;/p&gt;
&lt;p&gt;Anyways, we&amp;rsquo;re now on the fourth domain in the last 12 years or so, which feels pretty stable but also somehow pretty turbulent. I started on paddyforan.com, which was then abandoned in favor of paddy.io when I started my career and .io domains were all the rage. That paddy.io domain &lt;a href=&#34;https://paddy.carvers.com/posts/paddy-io&#34;&gt;got retired&lt;/a&gt; when I realized, a bit belatedly, that there were politics involved that I was uncomfortable with, and we moved from there to carvers.co. And now we&amp;rsquo;ve come to carvers.com, which I think I&amp;rsquo;ll be hunkering down on for a while, because Ethan will likely murder me if I don&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Hey, at least all the links to all those domains have kept working. That&amp;rsquo;s pretty good, right?&lt;/p&gt;
&lt;p&gt;Anyways, new domain, fresh coat of paint. I&amp;rsquo;ve replaced the Don Quixote motif and random picture of windmills that have been my homepage for seven years (!!), substituting in a picture of me and my husband in front of a local mural by our friend Amy Lynn Taylor. I liked the colors. 🤷&lt;/p&gt;
&lt;p&gt;There are probably things that are broken, because I&amp;rsquo;ve been half-assing that design since, uh, winter of 2018. 😭 And belatedly decided to apply only part of it (the homepage) as part of making this switch.&lt;/p&gt;
&lt;p&gt;Eh, whatever.&lt;/p&gt;
</description>
      <carvers:summary>Another year, another new domain.</carvers:summary>
    </item>
    
    <item>
      <title>Now Playing Music in Git</title>
      <link>https://paddy.carvers.com/posts/git-now-playing/</link>
      <pubDate>Sun, 13 Feb 2022 15:25:02 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/git-now-playing/</guid>
      <description>&lt;p&gt;About 20 years ago (😭), before we had smartphones, when using a computer meant
&lt;em&gt;sitting at a desk the entire time&lt;/em&gt;, we had these things called &amp;ldquo;away
messages&amp;rdquo;. You see, because sometimes you would be away from computers and
unreachable. It was a wild time.&lt;/p&gt;
&lt;p&gt;AOL was a company that distributed free discs to your mail and as a side hustle
they provided internet services by making two computers scream at each other
over the phone line. I swear to you I&amp;rsquo;m not making any of this up, kids. AOL
Instant Messenger, or AIM, was a free chat program they provided, and it was
the most popular place to chat for a time (among certain social circles, during
a specific time, look there are all sorts of disclaimers here, just let me have
my nostalgia). AIM had away messages for when your computer was still screaming
at another computer over the phone line, but you weren&amp;rsquo;t actively sitting at
it. You were what was known as &amp;ldquo;afk&amp;rdquo; or &amp;ldquo;away from keyboard&amp;rdquo;, because at the
time it was conceivable that you wouldn&amp;rsquo;t be within arm&amp;rsquo;s reach of a keyboard
sometimes. Again, this is wild to remember, but it was just normal.&lt;/p&gt;
&lt;p&gt;But the thing about AIM messages is they had cultural tropes. Prototypical
memes, basically. When you were dating someone, you declared undying love to
them in your away message, and if it was Serious you included song lyrics
dedicated to them. You could include quotes or jokes or try and be witty. Look,
it was basically early Twitter, okay?&lt;/p&gt;
&lt;p&gt;But the most common trope I saw was including whatever was currently playing on
your computer in your AIM away message. OK, I need to explain this one. We used
to download files onto our hard drives, meticulously and manually organize them
in this program called iTunes, and play them. (Before that there was this thing
called Winamp, which represented an era of software development that was just
so great, but that&amp;rsquo;s neither here nor there.) And if you wanted to listen to
them on another device, you had to copy the files over by hand. If you wanted
to listen to them in your car, you had to &lt;em&gt;burn them onto a CD&lt;/em&gt; and put the CD
in. If your car didn&amp;rsquo;t have a CD drive, you probably just listened to the radio
in the car instead of your music. The &amp;ldquo;radio&amp;rdquo; was basically like the free
version of Spotify, but you didn&amp;rsquo;t get to pick what songs were played unless
you called up an actual person on the phone and asked nicely and they decided
to listen to you. Oh and also everyone in a village/town/city listened to one
of the 12 stations at the time, so they were basically just broad genres, and
you had to listen to whatever song was playing in that genre &lt;em&gt;or nothing&lt;/em&gt;. Oh,
and also there were prototypical podcasts, too, but sometimes it was just a
podcast host talking between songs. It was weird.&lt;/p&gt;
&lt;p&gt;So anyways, yeah, if you were playing music and it was &lt;em&gt;your&lt;/em&gt; music you had
either 1) bought it or 2) stole it (this was more popular, which is part of the
reason copyright is the way it is right now, sorry about that) and you were
playing it on &lt;em&gt;a specific device&lt;/em&gt;, and &lt;em&gt;if&lt;/em&gt; that device happened to be the same
one you were logged into AIM on, you got to display the song you were currently
listening to as part of your AIM away message.&lt;/p&gt;
&lt;p&gt;Recently, I had albums from boy bands from this time period playing on repeat
as I fought with a hard programming problem, and it made me smile thinking
about all of the Very Serious Engineers that would be using this thing I was
making and imagining them all offering thanks to &amp;ldquo;Everybody (Backstreet&amp;rsquo;s
Back)&amp;rdquo; (ask your parents) for the problem being solved, because music is an
important part of how I write software. ADHD is wild, and I need to give my
brain an overly-dramatic or grandiose bone to gnaw on so that I can do things.&lt;/p&gt;
&lt;p&gt;Months later, no longer working on those kinds of problems, I was thinking
about it again and got nerdsniped. I want to partially blame &lt;a href=&#34;https://dashes.com&#34;&gt;Anil
Dash&lt;/a&gt; for &lt;a href=&#34;https://twitter.com/anildash/status/1478195004204105733?s=20&#34;&gt;this
one&lt;/a&gt;, I think,
because I&amp;rsquo;ve had &amp;ldquo;how many things you use are made by people who care about you
instead of by giant corporations&amp;rdquo; on my brain ever since he said something like
that. And I was thinking about making things while being yourself and what a
great way to make &lt;a href=&#34;https://twitter.com/zigged&#34;&gt;friends&lt;/a&gt; that is.&lt;/p&gt;
&lt;p&gt;And so I made a monstrosity.&lt;/p&gt;
&lt;p&gt;I put together &lt;a href=&#34;https://github.com/paddycarver/git-now-playing&#34;&gt;a Go program&lt;/a&gt;
to replicate the experience of having an AIM message with your currently
playing song in it, but for git. It checks in with Spotify and/or Plex every
ten seconds and asks what you&amp;rsquo;re listening to. It then updates the default git
commit template to include that information. A few notes about how it includes
that information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I put each piece of metadata (artist, track, album, any unique IDs I could
get my hands on) in its own line of the commit, for easier parsing. Because I
want it to be human readable, but still machine-parseable. We&amp;rsquo;ll get back to
that.&lt;/li&gt;
&lt;li&gt;I prefixed every line with a 🎵 emoji, for easier machine parsing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why do I want to be able to parse these with a machine? Because it seemed neat
to me to be able to look at all the commits in a release and say &amp;ldquo;this release
was brought to you by these songs&amp;rdquo;. I&amp;rsquo;ve grown enamored with
&lt;a href=&#34;https://twitter.com/meakoopa&#34;&gt;authors&lt;/a&gt; releasing
&lt;a href=&#34;https://open.spotify.com/playlist/4Le5nnbep8wiYbL0mRDyGl?si=3f10dba31c5d4778&#34;&gt;playlists&lt;/a&gt;
for their books, and wondered what a software release&amp;rsquo;s playlist would look
like. And it turns out if we&amp;rsquo;re recording what we&amp;rsquo;re listening to in git
commits when we make them, we can generate one! That seemed like a neat
possibility, so I left the door open for it.&lt;/p&gt;
&lt;p&gt;Now, this whole thing is a bad idea for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your employer probably will not be thrilled about you including which boy
band you were listening to at work in your git commits. Something something
&amp;ldquo;professionalism&amp;rdquo; something something &amp;ldquo;keep git commit messages useful&amp;rdquo;
something something. I will not be using this at work, and only partially
because I&amp;rsquo;ve stopped working on things that people outside the company use
and so the audience is limited.&lt;/li&gt;
&lt;li&gt;Honestly, I probably &lt;a href=&#34;https://github.com/paddycarver/git-now-playing/issues/1&#34;&gt;could&amp;rsquo;ve done this as a git hook instead of a
daemon&lt;/a&gt;, but there&amp;rsquo;s
a trade-off there of &amp;ldquo;not needing to poll APIs&amp;rdquo; vs &amp;ldquo;needing to wait for API
requests to be made before writing a commit&amp;rdquo;. We&amp;rsquo;ll see if/how that evolves.&lt;/li&gt;
&lt;li&gt;It turns out Plex has no useful IDs for music exposed, despite matching your
library with MusicBrainz&amp;rsquo; data to get its metadata. Plex&amp;rsquo;s API (technically,
not a thing) in general makes me sad. Imagine going to all the trouble to own
your media and keeping it on your local network and then not being able to
build any automation around that. What the heck, Plex.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But you know what? I think it&amp;rsquo;s okay to include some of ourselves in the
software we write, and to make some software at least the creation of people,
not corporations. And this felt like a small, silly step towards that. And when
I think about my ideal future of technology, what I envision is a bit small, a
bit silly.&lt;/p&gt;
</description>
      <carvers:summary>git commits are the new AIM away messages.</carvers:summary>
    </item>
    
    <item>
      <title>Hey, LaunchDarkly</title>
      <link>https://paddy.carvers.com/posts/hey-launchdarkly/</link>
      <pubDate>Sun, 02 Jan 2022 20:43:37 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/hey-launchdarkly/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m really excited to officially join LaunchDarkly and work on their Internal
Tools team on Tuesday, January 4th.&lt;/p&gt;
&lt;p&gt;When I was 22 and just starting my career, I remember thinking in my parents&#39;
kitchen about what I want out of a job. I came up with three things, because my
brain starts protesting really loudly when I don&amp;rsquo;t follow the &lt;a href=&#34;https://en.wikipedia.org/wiki/Rule_of_three_(writing)&#34;&gt;rule of
three&lt;/a&gt;.  Those three
things haven&amp;rsquo;t really changed much in the decade since, and served as a weirdly
good compass to navigate my employment opportunities. These aren&amp;rsquo;t things I
think everyone, or even anyone else, should use as their compass; they&amp;rsquo;re just
mine.&lt;/p&gt;
&lt;h2 id=&#34;i-want-to-solve-problems-i-care-about&#34;&gt;I Want to Solve Problems I Care About&lt;/h2&gt;
&lt;p&gt;The first thing I thought of is that I want my job to be solving problems I
care about. I have ADHD, and executive dysfunction is a bear. It&amp;rsquo;s &lt;em&gt;so much
easier&lt;/em&gt; to do my job when I&amp;rsquo;m invested in the outcome. But I can&amp;rsquo;t get behind
tech for tech&amp;rsquo;s sake; the point is and has always been, for me at least, to
help people solve their problems. They may be &lt;em&gt;silly&lt;/em&gt; or &lt;em&gt;frivolous&lt;/em&gt; problems,
but at the end of the day, someone can do something they couldn&amp;rsquo;t do before,
and the ability to do it makes their life &lt;em&gt;better&lt;/em&gt;. And that&amp;rsquo;s what kicks my
executive dysfunction&amp;rsquo;s ass, and helps me engage my brain.&lt;/p&gt;
&lt;p&gt;When I was looking for my next thing, that largely meant that I didn&amp;rsquo;t want to
work on cryptocurrencies or healthcare systems or insurance platforms. Not that
solving those problems isn&amp;rsquo;t useful&amp;ndash;except for cryptocurrency, that is a
solution in search of a problem and we&amp;rsquo;d all be better off if people stopped
building in that area&amp;ndash;but it seems unlikely I&amp;rsquo;d be able to make people
&lt;em&gt;happier&lt;/em&gt; with my work. And that&amp;rsquo;s less fulfilling for me, personally.&lt;/p&gt;
&lt;p&gt;LaunchDarkly offered me a role on their Internal Tools team, and the best job
description I&amp;rsquo;ve heard so far is &amp;ldquo;bring an engineering mindset to everything
our business does&amp;rdquo;. It sounds an awful lot like I&amp;rsquo;m going to be pointed at
problems and asked how we can make them go away, and I&amp;rsquo;m excited about that
prospect. We&amp;rsquo;ll see how it all works out, but LaunchDarkly is a product I
believe in helping people do neat things I care about, and so I&amp;rsquo;m optimistic
I&amp;rsquo;ll find plenty of problems I care about to solve. I&amp;rsquo;m even more optimistic
that solving them will be in my job description when I find them.&lt;/p&gt;
&lt;h2 id=&#34;i-want-to-work-with-people-i-like&#34;&gt;I Want to Work With People I Like&lt;/h2&gt;
&lt;p&gt;We spend almost a third of our time working, and if you don&amp;rsquo;t like the people
you work with, that&amp;rsquo;s a lot of time to spend with people you don&amp;rsquo;t like. Even
people you&amp;rsquo;re neutral on can make that a slog. The people I surround myself
with can have a huge impact on how I feel and think, and so it&amp;rsquo;s worth
surrounding myself with good people.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been fortunate in my career so far and have found just &lt;em&gt;so many&lt;/em&gt; good
people to surround myself with. I&amp;rsquo;ve got a reputation for referring to people
as &amp;ldquo;friend&amp;rdquo; at the drop of a hat, but it&amp;rsquo;s sincere. The real career is the
friends you make along the way.&lt;/p&gt;
&lt;p&gt;I got to talk to so many people at LaunchDarkly when interviewing with them,
and they were all excellent. I have no concerns or qualms on this point, I&amp;rsquo;m
just excited to meet everyone.&lt;/p&gt;
&lt;h2 id=&#34;i-want-to-do-work-i-can-be-proud-of&#34;&gt;I Want to Do Work I Can Be Proud Of&lt;/h2&gt;
&lt;p&gt;The last thing I thought about in my parents&amp;rsquo; kitchen ten years ago was why I
wasn&amp;rsquo;t focusing on the easiest or most lucrative opportunities in front of me.
The answer I came up with is that the third thing I want from my employment is
to be proud of the work I do during it. I want to be able to tell my family, my
friends, my kids what I do not only without shame, but with pride. Someone on
Twitter (I want to say &lt;a href=&#34;https://twitter.com/QuinnyPig&#34;&gt;Corey Quinn&lt;/a&gt;?) said they
want to feel good when they tell their kids where their college funds came
from, and I feel like that&amp;rsquo;s part of it. But also, the externality of my
employment that I&amp;rsquo;m interested in isn&amp;rsquo;t the salary (though money is important!
And it&amp;rsquo;s an important way employers show they value you, which is a healthy
thing to demand of them!) it&amp;rsquo;s the work I produce. There are a lot of ways to
make a lot of money, often rather quickly, if you are good with computers. But
what&amp;rsquo;s the point? At the end of it all, all you&amp;rsquo;ve got to be proud of is your
bank account, and I felt like that was a bottomless pit that would lead ot me
never having made &amp;ldquo;enough&amp;rdquo; and that at the end of it, the bank account wouldn&amp;rsquo;t
actually make me proud.&lt;/p&gt;
&lt;p&gt;This took on an unexpected importance the more I realized my responsibilities
as an engineer. That &lt;a href=&#34;https://neveragain.tech/&#34;&gt;I&amp;rsquo;m responsible for what I
build&lt;/a&gt; and who I build it for, even if I didn&amp;rsquo;t mean
to do harm when I built it. There is no ethical consumption under capitalism,
and there is no ethical labor under capitalism, but there is certainly &lt;em&gt;less&lt;/em&gt;
ethical labor and &lt;em&gt;more&lt;/em&gt; ethical labor. It&amp;rsquo;s important to me to have those
ethical standards for myself, and important to me that I do not allow myself to
cross them for my work.&lt;/p&gt;
&lt;p&gt;I had some really good conversations with LaunchDarkly about this when I was
interviewing, and I&amp;rsquo;m really confident that I&amp;rsquo;m going to be as proud looking
back on my tenure there as I am on my tenure at HashiCorp.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;It&amp;rsquo;s going to be weird starting a new job after five years. Especially since I
know by now that my jobs never turn out to be what I think they&amp;rsquo;ll be at the
beginning, so I&amp;rsquo;m not fully sure what to expect. I think so much of how
HashiCorp works has been ingrained in how I work that it&amp;rsquo;ll be jarring to be in
a new system. But I think that will be healthy, and I&amp;rsquo;ll learn things from
working in new ways.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s &lt;a href=&#34;https://en.wikipedia.org/wiki/File:The_Voyager_Interstellar_Record_-_131_Greetings_From_The_Secretary_General_Of_The_UN_Kurt_Waldh_(1).ogg&#34;&gt;a
quote&lt;/a&gt;
on the &lt;a href=&#34;https://en.wikipedia.org/wiki/Voyager_Golden_Record&#34;&gt;Voyager Golden
Record&lt;/a&gt; that I&amp;rsquo;ve loved
ever since I read it in &lt;a href=&#34;https://en.wikipedia.org/wiki/To_Be_Taught,_if_Fortunate&#34;&gt;one of Becky Chambers&#39;
books&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We step out of our solar system into the universe seeking only peace and
friendship, to teach if we are called upon, to be taught if we are fortunate.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I love this quote because of its framing: that we don&amp;rsquo;t know that we have
anything to teach, but if there&amp;rsquo;s something we know that you want to learn, we
are committed to teaching. That we don&amp;rsquo;t feel entitled to learning from you,
but if we are very lucky, we will be taught.&lt;/p&gt;
&lt;p&gt;Given LaunchDarkly&amp;rsquo;s space aesthetic, this has been on my mind as I navigate
this transition out of the professional world I know and into one I have
guesses about but have yet to explore. One in which I will teach, if called
upon, and in which I will be taught, if I&amp;rsquo;m fortunate.&lt;/p&gt;
</description>
      <carvers:summary>I&amp;rsquo;m joining LaunchDarkly to work on their Internal Tools team.</carvers:summary>
    </item>
    
    <item>
      <title>Book Ratings Considered Harmful</title>
      <link>https://paddy.carvers.com/posts/book-ratings-considered-harmful/</link>
      <pubDate>Fri, 31 Dec 2021 04:03:03 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/book-ratings-considered-harmful/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been thinking a lot about how we talk about books. Partially because I&amp;rsquo;ve been reading a lot of books, partially because I&amp;rsquo;ve started listening to a lot of authors (especially marginalized authors) talk on Twitter, and partially because I&amp;rsquo;m reading so many truly excellent books and I need everyone to read them so I can discuss them with you. I have So Many Thoughts.&lt;/p&gt;
&lt;p&gt;And, as is my nature, I have So Many Thoughts about how we engage with rating, reviewing, and recommending books. And I&amp;rsquo;m noticing some things I think we could, honestly, do a bit better.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m toying with the idea of writing up some thoughts on a bunch of books I read in the last few years, so I wanted to talk a bit about how I think about reviewing, recommending, and rating books, because I think that&amp;rsquo;s a useful foundation for understanding me talking about books. Or maybe it doesn&amp;rsquo;t matter and I&amp;rsquo;m overthinking it. I&amp;rsquo;m known to do that. I may also be imagining people to care more than they actually do about nuances I care about. I&amp;rsquo;m known to do that, too.&lt;/p&gt;
&lt;p&gt;And I guess the proper place to start is to describe what I think I&amp;rsquo;m seeing, or at least how I&amp;rsquo;m interpreting what I&amp;rsquo;m seeing.&lt;/p&gt;
&lt;h2 id=&#34;whats-the-point-of-reviewingrating-books&#34;&gt;What&amp;rsquo;s the Point of Reviewing/Rating Books?&lt;/h2&gt;
&lt;p&gt;Why do we have sites like GoodReads or TheStoryGraph? What&amp;rsquo;s their &lt;em&gt;point&lt;/em&gt;? Why use them?&lt;/p&gt;
&lt;p&gt;I think the point is to help people find books they&amp;rsquo;ll enjoy reading. I keep thinking about it like product reviews: hear from an unbiased (or at least, with different biases than the author/publisher) party about something before you invest time or money in it.&lt;/p&gt;
&lt;p&gt;I think they exist to help us identify, surface, and share &amp;ldquo;good books&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;We do this by assigning star ratings to them; a one star book is to be avoided, a five star book is a strong endorsement. We recommend books by saying &amp;ldquo;if you like X, you&amp;rsquo;ll probably like Y&amp;rdquo;&amp;ndash;sometimes human-curated, sometimes algorithmically determined based on what people who bought that also bought. We review things to tell people if they&amp;rsquo;re a good book, and what we enjoyed about them, or if they&amp;rsquo;re a bad book, and what was wrong with them.&lt;/p&gt;
&lt;p&gt;Everything distills down to that binary distinction: good book, read it; or bad book, avoid it.&lt;/p&gt;
&lt;h2 id=&#34;whats-the-problem&#34;&gt;What&amp;rsquo;s the Problem?&lt;/h2&gt;
&lt;p&gt;Surfacing &amp;ldquo;good books&amp;rdquo; is great and all, but it begs the question: what&amp;rsquo;s a good book? Well, a book you&amp;rsquo;ll enjoy. And that&amp;rsquo;s a tricky thing to navigate, because it turns out people are different and like different things. A million years ago, in high school, I was taught that the story you read can be as much about what you bring to it as it can be about what the author wrote. And I think that&amp;rsquo;s a neat way to think about reading; it&amp;rsquo;s personal, it&amp;rsquo;s individual. Two people aren&amp;rsquo;t going to get the same thing out of the same story. Reading a story, by necessity, changes it. Talking about it changes it further. I like that idea, the living story.&lt;/p&gt;
&lt;p&gt;But that idea is incompatible with how we&amp;rsquo;re talking about books. We try to distill the entirety of a book into a number of stars, or trying to say what people will like based on liking things we consider similar, but those discard so much important context that the results are pretty hit-or-miss. You never quite know what someone else brought to the story that made them rate it that way, or what made them decide it was similar to another book.&lt;/p&gt;
&lt;p&gt;Consider, for example, that I like Cory Doctorow&amp;rsquo;s &lt;em&gt;Little Brother&lt;/em&gt;; you may be tempted to recommend Orwell&amp;rsquo;s &lt;em&gt;1984&lt;/em&gt;. &lt;em&gt;Little Brother&lt;/em&gt; is heavily inspired by &lt;em&gt;1984&lt;/em&gt;, after all! There are even &lt;em&gt;1984&lt;/em&gt; references in it. I&amp;rsquo;ll love it. But that recommendation fails to consider what I actually enjoyed most about &lt;em&gt;Little Brother&lt;/em&gt;: it wasn&amp;rsquo;t about the anti-authoritarian message, or the dystopia, or anything like that; it was the rhythm of surfacing problems and then finding solutions to them. That&amp;rsquo;s what drives the plot forward: problem, finding solution, repeat. So a more appropriate recommendation would be Andy Weir&amp;rsquo;s &lt;em&gt;The Martian&lt;/em&gt;, even though that has so much less to do with &lt;em&gt;Little Brother&lt;/em&gt;&amp;rsquo;s main themes than &lt;em&gt;1984&lt;/em&gt; does. It turns out I wasn&amp;rsquo;t in it for the main themes.&lt;/p&gt;
&lt;p&gt;Similarly, consider that I &lt;em&gt;love&lt;/em&gt; queer books. I read so many queer books. But I love reading about &lt;em&gt;certain parts&lt;/em&gt; of the queer experience much more than other parts, and depending on what the author likes or wants to write about, that may or may not be in their book &lt;em&gt;at all&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Does that make those books bad? Well, by some definition, yeah. I didn&amp;rsquo;t enjoy them at all. If one star is &amp;ldquo;I didn&amp;rsquo;t get any enjoyment from this at all&amp;rdquo; and five is &amp;ldquo;I read this over and over again because it makes me happy&amp;rdquo;, they would get a single star.&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s not &lt;em&gt;useful&lt;/em&gt;, because someone else may love those books. We&amp;rsquo;re allowed to like different things. It&amp;rsquo;s not a bad book, it&amp;rsquo;s a bad book &lt;em&gt;for me&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This mostly would be fine, if suboptimal, except it turns out ratings and reviews are how a lot of people buy books. And so a lot of one star ratings on, say, GoodReads can impact your sales.&lt;/p&gt;
&lt;p&gt;So if a lot of homophobes read your book and are surprised it has Gay Stuff in it, you&amp;rsquo;re going to be in for a bad time. Or if racists are surprised that Black people exist in your fictional world.&lt;/p&gt;
&lt;p&gt;Things can also get &lt;em&gt;mean&lt;/em&gt;. I&amp;rsquo;ve heard some authors just won&amp;rsquo;t read GoodReads reviews anymore because who wants to hear people talk shit about something they worked hard on? It is astounding the lengths people will go to to tell authors that they hated their book. And I never really understood that impulse. What good does that do?&lt;/p&gt;
&lt;p&gt;And then I started generalizing that a bit further. What good does it do to tell people that you hated a book? That you got no enjoyment out of it? I can see the benefit in letting people self-select out, so people who are unlikely to enjoy something know that up front, but that&amp;rsquo;s not &amp;ldquo;this book is bad&amp;rdquo;, that&amp;rsquo;s &amp;ldquo;this book contains X&amp;rdquo;. People can decide whether containing &amp;ldquo;X&amp;rdquo; makes a book enjoyable or not.&lt;/p&gt;
&lt;p&gt;So, to recap: ratings and recommendations don&amp;rsquo;t surface enough information to be the best solution to the problem they&amp;rsquo;re trying to solve, and authors can pay the price for that, especially marginalised authors.&lt;/p&gt;
&lt;h2 id=&#34;so-how-should-we-talk-about-books&#34;&gt;So How Should We Talk About Books?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m going to propose that there&amp;rsquo;s a better system for talking about books. It has already been trialed, you can find it in most libraries. The fine people at &lt;a href=&#34;https://readsrainbow.com&#34;&gt;readsrainbow.com&lt;/a&gt; have been executing on it splendidly. &lt;a href=&#34;https://letterboxd.com&#34;&gt;Letterboxd&lt;/a&gt; sort of does it for films.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s the good ol&amp;rsquo; fashioned &amp;ldquo;list of books on a theme&amp;rdquo; approach.&lt;/p&gt;
&lt;p&gt;It is a way more productive signal for me that the book is in the &lt;a href=&#34;https://readsrainbow.com/2020/09/22/book-recs-lgbt-ya-books-with-supportive-parents/&#34;&gt;&amp;ldquo;YA Books with Supportive Parents&amp;rdquo; list&lt;/a&gt; than it is that the book is &amp;ldquo;like &lt;em&gt;Simon vs. the Homo-Sapiens Agenda&lt;/em&gt;&amp;rdquo;. It tells me what part of the book you&amp;rsquo;re highlighting, and if that&amp;rsquo;s a thing I care about (or care to avoid), I can select or select out of that experience appropriately. And when I&amp;rsquo;m looking for something specific, say &lt;a href=&#34;https://readsrainbow.com/2021/03/book-recs-lgbt-found-family&#34;&gt;found family stories&lt;/a&gt; you can conveniently index on that. But it also means that if, for example, a book is on a list of a topic I know I won&amp;rsquo;t enjoy&amp;ndash;say, &amp;ldquo;Protagonist Unlearns Toxic Masculinity&amp;rdquo;&amp;ndash;I know I can avoid it and that&amp;rsquo;s an &lt;em&gt;equally useful signal&lt;/em&gt; for people who actually enjoy reading books on that theme.&lt;/p&gt;
&lt;p&gt;What I love &lt;em&gt;most&lt;/em&gt; about this is that it acknowledges the complexity of stories, and builds in the understanding that stories can mean different things to different people. There&amp;rsquo;s no attempt to reduce stories to a single data point, a binary &amp;ldquo;buy&amp;rdquo; or &amp;ldquo;don&amp;rsquo;t buy&amp;rdquo;. But a pleasant side-effect is that it&amp;rsquo;s at least a little less geared towards inherently negative interactions about books. Yes, you can make a &amp;ldquo;Books I Hate&amp;rdquo; or &amp;ldquo;Books Not Worth the Paper They&amp;rsquo;re Printed On&amp;rdquo; list, but you have to actually &lt;em&gt;try&lt;/em&gt; to be negative. Whereas clicking 1 star can feel like you&amp;rsquo;re saying &amp;ldquo;I didn&amp;rsquo;t enjoy this&amp;rdquo; but be interpreted as &amp;ldquo;this book sucks, don&amp;rsquo;t buy it&amp;rdquo;. It&amp;rsquo;s much easier to accidentally be negative without meaning to.&lt;/p&gt;
&lt;p&gt;Obviously, because I&amp;rsquo;m me, I have a domain purchased and some notes and sketches about how to build out software that would aid people in curating these lists. It turns out the trickiest part is having a reliable catalog of books that people can search through to easily add to their lists; capitalism&amp;rsquo;s weird. Whether I&amp;rsquo;ll actually ever build the software remains to be seen, but it at least has made it onto the ever-expanding list of &amp;ldquo;things I would do if I had the time and energy&amp;rdquo;.&lt;/p&gt;
</description>
      <carvers:summary>Or: “why ReadsRainbow is way more useful than GoodReads”.</carvers:summary>
    </item>
    
    <item>
      <title>Today&#39;s My Last Day at HashiCorp</title>
      <link>https://paddy.carvers.com/posts/hashicorp-last-day/</link>
      <pubDate>Thu, 23 Dec 2021 15:00:00 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/hashicorp-last-day/</guid>
      <description>&lt;p&gt;Getting right to the point, today is my last day at HashiCorp. I&amp;rsquo;m leaving my position as &lt;a href=&#34;https://paddy.carvers.com/posts/engineering-leadership&#34;&gt;Engineering Lead&lt;/a&gt; of the Terraform Plugin SDK team for new challenges and adventures. After five years of working on Terraform, it&amp;rsquo;s time for me to turn my attention to new problems. I don&amp;rsquo;t want to talk too much about what&amp;rsquo;s next&amp;ndash;it feels gauche to celebrate the future while we&amp;rsquo;re celebrating the past&amp;ndash;but I do want to spend some time looking back. I&amp;rsquo;ve &lt;a href=&#34;https://paddy.carvers.com/posts/hashiversary&#34;&gt;done that before&lt;/a&gt;, but that was four years ago, and a lot has happened since then, so I wanted to spend some time fondly reminscing and celebrating the achievements, both my own and those I played even a small part in.&lt;/p&gt;
&lt;p&gt;I already posted a recap of my first year: my role in &lt;a href=&#34;https://paddy.carvers.com/talks/hashiconf-2019-lightning-talk&#34;&gt;the creation of our Pride sticker&lt;/a&gt;; my &lt;a href=&#34;https://paddy.carvers.com/talks/hashidays-london-2017&#34;&gt;talk at HashiDays London&lt;/a&gt;; being in &lt;a href=&#34;https://www.youtube.com/watch?v=1f-t0xIJvd4&#34;&gt;a marketing video&lt;/a&gt; with &lt;a href=&#34;https://twitter.com/danawillow&#34;&gt;my friend Dana&lt;/a&gt;; building the &lt;a href=&#34;https://www.hashicorp.com/blog/introducing-the-hashibot-github-bot&#34;&gt;bot&lt;/a&gt; that handled &lt;a href=&#34;https://www.hashicorp.com/blog/upcoming-provider-changes-in-terraform-0-10&#34;&gt;the migration&lt;/a&gt; of Terraform providers from all being in the &lt;code&gt;hashicorp/terraform&lt;/code&gt; repository and into their own repositories.&lt;/p&gt;
&lt;p&gt;The last four years haven&amp;rsquo;t been much different than that first year. I was privileged to be part of a great many initiatives, some of which I led, but none of which I did on my own or even did most of the work on. I said in my first post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the best and worst things about working at HashiCorp is that you’re surrounded by smart, kind people who care about what they do. It’s hard, because it’s intimidating. It feels hard to measure up. But it also means you’re surrounded with supportive people who will help you to feel like you measure up.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;and I stand by this assessment. The achievement I&amp;rsquo;m the most proud of over the last four years is the people I&amp;rsquo;ve had the privilege and honor of working with.&lt;/p&gt;
&lt;h2 id=&#34;terraform-provider-google&#34;&gt;terraform-provider-google&lt;/h2&gt;
&lt;p&gt;With the brilliant engineers of HashiCorp and the Google Cloud Graphite team, I continued to lead HashiCorp&amp;rsquo;s efforts on the Google Cloud Provider team. While the Cloud Graphite team did most of the work, I still got to serve as a partner in rolling out &lt;a href=&#34;https://github.com/GoogleCloudPlatform/magic-modules&#34;&gt;Magic Modules&lt;/a&gt;, making the Google provider the first machine generated official provider for Terraform. I got to &lt;a href=&#34;https://paddy.carvers.com/talks/hashiconf-2018/&#34;&gt;give a talk with Dana about it&lt;/a&gt; at HashiConf 2018. This allowed us to introduce the beta provider, which consumed beta APIs, which was another first&amp;ndash;normally, official providers (with some exceptions) would only introduce stable APIs, so the providers themselves could be stable.&lt;/p&gt;
&lt;p&gt;We made it through Terraform 0.12 together, and managed the difficult engineering task of having multiple long-running branches and working to hit moving targets. We tried to coordinate version 2 of the Google provider with the release of Terraform 0.12, before decoupling the two. We moved to weekly releases, and eventually &lt;a href=&#34;https://github.com/hashicorp/go-changelog&#34;&gt;automated our changelog generation&lt;/a&gt;, creating an approach that has subsequently been adopted by other HashiCorp projects with some success.&lt;/p&gt;
&lt;p&gt;To help power a feature Google was looking for, I was given patient tutelage on how Terraform core works so I could build &lt;a href=&#34;https://www.terraform.io/internals/provider-meta&#34;&gt;provider metadata&lt;/a&gt; into Terraform, my first significant contribution to the core functionality of Terraform. This learning laid the foundation of my &lt;a href=&#34;https://paddy.carvers.com/talks/hashiconf-2019&#34;&gt;2019 HashiConf talk&lt;/a&gt;, which was about the social and technical underpinnings that made Terraform 0.12 such a difficult upgrade.&lt;/p&gt;
&lt;p&gt;We released version 3 of the Terraform provider together, which was the first release of a provider to have a beta release period before its final release.&lt;/p&gt;
&lt;h2 id=&#34;building-a-better-terraform-provider-developer-experience&#34;&gt;Building a Better Terraform Provider Developer Experience&lt;/h2&gt;
&lt;p&gt;In the wake of the version 3 release, &lt;a href=&#34;https://twitter.com/ptyng&#34;&gt;Paul Tyng&lt;/a&gt; approached me about joining the Terraform Plugin SDK team to find a path to a better Terraform provider developer experience. I accepted, and moved over to that team in early 2020, just before the world changed. In my absence, the team at HashiCorp responsible for the Google provider and the team at Google working on it have continued to excel and push the boundaries of provider development, and I&amp;rsquo;m incredibly proud to have worked on that codebase with them. Doing so made me a better engineer.&lt;/p&gt;
&lt;p&gt;I started on the Plugin SDK team just in time to meet up with my teammates at HEX. I spent that time bending their ears about my cockamamie scheme to rebuild the Terraform provider developer experience from the ground up. The problem was, essentially, that SDKv1 (the latest version shipped at the time) was built on the abstractions of Terraform 0.11 and below. It didn&amp;rsquo;t incorporate any of the learnings of Terraform 0.12 or the versions that had come after, and the abstractions interacted in weird ways that were impossible to predict. It was no longer the best solution to the problem we had. But we couldn&amp;rsquo;t just throw it out and start over; there were over 1,000 providers built on it, and more were being built on it every day. Some of those providers had thousands of resources and data sources, hundreds of thousands of lines of code. We needed to find a way to change the abstractions, making it more approachable for new provider developers, without leaving our entire ecosystem behind us.&lt;/p&gt;
&lt;p&gt;We were inspired by webservers. I think it was when I was reading about GitHub&amp;rsquo;s upgrade of their Rails version that it struck me: large projects are built on frameworks every day, and those frameworks manage to evolve and upgrade, because they don&amp;rsquo;t force developers to do all the upgrade work in one massive deploy. Developers can upgrade between the two piecemeal, using something like nginx to split traffic between them. And when we asked &amp;ldquo;why couldn&amp;rsquo;t Terraform do that?&amp;rdquo;, and we decided it can. And that became the cornerstone of our strategy for redefining the provider developer experience.&lt;/p&gt;
&lt;h3 id=&#34;sdkv2&#34;&gt;SDKv2&lt;/h3&gt;
&lt;p&gt;The first step was to ship our ongoing project, &lt;a href=&#34;https://www.terraform.io/plugin/sdkv2/guides/v2-upgrade-guide&#34;&gt;version 2 of the Plugin SDK&lt;/a&gt;. Version 1 of the Plugin SDK was all about splitting the Plugin SDK out of the &lt;code&gt;hashicorp/terraform&lt;/code&gt; repo, putting it into its own repository. But the test framework for providers still had a dependency on Terraform to run tests, and so we had to keep manually porting over changes from the &lt;code&gt;hashicorp/terraform&lt;/code&gt; repository to an internal, vendored copy of the code. It was a pain, and we wanted to stop doing that. We also wanted to let providers run tests against different versions of Terraform, not just whatever not-actually-a-release version of Terraform was vendored inside the test framework. So version 2 became about dropping that reliance on &lt;code&gt;hashicorp/terraform&lt;/code&gt; and rewriting the underpinnings of our test framework to puppet around actual Terraform binaries when running tests. We also took the opportunity to introduce &lt;a href=&#34;https://pkg.go.dev/context#Context&#34;&gt;contexts&lt;/a&gt; into many function signatures.&lt;/p&gt;
&lt;p&gt;This was a technically complicated project; I got to build in some more new functionality into Terraform, got to dig into the inner workings of &lt;a href=&#34;https://github.com/hashicorp/go-plugin&#34;&gt;go-plugin&lt;/a&gt;, and got distressingly familiar with Terraform&amp;rsquo;s test framework.&lt;/p&gt;
&lt;h3 id=&#34;terraform-plugin-go--terraform-plugin-mux&#34;&gt;terraform-plugin-go &amp;amp; terraform-plugin-mux&lt;/h3&gt;
&lt;p&gt;In the wake of shipping v2 of the Plugin SDK, we worked to ship bug fixes restoring prior behaviors when we found unintended deviations from how the test framework worked in version 1. I also turned my attention to what eventually became &lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-go&#34;&gt;terraform-plugin-go&lt;/a&gt;. We needed a protocol-level binding to the Terraform protocol, something with no abstractions of its own that just surfaced the protocol itself. This gave us the bedrock that SDKs could be built on and all agree on the Go types that represent protocol types and endpoints. We &lt;a href=&#34;https://paddy.carvers.com/talks/hashicorp-live-terraform-plugin-go&#34;&gt;released&lt;/a&gt; it during a special HashiCorp Live alongside &lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-mux&#34;&gt;terraform-plugin-mux&lt;/a&gt;, our solution for combining providers built on separate SDKs into a single logical provider. Embarrassingly, I didn&amp;rsquo;t do a good enough job including my team in the design and implementation of these projects until the very end, and that was a mistake I was keen not to repeat. I was happy with the code we had shipped; I was unhappy with how we had gotten there.&lt;/p&gt;
&lt;h3 id=&#34;designing-the-framework&#34;&gt;Designing the Framework&lt;/h3&gt;
&lt;p&gt;terraform-plugin-go was purposefully low-level, a level of abstraction far below and far harder to work with than SDKv2. As 2021 kicked off, our major project was to envision, design, and ship a provider developer experience at the same level of abstraction and ease-of-use as SDKv2, but built on the new Terraform abstractions that terraform-plugin-go was built around and exposing. I struggled for months to figure out how we were going to come up with a design that the entire team felt ownership of; I didn&amp;rsquo;t want people to feel like they had the opportunity to offer feedback, I wanted them to feel like it was their idea. I wanted everyone to feel ownership of the idea.&lt;/p&gt;
&lt;p&gt;I kept thinking about building a five or ten year codebase in terms of what we were shipping and which artifacts should be prioritised higher than others. I made the controversial assertion that the code was the least important thing we were shipping. More important than the code, I argued, was shipping a mental model of provider development that developers could wrap their heads around, something I felt like we had lost by that point for SDKv2. I wanted us to keep thinking about what concepts we were creating, and how we&amp;rsquo;d teach them to provider developers. But even more important than that, I argued, was shipping a team that could steward this project. If you want a ship to sail for ten years, you don&amp;rsquo;t worry about each plank, you build a crew that can care for it. And I felt that was our biggest risk, that we&amp;rsquo;d build something only one person truly understood the context and tradeoffs of, and then the longevity of the project would hinge on their judgment and presence. That&amp;rsquo;s an unkind amount of pressure to put on someone.&lt;/p&gt;
&lt;p&gt;So the first thing we did when building the framework was to figure out how we were going to design together. We were used to coming up with ideas, fleshing them out, pitching them to each other, and incorporating feedback. But doing that means an idea has a clear owner. After discussing with some of my coworkers, most notably &lt;a href=&#34;https://thewebivore.com&#34;&gt;Pam Selle&lt;/a&gt;, we came up with a process: we&amp;rsquo;d create &amp;ldquo;&lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-framework/tree/main/docs/design&#34;&gt;design documents&lt;/a&gt;&amp;rdquo;, documents laying out the problem and recording all the context we could think of. Every bit of nuance that informed a decision should land there, as well as every possible way to solve the problem that we could think of, and no discussion of a decision can happen until we all agree that we have no more context or possible solutions to offer. That helped us design together, weighing the concerns and possible solutions together, making our arguments from a shared context we had all already agreed on. It also helped future maintainers; you can still go back and see why we made the decisions we made, and more importantly, what context we considered as we made those decisions. You can see which context no longer applies, you can see which bets and hopes and predictions didn&amp;rsquo;t pan out, and which did. You can see which fears were founded and unfounded. My hope is that future maintainers will be able to use this context to reevaluate our decisions over time, and even when the circumstances around us change, they&amp;rsquo;ll be able to maintain the software we wrote, because they&amp;rsquo;ll know what we were trying to achieve when we wrote it.&lt;/p&gt;
&lt;h3 id=&#34;shipping-the-framework&#34;&gt;Shipping the Framework&lt;/h3&gt;
&lt;p&gt;We worked really hard throughout 2021 to ship terraform-plugin-framework, and I&amp;rsquo;m really proud of how we shipped it. We quietly shipped a version 0.1.0 that served almost as a proof of concept; we set the criteria for a release as &amp;ldquo;a provider can &lt;em&gt;technically&lt;/em&gt; be built with this&amp;rdquo;. If you could &lt;em&gt;technically&lt;/em&gt; build a provider and have a resource do something, anything, it was ready to ship. Didn&amp;rsquo;t need to be &lt;em&gt;useful&lt;/em&gt;, didn&amp;rsquo;t need to be &lt;em&gt;ready&lt;/em&gt;, we just needed to be able to evaluate our decisions by using them to build something. And we shipped it, and it became real, and it hit me: we were doing this, and it was &lt;em&gt;good&lt;/em&gt;. My years old hypothesis that a much better provider developer experience was possible and &lt;em&gt;we could ship it&lt;/em&gt; was being validated. I still remember where I was sitting, what I was doing when that realization hit.&lt;/p&gt;
&lt;p&gt;We didn&amp;rsquo;t make a big deal about v0.1.0. Didn&amp;rsquo;t really make a huge splash anywhere about it. That was reserved for v0.2.0, which we shipped at the inaugural &lt;a href=&#34;https://events.hashicorp.com/hashitalksbuild&#34;&gt;HashiTalks: Build&lt;/a&gt; in a session &lt;a href=&#34;https://paddy.carvers.com/talks/hashitalks-build-framework&#34;&gt;introducing the framework&lt;/a&gt;. At this point, we wanted to have a compelling project that could build at least some useful providers. We shipped v0.2.0 along with the talk, and shipped a new &lt;a href=&#34;https://terraform.io/docs/plugin/framework&#34;&gt;section of the docs&lt;/a&gt; in partnership with our Education team at the same time. And my favorite detail, the Education team &lt;a href=&#34;https://learn.hashicorp.com/tutorials/terraform/plugin-framework-create?in=terraform/providers&#34;&gt;shipped a new Learn guide&lt;/a&gt; that offered a step-by-step introduction to building a new provider in the framework. Biting off more than I could chew, I also did a talk for HashiTalks: Build about &lt;a href=&#34;https://paddy.carvers.com/talks/hashitalks-build-into-the-unknown&#34;&gt;Terraform&amp;rsquo;s type system&lt;/a&gt; and another on &lt;a href=&#34;https://paddy.carvers.com/talks/hashitalks-build-terraform-friendly-apis&#34;&gt;designing Terraform-friendly APIs&lt;/a&gt;, two talks I&amp;rsquo;m proud of.&lt;/p&gt;
&lt;p&gt;Since then, we&amp;rsquo;ve been iterating on the framework. We added more features, smoothed out rough spots, fixed bugs. And this has grown from a demonstrative prototype of what the Terraform provider developer experience &lt;em&gt;could&lt;/em&gt; be into a codebase that could compete with SDKv2 for building production Terraform providers. And we have &lt;a href=&#34;https://github.com/hashicorp/terraform-provider-awscc&#34;&gt;real-world providers&lt;/a&gt; being built on it, which is extremely exciting and gratifying. I&amp;rsquo;m incredibly proud of what we&amp;rsquo;ve shipped, how we&amp;rsquo;ve shipped it, and the impact it has had.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re not at the end of the roadmap we defined back in 2020 for a new provider developer experience, but we&amp;rsquo;ve shipped some substantial pieces of it. And I&amp;rsquo;m confident that the team will continue to ship improvements and build amazing things, so I&amp;rsquo;m incredibly optimistic about the future of Terraform provider development. I wish I could&amp;rsquo;ve been there to ship more of it, but I&amp;rsquo;m excited about what&amp;rsquo;s next for me, and I&amp;rsquo;m excited to see what the team does with me out of the way.&lt;/p&gt;
&lt;h2 id=&#34;moving-on&#34;&gt;Moving On&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been working on Terraform for HashiCorp for about half my career now. I&amp;rsquo;ve learned so much from the problems, opportunities, and people I encountered here. I&amp;rsquo;m a better engineer and, I think, a better coworker for my time there. It&amp;rsquo;s sad and I have a heavy heart leaving it behind. Thanks for 5 years of growth and opportunity, HashiCorp. And thanks for all the support you&amp;rsquo;ve given me over the years, Terraform ecosystem.&lt;/p&gt;
&lt;p&gt;Happy Terraforming.&lt;/p&gt;
</description>
      <carvers:summary>Commemorating my last day at HashiCorp by looking back on my tenure.</carvers:summary>
    </item>
    
    <item>
      <title>HashiTalks: Build: A Modern Terraform Plugin Framework</title>
      <link>https://paddy.carvers.com/talks/hashitalks-build-framework/</link>
      <pubDate>Thu, 22 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashitalks-build-framework/</guid>
      <description>&lt;p&gt;For the inaugural &lt;a href=&#34;https://events.hashicorp.com/hashitalksbuild&#34;&gt;HashiTalks: Build&lt;/a&gt;, I did a talk with my team introducing our latest project, &lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-framework&#34;&gt;terraform-plugin-framework&lt;/a&gt;, a new, modernized approach to building Terraform providers.&lt;/p&gt;
&lt;p&gt;You can find a recording of the session &lt;a href=&#34;https://www.youtube.com/watch?v=xmHVf3RazzU&#34;&gt;on
YouTube&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A virtual talk announcing and introducing terraform-plugin-framework, a new way to build Terraform providers.</carvers:summary>
    </item>
    
    <item>
      <title>HashiTalks: Build: Into the Unknown</title>
      <link>https://paddy.carvers.com/talks/hashitalks-build-into-the-unknown/</link>
      <pubDate>Thu, 22 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashitalks-build-into-the-unknown/</guid>
      <description>&lt;p&gt;For the inaugural &lt;a href=&#34;https://events.hashicorp.com/hashitalksbuild&#34;&gt;HashiTalks: Build&lt;/a&gt;, I did a talk about Terraform&amp;rsquo;s type system, explaining the different types and special values and some of their requirements and quirks.&lt;/p&gt;
&lt;p&gt;You can find a recording of the session &lt;a href=&#34;https://www.youtube.com/watch?v=KkSq1TwDIvo&#34;&gt;on
YouTube&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A virtual talk on Terraform&amp;rsquo;s type system.</carvers:summary>
    </item>
    
    <item>
      <title>HashiTalks: Build: Terraform-Friendly API Design</title>
      <link>https://paddy.carvers.com/talks/hashitalks-build-terraform-friendly-apis/</link>
      <pubDate>Thu, 22 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashitalks-build-terraform-friendly-apis/</guid>
      <description>&lt;p&gt;For the inaugural &lt;a href=&#34;https://events.hashicorp.com/hashitalksbuild&#34;&gt;HashiTalks: Build&lt;/a&gt;, I did a talk about how to design an API that it will be easy to build a Terraform provider for, going into some of the lessons we&amp;rsquo;ve learned over the years of building Terraform providers.&lt;/p&gt;
&lt;p&gt;You can find a recording of the session &lt;a href=&#34;https://www.youtube.com/watch?v=dBAaj-7UMro&#34;&gt;on
YouTube&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A virtual talk describing how to build your API such that it will be easier to implement a Terraform provider for it.</carvers:summary>
    </item>
    
    <item>
      <title>Building a Baby Button</title>
      <link>https://paddy.carvers.com/posts/babybutton/</link>
      <pubDate>Sun, 17 Jan 2021 12:09:45 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/babybutton/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been &lt;a href=&#34;https://paddy.carvers.com/posts/scared-shipless&#34;&gt;struggling to finish a side project for a
while&lt;/a&gt;, but I&amp;rsquo;ve finally &lt;em&gt;actually finished something&lt;/em&gt;,
so I thought I&amp;rsquo;d write it up.&lt;/p&gt;
&lt;p&gt;Ethan and I are &lt;a href=&#34;https://adoption.carvers.com/progress/1/&#34;&gt;in the process&lt;/a&gt; of
&lt;a href=&#34;https://paddy.carvers.com/posts/family&#34;&gt;adopting a baby&lt;/a&gt;, and we&amp;rsquo;re at the point in the process where
we can get a phone call basically at any time saying our baby is being born and
we need to travel to some hospital anywhere in the United States to pick them
up. Like, &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is stressful, and one of the things that was stressing me out was telling
everyone what was going on in that moment. We needed to tell my boss I was not
going to be in work, we needed to tell our friends that were going to be taking
care of our house and dog that we were leaving, and we needed to tell our
families that things were in motion and we&amp;rsquo;d be in touch soon. That&amp;rsquo;s a lot of
texting and calling when you&amp;rsquo;re trying to arrange travel and lodgings and get
out the door.&lt;/p&gt;
&lt;p&gt;Fortunately, computers.&lt;/p&gt;
&lt;p&gt;We decided we wanted a button we could slam that would just&amp;hellip; tell everyone
&lt;em&gt;for&lt;/em&gt; us. No texting, no calling, just smacking a button in the garage as we
got in the car. This seemed doable! A button that, when pushed, calls a
program, which contacts any of the very-usable APIs for communicating with our
loved ones, and sends a message on our behalf. This seemed like a thing I could
do in, like, a night.&lt;/p&gt;
&lt;p&gt;For once, my instincts about how long a project would take to build were
&lt;em&gt;mostly&lt;/em&gt; right. Getting programmatic access to all these communication methods
took a little longer, just because we&amp;rsquo;re not administrators for all the
communication methods we use, and so couldn&amp;rsquo;t grant ourselves API access. Which
meant waiting for and convincing other people to give us access.&lt;/p&gt;
&lt;p&gt;We used &lt;a href=&#34;https://smile.amazon.com/gp/product/B0814C1Q43/&#34;&gt;a random USB button we found on
Amazon&lt;/a&gt; to be the push button.
It doesn&amp;rsquo;t have mounting hardware, so we just screwed right through the plastic
to affix it to our garage wall. YOLO.&lt;/p&gt;
&lt;p&gt;We used &lt;a href=&#34;https://www.raspberrypi.org/products/raspberry-pi-4-model-b/&#34;&gt;a Raspberry Pi 4 Model
B&lt;/a&gt; with &lt;a href=&#34;https://www.raspberrypi.org/products/poe-hat/&#34;&gt;a PoE
hat&lt;/a&gt; to plug the button into and
run the program. Probably overkill, but whatever. When we bought our house, the
first thing we did upon getting inside was pay people to run CAT-6 ethernet all
over it for us, and fortunately had thought to have them put an ethernet port
in the garage. Right where we wanted the button, coincidentally! The PoE hat
meant we could just plug the Raspberry Pi into the ethernet port and didn&amp;rsquo;t
need to worry about power at all. It is not, strictly speaking, necessary. But
I like the one cable setup. Putting the Raspberry Pi in a &lt;a href=&#34;https://chicagodist.com/products/securepi-case&#34;&gt;SecurePi
case&lt;/a&gt; let us protect it and
mount it securely on the wall next to the button.&lt;/p&gt;
&lt;p&gt;Then I &lt;a href=&#34;https://github.com/carvers/babybutton&#34;&gt;wrote some software&lt;/a&gt;. It&amp;rsquo;s just
a Go binary that, when called, calls the Slack, Discord, Twilio, and Matrix
APIs to send the messages you specified. I used
&lt;a href=&#34;https://github.com/hashicorp/hcl&#34;&gt;HCL&lt;/a&gt; for the configuration file to specify
the messages you want sent, and I stored the credentials for all these services
in a &lt;a href=&#34;https://vaultproject.io&#34;&gt;Vault&lt;/a&gt; cluster we already had running on our
home network.&lt;/p&gt;
&lt;p&gt;The last bit to do was wire the program up to run when the button is pushed.
&lt;a href=&#34;https://github.com/rbarrois/inputexec&#34;&gt;inputexec&lt;/a&gt; is a neat little utility for
that, though it hasn&amp;rsquo;t been updated in a while. It lets you listen for keypress
events from a specific input device, then execute a program when they happen.
Exactly what I wanted! I configured the button (it has a hardware pin-based
configuration inside) to send F12 when it&amp;rsquo;s pushed, and set up inputexec to run
my Go binary when F12 is pushed. The code for inputexec is a little out of
date, so to get it working with the Python version that ships with Raspberry Pi
OS I had to modify it a little bit, but it was only two lines and didn&amp;rsquo;t derail
me too much.&lt;/p&gt;
&lt;p&gt;Put it all together, and it&amp;rsquo;s working exactly how we want. Now we know we&amp;rsquo;re
not going to need to be typing on our phones while running around the house and
packing things up, frantically searching our brains for who we need to contact
and what we need to tell them. We can just smack a button and go.&lt;/p&gt;
</description>
      <carvers:summary>A writeup on a project I actually completed. How to build a button that will send messages when pushed.</carvers:summary>
    </item>
    
    <item>
      <title>HashiCorp Live: terraform-plugin-go</title>
      <link>https://paddy.carvers.com/talks/hashicorp-live-terraform-plugin-go/</link>
      <pubDate>Fri, 20 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashicorp-live-terraform-plugin-go/</guid>
      <description>&lt;p&gt;Following the release of the
&lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-go&#34;&gt;terraform-plugin-go&lt;/a&gt; and
&lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-mux&#34;&gt;terraform-plugin-mux&lt;/a&gt;
modules, &lt;a href=&#34;https://katy.moe&#34;&gt;Katy Moe&lt;/a&gt; and I joined Tracy P. Holmes of the
HashiCorp Developer Advocacy team to do a livestreamed demonstration and
presentation of the modules, their features, and the possibilities they open
up.&lt;/p&gt;
&lt;p&gt;The code presented in the livestream is available &lt;a href=&#34;https://github.com/hashicorp/hashicorp-live-dadcorp&#34;&gt;on
GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find a recording of the session &lt;a href=&#34;https://www.youtube.com/watch?v=5DdGJhVxki0&#34;&gt;on
YouTube&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A livestreamed demo and presentation on new Terraform provider development modules, done in partnership with Katy Moe and Tracy P. Holmes.</carvers:summary>
    </item>
    
    <item>
      <title>The History of Terraform Providers</title>
      <link>https://paddy.carvers.com/talks/hashiconf-digital-2020/</link>
      <pubDate>Wed, 14 Oct 2020 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashiconf-digital-2020/</guid>
      <description>&lt;p&gt;I was fortunate enough to be able to give a lightning talk on the history of
Terraform provider development, a subject I find endlessly fascinating, with my
coworker &lt;a href=&#34;https://katy.moe&#34;&gt;Katy Moe&lt;/a&gt; at HashiConf Digital 2020. It was an
interesting experience doing a lightning talk with someone on a different
continent over a Zoom call, but Katy was an amazing co-presenter and I&amp;rsquo;m really
pleased with how it turned out.&lt;/p&gt;
&lt;p&gt;We discussed the major inflection points in the history of the six year old
framework that powers Terraform provider development, and drew attention to how
new some features were and how many abstractions predated the features they now
surface to the user.&lt;/p&gt;
&lt;p&gt;A recording of the session is embedded below.&lt;/p&gt;
&lt;video controls preload=&#34;metadata&#34;&gt;
	&lt;source src=&#34;https://video-files.carvers.com/paddy/hashiconf-digital-2020.mp4&#34; type=&#34;video/mp4&#34;&gt;
		&lt;p&gt;Cannot play video in your browser. &lt;a href=&#34;https://video-files.carvers.com/paddy/hashiconf-digital-2020.mp4&#34;&gt;Download it&lt;/a&gt; instead.&lt;/p&gt;
&lt;/video&gt;

</description>
      <carvers:summary>A brief history of notable events in Terraform provider development, this talk shows both how many patterns provider developers rely on are newer than they&amp;rsquo;d think, but also that the fundamental abstractions provider developers use have been around a lot longer than they&amp;rsquo;d think.</carvers:summary>
    </item>
    
    <item>
      <title>Engineering Leadership</title>
      <link>https://paddy.carvers.com/posts/engineering-leadership/</link>
      <pubDate>Fri, 14 Aug 2020 09:43:01 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/engineering-leadership/</guid>
      <description>&lt;p&gt;In the Fall of 2019, I was working on the &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/google&#34;&gt;Google Cloud Platform provider for
Terraform&lt;/a&gt; and was
asked to be the Engineering Lead for HashiCorp for the project. I agreed, but
wanted to know what that meant, and nobody had a really good answer for me.
Everyone agreed it largely looked like continuing to do the job I was already
doing, perhaps with some institutional authority behind my actions, and that
the boundaries of that authority are something that the Engineering Manager,
Product Manager, and Engineering Lead should negotiate amongst themselves.&lt;/p&gt;
&lt;p&gt;I ran with that and figured some things out, and six months later left the team
to work on the &lt;a href=&#34;https://github.com/hashicorp/terraform-plugin-sdk&#34;&gt;Terraform Plugin
SDK&lt;/a&gt; instead, leaving my
Engineering Lead role behind. Now that I&amp;rsquo;ve been asked to be the Engineering
Lead for the SDK team, I want to take the opportunity to talk about a couple of
the things the role means to me. It&amp;rsquo;s not an exhaustive or universal list, but
it&amp;rsquo;s a couple of things that feel right to me.&lt;/p&gt;
&lt;h2 id=&#34;making-good-technical-decisions&#34;&gt;Making Good Technical Decisions&lt;/h2&gt;
&lt;p&gt;I think the first priority of an Engineering Lead is to make sure their team is
making good technical decisions. Right? The &amp;ldquo;Lead&amp;rdquo; suggests guidance and
direction, and the &amp;ldquo;Engineering&amp;rdquo; suggests limiting that to technical scopes.
But thinking through this ends in priorities people tend not to expect.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s easy to think that means the Engineering Lead should be making every
decision or have veto power over every decision, but I think that&amp;rsquo;s putting too
much responsibility on a fallible human. Not all my ideas are good ideas, not
all my decisions are right, and I don&amp;rsquo;t want the pressure of the system relying
on me to be right. That&amp;rsquo;s not sustainable, safe, or kind to me.&lt;/p&gt;
&lt;p&gt;So if I&amp;rsquo;m not making the decisions myself, and don&amp;rsquo;t even have veto power over
them, how am I supposed to make sure the team is making good technical
decisions? Well, let&amp;rsquo;s look at how good technical decisions get made.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people who are well-rested. So it&amp;rsquo;s my job
to make sure we have a strong team culture of self-care and work/life balance.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people who trust each other. So it&amp;rsquo;s my
job to cultivate a high-trust environment on our team.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people who feel safe. So it&amp;rsquo;s my job to
cultivate an environment where people can feel safe, and can safely be
fearless. An environment where it&amp;rsquo;s hard to break things on accident. An
environment where, when something inevitably does break, it&amp;rsquo;s not &lt;em&gt;someone&amp;rsquo;s&lt;/em&gt;
fault, it&amp;rsquo;s the &lt;em&gt;team&amp;rsquo;s&lt;/em&gt; fault. This means encouraging team ownership of the
systems that keep us safe, so the root cause of any incident isn&amp;rsquo;t &amp;ldquo;someone did
something wrong&amp;rdquo;, it&amp;rsquo;s &amp;ldquo;we failed to make the system robust against someone
doing this thing&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people who feel empowered to bring their
insights, ideas, and experiences to the table, and who feel secure that their
contributions will be respected, valued, and recognised. So it&amp;rsquo;s my job to make
sure everyone has an opportunity to contribute, and every contribution is
valued, and that people get credit and recognition for their contributions.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people who can bring their whole selves to
work, people who don&amp;rsquo;t need to spend time and bandwidth gauging what&amp;rsquo;s safe to
share. So it&amp;rsquo;s my job to ensure a culture of respect, inclusivity, and kindness
on the team.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people when they&amp;rsquo;re given time and space
for consideration and processing. So it&amp;rsquo;s my job to work with the Engineering
Manager and the Product Manager to make sure that the workload we&amp;rsquo;re doing is
scoped appropriately for the time we have to do it in, and that people feel
comfortable standing up and walking away from the computer to go think for a
bit.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made by people who are aware of the context and
history of the problem they&amp;rsquo;re working on. So it&amp;rsquo;s my job to surface details,
and build a culture of asking &lt;em&gt;why&lt;/em&gt; things are the way they are, encouraging
and giving space for gathering the context necessary to make an informed
decision. It&amp;rsquo;s my job to build a culture of writing our ideas and reasoning
down in discoverable places, so that future-us or those that follow us will be
able to understand our context.&lt;/p&gt;
&lt;p&gt;Good technical decisions are made. A decision, therefore, is better than no
decision. So it&amp;rsquo;s my job to understand when we&amp;rsquo;re getting lost in the weeds, or
bikeshedding, and force a decision in a timely manner.&lt;/p&gt;
&lt;p&gt;Whenever I think about culture, I think about the phrase &amp;ldquo;that&amp;rsquo;s not what we do
here&amp;rdquo;, usually deployed when a cultural norm is violated. It&amp;rsquo;s not a value
judgment on what was done, it&amp;rsquo;s a simple assertion about the identity and
culture of the team and how that manifests. As an Engineering Lead, my job is
to ensure that what we do here and what we don&amp;rsquo;t do here are going to lead to
good technical decisions.&lt;/p&gt;
&lt;p&gt;I am not the only person on the team with these responsibilities, but they are
my responsibilities, too.&lt;/p&gt;
&lt;h2 id=&#34;making-it-not-depend&#34;&gt;Making It Not Depend&lt;/h2&gt;
&lt;p&gt;An answer we like to give at HashiCorp is &amp;ldquo;it depends&amp;rdquo;. And that&amp;rsquo;s true! It
often does. Things are different for an enterprise and a startup, for a bank
and for a blog. And recognising that complexity and spectrum is something that
I think HashiCorp does really well at. And that applies internally, too; there
are differences between managing a Terraform provider and managing Vault, and
those differences should be respected and reflected in our processes.&lt;/p&gt;
&lt;p&gt;Unfortunately, &amp;ldquo;it depends&amp;rdquo; comes with the drawback that it leaves a &lt;em&gt;lot&lt;/em&gt; of
room for uncertainty. Which is the best path? Who has the authority to pick a
path? Something has to be done, but how do we decide what? A clearer policy
sidesteps all these issues, especially for newer team members without the
context other team members have, or who don&amp;rsquo;t feel empowered to make that call
themselves.&lt;/p&gt;
&lt;p&gt;My job is to turn &amp;ldquo;it depends&amp;rdquo; into a policy whenever it comes up for our team.
That doesn&amp;rsquo;t necessarily mean making the policy myself; it could mean that I
talk with the Product Manager and Engineering Manager and the three of us
decide on a policy together. It could mean that the team decides collectively
on a policy. But it is my job to make sure that there is clarity within the
team about what the policy is in our specific context.&lt;/p&gt;
&lt;h2 id=&#34;probably-other-stuff&#34;&gt;Probably Other Stuff&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s my two things I feel pretty secure about after six months or so of being
an Engineering Lead. I&amp;rsquo;m hoping for a longer tenure this time around, and hope
I can figure out more of the responsibilities that come with the role, and the
authority vested in me to fulfill those responsibilities.&lt;/p&gt;
&lt;p&gt;If you have any suggestions, I&amp;rsquo;d love to hear them in
&lt;a href=&#34;mailto:paddy@carvers.com&#34;&gt;email&lt;/a&gt; or on
&lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>To mark becoming the Engineer Lead for the Terraform Plugin SDK, some thoughts on what engineering leadership means to me.</carvers:summary>
    </item>
    
    <item>
      <title>Upgrading Your Provider for Terraform 0.12</title>
      <link>https://paddy.carvers.com/talks/hashiconf-2019/</link>
      <pubDate>Wed, 11 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashiconf-2019/</guid>
      <description>&lt;p&gt;A talk about how to upgrade your provider to support the v0.12 release of
Terraform, which accidentally turned into a history lesson on Terraform and a
deep dive into why the 0.12 upgrade process was difficult.&lt;/p&gt;
&lt;p&gt;You can find the transcript for this talk and the video of it &lt;a href=&#34;https://www.hashicorp.com/resources/upgrading-your-provider-for-terraform-0-12&#34;&gt;on
HashiCorp.com&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A deep dive into why the v0.12 release for Terraform was so difficult, and tips for upgrading your provider to support it.</carvers:summary>
    </item>
    
    <item>
      <title>When You Give an Engineer A Sticker</title>
      <link>https://paddy.carvers.com/talks/hashiconf-2019-lightning-talk/</link>
      <pubDate>Tue, 10 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashiconf-2019-lightning-talk/</guid>
      <description>&lt;p&gt;The HashiCorp community team asked if I&amp;rsquo;d do a lightning talk about the history
of HashiCorp&amp;rsquo;s popular pride stickers, which I&amp;rsquo;d had a hand in creating in
2017. I was delighted to, and got to talk on a stage for several minutes about
representation in the workplace and how we can use symbols to make space for
others.&lt;/p&gt;
&lt;p&gt;I was fortunate enough to be able to reprise this talk at the Seattle HUG a
couple days later.&lt;/p&gt;
&lt;p&gt;You can find the slides for this talk
&lt;a href=&#34;https://talks.paddy.io/Pride.pdf&#34;&gt;online&lt;/a&gt; and my husband recorded a video of
it on his phone, which you can find embedded below.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
</description>
      <carvers:summary>A talk about the origins of HashiCorp&amp;rsquo;s pride stickers, and about the importance of representation in the workplace.</carvers:summary>
    </item>
    
    <item>
      <title>Whose Pride?</title>
      <link>https://paddy.carvers.com/posts/whose-pride/</link>
      <pubDate>Sat, 01 Jun 2019 02:00:08 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/whose-pride/</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally written for the June 2019 edition of &lt;a href=&#34;https://tumbleweird.org&#34;&gt;Tumbleweird&lt;/a&gt;. They were kind enough to print it. If you enjoy it, please consider supporting Tumbleweird so they can publish more writing like it in the future.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This June, on the 28th, marks the 50th anniversary of the Stonewall uprising. It has been 50 years since New York City’s finest raided the Stonewall Inn, arresting the occupants and dragging them out of the club to paddy wagons. It has been 50 years since Stormé DeLarverie, a lesbian at the bar, fought back while being dragged out. It has been 50 years since she looked at the crowd and asked &amp;ldquo;Why don&amp;rsquo;t you guys do something?&amp;rdquo; It has been 50 years since the crowd started to throw change and beer bottles, bricks and garbage cans. 50 years since the first trash can lit on fire was thrown through the windows, hoping to smoke out the police inside, hoping to end the siege to free the patrons still inside.&lt;/p&gt;
&lt;p&gt;Last year, the New York Police Department marked the occasion by decking out a patrol car in rainbow. Brands paint their logos rainbow, brand it a Pride product, and sell it for profit. Queer people have gone from an unspeakable underbelly of our culture to a marketable demographic. Levi’s has a good track record of supporting queer non-profits with the proceeds of their sales. Look into where your dollars are going when buying queer merch. If it’s hard to find, they’re probably not going where they should. Manchester Pride is scheduled to have Ariana Grande as a headliner, causing ticket prices to skyrocket as straight people treat it as a concert. “Pride is for everyone”, they say.&lt;/p&gt;
&lt;p&gt;And a lot of queer people are angry about this. “Stonewall was a riot”, they’ll tell you, hoping we’ll remember the anger, the wrath that seems to have ebbed. The joke is circulated that we should celebrate Pride in June, and Wrath in July, throwing proverbial bricks at those who wrong us, rebelling against the oppression still rampant. The glib and bitter quip that “straight people ignored our invitation to Pride when it was a riot, but seem to have invited themselves now that it’s a party” is passed around. And that anger is understandable. We have been harmed. We have been mistreated. And those that hurt us suffered no repercussions, never had to answer to justice. They just got to skip straight to showing up at our party, claiming to be part of our accomplishments, trumpeting their inclusivity.&lt;/p&gt;
&lt;p&gt;But there’s something to be said for a month dedicated to normalising queerness, something to be said for creating a non-alcoholic, incredibly public queer space in cities across the country. There’s value in remembering that we, as a community and as individuals, have won a lot of fights, and to be proud of what we have built for ourselves. Brick by brick, when we had to. It’s a nice time of hope, seeing all the queer kids so much younger than you, doing things you didn’t get to do, knowing that they will never have to face the things you had to face.&lt;/p&gt;
&lt;p&gt;I would like to propose that we can have both. That Pride and Wrath are not mutually exclusive sins, and that we can contain multitudes. I would like to propose that a party can be a riot, and a riot can be a party. I’d like to assert that we deserve and have earned both. They say that existence is resistance, and there is a wholesome violence in reveling in and celebrating your continued existence in the face of subtle and explicit efforts to erase it. There is nothing queerer than meeting hostility and oppression with hostility disguised as festivity; just ask the drag queens who formed a kick line in the face of an advancing line of riot police during the Stonewall uprising, forcing them back, one high-kick at a time.&lt;/p&gt;
&lt;p&gt;My Pride wish for this year is that we show up and celebrate our triumphs over those who would harm us. And that we do so with a renewed sense of resentment and wrath for those that have and continue to harm us. That we dance in the streets to celebrate the rights we have reclaimed, and we show up in the polls to fight for the rights that elude us to this day. That we exult in the accomplishments of and freedoms afforded to the most privileged among us, while fiercely supporting and fighting for the least privileged among us, those who fought for our community during every part of our history, and who do not deserve to be abandoned or forgotten now.&lt;/p&gt;
&lt;p&gt;And for our allies, I have a Pride wish for you, too. I maintain that attending Pride is a wonderful ally activity, provided you treat it like a birthday party or wedding: it’s not about you, and you’re there to celebrate who it is about. But before, during, and after Pride this year, take some time. Notice that up to 40% of unaccompanied homeless youth are queer, and ask yourself what you can do about it. Notice that trans people are being banned from military service. Ask yourself what you can do about it. Notice that though we have equal marriage rights, that doesn’t extend to non-discrimination rights in housing, education, loans, adoption, or other things you take for granted. Ask yourself what you can do about it. You are welcome at our party, but only if you plan on being part of our rebellion, too. 50 years later, I’ll ask Stormé DeLarverie’s question anew:&lt;/p&gt;
&lt;p&gt;Why don&amp;rsquo;t you guys do something?&lt;/p&gt;
</description>
      <carvers:summary>A look at what Pride is about, whether it&amp;rsquo;s a riot or a party, and who should be proud, in celebration of the 50th anniversary of the Stonewall Rebellion.</carvers:summary>
    </item>
    
    <item>
      <title>Mayor Pete</title>
      <link>https://paddy.carvers.com/posts/mayor-pete/</link>
      <pubDate>Fri, 29 Mar 2019 04:30:18 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/mayor-pete/</guid>
      <description>&lt;p&gt;I don&amp;rsquo;t know if y&amp;rsquo;all have heard, but Pete Buttigieg (a.k.a. Mayor Pete), the openly gay mayor of South Bend, Indiana, is running to be president of the United States, and vying for the Democratic nomination, along with like a billion other Democrats. Many of whom are boring white dudes with bad takes. (Bernie&amp;rsquo;s running again!)&lt;/p&gt;
&lt;p&gt;A lot of people in the Democrat base are tired of boring white dude Presidents. Which, fair, we&amp;rsquo;ve had 44 of them and one not-boring-white-dude. But there&amp;rsquo;s concern that the Democrats are going to play it conservative (heh) in 2020 because Hillary Clinton lost (&amp;ldquo;lost&amp;rdquo;?) in 2016. And the question I want to talk about today is:&lt;/p&gt;
&lt;p&gt;Should we consider Mayor Pete to be a boring white dude, or does his gayness &amp;ldquo;count&amp;rdquo;?&lt;/p&gt;
&lt;h2 id=&#34;thats-a-bad-question-and-you-should-feel-bad&#34;&gt;That&amp;rsquo;s a Bad Question (and You Should Feel Bad)&lt;/h2&gt;
&lt;p&gt;I know I posed and framed the question, but in fairness, I &lt;em&gt;am&lt;/em&gt; just echoing the framing of the debate I&amp;rsquo;m seeing. But the crux of my answer is: it&amp;rsquo;s complicated, and that question is meaningless. Does it count? Count for what? Diversity? Diversity of what?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s try some others instead, to shed some light on what people may be getting at.&lt;/p&gt;
&lt;h2 id=&#34;do-gay-people-still-count-as-an-oppressed-class&#34;&gt;Do gay people still count as an oppressed class?&lt;/h2&gt;
&lt;p&gt;Please put down the phone or computer, take a moment to collect yourself, and then go fuck yourself.&lt;/p&gt;
&lt;p&gt;Queer people &lt;em&gt;today&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;can legally be denied services, because no public accommodations protection laws exists&lt;/li&gt;
&lt;li&gt;can legally be discriminated against in housing&lt;/li&gt;
&lt;li&gt;can legally be discriminated against in the workplace&lt;/li&gt;
&lt;li&gt;cannot donate blood or organs&lt;/li&gt;
&lt;li&gt;can legally be discriminated against when adopting&lt;/li&gt;
&lt;li&gt;can legally be tortured with &amp;ldquo;conversion therapy&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just the tip of the iceberg. We currently have the Equality Act proposed, which would extend a lot of civil rights laws to include queer people. &lt;em&gt;Which means they do not today.&lt;/em&gt; And that&amp;rsquo;s just &lt;em&gt;gay&lt;/em&gt; people. That doesn&amp;rsquo;t include trans people and other queer communities that face even more problems and oppression.&lt;/p&gt;
&lt;p&gt;Queer people are still being murdered for being queer, queer people are still 40% of the homeless population, and most queer rights that exist come from Supreme Court rulings or Executive Orders, neither of which are looking as iron-clad as they once did, as far as solutions go.&lt;/p&gt;
&lt;p&gt;So yeah, queer people are still an oppressed class.&lt;/p&gt;
&lt;h2 id=&#34;if-hes-the-nominee-are-the-dems-just-playing-it-safe&#34;&gt;If he&amp;rsquo;s the nominee, are the Dems just playing it safe?&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s complicated.&lt;/p&gt;
&lt;p&gt;On the one hand, absolutely not. There has never been an openly queer president. There have been three confirmed queer Senators &lt;em&gt;in the history of the country&lt;/em&gt;, and one of them was elected just this year. One of them was not out during their Senate career. There have been 22 confirmed queer Representatives in the House in the history of the country. Four of them were just elected this year. Two of them retired to become two of the Senators we just talked about. That&amp;rsquo;s 23 queer individuals in the history of our country (that we know about), and as far as I can tell, about a third of them did not get elected or reelected after coming out. So clearly, the representation of queer people in our legislative and executive branches is not what it should be, and voters have shown no indication that choosing a queer person as your nominee is an easy or safe choice.&lt;/p&gt;
&lt;p&gt;On the other hand, intersectionality is a thing. You can have a queer person who is also not a white man. That&amp;rsquo;s a thing. Queer people of color exist, queer women exist. You can also have trans people, who have &lt;em&gt;never&lt;/em&gt; been out in Congress or the Presidency, as your candidate. And while I haven&amp;rsquo;t had the bandwidth or the emotional energy to dig into Buttigieg&amp;rsquo;s policies in depth, he does &lt;a href=&#34;https://www.washingtonpost.com/opinions/pete-buttigieg-has-broken-through-the-noise-on-community-and-religion/2019/03/24/8fc72084-4ce0-11e9-93d0-64dbcf38ba41_story.html?utm_term=.8d8af96233af&#34;&gt;talk openly about his faith and advocate for politicians being able to discuss their faith&lt;/a&gt;, which makes him more palatable to many religious voters than an atheist or agnostic queer person may be. It feels like, again, without looking at policies, just presented identity (and only summarily at that), that the electability of Buttigieg hinges on queerness being the only revolutionary aspect of the identity being presented. And even then, his presented relationship with his queerness is assimilationist, viewing it as an uninmportant distinction. Which is a valid, but not radical, take on queerness. (There&amp;rsquo;s an entire post to be written about the complexity of assimilationism vs. queer exceptionalism. Another day.)&lt;/p&gt;
&lt;h2 id=&#34;is-it-better-to-have-a-gay-president-or-a-female-president&#34;&gt;Is it better to have a gay president or a female president?&lt;/h2&gt;
&lt;p&gt;Both? Both? Both is good.&lt;/p&gt;
&lt;p&gt;But seriously, this is an asinine question. We can have both&amp;ndash;lesbians, bisexual women, and trans women exist, as do other female-identifying queer people. And while the injustice of having no representation has gone on for too long, we cannot solve that by refusing to elect someone who doesn&amp;rsquo;t represent all groups who are suffering oppression, and I think it&amp;rsquo;s wrong to try and reason about which group is &lt;em&gt;more&lt;/em&gt; deserving, because we all deserve representation. I think, for me at least, agreeing on &amp;ldquo;maybe we&amp;rsquo;ve had enough straight white dudes for a hot minute&amp;rdquo; is a good place to start, and candidates with policies you can get behind that represent a margnialised community should be supported.&lt;/p&gt;
&lt;h2 id=&#34;who-should-i-supportvote-forvolunteer-fordonate-to&#34;&gt;Who should I support/vote for/volunteer for/donate to?&lt;/h2&gt;
&lt;p&gt;Whoever inspires you. Whoever you believe in. Whoever has policies you support. Multiple candidates, if you like multiple people. If we don&amp;rsquo;t get a woman president in 2020, let&amp;rsquo;s aim for 2024. If we don&amp;rsquo;t get a queer president in 2020, let&amp;rsquo;s aim for 2024. Sure, both groups have been waiting for too long, and justice delayed is justice denied. But as there are queer women, you can&amp;rsquo;t support women and not support a queer candidate, and you can&amp;rsquo;t support queer people and not support a woman candidate, because either outcome is an important representation milestone for a subset of those communities and is important to getting their voices heard.&lt;/p&gt;
&lt;p&gt;Could we do better? Always. Are both these options better than another straight white man? You bet.&lt;/p&gt;
&lt;h2 id=&#34;but-how-do-you-feel-about-mayor-pete&#34;&gt;But how do you feel about Mayor Pete?&lt;/h2&gt;
&lt;p&gt;Personally? Not a fan. In the interviews I&amp;rsquo;ve seen, he&amp;rsquo;s too conservative for my tastes, too unwilling to critique the current system or disrupt it too much. I don&amp;rsquo;t think electing him would be a tectonic shift, I think it&amp;rsquo;d be a quiet victory of not-much note outside its historical significance.&lt;/p&gt;
&lt;p&gt;But I don&amp;rsquo;t think that&amp;rsquo;s because his gayness doesn&amp;rsquo;t count as diversity. I think that framing is wrong; with better policies, his queerness would totally set him apart. I think that&amp;rsquo;s my point, here: unimaginative policies don&amp;rsquo;t make you any less queer, and queerness is inherently something that is fundamentally new to the White House. I&amp;rsquo;m not arguing we should elect Mayor Pete. I&amp;rsquo;m just arguing that his handicap is that his policies are boring, not that he&amp;rsquo;s part of the same straight white dude brigade everyone is fed up with.&lt;/p&gt;
</description>
      <carvers:summary>Does Pete Buttigieg&amp;rsquo;s gayness count as diversity?</carvers:summary>
    </item>
    
    <item>
      <title>Adoption Update</title>
      <link>https://paddy.carvers.com/posts/adoption-update/</link>
      <pubDate>Mon, 21 Jan 2019 02:50:02 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/adoption-update/</guid>
      <description>&lt;p&gt;I wanted to do this on the anniversary of my &lt;a href=&#34;https://paddy.carvers.com/posts/family&#34;&gt;first post&lt;/a&gt; but then car accidents and house-buying stuff happened, and well here we are.&lt;/p&gt;
&lt;p&gt;A little over a year ago, I mentioned Ethan and I were investigating what the road to having kids would look like for us. We did a &lt;em&gt;lot&lt;/em&gt; of reading, a lot of research, and had a bunch of very uncomfortable discussions about it. And we settled on a plan, which is what we’re going to be running with until something happens that changes things or we have the kids we want, whichever comes first.&lt;/p&gt;
&lt;p&gt;For background, our goals in this process are pretty straightforward. We know we want to have two kids, and we know we want to have the full parenting experience, from child birth (or as close as we can get to it) to adulthood.&lt;/p&gt;
&lt;p&gt;That leaves us with several options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Surrogacy: having one of us (or someone else) donate sperm, have someone else donate an egg, and either the egg donor or a third person carries the baby.&lt;/li&gt;
&lt;li&gt;Fostering and adoption: registering as foster parents, doing our best to raise children that are currently in the system until they’re placed with a permanent family, and eventually adopting someone from the system ourselves.&lt;/li&gt;
&lt;li&gt;International infant adoption: adopting a newborn baby from a country outside the United States.&lt;/li&gt;
&lt;li&gt;Domestic infant adoption: adopting a newborn baby from within the United States.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s talk about these, and why we decided against some.&lt;/p&gt;
&lt;h2 id=&#34;surrogacy&#34;&gt;Surrogacy&lt;/h2&gt;
&lt;p&gt;Surrogacy is something people usually think of when they think of queer couples having kids, and I get the appeal. You get to pass on at least one parent’s genes, you control the timing as much as you would in a couple naturally capable of having a child, and you generally have a bit more control of the situation than you normally would. And a few people who we love and who love us have told us if we were considering surrogacy, they’d help us. Which is incredibly kind of them.&lt;/p&gt;
&lt;p&gt;And on the surface, surrogacy doesn’t seem so bad. We get the full parenting experience, just like we wanted. We can do things on our schedule, which appeals to the control freak in me. We’re not super particular about being genetically related to our children; after all, only one of us could be, and it’s nice to have the child be equally both of ours.&lt;/p&gt;
&lt;p&gt;But surrogacy has basically no protections that go along with it. If the birth mother decides to keep the baby, there’s nothing really protecting the parents or guaranteeing the return of the medical or living expenses they’ve paid for. Washington state law is such that a birth mother can’t give up her parental rights until after the baby is born, and no amount of contract legalese can change that. Of course, we trust our friends and loved ones to not do that to us, but that brings up a second concern. Our kids are going to have two dads and no mom. Whenever anyone–a teacher, a stranger in a store, a police officer, a friend–uses the phrase “your mom” (as in, “where is your mommy?”, “have your mom or dad sign this”, “ask your mom”), we need our kids to instinctively and intuitively know that the person is &lt;em&gt;actually&lt;/em&gt; talking about their dads. If they see their mom every week at our game nights, or during holidays, or any other time we see our friends and loved ones, there’s a much greater chance for some confusion there.&lt;/p&gt;
&lt;p&gt;And while I &lt;em&gt;know&lt;/em&gt; our friends and family would be respectful and understanding, I wouldn’t be able to help feeling like I need to make sure my parenting lives up to their standards, like I need to do right by “their” kid. And while I have every intention of doing my best with my children, and raising them to the best of my ability, I married Ethan because I wanted to raise kids with &lt;em&gt;him&lt;/em&gt;, not him and somebody else. I need to have the safety of only caring what he thinks about my parenting, and letting everyone else’s opinions bounce off me. And surrogacy with a friend or loved one complicates that.&lt;/p&gt;
&lt;h2 id=&#34;fostering-and-adoption&#34;&gt;Fostering and Adoption&lt;/h2&gt;
&lt;p&gt;There are a lot of kids out there that need a loving family and a stable living situation, and I get that. It seems like it should be an easy choice to give two of them a home instead of having a new baby. But that would almost certainly lock us out of the first year or two of child-raising–because infants are much harder to adopt through the system–which is something we really want to do. I also don’t think I’m emotionally capable of having a temporary child; if I form an attachment, it’ll break me to let them go to their permanent family, even when that’s best for the child, but if I don’t form an attachment, they get a cold parent who’s afraid to invest in them. Which isn’t a great parent.&lt;/p&gt;
&lt;p&gt;It also plays back into raising a kid with Ethan, not Ethan and someone else. I don’t know that I’m up for the challenge of unteaching the norms and values someone else instilled in a child, and I’m not sure I have the right to. I don’t know that I’m capable of navigating picking up parenting where someone else left off.&lt;/p&gt;
&lt;h2 id=&#34;international-infant-adoption&#34;&gt;International Infant Adoption&lt;/h2&gt;
&lt;p&gt;One of the quicker ways to get a child is to adopt from somewhere else in the world, usually an Eastern European, Asian, or African country. And that would give us what we want, which is the full parenting experience. But there are complications. First, there are plenty of horror stories about the context of some of these adoptions: mothers told they’d get their kids back in a few years, only to find out that they won’t later; babies being kidnapped and adopted out; etc. There are a lot of ethical landmines in this field I’m just not willing to step on. I want kids. I want kids &lt;em&gt;really&lt;/em&gt; badly. But, maybe because of that, I’m incredibly unwilling to take someone else’s away from them unless they are knowingly, consciously, giving that child up for adoption. And I just don’t feel I can verify that to my satisfaction when dealing with international infant adoptions.&lt;/p&gt;
&lt;p&gt;Also, a lot of the countries I indicated above are countries in which Ethan and I aren’t married, or in which Ethan and I are illegal. So navigating where we have rights is tricky. But also, raising our children without erasing their culture, while also unwelcome in their culture, is a minefield I’m not sure I want to step into.&lt;/p&gt;
&lt;h2 id=&#34;domestic-infant-adoption&#34;&gt;Domestic Infant Adoption&lt;/h2&gt;
&lt;p&gt;This is what Ethan and I finally chose, a few weeks into reading and gathering info. The rest of this post is going to talk more about this process, the questions it raises, and our plans.&lt;/p&gt;
&lt;p&gt;Basically, domestic infant adoption looks like one of three things: you know someone who is pregnant and does not want to raise their baby, and will allow you to adopt it; you put out a bunch of ads and find someone who is pregnant and does not want to raise their baby, and will allow you to adopt it, usually in exchange for medical expenses and/or living expenses; or you find an adoption agency that puts you in a pool of people looking to adopt, and who people who are pregnant but do not want to raise their baby will then contact. The agency will then show the pregnant person profiles of the families looking to adopt, and the pregnant person will choose a family to adopt their baby.&lt;/p&gt;
&lt;p&gt;We chose to go through an agency, because we don’t know anyone looking to place a baby for adoption, and the advertise-yourself method generally leads to a lot of scams, and it’s entirely your responsibility to weed out the opportunities from the scams. It also carries no guarantee; again, a birth mother can decide to keep the baby at any point up until the adoption is finalised, and there’s pretty much nothing the adoptive parents can do to recoup the expenses they’ve paid out.&lt;/p&gt;
&lt;p&gt;With the agency, they’ll take care of weeding out the scams, and a lot of them will offer a money-back guarantee if the birth mother decides to keep the baby. They also assume the advertising portion, which keeps you from fruitlessly spending an unspecified amount of money trying to find people. And because they serve as a gathering place for families looking for adoption, a lot of birth mothers end up going to them when they decide to place their baby for adoption.&lt;/p&gt;
&lt;p&gt;With that decided, time to find an agency. From our research, we’re currently looking at &lt;a href=&#34;https://www.americanadoptions.com&#34;&gt;American Adoptions&lt;/a&gt;. We haven’t committed yet, but it’s currently what we’re thinking of. They seem to have good reviews, we wouldn’t be the only same-sex couple to go through their program and their program is designed to accommodate couples like us, and their process seems to make sense.&lt;/p&gt;
&lt;p&gt;So we reached out to them, and got some more information. My top priority was figuring out how much I should anticipate this costing. Mainly because we can only save money at a certain rate, and so the budget I should anticipate having would determine when we could do this.&lt;/p&gt;
&lt;p&gt;We had a couple emails and a phone call with a counselor there, and got a lot more information than we had hoped for, which is great. The first thing we learned is that &lt;em&gt;adoption is racist as hell&lt;/em&gt;. Like, adopting-an-African-American-baby-costs-less-and-has-less-wait-time-than-adopting-any-other-race-of-baby racist as hell. In 2018, the average adoption budget for the “traditional” program (non-African-American babies) averaged around $44,000-$48,000, and the average wait time was around 3-12 months. For the “agency-assisted” program (African-American babies) the budget averaged $38,000-$41,000, and the average wait time was 1-9 months. You could also start the agency-assisted program at age 22 with any number of kids, while you had to wait until 25 and have 2 or fewer kids for the traditional program. I have a lot of complicated feelings about those programs, and am unsure whether I consider the agency racist or just doing its best to respond to a society that’s racist, or if both of those things are true at once. I am definitely &lt;em&gt;very&lt;/em&gt; uncomfortable about it.&lt;/p&gt;
&lt;p&gt;But let’s talk about what’s included in those costs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Living expenses for the birth mother&lt;/li&gt;
&lt;li&gt;Medical expenses for the pregnancy&lt;/li&gt;
&lt;li&gt;Legal fees surrounding the adoption&lt;/li&gt;
&lt;li&gt;Termination of parental rights expenses&lt;/li&gt;
&lt;li&gt;Advertising fees&lt;/li&gt;
&lt;li&gt;An “activation fee” for the agency&lt;/li&gt;
&lt;li&gt;A video profile (to show to birth mothers) production fee&lt;/li&gt;
&lt;li&gt;An application fee for the agency&lt;/li&gt;
&lt;li&gt;Foster care and agency travel expenses, if necessary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notably not included in those costs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The cost of having a home study done, which you must do to be eligible to adopt&lt;/li&gt;
&lt;li&gt;A $300 review fee for the agency to review the home study&lt;/li&gt;
&lt;li&gt;Any travel expenses the adoptive parents incur&lt;/li&gt;
&lt;li&gt;Costs for post-placement reports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, a lot of those expenses aren’t fixed costs, and vary depending on the situation. So rather than saying “it costs $X to adopt”, the agency asks you to set a budget for how much you can pay to adopt, and then only shows your profile to mothers in situations that they think your budget can cover. So the higher your budget, the more exposure you get, and the less time you’re like to have to spend waiting. We’re looking at setting our budget to about $50,000 per kid, which should make most opportunities available to us.&lt;/p&gt;
&lt;p&gt;Of course, with varying costs, our budget may not get used up entirely. In which case, the money is refunded to us.&lt;/p&gt;
&lt;p&gt;Once we’re ready, we submit the application fee ($295) and an application to be accepted as prospective adoptive parents. We then do an adoption planning questionnaire and complete a home study ($800 for the study, $300 for the agency to review it), and start preparing our online and print profiles, as well as our profile video ($1,300). We then pay an activation fee ($2,000) and an Online Marketing Services Fee ($10,750) to get our profile listed. Then we settle in to wait.&lt;/p&gt;
&lt;p&gt;While we wait, the agency is showing our profile to any birth mothers that match our criteria–both our budget, and our preferences expressed in the questionnaire, which we’ll get to. When a birth mother chooses us, we have three days to wire the remainder of our budget to the agency ($35,655 if we have a $50,000 budget). At that point, we can start doing trips out to meet the mother, be there for any tests, ultrasounds, and check ups, and finally be at the hospital for the birth.&lt;/p&gt;
&lt;p&gt;Once the baby is born, the birth mother needs to give up her rights, and we need to legally adopt the baby. Because this is likely to be happening in another state, we need to have judges from both states sign off on it, and a thing called the Interstate Compact on the Placement of Children applies at that point. Which is just a fancy way of saying a lot of lawyers, time, and court dates, and that the kid isn’t legally ours until a judge from each state says so. Which, depending on states, could be a quick thing, or could take a week or more. So we’re likely to spend our first days as parents in a hotel room, waiting to get permission to take the baby out of the state. Also, because we’re likely to have to catch a flight to get to the hospital, and there’s a chance the baby could come before the due date, we’re already making plans with friends and my work that once our profile is listed, we may be leaving the house for an indeterminate time at a moment’s notice. We’ve discussed having go-bags we can grab, and a physical button we can slam that will send a Slack message to my manager notifying that I’m leaving and will check in when I can and sending messages to our friends saying we’re on our way to the airport and can you all figure out who’s going to watch the dog amongst yourselves.&lt;/p&gt;
&lt;p&gt;But the situation also raises a problem of planning. I think I mentioned that I couldn’t deal with having a kid I had formed an attachment to taken from me. In a similar vein, I think having a nursery all furnished and coming home with no kid because the mother changed her mind would kill me. Ethan would find mean hunched against a crib, sobbing, in the middle of the night. So we also plan on just ordering the bare essentials to the house while we do that wait in the hotel room after the baby is born, when it’s finally ours. Our friends can bring the packages in, but we’d still want to build the crib, and do everything ourselves. Again, we want the full baby experience, and it would mean a lot to me to put that stuff together.&lt;/p&gt;
&lt;p&gt;It also proves a problem for family. My parents are wonderful, and would want to throw a baby shower for us. But what do you do if you have a baby shower, and then the birth mother decides to keep the baby? Do you return the gifts? Do you just wait for the next opportunity? I think both would crush me. So we’re going to have to do that &lt;em&gt;after&lt;/em&gt; we come home with the kid.&lt;/p&gt;
&lt;p&gt;We figured this out through a lot of soul searching and talking and reading, and being brutally honest with ourselves about how we’d feel about various scenarios. But this wasn’t even the hardest conversation. That questionnaire I mentioned? That was brutal. It included a bunch of really uncomfortable questions, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What ethnicity and mix of ethnicities are you willing to accept in a baby? (After a bunch of really uncomfortable conversations, we chose ethnicities we felt our area had sufficient representations of such that we wouldn’t be the kid’s only exposure to that culture. No matter how hard we try, it would feel too much like they were only getting the white dude take on their culture, and we want them to have the opportunity to engage with their cultural identity in a non-appropriative, fulfilling way.)&lt;/li&gt;
&lt;li&gt;Are you willing to have contact with the birth mother? (The agency only does “open” adoptions, where both parties know who the other is, and there’s &lt;em&gt;some&lt;/em&gt; level of communication. Studies have shown this to be better for kids, so we’re fine with it. Our line in the sand is that we need to obviously be the kid’s parents, and there can be no confusion about that–see the section on surrogacy.)&lt;/li&gt;
&lt;li&gt;What kind of medical history will you accept in birth mothers? (We checked off anything that science hadn’t linked to the health of the child, any mental health issues we felt confident we were equipped to handle, and in general any health concern that we felt we’d be able to adapt to.)&lt;/li&gt;
&lt;li&gt;What drug use are you comfortable with from the birth mothers? (We largely checked off anything that scientific studies hadn’t linked to health concerns for the child. This was one we were more restrictive about.)&lt;/li&gt;
&lt;li&gt;Will you accept a child that is the product of rape? (We said yes, because apart from not knowing the father’s medical history, it shouldn’t affect the health and well-being of the child.)&lt;/li&gt;
&lt;li&gt;Will you accept twins or triplets? (We said twins, which we’d actually &lt;em&gt;love&lt;/em&gt;. But we can’t be outnumbered.)&lt;/li&gt;
&lt;li&gt;Will you accept sibling groups? (I believe we said no, because that implies that one child is not an infant. And if we’re going to have one child from birth, and one child from age two or three, eventually the older child will think we don’t love them as much because we don’t have photos/videos/keepsakes of their birth, first laugh, first word, first step, etc.)&lt;/li&gt;
&lt;li&gt;Will you accept a special needs baby? (I don’t remember what we said to this.)&lt;/li&gt;
&lt;li&gt;What’s the maximum age of a baby, in months, you’ll accept?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A really hard part of the questionnaire was shaking the feeling that I was designing a baby, or that I was saying I wouldn’t or couldn’t love my child if they fell outside our criteria. It took reframing the questions as “what risks would you minimise if you were having a child?” before I could stop feeling bad about it. Because I would minimise the risk that my child would have health issues from birth; nobody can guarantee they won’t, and I’d love them no matter what. But I’d not drink during the pregnancy to minimise that risk, because that feels like doing what’s best for the child to me. And that’s really what Ethan and I kept coming back to: what’s best for the kid? Is it better that they be placed with a family that is going to be better equipped for their specific situation? It’s easy to just say that you’ll accept any kid, but are you going to do as good a job for that child? That’s a hard question.&lt;/p&gt;
&lt;h2 id=&#34;timeline&#34;&gt;Timeline&lt;/h2&gt;
&lt;p&gt;Because of the structure of the fees, we can’t really list ourselves until we have the money to complete the adoption, because we could be contacted that day and need to cough up the rest of the money three days later. So given our $50,000 budget, we’re currently looking at January, 2021 being when we list ourselves, meaning hopefully by January, 2022 we’ll have our first kid. Because of weird money things (my employer will reimburse up to $10,000 of adoption costs, for example!) we hope we can be listed for the second kid in January, 2022, and we’ll hopefully have both kids by January, 2023. Which puts both of us at 32 years old, which is older than we wanted, but what can you do? Money takes time.&lt;/p&gt;
&lt;p&gt;It’s going to be a long process and one we’re incredibly anxious for. But at this point, it just takes time. Knowing our budget, and understanding that we’d need a home study, we wanted to buy a house before we started saving for the first kid. We’re under contract now, and hopefully will be moving in in six weeks. When that’s done, we’ll certainly have some house expenses we need to pay for, and we want to take some time to get our finances back in the shape we want them, but by the end of the year we anticipate making regular, large deposits into our savings account to start that $50,000 fund.&lt;/p&gt;
&lt;p&gt;24 months isn’t that long to wait, right?&lt;/p&gt;
</description>
      <carvers:summary>An update on last year&amp;rsquo;s post about starting a family.</carvers:summary>
    </item>
    
    <item>
      <title>2019</title>
      <link>https://paddy.carvers.com/posts/2019/</link>
      <pubDate>Tue, 01 Jan 2019 05:50:21 -0800</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2019/</guid>
      <description>&lt;p&gt;I didn’t write a post for 2018, and I don’t really intend to. Mostly because I don’t have much to say about it. It was a quiet year; we largely just saved money to buy a house and worked. Even work was a quiet year for me; I focused on &lt;a href=&#34;https://terraform.io/docs/providers/google&#34;&gt;the Google Cloud Platform provider for Terraform&lt;/a&gt;, and helped make a bunch of changes that, while important and valuable, don’t lend themselves well to things I can point at and say “look, I spent my year on that”. I spent my year on making the provider better, and I think the &lt;a href=&#34;https://www.hashicorp.com/resources/google-provider-new-terraform&#34;&gt;talk&lt;/a&gt; I gave with &lt;a href=&#34;https://twitter.com/danawillow&#34;&gt;Dana&lt;/a&gt; at &lt;a href=&#34;https://www.hashiconf.com&#34;&gt;HashiConf&lt;/a&gt; and the &lt;a href=&#34;https://www.hashicorp.com/resources/hashiconf-2018-closing-keynote-gcp-vault-terraform&#34;&gt;closing keynote&lt;/a&gt; both offer evidence that we &lt;em&gt;did&lt;/em&gt; make the provider better.&lt;/p&gt;
&lt;p&gt;But it was a quiet year, and so rather than looking back, I want to look forward at 2019.&lt;/p&gt;
&lt;p&gt;I don’t want to make resolutions. Mainly because I’ve never been good at resolutions. I don’t know how much I can reasonably achieve in a year. I don’t know what’s going to happen during the year. I also want to make decisions about what to do with my time in the moment, when I have the most information possible about &lt;a href=&#34;https://en.wikipedia.org/wiki/Spoon_theory&#34;&gt;how many spoons I have available&lt;/a&gt;, how my &lt;a href=&#34;https://paddyforan.getsby.co&#34;&gt;sleep schedule&lt;/a&gt; is working out, how our finances are actually working out, and what’s important to me.&lt;/p&gt;
&lt;p&gt;Instead, I want to talk about priorities. These aren’t things I plan to get done in 2019, these are things I’m entering 2019 carrying in the back of my mind, the projects I’m devoting active mental space to instead of putting them on the backburner. I’m also going to limit these to things that aren’t work-related; work is its own beast and its own brainspace, and fluctuates on its own rhythm.&lt;/p&gt;
&lt;h2 id=&#34;buy-a-house&#34;&gt;Buy a House&lt;/h2&gt;
&lt;p&gt;We spent 2018 saving to buy a house. It didn’t work out the way we had hoped–we had been talking to our landlord about buying the house we’ve been renting since before we got married, but as we tried to sit down with him to agree on a final purchase price and draw up the paperwork, he decided he didn’t want to sell after all. Which is a bummer, and put us in an awkward spot with regard to timing, because it meant any house we found at that point would likely have us moving in during the holidays, which we didn’t want.&lt;/p&gt;
&lt;p&gt;So we decided to wait until after the holidays, and buy a house in the first months of 2019. We took some of the cash we had stockpiled and used it for a different financial goal–exercising some of the stock options I had vested–and used the months spent waiting for the holidays to end to replenish our cash on hand. We’re nearly back at the point where we have enough cash on hand to be able to afford a down payment, so I’m excited to find the house, make the transaction, and move on with our lives.&lt;/p&gt;
&lt;p&gt;I’m frustrated that the real estate market in our area is exploding and everyone is losing their damn minds, but what can you do? Roughly half the available housing in our market sells for $400,000+ right now, and the median income for the area is like $60,000. Houses that sold for $120,000 five years ago are selling for $300,000 now. Which doesn’t make sense to me, and smells and feels like a bubble. So I anticipate we’ll buy a house only to have its value crash, but… a house is a place to live, not an investment, and I will die on that hill.&lt;/p&gt;
&lt;p&gt;What can you do? Timing sucks. The options are to suck it up and deal with it, or wait for the timing to be better. I have other things I want to be doing with my life, and I’m tired of ten years of renting, so we’re gonna suck it up and deal with it.&lt;/p&gt;
&lt;h2 id=&#34;start-pulling-together-money-for-kids&#34;&gt;Start Pulling Together Money for Kids&lt;/h2&gt;
&lt;p&gt;I &lt;a href=&#34;https://paddy.carvers.com/posts/family&#34;&gt;talked&lt;/a&gt; earlier this year about how we’re looking at having kids, and we spent a good amount of 2018 reading, learning, and researching the topic until we arrived at a plan we’re comfortable with. And while I anticipate I’ll be doing an update post on that effort in just under two weeks, a year after the first post, the short version is that we’re looking at adopting through an infant adoption agency. I’ll post more details about what that means, how and why we chose that, and some of the new questions it raised in that other post, but for the purposes of this discussion, here’s what’s important: we’re gonna need to pull together $50,000, submit an application to an agency, the agency will show us to prospective birth mothers who are interested in finding adoptive families for when their children are born, and we’ll wait for someone to pick us. When we’re picked, we need to wire the money to the agency within three days. So we can’t really &lt;em&gt;start&lt;/em&gt; until we have the money, because we could be chosen the day we apply. On average, it looks like families are waiting 3-12 months after applying before being chosen.&lt;/p&gt;
&lt;p&gt;Once we’re done with the house shenanigans and our budget has settled, we’re going to want to turn our attention on this next step, to try and get kids as quickly as we can. $50,000 is a lot of cash to have on hand, and we’re not going to be able to get it all in 2019. I’m hoping we end up with like $10,000 on hand at the end of 2019, which will set us up nicely to be ready in early 2021 to start the process.&lt;/p&gt;
&lt;p&gt;And that’s just the first kid. We’re hoping for two. Clearly, the next three years or so will be spent scrounging up every dollar we can get our hands on, without tiring ourselves out by being in frugal mode for five years straight.&lt;/p&gt;
&lt;h2 id=&#34;read&#34;&gt;Read&lt;/h2&gt;
&lt;p&gt;I have something like 36 books on my to-read list, things I’ve been meaning to get around to, and I’d like to try to read as much of that as I can. The books range a lot of topics, from racial justice, to adoption ethics, to communication and collaboration, to community, to queer history. And there’s a healthy amount of fiction thrown in there, too. I don’t expect to get to all 36 this year, but I’d like to pick up a &lt;a href=&#34;https://us.kobobooks.com/products/kobo-forma&#34;&gt;Kobo Forma&lt;/a&gt; and start making a dent. I miss reading; it’s unapologetically an investment in relaxing. Video games, TV, and movies are all easy forms of entertainment for me because they’re discrete chunks; I can kid myself that I’m taking a two hour break and then will go back to being productive. A book feels more like an undertaking, something that I will invest many hours in for no reason other than I want to. I need to get better about prioritising unapologetically taking time to do things because I feel like it, and reading seems like a nice way to work on that.&lt;/p&gt;
&lt;h2 id=&#34;deprecate-my-budget-spreadsheet&#34;&gt;Deprecate My Budget Spreadsheet&lt;/h2&gt;
&lt;p&gt;Since January 2014, I’ve kept a spreadsheet of every transaction I’ve made, to keep my budget balanced and to be able to keep track of monthly expenses. Knowing my monthly income and expenses has let me forecast my finances, allowing me to reasonably estimate how long it will take me to pull together money to move across the country, get married, and buy a house. As we move on to having kids, the tooling is showing its age. We have to manually sync it back to our bank account, transactions that come in out of order are a bit fiddly to adjust, and recurring expenses that don’t have a fixed amount (e.g., buying groceries every week, buying gas for the car, eating out) aren’t forecasted, leaving us to guess about them.&lt;/p&gt;
&lt;p&gt;I’ve been thinking about tooling for a while that will automate large portions of this, syncing our bank accounts, detecting trends, and forecasting into the future. In 2018, I finally started writing it, and have the syncing and trend detection largely working. I’ll write another blog post about my approach to budgeting and how the tooling works at some point, but the software should get some attention in 2019 so we can retire the spreadsheet and move on to a real database. As we start saving for our largest amounts yet, having more accurate information with less maintenance work will be useful.&lt;/p&gt;
&lt;h2 id=&#34;take-a-vacation&#34;&gt;Take a Vacation&lt;/h2&gt;
&lt;p&gt;Ethan and I haven’t taken a real vacation since our honeymoon, and we… should? We’ve talked a lot about driving down the western coast with our friends, doing our own &lt;a href=&#34;https://finalfantasyxv.square-enix-games.com/&#34;&gt;big gay roadtrip&lt;/a&gt;, so maybe we’ll try to do that. We’ve also talked a lot about spending a month or two in Spain, seeing Europe and practising our Spanish, so maybe we’ll do that. Who knows. Maybe we’ll do neither, and I’ll take time off work to write budgeting software or read a lot of books. Maybe we’ll take a cruise. I don’t know yet. But if we’re going to spend 2020 saving up to have kids, and 2021 in the adoption/new parent process, our window of opportunity for some of these things that we want to do is shrinking. So may as well see if we can make them happen in 2019.&lt;/p&gt;
&lt;p&gt;Those are the projects I’m carrying into 2019 with me, the things that are occupying the front burners of my attention. I want to continue to be a better coworker and employee, too, and a better and kinder friend, and to get more involved with my local community, and to keep my house cleaner, and to write on my blog more, and finish a million software projects, and learn more about cooking, and work on my confidence and self-esteem, and do a slew of other things that I think will make me a better person. And maybe I will! But when people ask me what’s up this year, I expect I’ll probably be talking about the above five things.&lt;/p&gt;
</description>
      <carvers:summary>Looking ahead to 2019, examining what my priorities are.</carvers:summary>
    </item>
    
    <item>
      <title>The Magic of Friendship: The Google Provider&#39;s New Approach to Terraform</title>
      <link>https://paddy.carvers.com/talks/hashiconf-2018/</link>
      <pubDate>Sun, 14 Oct 2018 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashiconf-2018/</guid>
      <description>&lt;p&gt;A talk I gave with my friend Dana Hoffman, of Google, about the &lt;a href=&#34;https://github.com/GoogleCloudPlatform/magic-modules&#34;&gt;Magic
Modules&lt;/a&gt; project, how we
were using it with Terraform, the new possibilities it opened up, and a brief
history of the GCP provider for Terraform. We also talked about how our two
companies worked together.&lt;/p&gt;
&lt;p&gt;You can find the video for the talk and a transcript on
&lt;a href=&#34;https://www.hashicorp.com/resources/google-provider-new-terraform&#34;&gt;HashiCorp.com&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A talk I gave with Dana Hoffman of Google about the advancements and innovations the GCP provider for Terraform had pioneered, and about the friendship we had cultivated between our companies.</carvers:summary>
    </item>
    
    <item>
      <title>Good-bye, paddy.io</title>
      <link>https://paddy.carvers.com/posts/paddy-io/</link>
      <pubDate>Mon, 23 Jul 2018 10:17:07 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/paddy-io/</guid>
      <description>&lt;p&gt;Some of you may have noticed links to my site have changed. I’ve stopped linking to paddy.io, and started linking to paddy.carvers.co instead.&lt;/p&gt;
&lt;p&gt;All the links should still work, and will redirect appropriately. I believe I’ve updated all the internal links; if you find one that still points to paddy.io, please do let me know!&lt;/p&gt;
&lt;p&gt;I also updated my picture on here to be of my jerk husband shoving his hands in my face instead of the photo from 7 years ago of me talking at Google executives. The new photo was taken by Ali Walker. Who is great.&lt;/p&gt;
&lt;p&gt;Some of you may be wondering why I’m migrating away from paddy.io. It’s largely due to me figuring out–4 years late–that &lt;a href=&#34;https://gigaom.com/2014/06/30/the-dark-side-of-io-how-the-u-k-is-making-web-domain-profits-from-a-shady-cold-war-land-deal/&#34;&gt;.io domains pay Great Brtain for colonizing and forcing people off an island&lt;/a&gt; and I’m just not super down with that. And I believe my domain reflects my identity online, and that’s not really what I want my identity to be associated with.&lt;/p&gt;
&lt;p&gt;But I also believe that &lt;a href=&#34;https://www.w3.org/Provider/Style/URI&#34;&gt;cool URIs don’t change&lt;/a&gt;, and after painstakingly keeping URLs alive and largely pointing to this domain for the last ~6 years or so, I‘m hesitant to just let the domain lapse and the old links die. But I also don‘t want to keep contributing money to exploitation. I‘m torn as to what to do about this at the moment.&lt;/p&gt;
&lt;p&gt;But the best time to change your domain is always yesterday, so I figured I’d make sure all future links are pointing to a domain I’m comfortable with &lt;em&gt;now&lt;/em&gt;, and sort out what to do with the domain I’m uncomfortable with at some future date.&lt;/p&gt;
</description>
      <carvers:summary>Dropping the domain name I&amp;rsquo;ve had my entire professional career.</carvers:summary>
    </item>
    
    <item>
      <title>Starting a Family</title>
      <link>https://paddy.carvers.com/posts/family/</link>
      <pubDate>Thu, 11 Jan 2018 13:58:37 -0500</pubDate>
      
      <guid>https://paddy.carvers.com/posts/family/</guid>
      <description>&lt;p&gt;I started growing my family in September of 2015. I don&amp;rsquo;t have a specific date, but I know it was then. And, of course, I had family before that, too. But there was definitely an inflection point, a point where we started rapidly adding people to our lives that we have no other word for besides &amp;ldquo;family&amp;rdquo;. When we moved to Washington, the people we surrounded ourselves with couldn&amp;rsquo;t really be considered friends; we spend holidays with them, we miss them when we travel, we try to ensure we&amp;rsquo;re setting good examples for their children, and we love them without reserve. They&amp;rsquo;re our family.&lt;/p&gt;
&lt;p&gt;And since we&amp;rsquo;ve moved to Washington, something we&amp;rsquo;ve always known has become starkly clear: we choose our family. Families aren&amp;rsquo;t defined by biology, they&amp;rsquo;re defined by love.&lt;/p&gt;
&lt;p&gt;In July of 2017, I &amp;ldquo;officially&amp;rdquo; added Ethan to my family. We got married on the steps of the &lt;a href=&#34;http://www.mooremansion.com&#34;&gt;Moore Mansion&lt;/a&gt;, and promised to love each other as best we could in front of our family, biological or otherwise. It was an important day for us; not because it changed something between the two of us&amp;ndash;we had been operating as a family for years&amp;ndash;but because it was the first, and maybe the only, time our family was all gathered in one place. Thinking about that still makes me so happy.&lt;/p&gt;
&lt;p&gt;This holiday season, I took advantage of the two week shutdown that HashiCorp does (we didn&amp;rsquo;t have work from December 21st through January 2nd) to go visit with the family I don&amp;rsquo;t get to see very often. We spent some time in Buffalo with Ethan&amp;rsquo;s mother, some time in Syracuse with my family, and some time in Buffalo with Ethan&amp;rsquo;s father.&lt;/p&gt;
&lt;p&gt;If there was a theme to the trip (beyond illness; ugh) it would be &lt;em&gt;babies&lt;/em&gt;. Ethan&amp;rsquo;s older brother had a baby boy right before our wedding, so he&amp;rsquo;s six months old now, and we got to meet him for the first time. Ethan&amp;rsquo;s younger brother is due to have a baby in a few months, so they were gearing up for that while we were there. My little brother had a girl in July of 2016 while he was stationed in Okinawa with the Marines, and now that his contract has ended, his family is spending a few months with my parents. She was at our wedding, and absolutely adores her Favourite Uncle (Funcle!) Ethan. And my sister&amp;rsquo;s boyfriend has a teenage son that we got to meet over the holidays for the first time.&lt;/p&gt;
&lt;p&gt;And for the first time, I got to see my husband interact at length with a baby. And y&amp;rsquo;all, I can&amp;rsquo;t wait for him to be a dad, because he&amp;rsquo;s gonna be &lt;em&gt;so good at it&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve been talking about having kids since before we started dating. Back when we were roommates, we talked about what we&amp;rsquo;d name our kids. As we dated, then got engaged, then got married, it became more and more explicitly clear that kids were in the plans for the future. We started to keep track of the things we wanted to do, and started thinking out timelines of how to make sure we got stuff done before having kids, while still having kids at an age we were comfortable with. We started thinking through the ducks we&amp;rsquo;d like to get in a row before we had kids&amp;ndash;things like getting married, buying a house, getting rid of student loan debt&amp;ndash;so we could devote our attention fully to the process of getting the kids, and once that was done, there was nothing left undone to distract us from them.&lt;/p&gt;
&lt;p&gt;It was barely a few days into watching Ethan interact with our niece that I started buying books on Amazon about how to go about having kids as a same-sex couple. We&amp;rsquo;re still not ready, but it&amp;rsquo;s pretty clear it&amp;rsquo;s time for those plans to become less fuzzy and vague.&lt;/p&gt;
&lt;p&gt;There are a lot of paths to parenthood, and we don&amp;rsquo;t know which we&amp;rsquo;ll take yet. We need to explore our choices, investigate costs, consider ramifications, and come to grips about what&amp;rsquo;s &lt;em&gt;really&lt;/em&gt; important to us, as parents.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m excited to get started. I think we&amp;rsquo;re still a few years out from adding someone to our family, but as I learn more and research more, I&amp;rsquo;ll probably want to talk about things more. So I figured I&amp;rsquo;d start off with some context, rather than just dropping a post about the nuances of open vs. closed adoption on y&amp;rsquo;all in six months with no backstory.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a lot of reading, and research, and hard questions, and anxiety, and hope, and planning in our future. And then we get to the &lt;em&gt;real&lt;/em&gt; hard part, raising someone to be as kind, generous, and wonderful as the family we&amp;rsquo;ve surrounded ourselves with.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m looking forward to that challenge.&lt;/p&gt;
</description>
      <carvers:summary>I think I want an even bigger family.</carvers:summary>
    </item>
    
    <item>
      <title>Hashiversary</title>
      <link>https://paddy.carvers.com/posts/hashiversary/</link>
      <pubDate>Tue, 31 Oct 2017 09:45:29 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/hashiversary/</guid>
      <description>&lt;p&gt;A year ago, I joined HashiCorp to work on the Terraform team. I was excited, and baffled.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d heard of HashiCorp, I&amp;rsquo;d used Vagrant, but I hadn&amp;rsquo;t kept up. I had never used Terraform. But I knew the calibre of people that worked there, and I wasn&amp;rsquo;t sure I fit that description.&lt;/p&gt;
&lt;p&gt;But I loved working in Go. I loved working remotely. I had learned some things about operations from very kind people. And I loved open source, and wanted nothing more than to answer, first and foremost, to the people using whatever I made.&lt;/p&gt;
&lt;p&gt;For whatever reason, HashiCorp decided to give me a shot. And I&amp;rsquo;m really glad they did.&lt;/p&gt;
&lt;p&gt;My very first week on the job, they flew me to the HQ in San Francisco. I sat down with one of the co-CTOs, and he explained to me and another new employee the history of the company, the vision, and talked a bit about his perspective on the ecosystem. If you&amp;rsquo;ve never heard Armon explain anything, I definitely recommend finding an opportunity for it. Ethan is probably tired of hearing how excited I am to have a leadership that can explain things in a way that makes it sound simple and obvious when first you hear it, but thinking back on it, it contains half a dozen brilliant ideas. From what I can gather, I&amp;rsquo;m far from the only engineer at HashiCorp that has picked up on this quality.&lt;/p&gt;
&lt;p&gt;A few months in, I decided I wanted a HashiCorp Pride sticker, with our logo in rainbow. I asked my manager if I could make one, and he told me to talk to the marketing team. The marketing team told me no, I am not allowed to make one. &lt;em&gt;But&lt;/em&gt; they&amp;rsquo;d be happy to have one of our contractors design one and submit it for my approval. Which was an even better answer than I had hoped for. We went through a couple iterations, and they delivered a final design to me. I ordered a sample pack off StickerMule and got like a dozen for $9 or something. A few weeks later, a co-CTO saw it on my laptop, and asked for one. Then other coworkers wanted one. Then the company decided to do a run of 50. And now, suddenly, they&amp;rsquo;re a very popular sticker, and we&amp;rsquo;re stocking them. I had anticipated a conversation about politics and the company and neutrality being why &lt;em&gt;I&lt;/em&gt; couldn&amp;rsquo;t make something, and it turned into the company designing and making large quantities of it, instead.&lt;/p&gt;
&lt;p&gt;Working on Terraform has been interesting. My responsibilities and focus have shifted as needs change. Terraform has advanced dramatically in the last year, and though I feel like I&amp;rsquo;ve played an undersized part in that, it&amp;rsquo;s still something I&amp;rsquo;m proud of being part of. I&amp;rsquo;ve learned a lot, and struggled a lot, in the last year.&lt;/p&gt;
&lt;p&gt;One of the best and worst things about working at HashiCorp is that you&amp;rsquo;re surrounded by smart, kind people who care about what they do. It&amp;rsquo;s hard, because it&amp;rsquo;s intimidating. It feels hard to measure up. But it also means you&amp;rsquo;re surrounded with supportive people who will help you to feel like you measure up.&lt;/p&gt;
&lt;p&gt;Of course, there&amp;rsquo;s a lot of work to do, and that can be hard. It&amp;rsquo;s hard not to feel guilty when there are so many open issues and PRs, when you have so much to do at any given moment. But I&amp;rsquo;m surrounded by people who are deeply invested in making sure I don&amp;rsquo;t burn out, and that&amp;rsquo;s really helpful.&lt;/p&gt;
&lt;p&gt;The past year has flown by, and I can&amp;rsquo;t believe it&amp;rsquo;s been an entire year. I&amp;rsquo;ve gotten to do so many things; I&amp;rsquo;ve contributed to a massive open source community; I&amp;rsquo;ve made friends with amazing people who I can&amp;rsquo;t believe give me the time of day; I was in a &lt;a href=&#34;https://www.youtube.com/watch?v=1f-t0xIJvd4&#34;&gt;marketing video&lt;/a&gt; with Dana, a Googler I get to collaborate with; I went to London to give a &lt;a href=&#34;https://www.youtube.com/watch?v=e42A4aBZUkQ&#34;&gt;live demo&lt;/a&gt; on the same stage as some of the smartest people I&amp;rsquo;ve ever met; I &lt;a href=&#34;https://www.hashicorp.com/blog/introducing-the-hashibot-github-bot&#34;&gt;wrote a bot&lt;/a&gt; and &lt;a href=&#34;https://www.hashicorp.com/blog/upcoming-provider-changes-in-terraform-0-10&#34;&gt;programmatically migrated&lt;/a&gt; thousands of issues (while flying cross-country immediately after giving that live demo). When I joined I thought I might do one or two things that exciting during my first year, but I&amp;rsquo;ve been given so many opportunities.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m really looking forward to what I get to celebrate in next year&amp;rsquo;s post.&lt;/p&gt;
</description>
      <carvers:summary>Reflecting on a year working at HashiCorp.</carvers:summary>
    </item>
    
    <item>
      <title>Going Multi-Cloud With Terraform and Nomad</title>
      <link>https://paddy.carvers.com/talks/hashidays-london-2017/</link>
      <pubDate>Mon, 12 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/hashidays-london-2017/</guid>
      <description>&lt;p&gt;I was invited to give a talk on multi-cloud strategies using Terraform and
Nomad at HashiDays London. In my talk, I talk through why you may want to
deploy to multiple clouds, and do a live demo of deploying a Nomad cluster to
Google Cloud Platform and Amazon Web Services, all using Terraform.&lt;/p&gt;
&lt;p&gt;You can find the code used in the talk &lt;a href=&#34;https://github.com/paddycarver/hashidays-london&#34;&gt;on
GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can find the video of my talk &lt;a href=&#34;https://www.youtube.com/watch?v=e42A4aBZUkQ&#34;&gt;on
YouTube&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A livecoding demo of deploying Nomad clusters across AWS and GCP using Terraform.</carvers:summary>
    </item>
    
    <item>
      <title>Using Google Cast With Your Record Player</title>
      <link>https://paddy.carvers.com/posts/casting-records/</link>
      <pubDate>Mon, 29 Aug 2016 23:36:50 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/casting-records/</guid>
      <description>&lt;p&gt;I dunno how you ended up at this place. Maybe you hate yourself a little. Maybe, like me, you have a loved one who, for some reason, enjoys records even though you have subscriptions to a music streaming service that &lt;em&gt;has all these songs already&lt;/em&gt;. Maybe, like me, you’re a little annoyed that what could be a general-purpose solution for making all the speakers in your house talk to each other is arbitrarily limited to only a handful of apps that have bothered implementing its specific protocol. (I can’t cast YouTube Music to my speakers? You’re joking, right?)&lt;/p&gt;
&lt;p&gt;Whatever sins led you to this place in your life, here you are: trying to make something that communicates through analog wires talk to your Chromecast Audios. (Or your Chromecasts, I suppose, but for me it was the Audios.)&lt;/p&gt;
&lt;p&gt;Well, friend, fortunately for you, I already went through the pain of figuring this out, and have some pointers. It involves PulseAudio. Abandon all hope, ye who enter here. Here there be dragons.&lt;/p&gt;
&lt;h2 id=&#34;what-youll-need&#34;&gt;What You’ll Need&lt;/h2&gt;
&lt;p&gt;You’re gonna need a Linux box. It needs a microphone input. You’ll also want speakers for it, for testing. You can find them for like $15 &lt;a href=&#34;http://smile.amazon.com/dp/B00GHY5F3K&#34;&gt;on Amazon&lt;/a&gt;. A Raspberry Pi could work, if you get a USB adapter to give it a mic input. I haven’t tried it yet, it may be underpowered and your performance could suffer. No idea, really. Someone not-me try it and &lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;tell me about it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You’re going to need a record player, or whatever it is you want to send music from. Important thing is that it needs to be able to plug into that mic input on your Linux box. For me, this involved an RCA-to-3.55mm adapter. It cost like $5.&lt;/p&gt;
&lt;p&gt;You’re going to need at least one Chromecast. Or, hypothetically, any DLNA-capable device, though I haven’t tried that yet.&lt;/p&gt;
&lt;p&gt;You’re going to need a whole lot of patience, a chunk of time on your hands, and a thorough knowledge of curse words. We’re dealing with PulseAudio, after all.&lt;/p&gt;
&lt;h2 id=&#34;the-plan&#34;&gt;The Plan&lt;/h2&gt;
&lt;p&gt;OK, so here’s what we’re going to do. We’re going to feed the output of that record player (or whatever you’re using, this could be your phone or your TV or whatever silly thing you want to use) into the mic input for your Linux box. That moves the sound into Linux land, where we can (in theory) do stuff with it.&lt;/p&gt;
&lt;p&gt;Once we have the sound in Linux land, we’re going to route it through PulseAudio, where we can (in theory) make it available to other programs and control where it goes.&lt;/p&gt;
&lt;p&gt;We’re going to set up &lt;a href=&#34;https://github.com/masmu/pulseaudio-dlna&#34;&gt;pulseaudio-dlna&lt;/a&gt;, which will helpfully add all the Chromecasts and DLNA devices on your network as PulseAudio sinks. A sink is PulseAudio’s fancy way of saying &amp;ldquo;the place where you want to send the noise&amp;rdquo;, because &amp;ldquo;output&amp;rdquo; was too hard, I guess.&lt;/p&gt;
&lt;p&gt;To bring it all together, we’re going to use &lt;code&gt;pacat&lt;/code&gt; to direct the music from the record player (or whatever) to the Chromecast (or DLNA device) you want it to play from.&lt;/p&gt;
&lt;h2 id=&#34;step-1-making-the-music-digital&#34;&gt;Step 1: Making the Music Digital&lt;/h2&gt;
&lt;p&gt;OK, the first thing we’re doing is making the music digital. Start by plugging stuff in. You’re on your own for this, as it’s mostly a matter of figuring out what adapters you need to turn one plug into another plug. Google is your friend.&lt;/p&gt;
&lt;p&gt;Once you can plug your record player into your Linux box, life gets interesting. You need to get that sound into PulseAudio. Your mic input should be setup as a source (PulseAudio’s fancy word for &amp;ldquo;input&amp;rdquo;) already. If it’s not, Google away. Mine was, I’m of no use to you. Your speakers should be setup as a sink. Again, mine were automatically detected. If yours aren’t, I can’t help you. Google that.&lt;/p&gt;
&lt;p&gt;To get things rolling, you need PulseAudio to be running if it isn’t already. If, like me, you’re doing this headless (through SSH or a terminal, not through a GUI) it probably isn’t running yet. &lt;code&gt;ps -aux | grep pulse&lt;/code&gt; should give you an idea if it is or not. If it isn’t running, &lt;code&gt;pulseaudio -D&lt;/code&gt; will start it up in the background.&lt;/p&gt;
&lt;p&gt;Now you’re going to want to try playing your record player through the computer speakers, before we introduce the Chromecast to the mix. That way, we at least know your PulseAudio setup is working.&lt;/p&gt;
&lt;p&gt;You’re gonna need the name PulseAudio is using for your mic input and your speakers.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pacmd list-sinks&lt;/code&gt; will give you a helpful, if very verbose, list of places you can send your audio. &lt;code&gt;name:&lt;/code&gt; is the part we’re interested in. Figure out which one is your speakers. As a protip, the &lt;code&gt;device.string&lt;/code&gt; part has some helpful information, sometimes. &lt;code&gt;pacmd list-sinks | grep -e device.string -e &#39;name:&#39;&lt;/code&gt; is the command I ran, which helpfully showed the name (the part I need) and the device string for each of my sinks. Once you have the name, strip off the &lt;code&gt;&amp;lt;&lt;/code&gt; at the beginning and &lt;code&gt;&amp;gt;&lt;/code&gt; at the end.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pacmd list-sources&lt;/code&gt; is the yin to &lt;code&gt;list-sinks&lt;/code&gt;’ yang. It’s going to tell you all the places you can get your audio from. Same drill, find the mic input in that list.&lt;/p&gt;
&lt;p&gt;Finally, moment of truth: let’s bring it all together. Here’s the command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PULSE_SOURCE={YOUR MIC INPUT NAME} pacat -r --latency-msec=1 | PULSE_SINK={YOUR SPEAKERS NAME} pacat -p --latency-msec=1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That &lt;code&gt;PULSE_SOURCE&lt;/code&gt; environment variable tells &lt;code&gt;pacat -r&lt;/code&gt; which source to read from, and echos the audio to stdout. We then pipe that over to &lt;code&gt;pacat -p&lt;/code&gt;, which uses &lt;code&gt;PULSE_SINK&lt;/code&gt; to know which sink to send the audio from stdin to.&lt;/p&gt;
&lt;p&gt;You should hear music playing from the speakers right now. If you don’t, you got the &lt;code&gt;PULSE_SINK&lt;/code&gt; or &lt;code&gt;PULSE_SOURCE&lt;/code&gt; wrong. Try again. Do not proceed until you hear music, we’re about to make our lives more complicated, and knowing you have this part down pat will protect your sanity.&lt;/p&gt;
&lt;h2 id=&#34;step-2-pulseaudio-dlna&#34;&gt;Step 2: pulseaudio-dlna&lt;/h2&gt;
&lt;p&gt;Now that you’ve got the music playing through your speakers, take a moment to rejoice. That was the easy part.&lt;/p&gt;
&lt;p&gt;Next we need to tackle talking to DLNA/Chromecast devices using PulseAudio. Fortunately, we have &lt;a href=&#34;https://github.com/masmu/pulseaudio-dlna&#34;&gt;&lt;code&gt;pulseaudio-dlna&lt;/code&gt;&lt;/a&gt; for that. As long as it’s running, all the DLNA/Chromecast devices it can find will be added as PulseAudio sinks. Go ahead and download and install it.&lt;/p&gt;
&lt;p&gt;Now let’s run that: &lt;code&gt;pulseaudio-dlna --debug&lt;/code&gt;. If you’re using a GUI, you may see a lot of text scroll by real fast that ends with something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;08-29 16:57:09 pulseaudio_dlna.discover                       DEBUG    Binding socket to &amp;#34;&amp;#34; ...
08-29 16:57:10 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Kitchen (Chromecast)&amp;#34;.
08-29 16:57:10 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Desk (Chromecast)&amp;#34;.
08-29 16:57:10 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Great Room (Chromecast)&amp;#34;.
08-29 16:57:11 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Upstairs (Chromecast)&amp;#34;.
08-29 16:57:12 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Nexus Player (Chromecast)&amp;#34;.
08-29 16:57:12 pulseaudio_dlna.discover                       DEBUG    SSDPDiscover.search() quit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If that’s the case, go straight to step 3, you lucky jerk.&lt;/p&gt;
&lt;p&gt;The rest of us, running headless, are more likely to see something that looks like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;08-29 16:59:52 pulseaudio_dlna.discover                       DEBUG    Binding socket to &amp;#34;&amp;#34; ...
Failure: Module initialization failed
08-29 16:59:52 pulseaudio_dlna.pulseaudio                     CRITICAL PulseAudio seems not to be running or PulseAudio dbus module could not be loaded. The application cannot work properly!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you see that, lucky you! You get to try to run PulseAudio headless.&lt;/p&gt;
&lt;p&gt;We know that PulseAudio is running, so that means the PulseAudio dbus module could not be loaded. Let’s dig into that a bit. Run &lt;code&gt;pulseaudio -k&lt;/code&gt; to kill your PulseAudio daemon, and let’s run it again, in the foreground, with some debug information: &lt;code&gt;pulseaudio -vvvvv&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Odds are, if you look closely enough, you’re gonna see some output like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;W: [pulseaudio] server-lookup.c: Unable to contact D-Bus: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
W: [pulseaudio] main.c: Unable to contact D-Bus: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s the root of our problem here. We don’t have X11 running, so we can’t launch a dbus session for PulseAudio. Because we don’t have dbus running, &lt;code&gt;pulseaudio-dlna&lt;/code&gt; can’t talk to PulseAudio, so it can’t add sinks.&lt;/p&gt;
&lt;p&gt;One way to resolve this is to try to use the system PulseAudio session. This is officially discouraged, because it has security implications and &lt;a href=&#34;https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/WhatIsWrongWithSystemWide/&#34;&gt;other caveats&lt;/a&gt;. But this is a thing on embedded setups, I guess? So if you’re doing an embedded setup, maybe that’s something to investigate.&lt;/p&gt;
&lt;p&gt;Our other option is to start the dbus session ourselves. This sounds hard, but it’s the easiest path forward I’ve found. Let’s do it.&lt;/p&gt;
&lt;p&gt;Go ahead and run &lt;code&gt;dbus-run-session pulseaudio -vvvvv&lt;/code&gt;. You should now, if you look hard enough, see something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;D: [pulseaudio] main.c: Got org.PulseAudio1!
D: [pulseaudio] main.c: Got org.pulseaudio.Server!
I: [pulseaudio] main.c: Daemon startup complete.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you did, you’re in business. PulseAudio successfully found dbus and everything is right in the world.&lt;/p&gt;
&lt;p&gt;Here’s the new problem: that &lt;code&gt;dbus-run-session&lt;/code&gt; command kills the dbus session after the command following it (&lt;code&gt;pulseaudio -vvvvv&lt;/code&gt; in our case) terminates. So running &lt;code&gt;dbus-run-session pulseaudio -D&lt;/code&gt; is going to return right away. And we also need to run &lt;code&gt;pulseaudio-dlna&lt;/code&gt; in that dbus session.&lt;/p&gt;
&lt;p&gt;Fortunately, the fix is pretty easy. Write a small script containing the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pulseaudio -k
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pulseaudio -D
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pulseaudio-dlna --debug
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Name it &lt;code&gt;dlnapa.sh&lt;/code&gt; and make it executable. Then run &lt;code&gt;dbus-run-session ./dlnapa.sh&lt;/code&gt;. Now PulseAudio will start &lt;em&gt;and&lt;/em&gt; &lt;code&gt;pulseaudio-dlna&lt;/code&gt; will start within the same dbus session.&lt;/p&gt;
&lt;p&gt;If you look closely enough at the output, you should see something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;08-29 16:57:09 pulseaudio_dlna.discover                       DEBUG    Binding socket to &amp;#34;&amp;#34; ...
08-29 16:57:10 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Kitchen (Chromecast)&amp;#34;.
08-29 16:57:10 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Desk (Chromecast)&amp;#34;.
08-29 16:57:10 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Great Room (Chromecast)&amp;#34;.
08-29 16:57:11 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Upstairs (Chromecast)&amp;#34;.
08-29 16:57:12 pulseaudio_dlna.pulseaudio                     INFO     Added the device &amp;#34;Nexus Player (Chromecast)&amp;#34;.
08-29 16:57:12 pulseaudio_dlna.discover                       DEBUG    SSDPDiscover.search() quit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hooray! It finally works!&lt;/p&gt;
&lt;h2 id=&#34;step-3-bringing-it-all-together&#34;&gt;Step 3: Bringing It All Together&lt;/h2&gt;
&lt;p&gt;OK, we finally have the record player feeding into PulseAudio, and we have our Chromecasts and DLNA devices as sinks for PulseAudio. The last step of this is to feed the record player source into the Chromecast sink we want to use. We’re going to use that same command from the very beginning for this (making sure to leave the &lt;code&gt;dbus-run-session ./dlnapa.sh&lt;/code&gt; running!):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PULSE_SOURCE={YOUR MIC INPUT NAME} pacat -r --latency-msec=1 | PULSE_SINK={YOUR CHROMECAST NAME} pacat -p --latency-msec=1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Chromecast name is much easier to find: &lt;code&gt;pacmd list-sinks | grep &amp;quot;chromecast&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If all went well, you should hear sound from your speakers! There will almost certainly be some delay. But, for me at least, it’s a small price to pay.&lt;/p&gt;
&lt;p&gt;Keep in mind, the music only places as long as &lt;em&gt;both&lt;/em&gt; the &lt;code&gt;dbus-run-session ./dlnapa.sh&lt;/code&gt; command &lt;em&gt;and&lt;/em&gt; the &lt;code&gt;pacat&lt;/code&gt; command are running. Kill either one, and the music will cut off.&lt;/p&gt;
&lt;p&gt;Also, sometimes the music gets garbled weirdly. I haven’t quite figured out why this is yet. The easiest solution I’ve come up with is killing and immediately restarting the &lt;code&gt;pacat&lt;/code&gt; command. A few seconds later, the music will cut out for a split second, then come back in sounding just fine.&lt;/p&gt;
&lt;h2 id=&#34;further-work&#34;&gt;Further Work&lt;/h2&gt;
&lt;p&gt;So that’s where I am right now, and I’m pretty happy with it. The next thing I’m going to try to figure out is getting a dbus session running whenever I SSH in, so I don’t need the &lt;code&gt;dlnapa.sh&lt;/code&gt; script. If I can get that working, and get PulseAudio starting when I SSH in, and the &lt;code&gt;pulseaudio-dlna&lt;/code&gt; server running when I SSH in, then I just need to SSH in and run the &lt;code&gt;pacat&lt;/code&gt; command. And eventually, I’d like to get a better interface on that, so Ethan can use it when I’m not around, without learning what SSH is and how to operate a command line.&lt;/p&gt;
</description>
      <carvers:summary>How to cast your record player to a Chromecast Audio, through PulseAudio. For a bonus challenge, it will involve running PulseAudio headless.</carvers:summary>
    </item>
    
    <item>
      <title>Contexts &amp; Dependency Injection</title>
      <link>https://paddy.carvers.com/posts/contexts-and-dependency-injection/</link>
      <pubDate>Mon, 25 Jul 2016 18:31:27 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/contexts-and-dependency-injection/</guid>
      <description>&lt;p&gt;Just before GopherCon, Peter Bourgon was tweeting about contexts and dependency injection. For background, Peter is someone whose best practices have rung true or been proven over time since he started talking about them (to my knowledge) at the first GopherCon. So when he &lt;a href=&#34;https://twitter.com/peterbourgon/status/752022730812317696&#34;&gt;said&lt;/a&gt; not to use &lt;a href=&#34;https://golang.org/x/net/context&#34;&gt;contexts&lt;/a&gt; as a way to manage dependency injection, I was pretty sad. That’s typically how I handle dependency injection.&lt;/p&gt;
&lt;p&gt;(While I was working on this post, Peter &lt;a href=&#34;https://peter.bourgon.org/blog/2016/07/11/context.html&#34;&gt;published his own&lt;/a&gt;, which is significantly more succinct, but also focused a bit differently than this one. I suggest checking it out.)&lt;/p&gt;
&lt;p&gt;But I’m getting ahead of myself. Let’s back up and talk about dependency injection in Go more holistically.&lt;/p&gt;
&lt;h2 id=&#34;the-global-mutable-dark-days&#34;&gt;The (Global, Mutable) Dark Days&lt;/h2&gt;
&lt;p&gt;To tell this story properly, we need to travel all the way back to when I was learning Go, in 2012. In those dark days, I was pretty happy to just declare a variable, hoist it to a global variable, and then reference that variable wherever I needed my dependency.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;There are&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gophers&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;() (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And everything was rainbows and sunshine. And then Gustavo Niemeyer &lt;a href=&#34;https://groups.google.com/d/topic/mgo-users/idqcsLtq6FA/discussion&#34;&gt;pointed out&lt;/a&gt; that I was making my life hard when it comes to testing. How am I supposed to test &lt;code&gt;getCount&lt;/code&gt;? I have to stand up a MySQL database, then muck about with it. And I can’t have parallel tests, because &lt;code&gt;COUNT(*)&lt;/code&gt; works on the entire table, and I can only specify a single database. So I can’t give my tests their own namespace, so I can’t have parallel tests. Parallel tests are nice. I’d like to be able to use them.&lt;/p&gt;
&lt;h2 id=&#34;for-the-sake-of-arguments&#34;&gt;For The Sake Of Argument(s)&lt;/h2&gt;
&lt;p&gt;Gustavo’s suggestion to me was that I simply pass my database connection (well, mgo session, but let’s stick to database connections to make this easy) as an argument to the functions that need it. And that’s fair, and simple, and &lt;a href=&#34;https://paddy.carvers.com/posts/cleverness/&#34;&gt;I like simple things&lt;/a&gt;, so let’s give that a shot.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;There are&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gophers&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s much better! We can use one database for each test, and run them in parallel. If we use an interface, we could stub out that database for tests, and just pass in the stub. Hooray, problem solved!&lt;/p&gt;
&lt;h2 id=&#34;handling-handlers&#34;&gt;Handling Handlers&lt;/h2&gt;
&lt;p&gt;I like to describe my job as “wrangling state and formatting strings”, because that’s mostly what developing web servers is. At least, in my experience. As a backend developer for the web, there’s one function signature that, were I a tattoo person, I’d absolutely have tattooed somewhere:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s how you write an HTTP handler in Go, and it’s the entry point for any HTTP endpoint in your Go programs. (Unless you’re doing weird stuff with servers, I guess?) But there’s a problem… Where do I put my database connection now? I don’t get to pick my function signature anymore, I have to work within the constraints I’m given.&lt;/p&gt;
&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; use a wrapper to modify the function signature but still be an &lt;code&gt;http.Handler&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;wrapDB&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wrapDB&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;)) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that seems to be fine, right? Everything is great. Except we don’t need to embed a database. We need a database, and a logger, and a metrics collector, and a client for another HTTP service, and a…&lt;/p&gt;
&lt;h2 id=&#34;adding-some-context&#34;&gt;Adding Some Context&lt;/h2&gt;
&lt;p&gt;Fortunately, There’s A Package For That. The &lt;a href=&#34;https://golang.org/x/net/context&#34;&gt;context&lt;/a&gt; package, mentioned in our opening, gives us a &lt;code&gt;Context&lt;/code&gt; type. The &lt;code&gt;Context&lt;/code&gt; type has &lt;a href=&#34;https://blog.golang.org/context&#34;&gt;some concurrency tooling&lt;/a&gt; it provides, but what we’re interested in right now is its ability to embed a value. The &lt;code&gt;Context&lt;/code&gt; type can act as a map, letting us assign values to keys. (There’s a bit more to this, but it’s not really material right now.)&lt;/p&gt;
&lt;p&gt;This is useful, because now we can use our wrapper paradigm from earlier:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;golang.org/x/net/context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dbKey&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mydb&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// don’t use a string here, but that’s another blog post…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithValue&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;dbKey&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;wrapContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dbKey&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;.(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wrapContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;)) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We reuse the idea of wrapping, but everything gets bundled in the &lt;code&gt;context.Context&lt;/code&gt;, and pulled out of it from inside the &lt;code&gt;http.Handler&lt;/code&gt;. Perfect! This is going great.&lt;/p&gt;
&lt;h2 id=&#34;reusable-middleware&#34;&gt;Reusable Middleware&lt;/h2&gt;
&lt;p&gt;Unfortunately, we have a problem now. Our handler works fine, but if we want to take advantage of any middleware for our request, we’re going to have a bad time of it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Quick aside: if you’re not familiar with middleware, I recommend &lt;a href=&#34;https://justinas.org/writing-http-middleware-in-go/&#34;&gt;this post&lt;/a&gt; from Justinas Stankevičius.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The thing about middleware is that the Go community has come to consider the &lt;code&gt;http.Handler&lt;/code&gt; type sacred. If you’re not accepting and returning an &lt;code&gt;http.Handler&lt;/code&gt; type in your middleware, it’s probably not getting very popular. Additionally, if you can’t use middleware that accepts and returns an &lt;code&gt;http.Handler&lt;/code&gt;, you’re probably going to miss out on most the community-provided middleware available.&lt;/p&gt;
&lt;p&gt;You’ll notice we’re returning an &lt;code&gt;http.Handler&lt;/code&gt; above. So we &lt;em&gt;can&lt;/em&gt; use the community-provided middleware, but there’s a catch: we now have two types of middleware. The &lt;code&gt;http.Handler&lt;/code&gt; interface accepts an &lt;code&gt;http.Handler&lt;/code&gt; and returns an &lt;code&gt;http.Handler&lt;/code&gt;, and doesn’t get to use any of the information in the &lt;code&gt;Context&lt;/code&gt;. Then our internal middleware can accept our &lt;code&gt;Context&lt;/code&gt; as part of its function signature (so &lt;code&gt;func(ctx context.Context, w http.ResponseWriter, r *http.Request)&lt;/code&gt;) and gets to take advantage of the values within. The general structure is:&lt;/p&gt;
&lt;p&gt;Request Muxer -&amp;gt; &lt;code&gt;http.Handler&lt;/code&gt; middleware -&amp;gt; &lt;code&gt;wrapContext&lt;/code&gt; -&amp;gt; &lt;code&gt;Context&lt;/code&gt; middleware -&amp;gt; &lt;code&gt;Context&lt;/code&gt;-aware handler&lt;/p&gt;
&lt;p&gt;This is not ideal, but it &lt;em&gt;does&lt;/em&gt; work. It’s what I currently am doing in my projects, and my life has been worse.&lt;/p&gt;
&lt;h2 id=&#34;go-17-to-the-rescue&#34;&gt;Go 1.7 To The Rescue&lt;/h2&gt;
&lt;p&gt;So when I heard &lt;a href=&#34;https://tip.golang.org/pkg/net/http/#Request.Context&#34;&gt;Go 1.7 embeds a Context in &lt;code&gt;http.Request&lt;/code&gt;&lt;/a&gt;, I was very excited. Good-bye &lt;code&gt;wrapContext&lt;/code&gt;, good-bye artificial division between my middlewares. I can now arrange my middleware in any way I like. I’ll just embed my database-aware &lt;code&gt;Context&lt;/code&gt; inside the &lt;code&gt;*http.Request&lt;/code&gt; and suddenly I’ll be back to that magic function signature: &lt;code&gt;func(w http.ResponseWriter, r *http.Request)&lt;/code&gt;. This is &lt;em&gt;so great&lt;/em&gt;. We &lt;em&gt;can&lt;/em&gt; have nice things. Good job everyone, we can all take tomorrow off.&lt;/p&gt;
&lt;p&gt;Except, wait, hang on. How are we going to inject those variables into the &lt;code&gt;*http.Request&lt;/code&gt; type’s &lt;code&gt;Context&lt;/code&gt;? We can’t do it in &lt;code&gt;main&lt;/code&gt; anymore, because we don’t have the &lt;code&gt;*http.Request&lt;/code&gt; instance yet. Hrm.&lt;/p&gt;
&lt;p&gt;OK, time for another ugly wrapper:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;dbKey&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mydb&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// don’t use a string here, but that’s another blog post…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithValue&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;dbKey&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;wrapContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dbKey&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;.(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wrapContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithContext&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, ok, so we still have to use a wrapper, but it’s a pretty straightforward piece of middleware. And we now get to use middleware in whatever order our code requires. This is okay. We can live with this.&lt;/p&gt;
&lt;p&gt;But we’ve got a new problem. (&lt;em&gt;Of course&lt;/em&gt; we have a new problem.) Remember when I said the &lt;code&gt;Context&lt;/code&gt; type had some concurrency tooling? Yeah, that stuff is going to come back to bite us now. We just broke the &lt;code&gt;*http.Request&lt;/code&gt;’s &lt;code&gt;Context&lt;/code&gt; cancellation and deadline semantics.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For incoming server requests, the context is canceled when the ServeHTTP method returns.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;That’s a nice piece of the docs for &lt;a href=&#34;https://tip.golang.org/pkg/net/http/#Request.Context&#34;&gt;&lt;code&gt;*http.Request#Context()&lt;/code&gt;&lt;/a&gt;, and it’s basically telling us our &lt;code&gt;Context&lt;/code&gt; will be canceled after every request. Which sounds fine, right? It is, when each &lt;code&gt;*http.Request&lt;/code&gt; has its own &lt;code&gt;Context&lt;/code&gt;. But our wrapper above is replacing each &lt;code&gt;*http.Request&lt;/code&gt;’s &lt;code&gt;Context&lt;/code&gt; with a copy of a &lt;em&gt;shared&lt;/em&gt; &lt;code&gt;Context&lt;/code&gt; instance. And when a &lt;code&gt;Context&lt;/code&gt; is canceled, the resources associated with it are released. So if we’re still using it… that sounds bad?&lt;/p&gt;
&lt;p&gt;Oh, and also the docs say this about &lt;code&gt;Context&lt;/code&gt;s:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Incoming requests to a server should create a Context, and outgoing calls to servers should accept a Context. The chain of function calls between them must propagate the Context, optionally replacing it with a derived Context created using WithCancel, WithDeadline, WithTimeout, or WithValue.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;You’ll notice the &lt;code&gt;Context&lt;/code&gt; we’re injecting in the &lt;code&gt;*http.Request&lt;/code&gt; wasn’t derived from the &lt;code&gt;Context&lt;/code&gt; in the &lt;code&gt;*http.Request&lt;/code&gt;. Oops. So we’re breaking this (probably really important?) assumption.&lt;/p&gt;
&lt;h2 id=&#34;peter-steps-in&#34;&gt;Peter Steps In&lt;/h2&gt;
&lt;p&gt;There are ways to fix these problems: rather than injecting a new &lt;code&gt;Context&lt;/code&gt; in our middleware, we just need a middleware that injects our dependencies into the existing &lt;code&gt;*http.Request&lt;/code&gt;. Which is annoying, but we can make it simple.&lt;/p&gt;
&lt;p&gt;But this is where Peter shows up in my timeline, so we’re not going to explore that. We’ve spent all this time establishing why &lt;code&gt;Context&lt;/code&gt; is a great solution and what it offers for us, now let’s start exploring the points Peter’s bringing in that explain why this is The Worst and You Shouldn’t Do It. As I said at the beginning, Peter has a really strong track record of predicting the things that will bite me before I’m bitten, so when he says “don’t do this, you’ll be sad”, I pay attention.&lt;/p&gt;
&lt;p&gt;So let’s talk about why this latest solution I’ve found isn’t a solution, but a sad-maker in waiting.&lt;/p&gt;
&lt;h2 id=&#34;tell-me-what-you-need&#34;&gt;Tell Me What You Need&lt;/h2&gt;
&lt;p&gt;If I understand correctly, Peter’s core argument is that by embedding your dependencies (the database connection, the logger, the metrics client, your service clients, etc.) in the &lt;code&gt;Context&lt;/code&gt;, you’re obscuring them, and it’s no longer obvious what your function depends on.&lt;/p&gt;
&lt;p&gt;And, I mean, he’s right… but so what?&lt;/p&gt;
&lt;p&gt;The rest of our conversation broke down into essentially two portions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How important is it that your function makes its dependencies clear?&lt;/li&gt;
&lt;li&gt;What other options do we have?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There was also some talk in there about testability, but I never really wrapped my head around what Peter was getting at, so I’m not going to attempt to address that. But Peter is nice, and patient about explaining things, so if you’re interested, I’d ask him. But &lt;a href=&#34;https://storify.com/paddyforan/contexts-and-dependency-injection&#34;&gt;read the conversation I already had with him about it&lt;/a&gt;, first, so you don’t ask the poor guy to retread the same ground over and over.&lt;/p&gt;
&lt;h2 id=&#34;i-clearly-need-you&#34;&gt;I Clearly Need You&lt;/h2&gt;
&lt;p&gt;So let’s address that first question. How important is it that your function makes its dependencies clear?&lt;/p&gt;
&lt;p&gt;And this question, in itself, really has two parts: how important is it that the dependencies are clear, and how important is it that their &lt;em&gt;types&lt;/em&gt; are clear?&lt;/p&gt;
&lt;p&gt;That second one is the most clear-cut, objective downfall of &lt;code&gt;Context&lt;/code&gt;s. The key and value you define in your &lt;code&gt;Context&lt;/code&gt; are &lt;code&gt;interface{}&lt;/code&gt; types, meaning we’re taking an escape hatch out of the type system, and the compiler washes its hands of us. It will not help us if we’re using the wrong types, we’ll just blow up at runtime. That is, no matter who you ask, worse than blowing up when you try to build your package.&lt;/p&gt;
&lt;p&gt;How important it is that your dependencies are clear is a harder question to talk about. There’s more nuance there, more squishy things it’s hard to measure and reason about.&lt;/p&gt;
&lt;p&gt;What we really boiled it down to, from what I can tell, is how approachable your code base is. And Peter is definitely more an expert on this than I am: he works with more people than I do.&lt;/p&gt;
&lt;p&gt;And I want to dig into this a bit, because it’s something I’ve been contemplating a lot recently at work. My codebases have a lot of ideas in them and patterns that I use, and once you understand them, the codebase is really easy to navigate and understand. But how do I surface that information to people new to the codebase?&lt;/p&gt;
&lt;p&gt;According to Peter, part of that is the function signatures. And after thinking about that a bit, I’m inclined to agree with him. By removing the black hole the &lt;code&gt;Context&lt;/code&gt; represents for our dependencies (they go in, magic happens, they come out), it makes it easier for people to trace the flow of information throughout the program.&lt;/p&gt;
&lt;p&gt;It also makes it easier to modify the program. You only need to fill the function signature, you don’t need to have this other knowledge that other stuff is needed, and where the list of that stuff resides. There’s less reliance on convention and documentation, which is a preferable state of affairs.&lt;/p&gt;
&lt;h2 id=&#34;what-else-is-there&#34;&gt;What Else Is There?&lt;/h2&gt;
&lt;p&gt;So we’ve established that, all else equal, it’s better to explicitly list your dependencies as function params. But all else isn’t equal. We’ve spilled a lot of pixels already talking about why things aren’t equal. Can we retain the benefits we got from the &lt;code&gt;Context&lt;/code&gt; but without the black hole approach to dependency injection?&lt;/p&gt;
&lt;p&gt;Peter’s first suggestion is to abuse closures to inject the variable into a handler, like we did to wrap our &lt;code&gt;Context&lt;/code&gt; before:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here we’re using closures to inject the database connection into our handler function. This works, it fits the criteria above, but I find it annoying because (in my opinion) it obscures what the handler is actually doing, by hiding it amongst the tomfoolery to get the database connection injected into our scope.&lt;/p&gt;
&lt;p&gt;It also does not make the connection available to any of our middleware, but Peter has a solution for that: just inject the connection into the middleware.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophers&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;)(&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophers&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// call our handler only if there are more than 5 gophers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusBadRequest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error: not enough gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But looking at that &lt;code&gt;http.Handle&lt;/code&gt; line, I can already feel the repetition coming. I’ll have five pieces of middleware, injecting the log five times. And the metrics. The &lt;code&gt;http.Handle&lt;/code&gt; line starts getting really complicated and looks like magic and then nobody wants to touch it and it becomes unclear what arguments belong to which function and we’re not in a much better place than we are with &lt;code&gt;Context&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;It works, but I don’t like it. It looks uncomfortably similar to a magic incantation at first glance. Can we do better?&lt;/p&gt;
&lt;h2 id=&#34;add-a-little-structure&#34;&gt;Add a Little Struct(ure)&lt;/h2&gt;
&lt;p&gt;So, ok, we keep coming back to “I have more than one thing I need to be passing around”, but we can solve that. Let’s just bundle them up in a struct. Still type-safe, still easy to discover, no big deal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Deps&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// also logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and service consumers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Deps&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophers&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt;)(&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophers&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Deps&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#75715e&#34;&gt;// call our handler only if there are more than 5 gophers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusBadRequest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error: not enough gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Deps&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;deps&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s at least &lt;em&gt;better&lt;/em&gt;. We no longer have to worry about 5 different dependencies polluting our function signatures, obscuring what’s going on in our &lt;code&gt;http.Handle&lt;/code&gt; line. We also don’t need to edit every single &lt;code&gt;http.Handle&lt;/code&gt; call to add a logger, or telemetry client, or what have you.&lt;/p&gt;
&lt;p&gt;But wait, if we’re just including a struct as the first parameter of a function, that reminds me of a language feature…&lt;/p&gt;
&lt;h2 id=&#34;a-better-method&#34;&gt;A Better Method&lt;/h2&gt;
&lt;p&gt;Methods, I’ve been led to understand, are equivalent to a function with the receiver as the first parameter. So &lt;code&gt;func (a *MyType) Hello(world string)&lt;/code&gt; is equivalent to &lt;code&gt;func Hello(a *MyType, world string)&lt;/code&gt;. But–and this is important–the function signature doesn’t actually include the receiver. So &lt;code&gt;func (a *MyType) HandleFoo(w http.ResponseWriter, r *http.Request)&lt;/code&gt; actually fills our &lt;code&gt;http.HandlerFunc&lt;/code&gt; function signature. You can probably guess where I’m going with this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// also logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and service consumers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandleFunc&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is nice. This works well, our &lt;code&gt;http.Handle&lt;/code&gt; call is clear as day, we can track the dependencies easily (you need an &lt;code&gt;APIv1&lt;/code&gt; struct!), we have type safety, we can use middleware… everything is great.&lt;/p&gt;
&lt;h2 id=&#34;concerns-about-separating&#34;&gt;Concerns About Separating&lt;/h2&gt;
&lt;p&gt;There’s one last thing bugging me, and then I’ll be happy with Peter’s advice. To understand it, we need to talk about how I tend to structure projects.&lt;/p&gt;
&lt;p&gt;Each project usually gets, at the repo root, the business logic for my application. This means, basically, state management, and a few helpers around other common things. I then have a subpackage for each version of the API; you’ll see &lt;code&gt;apiv1&lt;/code&gt;, &lt;code&gt;apiv2&lt;/code&gt;, etc. That way, each binary can have multiple versions of the API running at once.&lt;/p&gt;
&lt;p&gt;The reason this is important is because of that struct containing our dependencies. It begs the question: which package does that struct live in?&lt;/p&gt;
&lt;p&gt;The obvious answer is, of course, to put it in that root package, the one that owns the state manipulation and common helpers. This is, after all, essentially a common helper. But that package almost never has any knowledge of authorization or authentication, by design. So when I need to contact a service over HTTP to do authorization or authentication, I need to introduce that dependency into the dependencies struct, even though it’s not &lt;em&gt;really&lt;/em&gt; a dependency in that root package. Consider also that the authorization and authentication mechanisms may vary between separate versions of the API, and it’s easy to see how the struct gets to be bloated. It feels like we can do better, there.&lt;/p&gt;
&lt;p&gt;The next thought is to make it live in the API packages, but that also is problematic. It cuts off our root package from logging and metrics, and turns it into a black hole in terms of debugging for our application. Not good.&lt;/p&gt;
&lt;p&gt;We could separate it out into its own package, that both the APIs and the root package import, but we still have the problem of bloat and conflating dependencies. And that’s really the heart of the issue here: we’re trying to manage a single set of dependencies, but the way we’ve laid out our project and are conceiving of it really calls for multiple, overlapping sets of dependencies.&lt;/p&gt;
&lt;h2 id=&#34;composing-ourselves&#34;&gt;Composing Ourselves&lt;/h2&gt;
&lt;p&gt;The tentative solution I’m playing with, but haven’t really done enough with to recommend to others (yet) is to use composition; it seems well-suited to this problem. So we may have a &lt;code&gt;Dependencies&lt;/code&gt; struct in the root package holding the common dependencies for our root package (our logger, our metrics handle, our database connection), and an &lt;code&gt;APIv1&lt;/code&gt; struct in our &lt;code&gt;apiv1&lt;/code&gt; package, holding the common dependencies for that version of the API (authorization and authentication clients) and embedding the &lt;code&gt;Dependencies&lt;/code&gt; struct from our root package. Handlers then get defined on the &lt;code&gt;APIv1&lt;/code&gt; struct, and get access to all root package dependencies through type composition.&lt;/p&gt;
&lt;p&gt;Middleware is still an issue; developing shared middleware becomes tough, as we have no convenient way to make dependencies available in a type-safe way, and middleware can no longer opportunistically take advantage of any dependencies it can manage to detect, like we could with &lt;code&gt;context.Context&lt;/code&gt;. But we &lt;em&gt;can&lt;/em&gt; agree to a few methods to expose the important stuff, and use interfaces to achieve type-safety and reusability in multiple projects:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// also logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and service consumers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;GetDatabase&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// this would be in the apiv1 package, but for illustration purposes…&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// any APIv1-specific dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Databaser&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;GetDatabase&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;coreDeps&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;coreDeps&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophersMiddleware&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;coreDeps&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophersMiddleware&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Databaser&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;// call our handler only if there are more than 5 gophers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetDatabase&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusBadRequest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error: not enough gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It’s still doesn’t hide the cruft as nicely as the &lt;code&gt;context&lt;/code&gt; solution did, but I think hiding the cruft was a good portion of the objection to it, in the first place. We’re less interested in hiding it here than we are in managing it, and making sure it doesn’t overpower and obscure, but is still easily discoverable. This is about tidying things up, not magicking them away.&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;http.Handle&lt;/code&gt; line still looks pretty gnarly; a good solution may be to (as I prefer to) have all the muxing for a specific API version handled in its package, then just send requests based on their prefix to that version’s router. If we do that, we can define it in a &lt;code&gt;ServeHTTP&lt;/code&gt; method on the &lt;code&gt;APIv1&lt;/code&gt; type, which means we don&amp;rsquo;t need to cast to &lt;code&gt;http.HandlerFunc&lt;/code&gt; in the &lt;code&gt;http.Handle&lt;/code&gt; line, cleaning it up a bit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;database/sql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;strconv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// also logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and metrics&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// and service consumers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;GetDatabase&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// any APIv1-specific dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Databaser&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;GetDatabase&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql-dsn-goes-here&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;coreDeps&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;myDB&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;coreDeps&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ListenAndServe, you know the rest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;minGophersMiddleware&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Databaser&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#75715e&#34;&gt;// call our handler only if there are more than 5 gophers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetDatabase&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusBadRequest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error: not enough gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// use a router package here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// in this example we’re just gonna respond with the same&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// handler to every request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;minGophersMiddleware&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Dependencies&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HandlerFunc&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;)).&lt;span style=&#34;color:#a6e22e&#34;&gt;ServeHTTP&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIv1&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Database&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteHeader&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; gophers&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QueryRow&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SELECT COUNT(*) FROM animals WHERE name=?&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gopher&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Scan&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That &lt;code&gt;ServeHTTP&lt;/code&gt; function looks a bit gnarly, but it looks much better if you use a router package.&lt;/p&gt;
&lt;h2 id=&#34;can-we-do-better&#34;&gt;Can We Do Better?&lt;/h2&gt;
&lt;p&gt;This is where I am in my dependency injection story, at the moment. I’m interested in knowing where you all are. If you have a way you like better, or see a flaw in my approach, let me know. Hit me up on &lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;Twitter&lt;/a&gt;, or ping me on the &lt;a href=&#34;https://bit.ly/go-slack-signup&#34;&gt;Gophers Slack&lt;/a&gt; (my username there is paddy).&lt;/p&gt;
&lt;p&gt;Thanks to Peter for talking through a lot of this with me and sharing his best practices.&lt;/p&gt;
&lt;p&gt;Extra big thank you to &lt;a href=&#34;https://deadlugosi.blogspot.com&#34;&gt;Margaret Staples&lt;/a&gt; and &lt;a href=&#34;https://agocs.org&#34;&gt;Chris Agocs&lt;/a&gt; for giving me feedback and thoughts on earlier drafts of this post.&lt;/p&gt;
</description>
      <carvers:summary>An examination of different dependency injection strategies in Go.</carvers:summary>
    </item>
    
    <item>
      <title>How I Learned To Quit Worrying And Love Go’s Interfaces</title>
      <link>https://paddy.carvers.com/posts/go-interfaces/</link>
      <pubDate>Sat, 11 Jun 2016 17:04:58 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/go-interfaces/</guid>
      <description>&lt;p&gt;So &lt;a href=&#34;https://www.goinggo.net&#34;&gt;Bill Kennedy&lt;/a&gt; and &lt;a href=&#34;https://npf.io&#34;&gt;Nate Finch&lt;/a&gt; &lt;del&gt;bullied&lt;/del&gt; &lt;del&gt;peer-pressured&lt;/del&gt; talked me into writing about Go. This post is &lt;em&gt;all their fault&lt;/em&gt;. I figured I’d start with one of the things I love about Go that took me a while to figure out: Go’s interfaces. So we’re going to tell the story of how Go’s interfaces and I became BFFs, and the critical things I learned that helped that relationship develop.&lt;/p&gt;
&lt;h2 id=&#34;at-first-blush&#34;&gt;At First Blush&lt;/h2&gt;
&lt;p&gt;My first understanding was simple: interfaces are just duck-typing, right? Cool. Duck-typing is a thing I’ve heard about. Never quite understood what made it so useful, never used it, but it’s nice to know it’s a thing I can do.&lt;/p&gt;
&lt;p&gt;From there, I saw the usefulness of the empty interface: &lt;code&gt;interface{}&lt;/code&gt;. This is just an interface that everything matches. So I can bend the rules of the type system and ok, yeah, I see where that could be useful. The first place I saw it was in the &lt;code&gt;fmt&lt;/code&gt; package. It’s nice that we can have &lt;code&gt;fmt.Println&lt;/code&gt; instead of &lt;code&gt;fmt.StringPrintln&lt;/code&gt; and &lt;code&gt;fmt.IntPrintln&lt;/code&gt; and so on. That seems useful enough.&lt;/p&gt;
&lt;h2 id=&#34;casual-acquaintances&#34;&gt;Casual Acquaintances&lt;/h2&gt;
&lt;p&gt;As I started doing more with Go, I learned about type assertion.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;str&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;.(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that was useful-looking. But I was coming from Python, where I would often change the type of something somewhere in my code, then forget to change it elsewhere in my code, and then I’d get an uncaught exception at runtime and everything would blow up and I was &lt;em&gt;not&lt;/em&gt; a huge fan of that. And if &lt;code&gt;i&lt;/code&gt; is somehow not a string in the example above, you get a panic. So this made me nervous. I felt like I was taking very careful aim at my foot.&lt;/p&gt;
&lt;p&gt;Then I learned that the “comma OK” pattern was being followed for type assertions. Meaning I can do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;world&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;str&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;.(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;`i` wasn’t a string, you should probably return an error or something&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that made me feel a little better. I can have error handling around it! That’s nice. But it still felt a little dangerous. (That’s because it is a little dangerous!)&lt;/p&gt;
&lt;p&gt;Then I found &lt;a href=&#34;https://golang.org/pkg/sort#Interface&#34;&gt;&lt;code&gt;sort.Interface&lt;/code&gt;&lt;/a&gt;, which allowed me to take advantage of the code in the standard library on my own types just by making sure my types have the right method signatures. That’s cool! I can use interfaces as placeholders when I want to get around the type system.&lt;/p&gt;
&lt;h2 id=&#34;becoming-best-friends&#34;&gt;Becoming Best Friends&lt;/h2&gt;
&lt;p&gt;At this point, you’ll notice my relationship with interfaces existed entirely around the type system. To me it was a technical feature, not a semantic one.&lt;/p&gt;
&lt;p&gt;That subtly started to change when I noticed things like &lt;a href=&#34;https://golang.org/pkg/io#Writer&#34;&gt;&lt;code&gt;io.Writer&lt;/code&gt;&lt;/a&gt; and realised it was being used to convey an idea, not to share code. It helped set up a strong demarcation: I don’t care what I’m writing to, my job ends whenever it gets the data it needs.&lt;/p&gt;
&lt;p&gt;But at this point, things didn’t really click just yet. It took wanting to use multiple databases with the same business logic before I really got it.&lt;/p&gt;
&lt;p&gt;I made storing or retrieving data an interface type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Storer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Store&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;thingToStore&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Retrieve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;idOfThing&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As I wrote, I’d write the business logic and the logic for one database. Then I’d write the logic for the next database. And I’d find that sometimes the API I desired for the business logic meant I was doing validation in the database logic. Which meant that sometimes my two databases would validate things differently, as code drifted. Or I would have each database fill in default values when &lt;code&gt;Store&lt;/code&gt; gets called, and that meant doing it twice, possibly inconsistently. (That’s why the &lt;code&gt;Thing&lt;/code&gt; return value exists for the &lt;code&gt;Store&lt;/code&gt; method above; to send back the values that actually got stored.)&lt;/p&gt;
&lt;p&gt;As I wrote more, this became more annoying and more of a headache. It wasn’t working out the way I had hoped. Then I realised I was expecting too much of my interface functions.&lt;/p&gt;
&lt;p&gt;I shouldn’t be validating or filling in defaults in my &lt;code&gt;Store&lt;/code&gt; methods; it was a &lt;code&gt;Store&lt;/code&gt; method, not a &lt;code&gt;FillAndValidateAndStore&lt;/code&gt; method. I made it simpler:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Storer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Store&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;thingToStore&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Retrieve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;idOfThing&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Suddenly, I knew what my interface was for and what responsibilities it had: its &lt;code&gt;Store&lt;/code&gt; method needed to persist the data it was given, &lt;em&gt;exactly&lt;/em&gt; as it was given the data. If it couldn’t, it needed to return an error. That’s it. That’s its one job. Similarly, &lt;code&gt;Retrieve&lt;/code&gt; needed to pull the data back out, and that’s it. If it couldn’t, it needed to return an error.&lt;/p&gt;
&lt;p&gt;This definition was helpful for testing: to know if I had implemented the interface correctly, I could just store something, retrieve it, then compare whatever I retrieved to what was stored. They should match.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TestStorer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;storer&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someImplementationOfStorer&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Thing&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Paddy&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;storer&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Store&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Errorf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error storing thing %+v in Storer %T: %+v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;storer&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;retrieved&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;storer&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Retrieve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Errorf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error retrieving thing %s from Storer %T: %+v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;storer&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;compareThings&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;retrieved&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Errorf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Expected %+v from %T, got %+v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;thing&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;storer&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;retrieved&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What I didn’t anticipate was how helpful this definition would be for communicating and reasoning about my code. It helped me split things into defined chunks with explicit boundaries and defined responsibilities.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Interfaces are great for organizing code, not just sharing code.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And this is where I currently am. Interfaces serve as the backbone of my applications, helping to map out where things are and what things are responsible for.&lt;/p&gt;
&lt;p&gt;If people are interested, I’ll share some patterns I’ve embraced for interfaces, especially around things like testing. But feel free to reach out on Twitter to tell me how useful or not useful this post was. Bill (and, presumably, Nate) &lt;a href=&#34;https://twitter.com/goinggodotnet/status/740893963020861441&#34;&gt;think more people should blog about Go&lt;/a&gt;, but I don’t really know what to blog about. So… suggestions? Requests?&lt;/p&gt;
</description>
      <carvers:summary>Let’s talk about what makes Go’s interface type so freaking useful.</carvers:summary>
    </item>
    
    <item>
      <title>On Being Impractical</title>
      <link>https://paddy.carvers.com/posts/impractical/</link>
      <pubDate>Sat, 04 Jun 2016 04:48:58 -0700</pubDate>
      
      <guid>https://paddy.carvers.com/posts/impractical/</guid>
      <description>&lt;p&gt;I think it was my (wonderful) friendboss &lt;a href=&#34;http://ry4an.org&#34;&gt;Ry4an&lt;/a&gt; who first used the phrase “impractical zealot” to describe me. He wasn’t, if memory serves, espousing his own opinion; I believe he was trying to describe the impression I left on others. But it was definitely in the context of my propensity for making things harder than strictly necessary. The phrase stuck with me as a semi-accurate description, and I’ve been thinking about it for the last year or two.&lt;/p&gt;
&lt;p&gt;Lately, especially in conversations with my friend &lt;a href=&#34;http://tymulholland.com/&#34;&gt;Ty&lt;/a&gt;, I’ve started to be able to solidify my ideas around it into a semi-coherent worldview. So I figured it’s probably past due that I try to write about it.&lt;/p&gt;
&lt;p&gt;My favourite understanding of people trying to do impractical things (which, sadly, I can’t seem to find a source for; if anyone knows, I’d love a link so I can credit them properly) is that the people aren’t being difficult for the sake of being difficult, but are instead trying to move the goal posts. What separates the practical from the impractical, in this case, is that the practical is what is seen as necessary or prudent, and the impractical requires more than that. People trying to do impractical things is the result of people saying &lt;a href=&#34;https://paddy.carvers.com/posts/better&#34;&gt;“we can do better”&lt;/a&gt;, then insisting that what is practical is not acceptable. Implicit in the designation of something as impractical is the assertion that what is deemed practical is an acceptable solution.&lt;/p&gt;
&lt;p&gt;People arguing for the impractical are saying “I reject the practical as an acceptable solution”. If they win, and win enough, the impractical is suddenly practical, and the bar for “acceptable” gets raised.&lt;/p&gt;
&lt;p&gt;I’m routinely horrified by what is deemed “acceptable”, so this understanding resonates with me. It doesn’t hurt that this is also a flattering understanding: strategic progress, usually at the expense of tactical progress, happens because of people doing impractical things. It’s the difference between trying to win the game (making &lt;em&gt;all&lt;/em&gt; the money!) or trying to change the rules it’s played by (demanding more of our technology).&lt;/p&gt;
&lt;p&gt;It’s probably worth noting that you’re unlikely to win at a game if you’re simultaneously trying to change the rules it’s played by.&lt;/p&gt;
&lt;p&gt;But that’s what my interest in technology has always centered on: the tension between “this is hard/confusing/annoying” and my response of “but it doesn’t &lt;em&gt;need&lt;/em&gt; to be”. And then proving that. That’s why, when I decided to take the opportunity of relocating a company to change its name (more on that at some undetermined point in the future), I decided to call it &lt;a href=&#34;https://impractical.engineering&#34;&gt;Impractical Labs&lt;/a&gt;. Because the point of the company isn’t to be the biggest or the best or grow or make money, it’s to facilitate me doing impractical things and trying to make that sustainable.&lt;/p&gt;
&lt;p&gt;The state of the company probably doesn’t say flattering things about this impractical approach, but I remain hopeful for it.&lt;/p&gt;
&lt;p&gt;Impracticality is hard, and is not for everyone or every company. And I get that. And it needs to be moderated to different degrees in different situations, and I get that, too. And it is &lt;em&gt;absolutely&lt;/em&gt; a privileged position to be in, though I would argue it can be a responsible and beneficial use of privilege.&lt;/p&gt;
&lt;p&gt;But for my part, there are a great many hills I am happy to die on. And on the off chance I don’t die… maybe I can make it so nobody needs to die on that hill anymore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://paddy.carvers.com/img/posts/todie.gif&#34; alt=&#34;“To die will be an awfully big adventure.”&#34;&gt;&lt;/p&gt;
</description>
      <carvers:summary>I’ve started to talk more about and develop more ideas around being impractical, so it’s probably past due for me to write about what it means to me.</carvers:summary>
    </item>
    
    <item>
      <title>Professional Concerns</title>
      <link>https://paddy.carvers.com/posts/professional-concerns/</link>
      <pubDate>Thu, 21 Jan 2016 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/professional-concerns/</guid>
      <description>&lt;p&gt;So once again, &lt;a href=&#34;https://wiki.php.net/rfc/adopt-code-of-conduct&#34;&gt;we’re talking about a Code of Conduct&lt;/a&gt;, and once again, people are all up in arms about it. The word “fascism” is getting bandied about unironically, and I’m tweetstorming, so I guess it’s time for &lt;em&gt;another&lt;/em&gt; blog post about this. Don’t blame me, I’m not the one scare-mongering over this.&lt;/p&gt;
&lt;h2 id=&#34;first-amendment&#34;&gt;First Amendment&lt;/h2&gt;
&lt;p&gt;So let’s talk about the First Amendment first, because that seems to be every jerk’s favourite thing to appeal to when they want to say whatever they want without ramification.&lt;/p&gt;
&lt;p&gt;Here’s the entire, unabridged text of the first amendment:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Note that first word: &lt;em&gt;Congress&lt;/em&gt;. If you are having a dispute about something you said and ramifications of it, and neither of the parties involved is &lt;em&gt;Congress&lt;/em&gt;, then the first amendment doesn’t apply and isn’t relevant. It doesn’t matter if everyone gangs up on you just because you said the gays were smelly, your first amendment rights are still &lt;em&gt;totally secure&lt;/em&gt;, no matter how many jobs you’re fired from or how many conferences you’re uninvited from.&lt;/p&gt;
&lt;h2 id=&#34;political-vs-professional&#34;&gt;Political vs. Professional&lt;/h2&gt;
&lt;p&gt;This one comes as a reaction to my personal favourite Code of Conduct, the &lt;a href=&#34;http://contributor-covenant.org&#34;&gt;Contributor Covenant&lt;/a&gt;. There’s a clause in the Covenant that gets everyone in a tizzy, specifically:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;So &lt;em&gt;no matter where&lt;/em&gt; you’re being a jerk, it can still be held against you. And people get up in arms about this claiming that they’re going to be sanctioned for &lt;em&gt;political reasons&lt;/em&gt; not &lt;em&gt;professional reasons&lt;/em&gt;. What they mean by this is “for the way I interact with people, not for the code I write”.&lt;/p&gt;
&lt;p&gt;And I want to use an analogy here to illustrate why this is in fact an entirely reasonable stance for a project to take. I apologise in advance, and this is your trigger warning, there will be some slurs for gay people ahead.&lt;/p&gt;
&lt;p&gt;Suppose I go into work every morning in the same office. As I walk in, every morning, a man is standing outside the office on the sidewalk (crucially, not on company property, but in the vicinity) holding picket signs and yelling “You‘re going to burn in hell, faggot!” at me. Every morning.&lt;/p&gt;
&lt;p&gt;Then, further suppose, after I sit down, this man comes in and sits down at the desk next to me, turns to me, and says “hey, so I was looking at your designs for the message queue architecture, and they look solid, I think we can begin implementation today.”&lt;/p&gt;
&lt;p&gt;When I go to HR and tell them that this coworker is shouting slurs at me in public, do you think HR is going to look at me and say “Oooh, sorry, we’d love to help you, but unfortunately he’s not on company property or using a company email address, so there’s nothing we can do! He writes good code, just focus on the code with him.”&lt;/p&gt;
&lt;p&gt;More importantly, do you think that’s a &lt;em&gt;reasonable&lt;/em&gt; response?&lt;/p&gt;
&lt;p&gt;No, it’s absurd. But that is what people who are claiming they should be able to spew whatever nonsense they like on Twitter and not have it impact them in the project are arguing for.&lt;/p&gt;
&lt;h2 id=&#34;speech-as-fascism&#34;&gt;Speech as Fascism&lt;/h2&gt;
&lt;p&gt;Finally, we have these same people clutching at pearls about how with a Code of Conduct, their employer, or an event they’re speaking at, or a project they’re part of can be pressured because they’re voicing not-politically-correct views in public. This is where “fascism” really starts getting tossed around with vigor.&lt;/p&gt;
&lt;p&gt;I’m confused. That’s already a thing? Like, no Code of Conduct necessary, I can already email your employer and tell them I’m not doing business with them and am encouraging everyone I know to not do business with them because they’re enabling people that are trying to deny me basic rights. And they can already be like “Oh, yeah, that &lt;em&gt;is&lt;/em&gt; problematic! Dude, you’re fired.” Or they can decide they side with you, but like my money more than they like those particular views. This is called a boycott. It’s pretty old.&lt;/p&gt;
&lt;p&gt;And I guess what I’m asking is what, precisely, y’all want to change about this?&lt;/p&gt;
&lt;p&gt;Do you want me to not have any choice about who I do business with? That seems pretty not-great.&lt;/p&gt;
&lt;p&gt;Do you want me to not be able to tell people why I’m not doing business with them? I thought “free speech” was your whole thing?&lt;/p&gt;
&lt;p&gt;Should a company not be able to fire an employee that’s actively costing them money? I desperately want to hear you pitch &lt;em&gt;that one&lt;/em&gt; to the libertarians.&lt;/p&gt;
&lt;h2 id=&#34;back-where-we-started&#34;&gt;Back Where We Started&lt;/h2&gt;
&lt;p&gt;So we come full circle to &lt;a href=&#34;https://paddy.carvers.com/posts/code-of-conduct/&#34;&gt;where we started&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;You want to be able to say whatever you want and disenfranchise and marginalise whoever you want with no repercussions, and people are finally saying “too bad, you can’t”. And no matter how you try and dress it up like fascism, that is &lt;em&gt;absolutely&lt;/em&gt; not violating &lt;em&gt;any&lt;/em&gt; of your rights.&lt;/p&gt;
</description>
      <carvers:summary>Are we really talking about Codes of Conduct again?</carvers:summary>
    </item>
    
    <item>
      <title>&amp;yetConf 2015</title>
      <link>https://paddy.carvers.com/posts/andyetconf-2015/</link>
      <pubDate>Sat, 10 Oct 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/andyetconf-2015/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://paddy.carvers.com/posts/realtimeconfeu/&#34;&gt;Once again&lt;/a&gt;, I find myself in the position of describing an indescribable conference. But the effort should be made, because my brain feels like mush and I want to remember this.&lt;/p&gt;
&lt;p&gt;&amp;amp;yetConf was… emotionally heavy. It was a conference that asked us to look at what we’re making, why, and whether we’re actually ok with that or not. We were asked to take a look at the road we’re on, where it’s going, and whether that’s &lt;em&gt;really&lt;/em&gt; the destination we want. Most conferences are more concerned with upgrading our cars.&lt;/p&gt;
&lt;p&gt;If you came to &amp;amp;yetConf looking for new technical skills, you were bound to be disappointed. We had some of the best minds in technology sitting in a single room (on some very comfortable couches), but most business-focused people would call the event a failure. &lt;a href=&#34;https://twitter.com/carver_ethan&#34;&gt;My fiancé&lt;/a&gt; attended, and despite a very basic understanding of the industry, there were no talks he felt out of his depth for. We didn’t get into the nitty-gritty of JavaScript, nor did we discuss architectures or how to increase productivity.&lt;/p&gt;
&lt;p&gt;Instead we talked about how identities form online, and the part we (as creators) play in that. We talked about how information is dispersed on the ground in emergency response situations, and how creators can help (“don’t build another people finder app, we have enough, just fix one of the ones we have”). We talked about how we can help our users keep getting value out of our software long after we’ve stopped supporting it. We talked about our global economy, and where it’s headed. We talked about how to communicate with each other. And that was just day one.&lt;/p&gt;
&lt;p&gt;Day two continued our conversations, including a &lt;em&gt;fantastic&lt;/em&gt; talk about being more than one thing by the very excellent &lt;a href=&#34;http://lynnandtonic.com&#34;&gt;Lynn Fisher&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;img src=&#34;https://paddy.carvers.com/img/posts/andyetconf-2015/intersections.jpg&#34; alt=&#34;intersections&#34; /&gt;
&lt;/div&gt;

&lt;p&gt;But when lunch came around, the talks seemed a world away. We were put on buses, given sealed envelopes, and told to open them when the bus left. The letters would tell us where we were going.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;img src=&#34;https://paddy.carvers.com/img/posts/andyetconf-2015/letter.jpg&#34; alt=&#34;letter&#34; /&gt;
&lt;/div&gt;

&lt;p&gt;We were going to Richland’s &lt;a href=&#34;http://www.hanford.gov/page.cfm/BReactor&#34;&gt;B Reactor&lt;/a&gt;, the world’s first full-scale plutonium production reactor. Our envelope contained the above-excerpted letter, a copy of Einstein’s letter to President Franklin Roosevelt discussing the creation of the Manhattan project, and information about the site and the tour we were about to go on.&lt;/p&gt;
&lt;p&gt;It’s impossible to describe the feeling of sitting on that bus, surrounded by optimistic people pushing us into the future as best they know how, and having the greatest mistake of another generation of makers shoved in your face. Knowing that when the physicists were at their apex, it came with a body count. And here we are, on the rise. What will our legacy be?&lt;/p&gt;
&lt;p&gt;The uncomfortable feeling only grew more pronounced as the tour guide talked more about the engineering accomplishment, the “great science”, and our “triumph”. The discrepancy between how we felt and how the tour guide felt was palpable, and the tension did not go unnoticed.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;img src=&#34;https://paddy.carvers.com/img/posts/andyetconf-2015/breactor.jpg&#34; alt=&#34;B Reactor&#34; /&gt;
&lt;/div&gt;

&lt;p&gt;When we returned to our venue, we held an open discussion of how the trip made us feel and what we were thinking. We talked about remorse and attitude, we talked about how the Japanese felt. We talked about nuclear power, and we talked about local heritage. We talked about celebrating technological achievement, and we talked about how what that technology is used for fits into its value.&lt;/p&gt;
&lt;p&gt;I think it’s fair to say that, not for the first time during the conference, there weren’t many dry eyes among the attendees.&lt;/p&gt;
&lt;p&gt;After our talk, we took a trip into the future. While the details of this are a secret, I’ll say this: the experience was emotionally heavy in the &lt;em&gt;exact opposite&lt;/em&gt; way. It asked us to tap into the things we need most, and realised them in a palpable way.&lt;/p&gt;
&lt;p&gt;Taken altogether, the conference left me considering our legacy, considering courage, and rethinking my goals for my career. And that’s before we start taking into account the complex, nuanced, and relevant storyline that played throughout the conference. That’s before we talk about the opening parade. That’s before we discuss the lengths that &amp;amp;yet went to to make everyone feel included. That’s before we talk about the dozens of tiny details that made the conference seem… well, unreal. And returning to reality is hard.&lt;/p&gt;
&lt;p&gt;Imagine taking some of the most amazing, thoughtful people in our industry, putting them in a room, and asking them to take responsibility for the direction our industry is pursuing. That’s &amp;amp;yetConf.&lt;/p&gt;
</description>
      <carvers:summary>A conference for those doing the impractical.</carvers:summary>
    </item>
    
    <item>
      <title>Google Cloud Storage &amp; WAL-E (Part One)</title>
      <link>https://paddy.carvers.com/posts/gcs-wal-e/</link>
      <pubDate>Tue, 22 Sep 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/gcs-wal-e/</guid>
      <description>&lt;p&gt;I’ve been trying to get &lt;a href=&#34;https://cloud.google.com/storage&#34;&gt;Google Cloud Storage&lt;/a&gt; support for &lt;a href=&#34;https://github.com/wal-e/wal-e&#34;&gt;WAL-E&lt;/a&gt; for &lt;a href=&#34;https://github.com/wal-e/wal-e/issues/122&#34;&gt;years&lt;/a&gt;. Since July 2014, if we’re going to be precise about it. It is proving to be a fun nut to crack.&lt;/p&gt;
&lt;p&gt;(OK, in fairness, I haven’t actively been working on this and trying to solve the problem for like 14 months; it was more like a month of trying to solve the problem in stolen time chunks, then a year of not touching it, then another month of trying to solve the problem in stolen time chunks.)&lt;/p&gt;
&lt;p&gt;For those not familiar, WAL-E is a continuous archiving solution for Postgres. Basically, it helps you keep near-realtime backups of your database. Which is generally a Rather Useful Thing. It was built originally to support Amazon’s S3 storage solution, but it has been expanded to support Microsoft’s Azure and OpenStack’s Swift.&lt;/p&gt;
&lt;p&gt;Google Cloud Storage is a storage solution provided by Google, very similar to S3, but which works nicely when you’re already using Google Cloud for other parts of your application.&lt;/p&gt;
&lt;p&gt;WAL-E has four main modes: pushing point-in-time backups (full backups), pulling point-in-time backups, pushing incremental backups (which layer on top of full backups), and pulling incremental backups. If properly configured, it can help automatically manage your database clusters for you, so new instances that are spun up automatically just restore from the latest backup.&lt;/p&gt;
&lt;h2 id=&#34;the-good-news&#34;&gt;The Good News&lt;/h2&gt;
&lt;p&gt;The good news is that the WAL-E core team seem open to Google Cloud Storage being added as an option, as well as adding dependencies as necessary to make that reasonable for code maintenance.&lt;/p&gt;
&lt;p&gt;The WAL-E codebase is also nicely organised, with common functionality &lt;em&gt;mostly&lt;/em&gt; separated from storage provider-specific functionality.&lt;/p&gt;
&lt;p&gt;The Python code is clean, sort of documented (at least, better than a lot of the Python code lots of us have to deal with in private codebases), and seems reasonably dedicated to &lt;a href=&#34;https://paddy.carvers.com/posts/cleverness/&#34;&gt;clarity&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;the-bad-news&#34;&gt;The Bad News&lt;/h2&gt;
&lt;p&gt;What WAL-E does is actually more complex than it seems. Specifically, there’s a feature that allows backups to be &lt;a href=&#34;http://www.lzop.org/&#34;&gt;lzop&lt;/a&gt; compressed. When downloading a backup to restore from, WAL-E intelligently manages disk space by using &lt;a href=&#34;https://github.com/wal-e/wal-e/blob/98b81d0080a772fe26f4bb0e70bed04f9ecdb490/wal_e/blobstore/s3/s3_util.py#L68-L69&#34;&gt;streaming download and decompression&lt;/a&gt;, to avoid needing to download the entire file before decompression can start.&lt;/p&gt;
&lt;p&gt;Unfortunately, Google Cloud Storage’s &lt;a href=&#34;https://github.com/google/google-api-python-client&#34;&gt;&lt;code&gt;google-api-client-python&lt;/code&gt;&lt;/a&gt; library doesn’t &lt;em&gt;have&lt;/em&gt; a streaming download option. So using it would mean abandoning that nice property of “doesn’t require you to store the full compressed backup &lt;em&gt;while&lt;/em&gt; decompressing it”.&lt;/p&gt;
&lt;p&gt;Fortunately, the &lt;a href=&#34;https://github.com/boto/boto&#34;&gt;&lt;code&gt;boto&lt;/code&gt; library&lt;/a&gt; (which, incidentally, is what WAL-E is already using!) supports streaming downloads, and has support for Google Cloud Storage.&lt;/p&gt;
&lt;p&gt;Problem solved, right?&lt;/p&gt;
&lt;p&gt;Well, not quite.&lt;/p&gt;
&lt;p&gt;See, remember when I said that Google Cloud Storage works well when you’re already using Google Cloud for other stuff? What I was referencing, specifically, is that you can tell Google Cloud that any server in your project can upload to that project’s storage space using internal authentication, instead of storing credentials on the server. This is the same general principle as assigning IAM roles to your EC2 instances.&lt;/p&gt;
&lt;p&gt;You can probably see where I’m going with this.&lt;/p&gt;
&lt;p&gt;Yup, as far as I can tell, &lt;code&gt;boto&lt;/code&gt; doesn’t know how to take advantage of this for Google Cloud Storage.&lt;/p&gt;
&lt;p&gt;Well, that’s not &lt;em&gt;strictly&lt;/em&gt; true. &lt;code&gt;boto&lt;/code&gt; knows how to take advantage of this (through a &lt;a href=&#34;https://github.com/GoogleCloudPlatform/gcs-oauth2-boto-plugin&#34;&gt;plugin developed by Google&lt;/a&gt;), but not in a way that WAL-E likes.&lt;/p&gt;
&lt;p&gt;You see, when configuring WAL-E’s authentication mechanism for requests, WAL-E &lt;a href=&#34;https://github.com/wal-e/wal-e/blob/98b81d0080a772fe26f4bb0e70bed04f9ecdb490/wal_e/blobstore/s3/s3_credentials.py&#34;&gt;expects&lt;/a&gt; a &lt;a href=&#34;https://github.com/boto/boto/blob/cb8aeec987ddcd5fecd206e38777b9a15cb0bcab/boto/provider.py#L77&#34;&gt;&lt;code&gt;boto.provider.Provider&lt;/code&gt;&lt;/a&gt; subclass, which is a class that dictates how &lt;code&gt;boto&lt;/code&gt; authenticates requests, and where it pulls authentication information from. WAL-E has a very specific set of places it wants the authentication to come from, and it is not the default set by &lt;code&gt;boto&lt;/code&gt;’s Google provider.&lt;/p&gt;
&lt;p&gt;To exacerbate problems, the plugin provided by Google isn’t a provider, it’s an auth handler, which is &lt;em&gt;used&lt;/em&gt; by providers. And &lt;code&gt;boto&lt;/code&gt; &lt;em&gt;has&lt;/em&gt; a Google provider, which I &lt;em&gt;assume&lt;/em&gt; the auth handler hooks into, but I can’t find any good docs or writeups on how this works or what happens. Providers seems to be a very under-documented part of the (rather large) &lt;code&gt;boto&lt;/code&gt; library. But it feels non-obvious how you’re supposed to go about customising or overriding the behaviour of that provider.&lt;/p&gt;
&lt;p&gt;And to make things even more fun, it’s unclear whether the Google provider for &lt;code&gt;boto&lt;/code&gt; only works when you put Google Cloud Storage into &lt;a href=&#34;https://cloud.google.com/storage/docs/migrating#migration-simple&#34;&gt;compatibility mode&lt;/a&gt; which (as best I can understand) only allows you to work on one bucket in any given project. Which sounds… not ideal. It also just feels like a hack that is bound to become unsupported at some point; a marketing gimmick to boost adoption, instead of an engineering decision meant to be supported.&lt;/p&gt;
&lt;p&gt;So that’s where I’m standing now: trying to decide between a library that doesn’t quite match the tool I’m plugging it into, which doesn’t support a nice-to-have feature; or a library that matches the tool I’m plugging it into, supports all the features, but requires me to dig deep and understand a pretty-undocumented-but-rather-important class in an a different library, feels hacky, and may be unsupported in the future.&lt;/p&gt;
&lt;p&gt;If any of y’all reading this are &lt;code&gt;boto&lt;/code&gt; experts or know something I don’t, hitting me up on &lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;Twitter&lt;/a&gt; or &lt;a href=&#34;mailto:paddy+wale@carvers.com&#34;&gt;email&lt;/a&gt; would be appreciated.&lt;/p&gt;
</description>
      <carvers:summary>My efforts and progress on getting WAL-E to support Google Cloud Storage, and the stumbling blocks I’m facing.</carvers:summary>
    </item>
    
    <item>
      <title>Ampersand &amp; OAuth2, Part 1: Local Storage</title>
      <link>https://paddy.carvers.com/posts/ampersand-oauth-cache/</link>
      <pubDate>Thu, 02 Jul 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/ampersand-oauth-cache/</guid>
      <description>&lt;p&gt;We’re going to try something new today. We’re going to remember I’m a developer, and I’m going to post some code on my blog, and we’ll all just see how that works out, ok? To kick it off, I’m gonna do a small series on using &lt;a href=&#34;http://ampersandjs.com&#34;&gt;Ampersand.js&lt;/a&gt; as the front end for an API that uses OAuth2 for the authentication. In this post, we’re going to cover storing, loading, and maintaining the tokens and their metadata.&lt;/p&gt;
&lt;p&gt;So let’s get to it.&lt;/p&gt;
&lt;h2 id=&#34;our-setup&#34;&gt;Our Setup&lt;/h2&gt;
&lt;p&gt;I’m going to assume that you’re using &lt;a href=&#34;https://github.com/ampersandjs/ampersand-app&#34;&gt;&lt;code&gt;ampersand-app&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://github.com/ampersandjs/ampersand-model&#34;&gt;&lt;code&gt;ampersand-model&lt;/code&gt;&lt;/a&gt;. If you’re not, just move along, this article will very likely be useless to you. I’m also going to assume you’re using an ES6 transpiler, like &lt;a href=&#34;http://babeljs.io&#34;&gt;Babel&lt;/a&gt;. Because, well, I am. And it’s nice. So we’re going to, just this once, have nice things.&lt;/p&gt;
&lt;p&gt;Our problem (today) is, once we get the user authenticated, we need to keep track of their OAuth access token and refresh token. If we lose them, the user has to re-authenticate, and that’s not a fun user experience. So we want to avoid that.&lt;/p&gt;
&lt;p&gt;Fortunately, someone &lt;a href=&#34;http://learn.humanjavascript.com/react-ampersand/introduction&#34;&gt;smarter than me&lt;/a&gt; has &lt;a href=&#34;https://github.com/HenrikJoreteg/hubtags.com/blob/47dca17ef9fe58404a7f83b05c65bd01fa3cd268/src/models/me.js&#34;&gt;an example&lt;/a&gt; for how to do that using &lt;code&gt;ampersand-model&lt;/code&gt;. So we’re going to copy Henrik’s “Me” model:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-model&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://auth.server/path/to/token/endpoint&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;props&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;access_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;refresh_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;expires_in&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;int&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;token_created&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;date&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;profileID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So far, so good. We’ve got a basic model with some properties. Nothing earth-shattering here.&lt;/p&gt;
&lt;p&gt;We’re going to skip how to go ahead and populate the data. That’s, frankly, boring. (Hint: use &lt;a href=&#34;https://github.com/ampersandjs/ampersand-sync&#34;&gt;&lt;code&gt;ampersand-sync&lt;/code&gt;&lt;/a&gt; if you want to get some cool features from the next part of this series.)&lt;/p&gt;
&lt;p&gt;For now, we’re just going to assume you get a populated &lt;code&gt;Me&lt;/code&gt; instance, somehow.&lt;/p&gt;
&lt;h2 id=&#34;storing-the-tokens&#34;&gt;Storing the Tokens&lt;/h2&gt;
&lt;p&gt;We want to be able to cache that information in localStorage. The helper to do that is tiny:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;writeToCache&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Super silly simple, right? Let’s put it all together to just highlight how silly it is that I’m writing a whole blog post about this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-model&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://auth.server/path/to/token/endpoint&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;props&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;access_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;refresh_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;expires_in&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;int&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;token_created&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;date&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;profileID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;writeToCache&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You’ll notice that we’re using &lt;code&gt;JSON.stringify(this)&lt;/code&gt; instead of &lt;code&gt;this.toJSON()&lt;/code&gt;. If you check &lt;a href=&#34;https://ampersandjs.com/docs#ampersand-state-tojson&#34;&gt;the docs&lt;/a&gt;, you’ll see that &lt;code&gt;this.toJSON()&lt;/code&gt; does not, in fact, do what you think it does (emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Return a shallow copy of the state’s attributes for JSON stringification. This can be used for persistence, serialization, or augmentation, before being sent to the server. &lt;strong&gt;The name of this method is a bit confusing, as it doesn’t actually return a JSON string&lt;/strong&gt; — but I’m afraid that it’s the way that the JavaScript API for &lt;code&gt;JSON.stringify&lt;/code&gt; works.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I draw attention to this because it bit me. The moral of the story is that &lt;code&gt;this.toJSON()&lt;/code&gt; is a lying liar that lies, and there’s not much the very nice Ampersand folks can do about it.&lt;/p&gt;
&lt;h2 id=&#34;loading-the-tokens&#34;&gt;Loading the Tokens&lt;/h2&gt;
&lt;p&gt;Continuing on our journey, however, it occurs to me that if you’re going to store your data, you should probably, at some point, load it. After all, if data is stored in a forest, and no, uh, trees are there to, err, load… you know what, never mind. Point is, saving data and not loading it is rather silly. So let’s write a helper!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Super exciting, right? Pull the string out of localStorage, and if it worked, parse the JSON string into a Plain Ol’ JavaScript Object. Once that’s done, use it to update the &lt;code&gt;Me&lt;/code&gt; model with &lt;a href=&#34;https://ampersandjs.com/docs#ampersand-state-set&#34;&gt;&lt;code&gt;set&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So to keep our running sample all together:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-model&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://auth.server/path/to/token/endpoint&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;props&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;access_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;refresh_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;expires_in&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;int&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;token_created&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;date&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;profileID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;writeToCache&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;set-it--forget-it&#34;&gt;Set It &amp;amp; Forget It&lt;/h2&gt;
&lt;p&gt;We have a helper method to save our tokens to localStorage, but who wants to use that? You have to remember to call it every time your tokens change, they can get out of sync, it just feels like a pain.&lt;/p&gt;
&lt;p&gt;I have a better idea.&lt;/p&gt;
&lt;p&gt;One of the things we get for free from &lt;code&gt;ampersand-model&lt;/code&gt; (thanks, &lt;code&gt;ampersand-model&lt;/code&gt;!) is a set of events that get fired off. One of those events is the &lt;code&gt;change&lt;/code&gt; event, which gets triggered when an attribute changes.&lt;/p&gt;
&lt;p&gt;That sounds super handy. Let’s hook it up!&lt;/p&gt;
&lt;p&gt;In your &lt;code&gt;main.js&lt;/code&gt;, or whatever file is serving as the entrypoint for your app, include this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-app&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Me&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./me&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Me&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;change&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;writeToCache&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s just your basic &lt;a href=&#34;https://github.com/ampersandjs/ampersand-app&#34;&gt;&lt;code&gt;ampersand-app&lt;/code&gt;&lt;/a&gt; setup. We’re attaching an instance of your &lt;code&gt;Me&lt;/code&gt; model to the app singleton, so we can refer to the same instance throughout our application. Then we’re listening for changes to our instance, and calling its &lt;code&gt;writeToCache&lt;/code&gt; function when changes occur. This means whenever the tokens change, they &lt;em&gt;automatically&lt;/em&gt; get persisted to localStorage &lt;em&gt;for you&lt;/em&gt;. You don’t even have to think about it.&lt;/p&gt;
&lt;p&gt;Go ahead, try it. I’ll wait.&lt;/p&gt;
&lt;p&gt;But we have some issues. Some things (&lt;a href=&#34;https://github.com/ampersandjs/ampersand-sync&#34;&gt;&lt;code&gt;ampersand-sync&lt;/code&gt;&lt;/a&gt; comes to mind…) aren’t very conservative about updating things all at once. Sometimes they update properties one at a time. Which means we’d write to the cache every single time any property changed, instead of trying to batch them. That’s no good. We should obviously be batching these changes to reduce our resource usage.&lt;/p&gt;
&lt;p&gt;The trick is to &lt;em&gt;debounce&lt;/em&gt; the &lt;code&gt;writeToCache&lt;/code&gt; function. That just means that the function will only be called once every so often, rolling multiple calls in that time period into a single call. Which sounds like what we want.&lt;/p&gt;
&lt;p&gt;Here are the modifications you need:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-model&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;debounce&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;lodash.debounce&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;https://auth.server/path/to/token/endpoint&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;props&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;access_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;refresh_token&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;expires_in&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;int&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;token_created&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;date&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;profileID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;initialize&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;debouncedWriteToCache&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;debounce&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;writeToCache&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;250&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;writeToCache&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;setItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;localStorage&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getItem&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;me&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All we did was add an &lt;code&gt;initialize&lt;/code&gt; function to our &lt;code&gt;Me&lt;/code&gt; model, and have it set &lt;code&gt;this.debouncedWriteToCache&lt;/code&gt; to be a debounced version of &lt;code&gt;writeToCache&lt;/code&gt;, so multiple calls within 250 milliseconds are turned into a single call. There’s no reason we should be modifying our tokens more than once every 250 milliseconds, anyways.&lt;/p&gt;
&lt;p&gt;That done, we can update our application bootstrap to use the debounced version:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-app&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Me&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./me&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Me&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;change&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;debouncedWriteToCache&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now no matter how many properties change, you only write to localStorage once. Hooray!&lt;/p&gt;
&lt;p&gt;OK, so we have saving taken care of automatically and we don’t need to think about it anymore. How about loading?&lt;/p&gt;
&lt;p&gt;That’s actually phenomenally simple. Ready for this big code change?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ampersand-app&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Me&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;./me&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Me&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;change&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;me&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;debouncedWriteToCache&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yeah, we added &lt;code&gt;.load()&lt;/code&gt; to the end of our instantiation for &lt;code&gt;this.me&lt;/code&gt;. Super exciting stuff. It just loads the tokens out of localStorage when your app starts up.&lt;/p&gt;
&lt;p&gt;And you’re done! Now your tokens save automatically, get loaded automatically, and you can just treat them like they’re stored in memory &lt;em&gt;all the time&lt;/em&gt;. No muss, no fuss.&lt;/p&gt;
&lt;h2 id=&#34;paddy-you-just-blogged-about-like-40-lines-of-code&#34;&gt;Paddy, You Just Blogged About Like 40 Lines of Code&lt;/h2&gt;
&lt;p&gt;This blog post was dealing with an almost ridiculously trivial block of code. There’s nothing fancy in my code samples: I’m setting properties, parsing JSON, and using localStorage.&lt;/p&gt;
&lt;p&gt;But the simplicity of the code is &lt;em&gt;the point&lt;/em&gt; of this post. Ampersand’s event system let me use 40 lines of code to abstract away what could otherwise be a rather messy part of the application.&lt;/p&gt;
&lt;p&gt;And if you stick around for the next post in the series, we’re going to leverage this into truly mind-bending levels of “don’t make me think”.&lt;/p&gt;
&lt;p&gt;If you want, for some reason, a running version of this code (along with a transpiler to build it so it functions in your browser), I put it all in a &lt;a href=&#34;https://github.com/paddycarver/ampersand-oauth-cache&#34;&gt;Github repository&lt;/a&gt;. Because the only thing funnier than writing a big long blog post about 40 lines of code is putting it in a Github repo and slapping a license and README on it.&lt;/p&gt;
</description>
      <carvers:summary>Part one of an ongoing series about using Ampersand.js with OAuth2. We’ll talk about storing your tokens and their associated metadata.</carvers:summary>
    </item>
    
    <item>
      <title>Have a Code of Conduct</title>
      <link>https://paddy.carvers.com/posts/code-of-conduct/</link>
      <pubDate>Thu, 18 Jun 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/code-of-conduct/</guid>
      <description>&lt;p&gt;There was hubbub today over a project maintainer’s conduct on Twitter, and whether he should be allowed to continue to hold a position of authority in the project while marginalising a group of people.&lt;/p&gt;
&lt;p&gt;I don’t want to talk about that, because (honestly) we see this situation every month or so. Everyone wants to be able to marginalise people without any consequences, and so arguments about “censorship” perennially spring up.&lt;/p&gt;
&lt;p&gt;Instead, I want to talk about projects having Codes of Conduct. That same project had an issue open about creating a Code of Conduct, and what should be in it, and what it means, and where it applies. And I saw a lot of assertions about what a Code of Conduct means. So I want to clear up what a Code of Conduct means to me.&lt;/p&gt;
&lt;h2 id=&#34;what-is-a-code-of-conduct-anyways&#34;&gt;What is a Code of Conduct, anyways?&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&#34;http://geekfeminism.wikia.com/wiki/Code_of_conduct_evaluations&#34;&gt;Code of Conduct&lt;/a&gt; is, as Geek Feminism’s wiki says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“a document which sets out expectations for members of a community, with regard to how they will behave toward each other.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;All a Code of Conduct is is a &lt;strong&gt;statement of values&lt;/strong&gt;. We value people who can be polite, respectful, and kind over people that are rude, disrespectful, and cruel. When we have to make a choice about which people to include or exclude, we’re going to choose the one that will attract more of the people we want than the people we don’t want.&lt;/p&gt;
&lt;h2 id=&#34;but-what-about-abuse&#34;&gt;But what about abuse?&lt;/h2&gt;
&lt;p&gt;Some people are very concerned about censorship, and are concerned that the organization leaders (or the “Social Justice Warriors” on the Internet) will use the Code of Conduct to get rid of members in the community they don’t like.&lt;/p&gt;
&lt;p&gt;First, if that’s the case, the removed members were &lt;em&gt;already exhibiting behaviours the community has decided are unacceptable&lt;/em&gt;. I’m not sure how that can qualify as abuse.&lt;/p&gt;
&lt;p&gt;Second, if the worry is the organisers will go mad with power and ban people they don’t like, &lt;em&gt;not having a Code of Conduct won’t prevent that&lt;/em&gt;. Not having a Code of Conduct just says the organisers and members can do whatever is within their power. It’s an agreement that anything goes.&lt;/p&gt;
&lt;h2 id=&#34;but-i-cant-stop-people-contributing-they-can-just-fork-the-code&#34;&gt;But I can’t stop people contributing! They can just fork the code.&lt;/h2&gt;
&lt;p&gt;This is important. Repeat after me: &lt;strong&gt;the code is not the project&lt;/strong&gt;. The community around the code, the brand around the code, &lt;em&gt;these&lt;/em&gt; are your project. You can refuse to accept pull requests. You can refuse to give people authority in your community. To say there’s nothing you can do is misleading. You can’t stop people using your code or changing your code in their own repository, but that doesn’t mean they’re part of the project.&lt;/p&gt;
&lt;h2 id=&#34;this-is-censorship&#34;&gt;This is censorship!&lt;/h2&gt;
&lt;p&gt;Censorship is about suppressing speech. This is not suppressing speech. Anyone can say anything they want. All this is doing is making clear that there are repercussions for actions, and being clear about what actions will have repercussions. A &lt;em&gt;good&lt;/em&gt; Code of Conduct will even tell you what the repercussions will be!&lt;/p&gt;
&lt;p&gt;Not having a Code of Conduct does not prevent your actions from having repercussions. It just makes people guess which actions will have repercussions, and what those repercussions will be.&lt;/p&gt;
&lt;h2 id=&#34;ok-but-surely-people-are-entitled-to-their-opinions-on-twitterother-public-space&#34;&gt;OK, but surely people are entitled to their opinions on Twitter/{other public space}!&lt;/h2&gt;
&lt;p&gt;Of course they are. They’re just not entitled to voice their opinion with no repercussions. Nowhere is that a right, because that would be silly. You’re free to name your project &lt;a href=&#34;https://github.com/meh/fag&#34;&gt;as a slur for gay people&lt;/a&gt;, and I’m free to decide that I probably have a better use for my time than to contribute to that project. You’re free to tweet that racism is a myth, and black people are free to not contribute to or use your work.&lt;/p&gt;
&lt;p&gt;But when your community is led by someone that espouses an idea in public, that is a signal that your community finds that idea acceptable. And there’s nothing wrong with that. It could be that your community values “free speech” (by which they mean “consequence-free speech”) over all else. It could be that they actually agree with the idea.&lt;/p&gt;
&lt;p&gt;If people are offended, hurt, or upset by that idea, however, unless you take action, you are sending the signal that your community values the idea more than the people who are offended, hurt, and upset by it. Do not be surprised if those people want nothing to do with your project. You are, by the values you hold, excluding them from the project. Sure, you’ll accept contributions they may send you, but you’re making it unlikely they’ll send any contributions at all.&lt;/p&gt;
&lt;p&gt;As an example, I could say that all white dudes must pay me $5 per contribution before I’ll accept their contribution. I’ll accept their contribution, they just need to pay me to do it. But only white men need to pay. I’m excluding white men, right?&lt;/p&gt;
&lt;p&gt;That’s what you’re doing to marginalised people when you allow someone who is publicly marginalising them to hold a position of authority. You’re forcing them to deal with the emotional and mental problems (that nobody else has to deal with) that come from that figure of authority. You are forcing an emotional and mental tax on them.&lt;/p&gt;
&lt;h2 id=&#34;so-my-belief-that-marriage-is-between-a-man-and-a-woman-should-be-enshrined-in-the-code-of-conduct-and-respected-right-and-anyone-saying-gay-people-should-be-able-to-marry-or-any-married-gay-people-should-be-excluded-right&#34;&gt;So my belief that marriage is between a man and a woman should be enshrined in the Code of Conduct and respected, right? And anyone saying gay people should be able to marry, or any married gay people, should be excluded, right?!&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;YES&lt;/strong&gt;. 100% yes. That’s totally a valid thing to put in a Code of Conduct.&lt;/p&gt;
&lt;p&gt;But here’s the thing: don’t be surprised if no gay people, nobody who supports gay people, and nobody who has a problem with people trying to prevent gay people from getting married contributes to your project. Do not be surprised if those people fork your project, implement a new Code of Conduct, and build a new project around your codebase.&lt;/p&gt;
&lt;p&gt;Your Code of Conduct &lt;em&gt;is&lt;/em&gt; your community. It is the values you share and hold closest. Whether it’s written down or not, it is there. All people want you to do is to write it down, be explicit about it, and leave no room for confusion.&lt;/p&gt;
&lt;h2 id=&#34;can-you-give-me-a-tldr&#34;&gt;Can you give me a TL;DR?&lt;/h2&gt;
&lt;p&gt;Sure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You have a Code of Conduct; it’s what your community deems to be “ok”. People just want you to write it down.&lt;/li&gt;
&lt;li&gt;Your project is not your code. Forking your code doesn’t count as contributing to the project.&lt;/li&gt;
&lt;li&gt;You are entitled to say whatever you want. You are not entitled to not suffer any repercussions for whatever you say.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;my-pledge&#34;&gt;My pledge.&lt;/h2&gt;
&lt;p&gt;From today on, I will be checking every project before I make any contribution to it. If you do not have a Code of Conduct explicitly written down, I will not contribute to your project. I’m tired of Open Source being a cis het white dude zone. I’m tired of hearing “keep politics out of open source!” Software is made by people; people are political. We cannot keep politics out of open source. I’m tired of hearing a code of conduct isn’t necessary.&lt;/p&gt;
&lt;p&gt;Be clear about where your community stands. If it’s not a place I’m comfortable standing, that’s fine. I just will not be part of your community. But do not make people guess whether your community values them.&lt;/p&gt;
&lt;p&gt;We can do better than this. We need to do better than this.&lt;/p&gt;
</description>
      <carvers:summary>What a Code of Conduct means to me, why I think your Open Source project should have one, and responses to common objections to Codes of Conduct.</carvers:summary>
    </item>
    
    <item>
      <title>Here’s to the Yetis</title>
      <link>https://paddy.carvers.com/posts/yetis/</link>
      <pubDate>Thu, 09 Apr 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/yetis/</guid>
      <description>&lt;p&gt;It’s been a little while since I last posted, and I kind of want to get in the habit of posting more. (How will you know I’m alive if I’m not constantly sharing my opinions?)&lt;/p&gt;
&lt;p&gt;Also, today was kind of shitty, and &lt;a href=&#34;https://paddy.carvers.com/posts/negative/&#34;&gt;a lot of my posts tend to be about things that make me sad&lt;/a&gt;, so I figure it’s about time I just talked about something I love without really having a point. Or having several points. I don’t know.&lt;/p&gt;
&lt;p&gt;If you know me, you know where this is going: &lt;a href=&#34;https://andyet.com&#34;&gt;&amp;amp;yet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I believe I have the proud distinction of being &amp;amp;yet’s first fanboy. I don’t remember how it happened or when it started. I remember bumping into them, sort-of-kind-of-maybe, when I was investigating NodeJS. I picked that ball up and ran with it for a very short time, but never got very far. And yet (ha!), &amp;amp;yet remained in my life. From the excellent poem on their website, to the brand they’ve created, to the culture they promote.&lt;/p&gt;
&lt;p&gt;&amp;amp;yet is not my favourite company. &amp;amp;yet is my favourite group of people &lt;em&gt;that just so happen&lt;/em&gt; to &lt;a href=&#34;https://talky.io&#34;&gt;build cool things&lt;/a&gt; together. And get paid to make stuff. I think what I’m trying to get across is that, yes, they’re a company, but I don’t love them for the things they do as a company. I love them for the people they are. If &amp;amp;yet got bought today and replaced with entirely new people, even if the products stayed exactly the same, I wouldn’t love &amp;amp;yet anymore. I’d still just love those people. Which is not to say I don’t love new people who join the company; I totally do. &amp;amp;yet has had many and varied employees for differing amount of times, and as soon as I become aware of them, I universally end up loving them. But I don’t love them because they’re &amp;amp;yetis. &amp;amp;yet just happens to hire the kind of people I love.&lt;/p&gt;
&lt;p&gt;It’s kind of hard to explain how I relate to these people. Of course they’re my heroes, but… that seems too distant, impersonal. I have an &amp;amp;yet hoodie, that I got by simply asking for it. I treasure it. I &lt;a href=&#34;https://paddy.carvers.com/posts/realtimeconfeu/&#34;&gt;got to meet Adam&lt;/a&gt; and deliver a hug from the team to him. When I was in Philadelphia for training, I met up with &lt;a href=&#34;http://bear.im&#34;&gt;Bear&lt;/a&gt;, who gave me a hug. For each person on the team, by name, that heard we were meeting up and wanted to pass on a hug. We stood outside a bar embracing, stepping back, embracing, stepping back, over and over for at least five minutes. I got to meet up with &lt;a href=&#34;http://henrikjoreteg.com&#34;&gt;Henrik&lt;/a&gt; in Chicago because we happened to be in the same city at the same time and he kindly waited to meet up with me, see a giant bean, and chat about HTML5 and JavaScript, even though &lt;em&gt;I have no idea what I’m talking about&lt;/em&gt;. I got to meet up with &lt;a href=&#34;https://twitter.com/amydearest&#34;&gt;Amy&lt;/a&gt; and chat over bagels.&lt;/p&gt;
&lt;p&gt;And now they have &lt;a href=&#34;https://andyet.com/andyou&#34;&gt;an entire community&lt;/a&gt; of similarly wonderful people.&lt;/p&gt;
&lt;p&gt;And I love them all dearly.&lt;/p&gt;
&lt;p&gt;Sometimes it’s hard to explain, because I don’t stop loving people when they leave &amp;amp;yet, and sometimes I use “&amp;amp;yeti” to refer to people that don’t even &lt;em&gt;work&lt;/em&gt; for &amp;amp;yet and never have, but who I know exclusively through &amp;amp;yet. &amp;amp;yet isn’t a company, to me; it’s just a casual shorthand for “good, loving, compassionate, intentional people”. There is an entire group of people on Twitter that I can’t tell if they work for &amp;amp;yet or worked for &amp;amp;yet or just are always talking to &amp;amp;yet, but they’re decidedly my friends.&lt;/p&gt;
&lt;p&gt;In many ways, &amp;amp;yet is what I think of when I say “&lt;a href=&#34;https://paddy.carvers.com/posts/better/&#34;&gt;we can do better&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&#34;https://twitter.com/paddycarver/status/586292905704325120&#34;&gt;claimed&lt;/a&gt; today that you can tell how my day went based on how I react to &amp;amp;yet. Sometimes, it’s a pick-me-up to remember that a group of people like that can exist and work together. Sometimes, it’s a warm fuzzy feeling of remembering that people I respect and like &lt;em&gt;like me, too&lt;/em&gt;. Sometimes, it makes me sad and despondent, because the vibe of positivity and creativity and trying to do better is so far removed from my own reality that day.&lt;/p&gt;
&lt;p&gt;But I’m always happy to have &amp;amp;yet in my life. So here’s to the yetis.&lt;/p&gt;
</description>
      <carvers:summary>A love letter to some of my favourite people on earth.</carvers:summary>
    </item>
    
    <item>
      <title>Fool’s Literature</title>
      <link>https://paddy.carvers.com/posts/fool/</link>
      <pubDate>Mon, 02 Mar 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/fool/</guid>
      <description>&lt;p&gt;I tend to be a very &lt;a href=&#34;https://paddy.carvers.com/posts/negative/&#34;&gt;unhappy&lt;/a&gt; person. It’s just kind of the way things work out. I look to my left, I look to my right, and I tend to be dismayed by what I find. I’m constantly going on about how &lt;a href=&#34;https://paddy.carvers.com/posts/better/&#34;&gt;we can do better&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you work with me, you’ll recognise these traits in me, and will probably have a less complimentary way to describe them. It is a thing I try to be mindful of, to varying success.&lt;/p&gt;
&lt;p&gt;I was talking to my boss, &lt;a href=&#34;http://ry4an.org&#34;&gt;Ry4an&lt;/a&gt; (of whom I am a huge fan), and he told me I can portray myself as an “impractical zealot” at times. His use of the term, while gently and kindly intended, did not cast the impractical zealot in a good light. But when pressed to give myself a job title, I often insist upon calling myself an “Impractical Zealot and Windmill Jouster”.&lt;/p&gt;
&lt;p&gt;I get told a lot that it is my expectation, my &lt;em&gt;demand&lt;/em&gt;, that things get better that is at the root of all my existential angst. And I can more or less agree with this proposition. If, as many seem to suggest, I could just accept that everything is horrible and &lt;em&gt;that’s okay&lt;/em&gt;, then I would be much happier.&lt;/p&gt;
&lt;p&gt;And, to an extent, I actually believe this is the case.&lt;/p&gt;
&lt;p&gt;A lot of my internal turmoil right now revolves around the question of whether I should just give up on things and become &lt;em&gt;practical&lt;/em&gt;. Stop trying to make things &lt;em&gt;better&lt;/em&gt; and just try to let things go.&lt;/p&gt;
&lt;p&gt;I’m not entirely sure I can do that. My quest for “better” is what drives me. When I get out of bed it’s the thought that, when I go to sleep, I’ll leave things just a smidgen better that makes that worthwhile to me.&lt;/p&gt;
&lt;p&gt;When I don’t get out of bed it’s because I can’t conjure the belief that it actually matters. Not in the &lt;em&gt;put a dent in the universe&lt;/em&gt; sense, but in the simple &lt;em&gt;I’ll be happy tomorrow that I did&lt;/em&gt; sense.&lt;/p&gt;
&lt;p&gt;It happens more often than is probably good for me, at this point.&lt;/p&gt;
&lt;p&gt;But if there’s anything that defines the impractical zealot, the jouster of windmills, the greater fool, it’s &lt;em&gt;hope&lt;/em&gt;. The only way to become a greater fool is to hope, beyond all reason, that your endeavour will turn itself around. To hope, when all others have quit the field, that &lt;em&gt;things will get better&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Ironically, it’s not the part where things actually get better that interests me. I don’t need things to get better before I can be happy. In fact, I think it’s downright &lt;em&gt;dangerous&lt;/em&gt; to insist upon things &lt;em&gt;being&lt;/em&gt; better. Better is subjective, and being too invested in your version of better means that others will get left out in the cold. It means doing violence upon those who do not agree that your better is actually an improvement. It is a recipe for madness, chasing a utopia that will be as fault-ridden as the present.&lt;/p&gt;
&lt;p&gt;Instead, I find my happiness in &lt;em&gt;making&lt;/em&gt; things better. It is the process of improvement, not the end result of that process, that matters to me. I need not have my vision of better be achieved, I just need to be working towards something better. I can course-correct when I learn things and change. I can disagree with someone over what is better, but still find happiness in pursuing the common elements of our respective betters.&lt;/p&gt;
&lt;p&gt;I don’t need to make the whole world better. I can find happiness in just making my own little corner better.&lt;/p&gt;
&lt;p&gt;And I think that’s why I’m struggling. I’m not making my own little corner better. Getting out of bed wasn’t worth it.&lt;/p&gt;
&lt;p&gt;But I don’t know how to reclaim that agency, reclaim my ability to pursue &lt;em&gt;better&lt;/em&gt;. I work at it, but progress is frustratingly slow. I still feel like I have no latitude to make things better. But I still hope to regain that agency soon.&lt;/p&gt;
&lt;p&gt;More the fool me.&lt;/p&gt;
</description>
      <carvers:summary>I have a lot of existential angst about what I do and how I spend my time.</carvers:summary>
    </item>
    
    <item>
      <title>Washington</title>
      <link>https://paddy.carvers.com/posts/washington/</link>
      <pubDate>Fri, 09 Jan 2015 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/washington/</guid>
      <description>&lt;p&gt;Every few years, it seems, I’ve taken to moving. In 2008, I moved from Syracuse to Buffalo. In 2012, I started trying to move to San Francisco, and wound up back in Syracuse (long story). Then in 2013, I wound up in Buffalo again. Just before 2014 started, I switched over to Brooklyn to work for &lt;a href=&#34;https://www.dramafever.com&#34;&gt;DramaFever&lt;/a&gt;. And now here it is, the start of 2015, and I’m making plans to take &lt;a href=&#34;https://twitter.com/carver_ethan&#34;&gt;my fiancé&lt;/a&gt; and our &lt;a href=&#34;https://twitter.com/RoxyThePuppy&#34;&gt;puppy&lt;/a&gt; and head out to Washington when our lease ends in December, 2015. Yes, as in Washington State, across the country. No, not Washington D.C.&lt;/p&gt;
&lt;p&gt;And I haven’t blogged in a while, so I figured I’d write down some thoughts about it and what we’re looking for, our goals, and our rationale. Partially so I can think through it, and partially so I can point people here when they start asking me questions about it.&lt;/p&gt;
&lt;h2 id=&#34;the-prologue&#34;&gt;The Prologue&lt;/h2&gt;
&lt;p&gt;It took us only a few months (maybe six months, give or take?) to figure out we didn’t want to live in Brooklyn for years. I brought it up with DramaFever, and got approval to work fully remote, pretty much from anywhere. Which, hooray for forward-thinking employers. Our problems with Brooklyn are a subject for another post, but suffice to say:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We don’t think Brooklyn is a &lt;em&gt;bad&lt;/em&gt; place to live, we just think it’s the &lt;em&gt;wrong&lt;/em&gt; place to live &lt;em&gt;for us&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;We want a place that will let us have a backyard, a dishwasher, and laundry in-unit. Additionally, I’m finally willing to use a car to get around.&lt;/li&gt;
&lt;li&gt;I’d like to keep some of the money I earn instead of giving it to my landlord (though, to be clear, my landlord is amazing and we really lucked out). Brooklyn charges a premium for a certain set of value that it delivers, but we don’t want or take advantage of that value, so it’s not the right place for us.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, we want to move. Now what?&lt;/p&gt;
&lt;h2 id=&#34;narrow-the-search-region&#34;&gt;Narrow the Search: Region&lt;/h2&gt;
&lt;p&gt;We know we want to move, but we don’t know where. I promised this move to Ethan; he got the final say in where we go, because I dragged us to Brooklyn, and fair is fair. Ethan is notoriously terrible at making plans or making Major Life Decisions like this, so I had to help. We began with a process of elimination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Do we want to leave the country?&lt;/strong&gt; We have nothing against it, but we don’t want to take the amount of time we’d need to arrange work visas and all the headaches that go along with trying to live in a country you don’t have citizenship in. So we focused on the States. I think, ideally, we’d both enjoy holding dual-citizenship somewhere else, eventually. Not today.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Where are we considered people?&lt;/strong&gt; To narrow down the States, we crossed off every state that wouldn’t allow us to marry or adopt children.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fuck snow.&lt;/strong&gt; We’re kind of over the whole “get buried under snow every year” routine. He grew up in the fourth snowiest city in America, I grew up in the first. No snow, please.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not a desert.&lt;/strong&gt; Ethan doesn’t like being overly, uncomfortably hot, and we kind of prefer green things and life. I have a little bit of a romanticised crush on the southwest, because I like everything with bright colours, but I suspect the novelty would wear off pretty quickly, so I didn’t object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This process of elimination basically cut out the northeast, southeast, and southwest for us. We were left with what amounts to the Pacific Northwest. Which is okay by us; we’re both suckers for the trees. We also really like the range you can get: desert, mountains, forests, beaches. A little bit of everything, all within reasonable distance of each other. That’s a big plus.&lt;/p&gt;
&lt;h2 id=&#34;narrow-the-search-state&#34;&gt;Narrow the Search: State&lt;/h2&gt;
&lt;p&gt;The Pacific Northwest, or the part we’re looking at, basically amounts to Oregon and Washington. So we started figuring out where, between those two, we wanted to go.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Taxes&lt;/strong&gt;. Washington State, has no state income tax. Which, coming from New York, is a magical, magical thing. Oregon, on the other hand, has no sales tax. Which is also very nice. We hope to make more money than we spend, however, so it seems like the lack of income tax would be more beneficial than the lack of sales tax.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parks and Environment&lt;/strong&gt;. I’m marrying an animal nerd, so I guess this is important. Also, we probably should also go outside more, and it helps if you have somewhere to go outside to. Oregon has Mount Hood and the national park surrounding it, the Lewis and Clark national wildlife refuge, and Tillamook State Forest. Washington has Mount Rainier and the national park surrounding it, and the Olympic national park. Washington also gets points for the Puget sound. Either way, though, I don’t think we’ll be at a loss for nature to explore.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt;. From our brief and unscientific examination of Google Maps, it seems like it’s easier to get around Washington than Oregon. Oregon seems to have one main north/south highway (Route 5) that branches off to the east/west. Washington has ferries, and a forked highway system that means we can get from Port Angeles to Seattle in under three hours, or from Seattle to Richland in about three hours. So we felt that Washington was a little easier to get from place to place and take advantage of the whole state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;amp;yet&lt;/strong&gt;. Some of my favourite people in the world, &lt;a href=&#34;http://www.andyet.com&#34;&gt;&amp;amp;yet&lt;/a&gt; are based out of Richland, WA, which tips the scale ever-so-slightly towards being within driving distance of them. Because &lt;em&gt;c’mon&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither state has a really strong advantage over the other, but it looks like we slightly prefer Washington over Oregon, for entirely unscientific reasons.&lt;/p&gt;
&lt;h2 id=&#34;narrow-the-search-locale&#34;&gt;Narrow the Search: Locale&lt;/h2&gt;
&lt;p&gt;This is still an ongoing process, and we’re currently consulting Twitter. We know the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;We want a backyard.&lt;/strong&gt; We have a herding breed puppy. She likes to run. We would like to let her run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;We would like to have a little bit of space.&lt;/strong&gt; Ethan describes this as “I’d like to be able to look out my window without looking into my neighbour’s window.” I think it unlikely we’re going to be able to rent a place that fills that criteria within our budget, so that’s more of a vector than a hard requirement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;We want to live within our means.&lt;/strong&gt; We set our budget at $1500 a month in rent, which is a significant decrease in our current cost of living. If we can include utilities at that price range, that’s even better. Our projected budget shows that staying within that budget will allow us to build our savings. While that may seem like a lot, we’re looking at places with three or more rooms; one for a master bedroom, one for a home office, and one for visiting family and friends. We will be far from both our families, so we’d like to have a place for them to stay when they come visit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re currently examining in the area of Puyallup, somewhere on the Olympic peninsula, or somewhere within a couple hours of driving distance of Seattle. Which means we’ve narrowed it down to “somewhere within 75% of the state.”&lt;/p&gt;
&lt;p&gt;We have figured out we don’t want to live on the eastern side of Mount Rainier National Park, which is sad. That’s where &amp;amp;yet is, but that’s also quite a drive from the Seattle-Tacoma International Airport, which we’d like to be relatively close to, because it’s the cheapest way to fly across the country, and I get the feeling we’ll be doing that with some regularity.&lt;/p&gt;
&lt;p&gt;Other than that, though, we’re open to suggestions. Feel free to &lt;a href=&#34;mailto:paddy@carvers.com?subject=I%20know%20where%20you%20should%20live&#34;&gt;shoot me an email&lt;/a&gt; or &lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;ping me on Twitter&lt;/a&gt; if you have a suggestion on where we should move.&lt;/p&gt;
&lt;h2 id=&#34;getting-scared-about-the-weather&#34;&gt;Getting Scared About the Weather&lt;/h2&gt;
&lt;p&gt;Part of my research for any move is Googling what people hate about wherever I’m moving. It gives me a pretty good indicator about what I might hate and what I should be concerned about, which is generally a useful thing to know.&lt;/p&gt;
&lt;p&gt;For Washington, the resounding answer is the weather.&lt;/p&gt;
&lt;p&gt;From our research, it appears that rain is to Washington as snow is to New York: we should prepare to spend most our days with wet, gray weather. Which, to be perfectly honest, I’m not exactly pumped for. I’m a little worried that S.A.D. will make &lt;a href=&#34;http://paddyforan.getsby.co&#34;&gt;other issues&lt;/a&gt; even worse. But I’m also a little suspicious that the rain is a bit overstated, from looking at some figures.&lt;/p&gt;
&lt;p&gt;To get more accurate data on this, we sent a hunting camera out to &lt;a href=&#34;https://twitter.com/dead_lugosi&#34;&gt;my friend&lt;/a&gt; who lives on the Olympic peninsula, which is reportedly the worst area for the weather. She agreed to put it up outside, program it to take pictures every six hours or so, and send us the results every now and then. (She’s also working on &lt;a href=&#34;http://brunegame.com&#34;&gt;a crowd-funded game right now&lt;/a&gt;, so you should probably check that out.)&lt;/p&gt;
&lt;p&gt;That being said, we are used to spending six months out of the year in bitter cold, under snow, and generally miserable, so… we’re not exactly pampered, when it comes to winter. Maybe it won’t be so bad. We’ll be examining the data throughout the year to make a determination.&lt;/p&gt;
&lt;h2 id=&#34;planning-the-move&#34;&gt;Planning the Move&lt;/h2&gt;
&lt;p&gt;With a bit more to go on, we can begin planning. We narrowed down what we need to do: determine what possessions are worth dragging across the country behind us, determine how to get ourselves across the country, figure out how we’re going to get the pets (puppy, bearded dragon, pacman frog) across the country safely and without being assholes to the animals, and the schedule for the move.&lt;/p&gt;
&lt;p&gt;After some searching and math, we came up with the following, tentative plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ship what we can.&lt;/strong&gt; We can’t get a price quote from &lt;a href=&#34;http://www.pods.com&#34;&gt;PODS&lt;/a&gt; without calling them, and that’s a recipe for disaster. By going through &lt;a href=&#34;http://www.uhaul.com/UBox/&#34;&gt;U-Box&lt;/a&gt;, which is the U-Haul version of PODS, we got a quote for the move, and it seems to be the most reasonable approach. So we’re going to pack what we can into one of those, ship it across the country, and unpack it when we get there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abandon the dream of a cross-country drive.&lt;/strong&gt; Let’s be serious, who &lt;em&gt;doesn’t&lt;/em&gt; want to drive across the country with their fiancé and their puppy, with all their possessions in tow? But when you factor in the fact that we can’t pull a trailer behind a rental car, the fact that we aren’t willing to destroy a brand new vehicle by towing a trailer cross-country with it, and the frankly horrifying prospect of driving a moving truck across the country… it’s just not feasible. Which is sad, because I wanted to hang out with &lt;a href=&#34;https://twitter.com/zigged&#34;&gt;Sacha&lt;/a&gt; while stressed out and exhausted, because let’s face it, what could possibly go wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pretend the reptiles are bills and junk mail.&lt;/strong&gt; We’re just going to pack the reptiles up in carriers, toss in some heat packs, and have a friend overnight them once we get there. What could &lt;em&gt;possibly&lt;/em&gt; go wrong?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hope airlines care more about dogs than guitars.&lt;/strong&gt; We’re going to fly across the country and send the puppy on her first flight. She’s going to &lt;em&gt;hate us&lt;/em&gt; so much. But look, Roxy, a yard!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mooch horribly off family.&lt;/strong&gt; Our lease is supposed to end December 1st. Our internet service is supposed to end December 12th or something. &lt;em&gt;Obviously&lt;/em&gt;, one of these is more important than the other. So we’re working with our landlord to extend our lease by a couple weeks, then ship our crap and head upstate, where we’ll spend the holidays with our families (honestly, they may murder us violently in our sleep if we move right before Christmas again). We’ll spend a couple weeks with our families, then fly out to Washington in the first days of 2016.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Clearly, this is a comprehensive, sensible plan that has been thought out and well-researched.&lt;/p&gt;
&lt;p&gt;Obviously, we will end up doing pretty much anything but this.&lt;/p&gt;
&lt;h2 id=&#34;visiting-the-area&#34;&gt;Visiting the Area&lt;/h2&gt;
&lt;p&gt;We decided that we wanted to do three visits, mainly because Ethan gets two weeks of vacation time. So we’ll do two four-day trips to hang out and see this place we’re trying to move to. It’s a novel approach for me, but what the hell, right?&lt;/p&gt;
&lt;p&gt;We’ll visit once in February, because according to Twitter, that’s when Washington sucks the hardest. And I figure if we don’t get scared away then, we’re probably safe.&lt;/p&gt;
&lt;p&gt;We’ll also visit once in July, because according to Twitter, that’s when Washington is pretty great. And I figure we should probably really enjoy one of these trips, right?&lt;/p&gt;
&lt;p&gt;Finally, we’ll take a week in early December to find a place to live.&lt;/p&gt;
&lt;p&gt;Or that’s the plan at least. Let’s see how this works out. The areas to visit are still to be determined. Hopefully it will be less than “75% of the state.”&lt;/p&gt;
&lt;h2 id=&#34;after-the-move&#34;&gt;After the Move&lt;/h2&gt;
&lt;p&gt;That’s the plan. This ended up being &lt;em&gt;way&lt;/em&gt; more self-indulgent than I had thought at the start, but that’s ok, I think everyone that reads my blog is kind of used to that from me by this point.&lt;/p&gt;
&lt;p&gt;This is, I hope, my last major move. While we may move within the state when we get to Washington, trying out different areas, I’d like moving to start consisting of “rent a truck, put your crap in it, and unload it in a couple hours” instead of the months-long planning extravaganza it has been for the last few years. And yes, I think we’ll end up buying a house in Washington at some point in the future. So that is also something to look forward to.&lt;/p&gt;
&lt;p&gt;Then we just need to plan our wedding. So, you know, nothing going on in our household for the next few years.&lt;/p&gt;
</description>
      <carvers:summary>We’re looking at moving to the fine state of Washington, and people keep asking, so I thought I’d talk about it.</carvers:summary>
    </item>
    
    <item>
      <title>Child</title>
      <link>https://paddy.carvers.com/posts/child/</link>
      <pubDate>Thu, 06 Nov 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/child/</guid>
      <description>&lt;p&gt;I think I’ve grown up.&lt;/p&gt;
&lt;p&gt;That’s such a terrifying, anxiety-inducing sentence for me to put to paper. It feels like an existential threat.&lt;/p&gt;
&lt;p&gt;I’m having a hard time right now. I don’t know why. Well, I know &lt;a href=&#34;http://paddyforan.getsby.co&#34;&gt;why&lt;/a&gt;. But I don’t know why this particular moment is hard.&lt;/p&gt;
&lt;p&gt;When I was offered my first full-time job, I remember where I was. I remember what I was doing. I remember rushing home and calling a friend to tell him the news. Shaking. Panicking. I was going to have a real adult job and I just needed to hear the voice of somebody I loved. I needed the affirmation that some part of my life still held. That this wasn’t the end of everything I knew.&lt;/p&gt;
&lt;p&gt;I’ve always been a child.&lt;/p&gt;
&lt;p&gt;Childhood is a weird thing. It is the antithesis of empathy. It is existing in your own unique, all-encompassing world. Empathy is recognising other people’s worlds and respecting them. But to do that, you have to venture outside your own little comfort zone.&lt;/p&gt;
&lt;p&gt;It’s dangerous to go alone.&lt;/p&gt;
&lt;p&gt;I’ve been working hard on being more empathetic. I’m privileged. It is only fair that I use my privilege to try and make life better for the less privileged.&lt;/p&gt;
&lt;p&gt;I still am really bad at it. But I’m less bad.&lt;/p&gt;
&lt;p&gt;I’ve lost that myopia. I’m no longer Peter Pan, forgetting about my companions every so often or when something shiny distracts me. I’m no longer Dorian Gray, staring at myself all day.&lt;/p&gt;
&lt;p&gt;Well, I’ve lost &lt;em&gt;a little&lt;/em&gt;. As this proves, I’ve still got plenty of it.&lt;/p&gt;
&lt;p&gt;But children are also the ones that ask why, if I’m a boy, I have a boyfriend. and I say “because I love him.” and they say “Oh.” and that’s that.&lt;/p&gt;
&lt;p&gt;So sometimes children have more empathy than adults.&lt;/p&gt;
&lt;p&gt;Or maybe they care so little for the world outside themselves, they’re less invested in what it looks like. The world is simpler, because they aren’t looking closely.&lt;/p&gt;
&lt;p&gt;Either way, I almost kind of prefer it.&lt;/p&gt;
&lt;p&gt;But children also get more wonder out of the world. They want to share everything with you, beaming. Proud.&lt;/p&gt;
&lt;p&gt;I remember, distinctly, the feeling of being so excited about what I had made that I couldn’t wait to share it. It’s like being a balloon that’s about to pop. You have to drag the nearest person over and say “Look! See what I’ve made?” and they don’t care and you don’t care that &lt;em&gt;they&lt;/em&gt; don’t care because you’re infected with the pride and joy of doing a thing and now someone else knows, so it’s real.&lt;/p&gt;
&lt;p&gt;I can’t tell you the last time I felt that.&lt;/p&gt;
&lt;p&gt;And it hurts to admit that because I’m paid to do what I love.&lt;/p&gt;
&lt;p&gt;And I’ve lost the art of it.&lt;/p&gt;
&lt;p&gt;I center it around the users because that’s important to me. But we’ve made it so hard and everything’s so much work and I’m not sure I’m good enough. But all our effort at making things easier goes towards solutions that come at too high a cost because control and power are what corporations deal in now and this is the golden age.&lt;/p&gt;
&lt;p&gt;So I don’t take the easy way because how I do the thing is now as important as the thing being done which means that euphoria hit is not proportionate to my effort and comes after a long delay.&lt;/p&gt;
&lt;p&gt;But only children need immediate gratification.&lt;/p&gt;
&lt;p&gt;And I’m not a child.&lt;/p&gt;
&lt;p&gt;And that’s overwhelming.&lt;/p&gt;
&lt;p&gt;I’m shutting down.&lt;/p&gt;
&lt;p&gt;My boyfriend gently reminded me today that he’s not my errand boy. Because I keep asking him to go do things for me. Pick something up. Drop something off. Despite the fact that he works on his feet all day and I sit around and push buttons and sleep too much.&lt;/p&gt;
&lt;p&gt;I can’t find the words to tell him that walking out the front door puts me in contact with a world too big for me. With a world I can’t engage with on my own terms. With a world that is just… too overwhelming right now.&lt;/p&gt;
&lt;p&gt;Well, I guess those are the words. Surprise, Ethan. I love you.&lt;/p&gt;
&lt;p&gt;Still not his problem. Still not okay.&lt;/p&gt;
&lt;p&gt;As much as I hate to admit it, and as much as I hate to even think it, I have the recurring, distressing thought that I grew up when he followed me to Brooklyn. That’s a big burden to place on him, and that’s unfair. But even if it is the case, it was worth it. I’d do the same thing again tomorrow. I hope to do the same thing again soon. And maybe it will push this existential crisis further. Maybe it won’t. I don’t really care either way.&lt;/p&gt;
&lt;p&gt;But children do not have someone and their puppy relying on them. Not in a condescending, heteronormative, gender-roles-reinforcing financial sense. But he is very much my partner. In everything. And you take care of your partner.&lt;/p&gt;
&lt;p&gt;But children don’t take care of anyone. They’re taken care of.&lt;/p&gt;
&lt;p&gt;I’m still not ready to grow up.&lt;/p&gt;
&lt;p&gt;But ready or not, here it comes.&lt;/p&gt;
</description>
      <carvers:summary>I’m having a bit of an existential crisis. Don’t mind me.</carvers:summary>
    </item>
    
    <item>
      <title>Speaking of Mental Health…</title>
      <link>https://paddy.carvers.com/posts/mh-speaking/</link>
      <pubDate>Sun, 02 Nov 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/mh-speaking/</guid>
      <description>&lt;p&gt;For over a year now, I’ve been part of &lt;a href=&#34;http://engineyard.com&#34;&gt;EngineYard&lt;/a&gt;’s amazing &lt;a href=&#34;http://prompt.engineyard.com&#34;&gt;Prompt&lt;/a&gt; program. I’ve given a series of talks and been on a series of panels because of this program, but I realised this week that I’ve never made a formal offer on the subject. So here it is.&lt;/p&gt;
&lt;p&gt;I will come to your offices, to your team-building exercise, to your user group, to your conference. I will come prepared with a talk, or be there to do a brief overview of my experiences and then answer questions and just hold a discussion. If you are in Manhattan, Queens, or Brooklyn, I will get myself to your event and it will cost you nothing. If you are outside those areas, try to pick up the flights and room, if you can. If it is absolutely not in your budget, we can speak to Prompt about covering them.&lt;/p&gt;
&lt;p&gt;I will give you my time and talk about things that make me feel vulnerable and weak, because it is important that we do this. We talk about physical health in the workplace all the time. Employers sponsor gym memberships, and have physical health months. But we never talk about mental health. It’s hard. It’s not comfortable. But it’s important.&lt;/p&gt;
&lt;p&gt;I want to help you start a conversation about mental health. Please reach out if you’re interested.&lt;/p&gt;
&lt;p&gt;Contact info:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Email: &lt;a href=&#34;mailto:paddy@carvers.com&#34;&gt;paddy@carvers.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Twitter: @paddycarver&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;About me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I have been speaking about this for over a year. You can see &lt;a href=&#34;https://paddy.carvers.com/talks&#34;&gt;some of my talks&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I’m certified in &lt;a href=&#34;http://www.mentalhealthfirstaid.org&#34;&gt;Mental Health First Aid&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I am not a mental health professional&lt;/strong&gt;. I write code all day. I am here to start the conversation, but I cannot diagnose people, be a therapist, prescribe medication, or give you answers. I can instead point you to people who can and resources. I can only tell you about what does and does not work for me.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <carvers:summary>I will come talk to your organization, conference, or user group about mental health in tech.</carvers:summary>
    </item>
    
    <item>
      <title>Coming Out</title>
      <link>https://paddy.carvers.com/posts/coming-out/</link>
      <pubDate>Thu, 30 Oct 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/coming-out/</guid>
      <description>&lt;p&gt;Today coming out is in the news again, and while I have nothing special to say on that matter (“good for him!” kind of sums it all up), it coincides nicely with a lot of thinking I’ve been doing around coming out in the last few weeks.&lt;/p&gt;
&lt;p&gt;I have two ways of looking at this. The first is that I never really came out. The second is that I come out every day.&lt;/p&gt;
&lt;p&gt;When I was coming to terms with my sexuality as a teenager, my parents and I finally had a talk about it. It wasn’t very fun, and I don’t think any of us look back on that talk with much pride or fondness. But other than that, I never really… told anyone, specifically. They would find out when they saw me with a boyfriend, or heard about my boyfriend, or through some other relevant detail. In other words, I just kind of ignored it and waited to be asked or for it to become obvious, because &lt;em&gt;it didn’t deserve an announcement&lt;/em&gt;. I don’t run around telling everyone I meet that I’m right-handed. I don’t feel the need to make a grand announcement that I dislike olives. If it’s relevant, you’ll find out about it. If it’s not, who the fuck cares?&lt;/p&gt;
&lt;p&gt;None of this is meant as a critique of people who do feel the need to come out, to mark a point where the secret is widely known. That’s fine, and their own decision, and I support them completely in that. We all have a different relationship with this, and that’s okay.&lt;/p&gt;
&lt;p&gt;This is meant as a critique of the people who feel that someone they know coming out should be somehow about them.&lt;/p&gt;
&lt;p&gt;The other way to look at this is that I come out every day. Because every time I go to a hotel with my boyfriend and need to confirm that yes, we do only want one bed; or every time a coworker meets my boyfriend; or every time a recruiter asks about my family situation when trying to talk me into moving; or any time anyone notices I’m gay, I basically just came out to that person. Complete with the uncertainty of “Am I going to have to have a fight over this right now?”&lt;/p&gt;
&lt;p&gt;A few weeks ago, I was at a family event for my father’s side of the family. My father’s side is politically right-leaning, and rather conservative. I never brought a boyfriend around them, because (to be quite honest) I never really had any desire for my boyfriends to know them.&lt;/p&gt;
&lt;p&gt;We’re a little estranged like that.&lt;/p&gt;
&lt;p&gt;They’re family, and I love them, but it has never been super important to me to keep them up to speed on my love life.&lt;/p&gt;
&lt;p&gt;At the end of the event, a great aunt cornered me by myself and started asking about &lt;a href=&#34;https://paddy.carvers.com/posts/marine/&#34;&gt;my little brother&lt;/a&gt;. And none of the red flags went off, because my little brother was the only family member that wasn’t in attendance. So we chatted nonchalantly about my relationship with him, how we don’t get to talk much anymore, the usual.&lt;/p&gt;
&lt;p&gt;And then she pivoted. Hard.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“So does he know you came out?”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Err. Well that’s a hard question. I never really came out, so what do I say? My siblings never even got a “heads up, I like guys”—they got a “hey, meet my boyfriend”. I assume she means “does he know you’re gay?” and just say ”yeah, he knew for years”.&lt;/p&gt;
&lt;p&gt;“Oh,” she says, “so it was just a surprise for the rest of us.”&lt;/p&gt;
&lt;p&gt;And then she starts crying on me. “Just so long as you’re happy, that’s the important thing.” she assures me. I tell her thank you, I am. She repeats it.&lt;/p&gt;
&lt;p&gt;My family is Catholic. This is what a good ol’ fashioned Catholic guilting looks like, for those who aren’t familiar with it.&lt;/p&gt;
&lt;p&gt;But the reason I tell this story is not because my great aunt is somehow a bad person or to garner pity for having to talk to my relatives. I want to dissect this reaction, because she got to steer that conversation and it’s telling about how people interact with my gayness.&lt;/p&gt;
&lt;p&gt;First, she approached it through the lens of my little brother. My parents did something similar during our chat, suggesting my little brother would get beat up in school because of it. The point being made here is that I’m somehow selfish, or that this is unfair to others.&lt;/p&gt;
&lt;p&gt;For the record, my younger brother has never been anything but supportive of me. We’ve never talked about it, we’ve never had any interaction around it at all, and that’s really all I could ask for. He treats it as an inconsequential detail of my life.&lt;/p&gt;
&lt;p&gt;Second, I was supposed to feel guilty that I didn’t individually break it to my entire extended family (that would be the line about “surprise”), as if it was some confession that needed to be made or some achievement that needed to be celebrated. Honestly, I expected my extended family to find out when they were invited to my wedding, because that’s roughly the point around which it becomes relevant to them.&lt;/p&gt;
&lt;p&gt;As we talk about coming out, let’s just remember that in a perfect world, it doesn’t happen. And while it’s absolutely great to celebrate people coming out, it is not okay to have an expectation that every gay person will make an announcement out of it.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;Today coming out is in the news again, and while I have nothing special to say on that matter (“good for him!” kind of sums it all up), it coincides nicely with a lot of thinking I’ve been doing around coming out in the last few weeks.&lt;/p&gt;
&lt;p&gt;I have two ways of looking at this. The first is that I never really came out. The second is that I come out every day.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Not Invented Here</title>
      <link>https://paddy.carvers.com/posts/nih/</link>
      <pubDate>Wed, 22 Oct 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/nih/</guid>
      <description>&lt;p&gt;We’re circling back around in the dev community to talk about reinventing the wheel again. Sometimes you hear this referred to as “Not Invented Here Syndrome”.&lt;/p&gt;
&lt;p&gt;Because I’m a white, male, 20-something, &lt;em&gt;of course&lt;/em&gt; that means I &lt;em&gt;need to&lt;/em&gt; weigh in on this. Because I have a lot of feels about it.&lt;/p&gt;
&lt;p&gt;I’ve been criticised in the past for reinventing things. I actually gave &lt;a href=&#34;https://paddy.carvers.com/talks/treachery-of-hacker-news/&#34;&gt;an entire talk&lt;/a&gt; about how people got mad at me for making something and having the audacity to give it to them for free. So I’ve thought about this quite a bit. And I’ve come to a conclusion:&lt;/p&gt;
&lt;p&gt;Fuck right off.&lt;/p&gt;
&lt;p&gt;No, seriously, take your opinion and shove it.&lt;/p&gt;
&lt;p&gt;Here’s the thing: my time is mine. I get to use it however I want. If I want to stand on my head for hours, that’s my business. If I want to spend hours making something that has already been made, that’s my business. If I want to spend hours literally reinventing a wheel, guess what? Still my business.&lt;/p&gt;
&lt;p&gt;And a lot of people are on board with that, but still argue that I shouldn’t &lt;em&gt;want to&lt;/em&gt; reinvent the wheel. So today I want to talk about why you should reinvent the wheel.&lt;/p&gt;
&lt;h2 id=&#34;because-thats-how-you-learn&#34;&gt;Because That’s How You Learn&lt;/h2&gt;
&lt;p&gt;A lot of the hardest learned lessons of my career—the importance of testing, the importance of maintainability and ease of understanding, the importance of documenting what I do—are things I learned working on my own projects. Projects that I didn’t &lt;em&gt;really&lt;/em&gt; need to write myself, that &lt;em&gt;could&lt;/em&gt; have been accomplished through other means. Sure, I could’ve just stitched together other software to accomplish what I wanted, but then I wouldn’t have learned everything I did.&lt;/p&gt;
&lt;h2 id=&#34;because-knowing-how-stuff-works-is-important&#34;&gt;Because Knowing How Stuff Works Is Important&lt;/h2&gt;
&lt;p&gt;Bugs, loosely defined, are when our software doesn’t work the way we expect it to. I’ve found my tendency to &lt;em&gt;read&lt;/em&gt; the libraries I use is… not what it should be. Because it turns out it’s harder to read software than to write it.&lt;/p&gt;
&lt;p&gt;So the more libraries I use, the less I understand what my software is doing. And if I don’t understand what my software is doing, the more bugs I have, because the more incorrect expectations I have about how my software works.&lt;/p&gt;
&lt;h2 id=&#34;because-a-consistent-codebase-is-a-clean-codebase&#34;&gt;Because A Consistent Codebase Is A Clean Codebase&lt;/h2&gt;
&lt;p&gt;Libraries will not always conform to your particular conventions or styles. And usually that’s fine. If you use camelCase and a library uses snake_case, that generally isn’t a reason to rewrite the library.&lt;/p&gt;
&lt;p&gt;But if the way you approach the problem is fundamentally different, if the library integration sticks out like a sore thumb in your codebase, it may be worth it to reimplement the library to match the rest of your codebase. People reading your codebase will have an easier time. People debugging your codebase will have an easier time seeing what’s going on.&lt;/p&gt;
&lt;h2 id=&#34;because-diversity-matters&#34;&gt;Because Diversity Matters&lt;/h2&gt;
&lt;p&gt;We all saw what happened when a bug was found on &lt;a href=&#34;http://heartbleed.com/&#34;&gt;OpenSSL&lt;/a&gt;. While I’d argue crypto is a good area to avoid the NIH approach, it’s illustrative of an important point. Maybe a better example would be the relatively easier target that WordPress affords hackers.&lt;/p&gt;
&lt;p&gt;The more people use a specific technology, the more catastrophic any bugs or security flaws are. If we start with the premise that software is going to have bugs, and &lt;em&gt;all&lt;/em&gt; software is going to have bugs, then putting all of our eggs into a single basket may not be the best idea. Much like biological organisms diversify to keep a single virus from wiping them out, our ecosystem should have several solutions to a single problem.&lt;/p&gt;
&lt;h2 id=&#34;its-a-balance&#34;&gt;It’s A Balance&lt;/h2&gt;
&lt;p&gt;I’m not advocating Reinvent All The Wheels™—I’m just saying that blanket-condemning any reinvention is harmful, short-sighted, and really annoying.&lt;/p&gt;
&lt;p&gt;Some things should not be learning grounds, unless you’re willing to deal with the consequences of getting it wrong. Crypto, for example. Anything to do with money. Do not reinvent this unless you have ample opportunity to test your software, find bugs, and gain maturity… without putting your users at risk. Most people do not have that.&lt;/p&gt;
&lt;p&gt;But neither should you be afraid to write software just because someone else has already written something like it.&lt;/p&gt;
</description>
      <carvers:summary>Make. Relentlessly.</carvers:summary>
    </item>
    
    <item>
      <title>Prompt Panel at Distill ’14</title>
      <link>https://paddy.carvers.com/talks/distill14/</link>
      <pubDate>Thu, 07 Aug 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/distill14/</guid>
      <description>&lt;p&gt;In August, I was fortunate enough to be invited to &lt;a href=&#34;http://engineyard.com&#34;&gt;EngineYard&lt;/a&gt;’s &lt;a href=&#34;http://distill.engineyard.com&#34;&gt;Distill&lt;/a&gt; conference in San Francisco to speak about my experiences with mental illness.&lt;/p&gt;
&lt;p&gt;The talk was sponsored by EngineYard’s &lt;a href=&#34;http://prompt.engineyard.com&#34;&gt;Prompt&lt;/a&gt; program, which sponsors almost all my talks on mental illness in tech. I can’t give them enough credit for this program.&lt;/p&gt;
&lt;p&gt;If you aren’t following &lt;a href=&#34;https://twitter.com/MHPrompt&#34;&gt;Prompt on Twitter&lt;/a&gt;, you should be. And if you’re not certified in &lt;a href=&#34;http://mentalhealthfirstaid.org&#34;&gt;Mental Health First Aid&lt;/a&gt; (I am!), you totally should be. It’s absolutely worth your time. You’ll use it.&lt;/p&gt;
&lt;p&gt;A video of the panel is available &lt;a href=&#34;http://vimeo.com/105802592&#34;&gt;on Vimeo&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>I was fortunate enough to be invited to EngineYard’s Distill conference in 2014, to speak on a panel about their Prompt program and mental health.</carvers:summary>
    </item>
    
    <item>
      <title>We Are The Impressive Acts</title>
      <link>https://paddy.carvers.com/posts/we-are-impressive-acts/</link>
      <pubDate>Tue, 15 Jul 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/we-are-impressive-acts/</guid>
      <description>&lt;p&gt;I found myself reading past entries in &lt;a href=&#34;http://latentflip.com&#34;&gt;Philip Roberts’ blog&lt;/a&gt;. I’d say I’m not sure why I was reading through his archives, but that would be a lie. Secretly, I believe that everyone should read through his archives on a regular basis.&lt;/p&gt;
&lt;p&gt;In doing so, I came across &lt;a href=&#34;http://latentflip.com/rejection&#34;&gt;his thoughtful piece on rejection&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;His cry of failure cuts me deeper than I expect. In it I see my cries of failure, my tears of frustration in years gone by at my inability to just achieve things on the first, second, tenth try and to be accepted. As if we are all born perfect divers, skateboarders, mathematicians, lovers. As if the fact that we tried at all, even if we failed, is unimportant. How ridiculous a life to lead. To think that we should be perfect on our first, second even hundredth try. What a world this would be if we perfected everything instantly. How trivial, how easy, how boring!&lt;/p&gt;
&lt;p&gt;I know now what I should have done. What would have made Alex, myself and possibly everyone else feel much better about the world at that point. I should have congratulated him in his attempt. I should have walked over to him as he got out of the pool, stuck up my hand for a high-five, and said “good job! now go do it again”, with a big sincere smile on my face.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Then I saw the &lt;a href=&#34;http://kerr.io/rejection-done-right/&#34;&gt;predictable response&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The world does not need a lowering of the bar so that more people get congratulated for doing mundane things like jumping into a pool.  What we need instead are people with drive determined to continue to climb until they finally do something worthy of recognition.  Alex should take his lesson that jumping from the diving board didn’t illicit any sort of cheering and either learn to dive and possibly compete, quit diving all together, or be satisfied with the world not noticing how poorly he jumps off a diving board.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;These posts were written almost two full years ago. I almost didn’t write this, because of how old they are. But hey, it was worth saying then, and it’s worth saying now.&lt;/p&gt;
&lt;p&gt;The idea that there is an objective level of difficulty required to merit praise or celebration is &lt;em&gt;absurd&lt;/em&gt;. The idea that for some people, jumping off a high dive is not something to celebrate wildly is absurd. It is easier for certain individuals to form Fortune 500 companies and rise to the top of their industry than it is for them to jump off a high dive.&lt;/p&gt;
&lt;p&gt;Just because something is easy for you does not mean it is unworthy of celebration for someone else. Overcoming one’s fears is never mundane.&lt;/p&gt;
&lt;p&gt;I deserve celebration today. I got out of bed. That was hard. That was unreasonably hard, but I did it, and I am going to celebrate that. And I honestly have no time for anybody that thinks I shouldn’t.&lt;/p&gt;
&lt;p&gt;The author of the response post says “the world cheers for those who achieve impressive acts”.&lt;/p&gt;
&lt;p&gt;We &lt;strong&gt;are&lt;/strong&gt; the impressive acts. And we deserve to be celebrated.&lt;/p&gt;
</description>
      <carvers:summary>There is no objective metric of difficulty, and thus no act unworthy of celebration.</carvers:summary>
    </item>
    
    <item>
      <title>Adventures in Meatspace</title>
      <link>https://paddy.carvers.com/posts/its-not-you-its-me/</link>
      <pubDate>Mon, 30 Jun 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/its-not-you-its-me/</guid>
      <description>&lt;p&gt;So here’s the thing. I used to really, really love the casual connectedness of the Internet. I used to really, really love just speaking into the abyss and making friends when people replied.&lt;/p&gt;
&lt;p&gt;The operative word is “used to”.&lt;/p&gt;
&lt;p&gt;It has stopped being fun. It has started being work. It leaves me feeling drained, not invigorated.&lt;/p&gt;
&lt;p&gt;This could be the fault of &lt;em&gt;Kids These Days™&lt;/em&gt;. It could be that &lt;em&gt;Twitter is evil&lt;/em&gt;. It could be that I’m becoming a bitter old man (I &lt;em&gt;do&lt;/em&gt; turn 24 this month…)&lt;/p&gt;
&lt;p&gt;But here’s the thing: I don’t care anymore. I really, honestly, with all my heart, could not care less about which of those statements, if any, is true.&lt;/p&gt;
&lt;p&gt;And when I don’t care, it’s time to step away.&lt;/p&gt;
&lt;p&gt;So I’m going to step away for the month of July. I’m uninstalling Twitter on my phone. I’m blocking it on my computers.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong; I love the people I’ve met there. If we exchange @mentions even infrequently, or even if we exchanged them once, this is not a slight on you, nor a desire for you to stay away. I sincerely hope you will email me, text me, write love letters in my HTTP Referer logs, &lt;em&gt;knock on my goddamn door&lt;/em&gt;, and otherwise stay in touch. I’ll still be on XMPP. I’ll still hop on Freenode infrequently. I’ll still answer email, and I still want to see you.&lt;/p&gt;
&lt;p&gt;The people I’ve met are the reason something like this will be hard, because I rely on them for inspiration and courage and hope and smiles. I rely on &lt;em&gt;you&lt;/em&gt; for these things.&lt;/p&gt;
&lt;p&gt;But the scales have finally tipped, and it’s become a net negative in my life. So it is time for it to go.&lt;/p&gt;
&lt;p&gt;In the meantime, I might end up blogging more frequently here. Subscribe if you haven’t and you want to stay up to speed.&lt;/p&gt;
&lt;p&gt;I’ve also decided I am going to, at long last, start working on Tangles, a blogging project I’ve wanted to get going for, quite literally, years now. It will be running at &lt;a href=&#34;http://tangles.paddy.io&#34;&gt;tangles.paddy.io&lt;/a&gt; and will eventually become this blog, once I get the software to a stable enough state. I’ll post updates here if I get it going in the next month, but no promises.&lt;/p&gt;
&lt;p&gt;I’m planning to implement the blocks and uninstalls when I wake up July 1st. Make sure we swap contact information by then.&lt;/p&gt;
&lt;p&gt;I’ll see you all soon. Please be here when I get back. Please come find me while I’m gone.&lt;/p&gt;
&lt;p&gt;Hugs always,&lt;br&gt;
Paddy&lt;/p&gt;
</description>
      <carvers:summary>I’m leaving Twitter for the month of July.</carvers:summary>
    </item>
    
    <item>
      <title>Scared Shipless</title>
      <link>https://paddy.carvers.com/posts/scared-shipless/</link>
      <pubDate>Wed, 04 Jun 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/scared-shipless/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Sit down. Okay, let me hear it.&lt;/p&gt;
&lt;p&gt;You know—the thing you’re really passionate about. It’s distracting you completely right now. It keeps you up, wakes you up, and catches you daydreaming in between the rude interruptions of real life.&lt;/p&gt;
&lt;p&gt;You look down, take a breath, and then it all comes out, bursting forth like you’ve just backed over a sprinkler, a blubbering apology to your dreams for not living them.&lt;/p&gt;
&lt;p&gt;“I really want to—”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Great. Then you should do it.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;That’s an excerpt from &lt;a href=&#34;http://adambrault.com/2013/05/08/then-you-should-do-it&#34;&gt;Then you should do it.&lt;/a&gt;, a post by one of my favourite people in the world, &lt;a href=&#34;http://adambrault.com&#34;&gt;Adam Brault&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What I’m passionate about, what I”d do even if I had to pay to do it, is writing software in a socially just way.&lt;/p&gt;
&lt;p&gt;I’m very privileged. I have a lot of power that I didn’t really earn, at least no more so than many of those without power. I have a lot of freedom that I did nothing special to earn, freedom that is denied many of my peers.&lt;/p&gt;
&lt;p&gt;And most importantly, I’m in a position to shape, in very tangible ways, the world around me.&lt;/p&gt;
&lt;p&gt;Software is not a panacea, software is not the end-all-be-all, and software cannot solve all our problems. But software sure as hell should not be perpetuating our problems. &lt;a href=&#34;https://paddy.carvers.com/posts/superhuman/&#34;&gt;But it is.&lt;/a&gt; Rather than equalizing, software &lt;a href=&#34;https://paddy.carvers.com/posts/better/&#34;&gt;is polarizing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;People who can write software are becoming rich. They’re doing it by selling out the people who can’t write software.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://writing.jan.io/2013/08/16/lets-start-a-revolution.html&#34;&gt;We need a revolution.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;None of this is new. I’ve said this for a long time. A lot of people have said this for a long time, many of them more eloquently than I have.&lt;/p&gt;
&lt;p&gt;The reason I bring it up is because this is what I desperately want to be doing. This is what comes gushing out when I talk to people.&lt;/p&gt;
&lt;p&gt;I want to write open source software.&lt;/p&gt;
&lt;p&gt;I want to have an &lt;a href=&#34;http://opencompany.org&#34;&gt;open company.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I want to &lt;a href=&#34;http://indiewebcamp.com&#34;&gt;empower users, not constrain them.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And for a while, I was &lt;a href=&#34;https://paddy.carvers.com/posts/2cloud/&#34;&gt;doing just that&lt;/a&gt;. I learned how to write software and have a company and be responsible for users the hard way, by doing it.&lt;/p&gt;
&lt;p&gt;And then I left college, and I went to work for &lt;a href=&#34;http://iron.io&#34;&gt;one company&lt;/a&gt; and now &lt;a href=&#34;http://www.dramafever.com&#34;&gt;another&lt;/a&gt;, because I have student loans to pay and rent to pay. Because that’s the easy way to do that. And because the companies are companies I love, companies I support. It wasn’t selling my soul, it was an approximation of what I wanted that also put bread on the table.&lt;/p&gt;
&lt;p&gt;But since then, I’ve released nothing of substance on my own time.&lt;/p&gt;
&lt;p&gt;Sure, I released &lt;a href=&#34;http://secondbit.org/blog/introducing-pastry/&#34;&gt;Wendy&lt;/a&gt;, a Distributed Hash Table I wrote. It’s buggy, not production-ready, and more or less abandonware at this point. As you can tell, I’m very proud of it.&lt;/p&gt;
&lt;p&gt;I released &lt;a href=&#34;http://getsby.co&#34;&gt;Gets By&lt;/a&gt;, and I’m tremendously proud of the individuals that contributed their stories. But let’s be honest, all I did was hook up a &lt;a href=&#34;https://github.com/mojombo/jekyll&#34;&gt;static site generator&lt;/a&gt; to Nginx and automate it with &lt;a href=&#34;http://www.ansible.com&#34;&gt;Ansible&lt;/a&gt;. I did it in a weekend. I’m proud of the people, not my software.&lt;/p&gt;
&lt;p&gt;I’ve been “working on” the next version of 2cloud for, let’s all count… &lt;em&gt;32 months&lt;/em&gt; now.&lt;/p&gt;
&lt;p&gt;Let’s talk about insane development cycles, shall we? Almost 3 years of iterating a single version on a product that is already in the hands of thousands of users. Who thought that was a good idea?&lt;/p&gt;
&lt;p&gt;Well, nobody. I never &lt;em&gt;meant&lt;/em&gt; to do it.&lt;/p&gt;
&lt;p&gt;And the guilt and shame eats at me.&lt;/p&gt;
&lt;p&gt;In those 32 months, I’ve gone through countless architectures, coding styles, and databases. Rewrite upon rewrite upon rewrite. I’ve written more versions of 2cloud than the internet has written to-do list apps.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;By all logic, I shouldn’t be. I have users waiting for that software, users saddled with the buggy software of my yesteryears until I finish the new version. Why am I taking my sweet time in writing it?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I’m scared.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Terrified, petrified, anxiety-ridden. It haunts me and shapes me, this fear.&lt;/p&gt;
&lt;p&gt;I’m afraid, because until I release this update, it has potential. Once it is released, its potential is lost. It is now real; it is no longer &lt;em&gt;going to be&lt;/em&gt; something, it &lt;em&gt;is&lt;/em&gt; something. And I’m not as good at &lt;a href=&#34;https://paddy.carvers.com/posts/negative/&#34;&gt;picking faults and tearing down&lt;/a&gt; things that are going to be. But once a thing is, it’s fair game. All its unsanded edges, all its blemishes, I see them and can’t ignore them.&lt;/p&gt;
&lt;p&gt;And I know what the solution is, and that’s what is so frustrating about this. The solution is to release it, and congratulate myself on the work I’ve done, then go about sanding down the blemishes whenever I see them.&lt;/p&gt;
&lt;p&gt;But first I need to get over that initial fear and actually ship something and call it “good enough”.&lt;/p&gt;
&lt;p&gt;And what scares me, what terrifies me, is that a user will see the same blemishes and faults and failures I do, and they’ll ask me about them. Even nicely. Even asking me why something works the way it does, why the user has to do more work than they should… that’s terrifying.&lt;/p&gt;
&lt;p&gt;But I can’t just stop shipping things.&lt;/p&gt;
&lt;p&gt;And this fear has bled over. I now have trouble shipping anything at all. My Github repos are tombstones of half-finished projects, ideas that are fully-formed and partially implemented.&lt;/p&gt;
&lt;p&gt;Because that’s what is safe.&lt;/p&gt;
&lt;p&gt;But I’m tired. I’m so tired of not shipping anything. I’m tired of talking about what things &lt;em&gt;will&lt;/em&gt; be, knowing they likely never will &lt;em&gt;be&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I’m tired of being afraid.&lt;/p&gt;
</description>
      <carvers:summary>It has been a super long time since I’ve shipped any software of substance.</carvers:summary>
    </item>
    
    <item>
      <title>Negative</title>
      <link>https://paddy.carvers.com/posts/negative/</link>
      <pubDate>Tue, 03 Jun 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/negative/</guid>
      <description>&lt;p&gt;For the last year or so, I’ve gotten a lot of feedback about how I approach my work. Feedback about how I approach my life. I hear one thing consistently.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You’re very negative.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And it’s true. I have a tendency to notice things that are less than ideal, and point them out. Then keep pointing them out, hammering them home until they’re fixed.&lt;/p&gt;
&lt;p&gt;And I’m not sure how to feel about this.&lt;/p&gt;
&lt;p&gt;Because it’s no fun working with the hyper-critical guy. It’s no fun to hear ad-nauseum about the things you want to change, but don’t have the time to fix right now. It’s no fun to hear about how your work falls short of its ideals.&lt;/p&gt;
&lt;p&gt;Because it’s no fun to constantly be dissatisfied with everything. I’m hardest on my own work, as hard as I am on the work of others. But I also hate that I can’t just enjoy something for what it is, without thinking about what it should be. I feel like all of my work at this point is a tension between what I know I should be doing and what I have the time to do. I subscribe to the idea that “if you don’t have time to do it right, when will you ever find time to do it over?” while simultaneously realising that until it ships, it represents a business loss.&lt;/p&gt;
&lt;p&gt;Because it presents an uncomfortable amount of hubris to suggest that I can see how something &lt;em&gt;should&lt;/em&gt; be, what its ideal version looks like. Especially when it isn’t my own work.&lt;/p&gt;
&lt;p&gt;But the thing is, there’s another bit of feedback I consistently receive:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You’re valuable because you care.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Apparently, what makes me even sort of decent at what I do is that I care about providing a good experience to users. Probably to a fault, I care about what it’s like to use the things I make.&lt;/p&gt;
&lt;p&gt;And how can I make a user’s experience better if I can’t see where it could stand to improve?&lt;/p&gt;
&lt;p&gt;Maybe the fault lies in how I criticise things, not that I criticise everything. When I get frustrated, I tend more towards absolutes (e.g., “Our API is bad”) and less towards identifying what is making me frustrated (e.g., “Having polymorphic return types is really making my life more difficult than it needs to be”). Perhaps making the switch in how I criticise things would make others less likely to note my negativity.&lt;/p&gt;
&lt;p&gt;But that’s the thing; it’s not just that other people think I’m negative that bothers me. Yes, I’d much rather be a positive influence on people’s lives. Yes, the effect I have on other people matters to me. But even if I said nothing, I think this would still bother me.&lt;/p&gt;
&lt;p&gt;I haven’t shipped anything, &lt;em&gt;really&lt;/em&gt; shipped anything, in over a year now. And while I have a post I’m mulling over about that, it’s worth bringing up here:&lt;/p&gt;
&lt;p&gt;If I constantly focus on how things should be better, it becomes much harder to ever release anything.&lt;/p&gt;
&lt;p&gt;I refuse to subscribe to the school of thought that I should ship something before it’s actually at a certain level of quality—until it actually provides a service to the user, really. But I find myself swinging to the opposite end of the spectrum, with years-long development cycles.&lt;/p&gt;
&lt;p&gt;Which is &lt;em&gt;insane&lt;/em&gt; and drives an unsustainable level of guilt in my life.&lt;/p&gt;
&lt;p&gt;One of the things I love most about &lt;a href=&#34;http://andyet.com&#34;&gt;&amp;amp;yet&lt;/a&gt; is that they continue to push for better and better experiences, but they’re unrelentingly positive in how they do it. It’s a trick I need to learn.&lt;/p&gt;
&lt;p&gt;In the meantime, if you see me being negative about stuff, just call me out on it. Part of the solution to this problem may be in becoming aware of how frequently I’m picking flaws in stuff.&lt;/p&gt;
</description>
      <carvers:summary>I think I might need an attitude adjustment.</carvers:summary>
    </item>
    
    <item>
      <title>Depressed For A Day</title>
      <link>https://paddy.carvers.com/talks/tek14-summit/</link>
      <pubDate>Wed, 21 May 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/tek14-summit/</guid>
      <description>&lt;p&gt;This is a talk I delivered at &lt;a href=&#34;http://tek.phparch.com&#34;&gt;php[tek] 2014&lt;/a&gt; during the &lt;a href=&#34;http://tek.phparch.com/mental-health-summit/&#34;&gt;Mental Health Summit&lt;/a&gt;. It should be noted that my ability to attend this conference and speak on this topic was directly afforded to me through EngineYard’s awesome &lt;a href=&#34;http://prompt.engineyard.com&#34;&gt;Prompt&lt;/a&gt; program.&lt;/p&gt;
&lt;p&gt;This talk was delivered as a monologue. There were no slides, nothing memorized, just a scared kid on a stage with a notebook and a microphone. You can find the video &lt;a href=&#34;http://vimeo.com/97972519&#34;&gt;on Vimeo&lt;/a&gt;, but I’ve transcribed the talk in its entirety.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hi everyone, my name’s Paddy. I write software for a great company in New York City. I was asked to come talk to you about depression today, and at first I was at a loss for what to say. I could talk about how it makes my life more challenging, the pain and complexity it introduces. I could talk about the terrible state of treatment for it. But I want to do something else. I want to try to give you a complete picture.&lt;/p&gt;
&lt;p&gt;But I can’t limit this to my own experiences. I am extremely fortunate; through no special feats or effort or talents of my own, I manage to function at an unexpectedly normal level. I can pass myself off as health, with only the most attentive catching on. And as lucky as I am, some are more fortunate. Some are less. Depression is a spectrum, and my experiences aren’t enough to give you an accurate representation.&lt;/p&gt;
&lt;p&gt;So in my ten minutes, of which I suspect roughly nine remain, I’d like to try to tell you what every variation of depression is like.&lt;/p&gt;
&lt;p&gt;I’m going to fail, but if I’ve learned anything, it’s that trying things I know I’ll fail at is necessary to move forward.&lt;/p&gt;
&lt;p&gt;Before we begin, I need to ask you to close your eyes. And keep them closed.&lt;/p&gt;
&lt;p&gt;This is uncomfortable, I know. Closing your eyes in a public place makes you feel vulnerable. If there’s any approximation of depression I can give you, it’s this. This vulnerability.&lt;/p&gt;
&lt;p&gt;With that, we’re ready to begin.&lt;/p&gt;
&lt;p&gt;It’s eight a.m. Your alarm goes off.&lt;/p&gt;
&lt;p&gt;Or it doesn’t. Maybe you didn’t bother to set an alarm, thinking it doesn’t matter when or even if you wake up.&lt;/p&gt;
&lt;p&gt;You turn off the alarm and sit up.&lt;/p&gt;
&lt;p&gt;Or maybe you don’t. You hit the snooze button and fall back asleep, the hypersomnia of your depression keeping you in bed. Or the thought of facing your day is too overwhelming, so you hide under the covers, like nobody will find you.&lt;/p&gt;
&lt;p&gt;Your significant other rolls over and smiles at you, happy to see you.&lt;/p&gt;
&lt;p&gt;Or they don’t, because you argued with them last night in a mood you can’t rightly explain, that you knew was silly even as you felt it, and they’re still hurt.&lt;/p&gt;
&lt;p&gt;Or they don’t, because you don’t have a significant other, because you can’t believe anyone could love you, so you never open yourself to that possibility.&lt;/p&gt;
&lt;p&gt;You shower and leave your apartment or house.&lt;/p&gt;
&lt;p&gt;Or you don’t, because the thought of putting on clothes and cleaning yourself up feels exhausting, and it’s cold out, and your bed is right there.&lt;/p&gt;
&lt;p&gt;Or you don’t, because stepping outside is an act of faith that there’s something out there you want to experience.&lt;/p&gt;
&lt;p&gt;On the subway, you see the other people around you, and you wonder how they manage to function in their normal lives. You wonder what it’s like to have a normal life.&lt;/p&gt;
&lt;p&gt;No matter how depression affects you, you can’t help but wonder what it’s like to not be depressed.&lt;/p&gt;
&lt;p&gt;When you get to the office, you see your coworkers.&lt;/p&gt;
&lt;p&gt;Or you don’t, because you can’t get a job, because nobody will hire you—they think you’re unreliable and sporadic, and you can’t even protest, because you know they’re right. You’ve proven them right too many times.&lt;/p&gt;
&lt;p&gt;Or you arrive at the office and look around at all the talented individuals you work with, and feel like a fraud. They’re reliable, they think you’re reliable, but you know it’s only a matter of time before you prove them wrong.&lt;/p&gt;
&lt;p&gt;You go through your work day, and you can’t focus, because your brain petulantly refuses to think about the task at hand. It flits from task to task, keeping busy but never really accomplishing much.&lt;/p&gt;
&lt;p&gt;Or you can, but your body is reacting badly to your medication, so you can’t do your best work.&lt;/p&gt;
&lt;p&gt;Or you do your best work, and are terrified, because you know your best work comes right before the crash, and everything is going to go up in flames soon.&lt;/p&gt;
&lt;p&gt;Or maybe, just maybe, doing your work is the only place you feel normal.&lt;/p&gt;
&lt;p&gt;You sit in a meeting and feel bad about what you’ve accomplished. You’re always playing catch-up.&lt;/p&gt;
&lt;p&gt;Or you’re on top of your game, but you can’t create the interpersonal relationships you need to be effective in a team.&lt;/p&gt;
&lt;p&gt;Or everything’s going great, but you can’t help but wonder how much of your success—usually in a creative endeavour—is thanks to the illness you feel is such a handicap. You wonder if you’ll be as effective if that illness is cured. Not for the first time, you wonder whether your mental illness can be cured without fundamentally changing who you are. You wonder if your illness is part of who you are. You wonder if the pills you may or may not be taking, whether or not they’re prescribed, are killing off a part of you.&lt;/p&gt;
&lt;p&gt;You wonder if you’re okay with that.&lt;/p&gt;
&lt;p&gt;You wonder if this is how self-improvement happens, or if this is how peer-pressure works: forcing anything different to conform.&lt;/p&gt;
&lt;p&gt;You wonder if you really trust the people giving you pills that may change who you are.&lt;/p&gt;
&lt;p&gt;You get back on the subway to come home. Or maybe you never left. You cook dinner so your significant other can come home to a meal.&lt;/p&gt;
&lt;p&gt;Or you don’t, because the knives are kept under lock and key after last time.&lt;/p&gt;
&lt;p&gt;Or you lay on the floor and stare at the ceiling, thinking about everything and nothing.&lt;/p&gt;
&lt;p&gt;Or you collapse on the couch and fall asleep, worn out, to be woken by your significant other coming home, apologies for falling asleep already spilling out of your mouth.&lt;/p&gt;
&lt;p&gt;You sit and talk, or watch TV, and you reflect on your luck for having someone love you and support you.&lt;/p&gt;
&lt;p&gt;Or you worry that you’re slipping, and knowing they won’t understand.&lt;/p&gt;
&lt;p&gt;Or you see them try so hard to understand, see the pain as they wonder if it’s something they did, some failing of theirs. You don’t know how to reassure them that they’re perfect. That taking responsibility for your happiness is setting themselves up for failure.&lt;/p&gt;
&lt;p&gt;Your parents call. They’re worried about you. They check in to make sure you’re okay, with seemingly innocuous questions about work and your weekend and your plans.&lt;/p&gt;
&lt;p&gt;Or they really are innocuous. But you can’t help but feel that if they only knew how little you loved yourself sometimes, they’d be devastated. You pretend through the rough spots, when you most need help, to be fine. Because you can’t hurt them like that.&lt;/p&gt;
&lt;p&gt;When you go to bed, you lie awake, worrying about everything or nothing or both at once.&lt;/p&gt;
&lt;p&gt;Or your insomnia permits you to be tired, but not sleep.&lt;/p&gt;
&lt;p&gt;Or you fall asleep immediately, praying you’ll wake up in the morning to do it all over again.&lt;/p&gt;
&lt;p&gt;Or if it was a terrible day, you fall asleep immediately, praying you don’t wake up in the morning.&lt;/p&gt;
&lt;p&gt;No matter what, you’re not looking forward to tomorrow. That’s what depression means to me: never looking forward to tomorrow.&lt;/p&gt;
&lt;p&gt;That’s just one day. One hypothetical day, for a few hypothetical people. There are greater fluctuations. Not everyone lives in a city. Some people live in places where their illness is not recognized, where people ask why they can’t just stop being sad.&lt;/p&gt;
&lt;p&gt;Some people are so adept at dealing with it, they don’t even realise they’re ill.&lt;/p&gt;
&lt;p&gt;That was also trying to capture an ordinary day. There are good days, where you can’t conceive of being sad, where you go to bed feeling like everything in your life was worth it, for that one day.&lt;/p&gt;
&lt;p&gt;There are also terrible days, where you want to blot out the world and everyone in it, where you want to run until nobody can find you.&lt;/p&gt;
&lt;p&gt;Where you want to escape.&lt;/p&gt;
&lt;p&gt;What makes a day good or bad isn’t necessarily what happened that day.&lt;/p&gt;
&lt;p&gt;It’s not something that lends itself to metaphor. It’s not something you can set specific symptoms for, to easily recognise in people whether they want you to or not.&lt;/p&gt;
&lt;p&gt;Your mood doesn’t sneeze.&lt;/p&gt;
&lt;p&gt;Your brain doesn’t run a fever.&lt;/p&gt;
&lt;p&gt;Your emotions don’t get the chills.&lt;/p&gt;
&lt;p&gt;If you want to support people with depression, or any mental illness, the best advice I can give you is to have empathy for anyone and everyone.&lt;/p&gt;
&lt;p&gt;Be as kind as you can possibly be.&lt;/p&gt;
&lt;p&gt;Seek to understand those around you, to see them as they see themselves. To help them be the best versions of themselves by &lt;em&gt;their&lt;/em&gt; values, not by yours.&lt;/p&gt;
&lt;p&gt;In the best case scenario, you will quite literally save lives.&lt;/p&gt;
&lt;p&gt;In the worst case scenario, when nobody around you is suffering—which is unlikely—you’ll have been a fantastic human being for no reason whatsoever.&lt;/p&gt;
&lt;p&gt;That’s a pretty good worst case scenario.&lt;/p&gt;
&lt;p&gt;Thank you so much for your time. We’re almost done. If you have any questions, feel free to approach me and ask. If you’d rather, feel free to &lt;a href=&#34;mailto:paddy@carvers.com&#34;&gt;email me&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And if you’re suffering, just know that some stupid software engineer living in Brooklyn loves you, even if you’re having trouble loving yourself right now.&lt;/p&gt;
&lt;p&gt;Even if he’s having trouble loving himself right now.&lt;/p&gt;
&lt;p&gt;Open your eyes.&lt;/p&gt;
&lt;p&gt;Thank you.&lt;/p&gt;
</description>
      <carvers:summary>Depressed For A Day is a talk I gave at php[tek] as part of the Mental Health Summit, thanks to the sponsorship of EngineYard’s Prompt program.</carvers:summary>
    </item>
    
    <item>
      <title>Superhuman</title>
      <link>https://paddy.carvers.com/posts/superhuman/</link>
      <pubDate>Sun, 23 Mar 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/superhuman/</guid>
      <description>&lt;p&gt;My name is Paddy Foran, and I make superhumans.&lt;/p&gt;
&lt;p&gt;Anthropologists believe that technology is a major driving factor in the development of human civilization. Civilization is what allows us to perform feats outside the range of our biological abilities; it’s what permits us to build pyramids and skyscrapers, field armies and create advanced medicines.&lt;/p&gt;
&lt;p&gt;We are all superhumans, capable of so much more than our predecessors and even ancestors. We’ve connected our world—I have more friends across the Atlantic Ocean than I do in the city I live in.&lt;/p&gt;
&lt;p&gt;My work is in adding to those capabilities. It’s what I do, what I aim for.&lt;/p&gt;
&lt;p&gt;That is the purpose of technology.&lt;/p&gt;
&lt;p&gt;Some would have you believe that technology exists to serve a business, that technology is useful precisely to the degree that it drives revenues and profits. That the technology itself doesn’t matter, that whether it empowers or constricts its users doesn’t matter, that all that matters is whether the company’s valuation is increased or not.&lt;/p&gt;
&lt;p&gt;They are wrong. They are parasites, sucking dry our society and the people who are tasked with making superhumans.&lt;/p&gt;
&lt;p&gt;The business is useful insofar as it builds better superhumans.&lt;/p&gt;
&lt;p&gt;Insofar as it enables us to do so much more than we were able to do yesterday.&lt;/p&gt;
</description>
      <carvers:summary>Technology exists to make us superhuman, not rich.</carvers:summary>
    </item>
    
    <item>
      <title>An Open Letter To Recruiters</title>
      <link>https://paddy.carvers.com/posts/recruiters/</link>
      <pubDate>Wed, 26 Feb 2014 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/recruiters/</guid>
      <description>&lt;p&gt;Dear Recruiter,&lt;/p&gt;
&lt;p&gt;You are probably reading this post because you failed to approach me in a way that was in any way conducive to generating interest in working for your client. In the interest of getting fewer pitches that help nobody, I’ve written this handy guide to pitching me. I suspect it will serve you well in pitching other engineers.&lt;/p&gt;
&lt;h2 id=&#34;actually-pitch-me&#34;&gt;Actually Pitch Me&lt;/h2&gt;
&lt;p&gt;Telling me you have an opportunity is not pitching me. Telling me vague details about your opportunity is not pitching me. Telling me that there is an opportunity for me to work in {programming language} and {framework} backed by {database} in {broad industry} {buzzword} {buzzword} {buzzword} does absolutely nothing for me except lead me to suspect that you are ashamed of your client and don’t want to tell me who it is until I’ve invested in the idea of working for them. That, or your client is embarrassed to be hiring or considers it a competitive secret.&lt;/p&gt;
&lt;p&gt;Everyone is hiring. It’s not a secret. There’s absolutely no good reason you can’t just come right out and say “Super Awesome Company G is looking for {specific position}”. It’s much more efficient. I’m busy. You’re busy. Respect my time, and yours.&lt;/p&gt;
&lt;p&gt;Your client should be part of the pitch because I don’t work with technologies, I work with people. I want to know about your company, I want to know what’s important to them, I want to know what they are like to work with. Telling me their stack and nothing else is useless.&lt;/p&gt;
&lt;h2 id=&#34;know-something-about-me&#34;&gt;Know Something About Me&lt;/h2&gt;
&lt;p&gt;I &lt;a href=&#34;https://paddy.carvers.com/talks&#34;&gt;speak&lt;/a&gt; frequently. I &lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;tweet&lt;/a&gt; constantly. I &lt;a href=&#34;https://paddy.carvers.com/posts&#34;&gt;blog&lt;/a&gt; occasionally. I dominate the first few pages of Google search results for my name. I’m not saying you need to know everything about me, but c’mon, at least know when your job is obviously not a good fit. If you try to pitch me a Ruby job, there’s a 100% chance I’m hitting the “Mark As Spam” button before I even finish reading your pitch, because you obviously did absolutely no research. If you try to pitch me a job that has a degree as a minimum requirement, I’m going to snarkily ask if you’re going to give me the degree, too. C’mon.&lt;/p&gt;
&lt;p&gt;Yes, it takes time to do research, but it’s a competitive market, and I am not being paid to respond to recruiters. You are being paid to contact me. Clearly, one of us should have the responsibility for determining if this is a good fit, and it’s probably not me.&lt;/p&gt;
&lt;h2 id=&#34;dont-ask-me-to-call-you&#34;&gt;Don’t Ask Me To Call You&lt;/h2&gt;
&lt;p&gt;You know who I talk to on the phone?&lt;/p&gt;
&lt;p&gt;My mother. I talk to my mother on the phone.&lt;/p&gt;
&lt;p&gt;Even my father gets emails, not phone calls, because both of us are busy and phone calls are synchronous time sucks that require us to match up our schedules to find a point when we can talk.&lt;/p&gt;
&lt;p&gt;Talking to you on the phone is, 100% of the time, an absolutely useless exercise for me. I’ve talked to my fair share of recruiters, and there is never any information I gain over the phone that they couldn’t have just put in the email. Put the information in the email. Ask the question in the email.&lt;/p&gt;
&lt;p&gt;The only exception to this is if you’re actually making decisions as to who to hire and who to advance through the hiring process; in all other cases, the phone call to you is going to be followed up by a phone call with someone who can actually make decisions, and the phone call with you will achieve nothing.&lt;/p&gt;
&lt;h2 id=&#34;recognise-bad-timing&#34;&gt;Recognise Bad Timing&lt;/h2&gt;
&lt;p&gt;Look, if my LinkedIn profile shows I just started a job three months ago, I am almost certainly not looking to move jobs right now. If I &lt;em&gt;am&lt;/em&gt;, I’ll be quietly approaching companies, not the other way around.&lt;/p&gt;
&lt;p&gt;If you pitch me a job, even a job I want, when I have just started at another company, I’m almost certain to either A) tell you “Sorry, bad timing” or B) not respond at all, depending on how good the rest of your pitch was.&lt;/p&gt;
&lt;h2 id=&#34;in-conclusion&#34;&gt;In Conclusion&lt;/h2&gt;
&lt;p&gt;Your job is not to get me invested in the opportunity. That is the company’s job, by creating an exciting opportunity. Your job is to find good matches for that opportunity and to make the process from discovery to hiring easier. Your job is actually really cool; you get to help people find their dream jobs. And there’s no reason for anyone to dread an email from you if you do your job properly, because you should be contacting people when you think you’ve found a really exciting opportunity that they’d love to take advantage of. And who doesn’t love hearing ”Hey look at this really cool adventure! Do you want to take part?”&lt;/p&gt;
&lt;p&gt;Most engineers hate recruiter pitches not because we hate being pitched, it’s because we hate dealing with recruiters that treat us like email addresses that had the misfortune of ending up in Mail Merge, not like people.&lt;/p&gt;
&lt;p&gt;I hope this guide was helpful and informative. I hope you’ll send me amazing, appropriate opportunities that will benefit me and your clients. If you do your job well, I’ll remember you. I’ll forward you any friends I have looking for jobs, because I know you’ll take care of them.&lt;/p&gt;
&lt;p&gt;If you give me a terrible pitch, I’ll probably just hit “Mark as Spam” and move on with my life.&lt;/p&gt;
&lt;p&gt;Hugs and kisses,
Paddy&lt;/p&gt;
</description>
      <carvers:summary>A guide to pitching me, and probably other engineers.</carvers:summary>
    </item>
    
    <item>
      <title>Imitation Is the Sincerest Form of Failure</title>
      <link>https://paddy.carvers.com/posts/imitation-failure/</link>
      <pubDate>Sat, 30 Nov 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/imitation-failure/</guid>
      <description>&lt;p&gt;Open is a wonderful thing. I think everyone can agree on that. It’s nice to have control over our own data, our own tools. It’s nice to own the things we rely on. But today, most the tools we use aren’t open. We follow people on social networks using internal tools, not the standard created for that precise purpose: RSS or Atom. We use proprietary follow buttons, not my beloved &lt;a href=&#34;https://www.subtome.com&#34;&gt;SubToMe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A lot of open advocates will claim this is because people are greedy, and they want to build tools that will cement their position of power. Like they’re building a pyramid of control to elevate themselves, and each user that uses their proprietary solution is another block in the pyramid, another person that they ultimately have power over.&lt;/p&gt;
&lt;p&gt;That may be true in some cases, but today I’m going commit the ultimate blasphemy for an open advocate: I’m going to remind you that proprietary solutions actually have some really great benefits to them. Because recognising the strengths of proprietary solutions is necessary if we want open solutions to succeed.&lt;/p&gt;
&lt;h2 id=&#34;the-case-for-proprietary-solutions&#34;&gt;The Case for Proprietary Solutions&lt;/h2&gt;
&lt;p&gt;There are objective, reasonable benefits to making solutions proprietary. For example, early technologies are still defining themselves. That stage of product development is better handled by proprietary technologies, which are by nature nimbler and easier to change. More experimentation is allowed while figuring out what the solution should actually look like. A standard is supposed to define something that already exists; it’s not the right tool for the job of figuring out what something is.&lt;/p&gt;
&lt;p&gt;But a lot of things that are already defined—blogging/micro-blogging, code storage, social networks—are still created afresh today without standards. The reason for this is, a lot of the time, because it’s easier to build the desired experience that way.&lt;/p&gt;
&lt;p&gt;Imagine if each of your friends had to set up their own Facebook instance to have a profile. Or their own Twitter server to be able to write (or, worse, read!) tweets. Do you think we’d see the adoption we do today? Of course not. Even though standards for those things are well-defined, the cost of participation is still too high.&lt;/p&gt;
&lt;p&gt;But why can’t they just intoperate? Because keeping the data in one central place has definite advantages. It’s easier for Facebook to show you how many likes a status has. It’s easier for Twitter to surface suggested users. While these things are possible in open solutions, they’re much more involved to implement.&lt;/p&gt;
&lt;h2 id=&#34;the-open-solutions-of-the-future&#34;&gt;The Open Solutions of the Future&lt;/h2&gt;
&lt;p&gt;That being said, I do believe open solutions are the future. I do believe that we should have distributed social networking. I do believe we should own our own data.&lt;/p&gt;
&lt;p&gt;The distributed social networks we see today, however, are taking the wrong approach. They try to match Facebook or Twitter, feature for feature. They play the game by the rules laid out by centralised social networks, which of course play to the strengths of centralised social networks. But open solutions have strengths, too, and not just for the technically savvy. New categories of tools, new interactions, new possibilities are opened by this different paradigm of computing, and these distributed social networks need to play to these strengths.&lt;/p&gt;
&lt;p&gt;A revolutionary social network will not be created by looking at what is already there and trying to reproduce it with different priorities. The distributed social network that finally gains widespread use will look at the problem with fresh eyes, and try to create an experience the centralised social networks cannot possibly match.&lt;/p&gt;
&lt;p&gt;I think the decentralised social network of the future will look less like Facebook, a silo everything happens within. It won’t have the equivalent of a “Facebook me”. People will just say “check me out online”. It will be more about supplying your own information, having the ability to post your own statuses and events and such and get replies to them, but it won’t feel like “posting to” a website, it will feel like “broadcasting”. I think the spread of information will draw nearer to its conceptual base, without the intermediary of a specific website’s terms; the conceptual base, after all, is what the standard is derived from. The individual experience is tailored by the tools a user chooses to use. I also see the social network of the future being more all-encompassing; you don’t have Twitter and Tumblr and Facebook and Foursquare, you have the internet, and you broadcast information there.&lt;/p&gt;
&lt;h2 id=&#34;challenges&#34;&gt;Challenges&lt;/h2&gt;
&lt;p&gt;This kind of open, decentralised social network would fail today.&lt;/p&gt;
&lt;p&gt;It requires too much maturity in infrastructure that we simply don’t have. We need the average person to be able to set up and install this software on their own server—and keep it running—just as easily as they set up and install the software on their personal computers.&lt;/p&gt;
&lt;p&gt;That is the real power of centralised social networking. It makes things simple for end users, who will trade that convenience for control. And this is precisely what the open community needs to be working on: the infrastructure that brings the level of convenience low enough that non-hobbyists can run it.&lt;/p&gt;
&lt;p&gt;We need server architectures that can be administered by end users. My boyfriend’s not going to be on call for his server falling over in the middle of the night, he has a job and a life and things to do. My little brother isn’t going to fire up a terminal to troubleshoot a server. We need to bring our software deployment, ops, and infrastructure management tools up to the level of our desktop software installation tools.&lt;/p&gt;
&lt;p&gt;This is hard. But it’s worth doing. There continues to be, even in my own generation, a huge gap between the technically-savvy and those that don’t tell computers what to do for a living. While there will always be a gap—we are experts, and will always be needed—it should be a lot narrower than it actually is. Part of our problem is that we’re acting like impatient teachers; we just take the keyboard from the users, and do it ourselves. Fine, we’ll manage your servers for you. Fine, we’ll ensure your data stays safe.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Treat your audience like poets and geniuses and they’ll have the chance to become them.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Del Close said that. If we treat our users like they’re capable of owning and operating their own technology, maybe they’ll finally believe they can.&lt;/p&gt;
</description>
      <carvers:summary>A reminder that the decentralised web will not look the same as the centralised web.</carvers:summary>
    </item>
    
    <item>
      <title>Ceci n&#39;est pas un Canard</title>
      <link>https://paddy.carvers.com/talks/treachery-of-hacker-news/</link>
      <pubDate>Mon, 30 Sep 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/treachery-of-hacker-news/</guid>
      <description>&lt;p&gt;This is a talk I gave at &lt;a href=&#34;http://www.ignitebuffalo.com&#34;&gt;Ignite Buffalo&lt;/a&gt;, largely because I wanted to make the reference to &lt;a href=&#34;http://en.wikipedia.org/wiki/Ren%C3%A9_Magritte&#34;&gt;René Magritte&lt;/a&gt; and &lt;a href=&#34;http://en.wikipedia.org/wiki/The_Treachery_of_Images&#34;&gt;The Treachery of Images&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The talk walks through my experiences with Hacker News comments, and sums up why they’re terrible. It suggests ways to avoid them. And most of all, it serves as a reminder to &lt;a href=&#34;http://www.youtube.com/watch?v=ikAb-NYkseI&#34;&gt;Make Good Art&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can see a great &lt;a href=&#34;http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=8DvxT1W6cHI&#34;&gt;video&lt;/a&gt; of the talk. Ignore my “ummmm”s and “like”s.&lt;/p&gt;
</description>
      <carvers:summary>Ceci n’est pas un Canard: The Treachery of Hacker News is a talk about supporting each other and making good art.</carvers:summary>
    </item>
    
    <item>
      <title>Getting By</title>
      <link>https://paddy.carvers.com/posts/getting-by/</link>
      <pubDate>Mon, 30 Sep 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/getting-by/</guid>
      <description>&lt;p&gt;Almost a year ago, &lt;a href=&#34;https://paddy.carvers.com/posts/aaron/&#34;&gt;we lost Aaron&lt;/a&gt;. Yeah, I’m still going on about that. That hurt. A lot.&lt;/p&gt;
&lt;p&gt;I’ve long grown used to &lt;a href=&#34;http://paddyforan.getsby.co&#34;&gt;my depression&lt;/a&gt; and general craziness. After so many years, it just starts to fade into the background, y’know? Like water to a fish, you kind of stop noticing it.&lt;/p&gt;
&lt;p&gt;Which is kind of sad, that I’ve gotten so used to being broken, I don’t even notice it anymore.&lt;/p&gt;
&lt;p&gt;But there you have it.&lt;/p&gt;
&lt;p&gt;This utter nonchalance about my poor mental health has a nice side-effect: I’m always happy to &lt;a href=&#34;https://paddy.carvers.com/posts/open-web/&#34;&gt;talk about it&lt;/a&gt;. And it seems to help people I talk to. So, I thought, I should do more of that.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;I kind of hit a low point at the end of last winter. It wasn’t the lowest I’ve sunk by a long shot, but after everything going so well for so long, it was hard to have my sails deflated like that. Like I ran into an iceberg and the ship just capsized and I had forgotten how to respond.&lt;/p&gt;
&lt;p&gt;It started affecting my work. My employers started to notice. They were very kind about dealing with it. I started wondering to myself if I was just using my brain as an excuse, if I wasn’t actually sick at all, I just sucked.&lt;/p&gt;
&lt;p&gt;I talked to &lt;a href=&#34;https://twitter.com/funkatron&#34;&gt;Ed Finkler&lt;/a&gt; a bit. He reassured me I wasn’t a fraud, and gave me some ideas for strategies to cope.&lt;/p&gt;
&lt;p&gt;I thought about all the people who were in my position, but not fortunate enough to have someone like Ed to help them. How helpful that outside perspective, that insight from someone who has been there and done that, can be.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;I put a call out in late May, looking for people in tech with a mental illness.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;I got a few responses. I started talking to them about my crazy plan. I wanted to get a bunch of people with mental illnesses to write about their experiences and share their perspectives. The point wasn’t to prove anything or garner sympathy; if I wanted anything, it was awareness about how widespread an issue it is. But the real goal, the real motivation, was to let people who were in my position—unsure about their illness and what it meant, feeling like a fraud—to get more information and get reinforcement from others.&lt;/p&gt;
&lt;p&gt;There was some tweaking to my idea, and a lot of support. Then things got busy, and I let the idea gestate for a while.&lt;/p&gt;
&lt;p&gt;In August, I put out another call.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;This time, I got a huge response. Dozens of people came forward, interested in telling their story and sharing their perspective. I started the long process of emailing them all and obtaining responses that would fit the format I had in mind.&lt;/p&gt;
&lt;p&gt;My goal was never to say “you have a mental illness, yours doesn’t count, yours does count.” I’m not an arbiter of worthiness. If you think you have a mental illness, that’s good enough for me. Despite this, pretty much everyone expressed anxiety that they didn’t really have an illness and were impostors. A lot of people thought that their illness wasn’t severe enough to count.&lt;/p&gt;
&lt;p&gt;Which seems absurd. Nobody says “yeah, I’m not sick. I mean, I have bronchitis, but some people have cancer, so I don’t really count.” But that’s how mental illnesses work. They’re devious. They cut you off at the knees. The greatest trick the devil ever pulled was convincing the world he didn’t exist. The greatest trick a mental illness has ever pulled is convincing you you’re just seeking attention or being lazy.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;I launched &lt;a href=&#34;http://getsby.co&#34;&gt;gets by&lt;/a&gt; this weekend, with a couple interviews. More interviews gave me permission to publish over the course of the weekend and earlier today, so now we’re sitting pretty at seven interviews, and I have a bunch more queued up, waiting for permission to post.&lt;/p&gt;
&lt;p&gt;A lot of people have reached out to tell me how great this project is. Twitter has been really supportive.&lt;/p&gt;
&lt;p&gt;I’m so proud of the people that came forward. It’s so hard to talk about this kind of stuff. As I was reading through interviews, I realised how embarrassed I still am, years later, at having been in therapy. That my therapist’s number is still on speed dial.&lt;/p&gt;
&lt;p&gt;That I had to admit I needed help.&lt;/p&gt;
&lt;p&gt;It feels inherently like a weakness. It feels inherently like everyone else is normal, but I’m so damaged that I need other people to help me function. Which is such bullshit. My brain is injured. It’s sick. It’s not well. If I broke my leg, I’d have no shame about going to physical therapy.&lt;/p&gt;
&lt;p&gt;But it hurts to say that I spent an hour a week talking with someone about my feelings.&lt;/p&gt;
&lt;p&gt;How stupid is that?&lt;/p&gt;
&lt;p&gt;That’s why I’m so proud and humbled by the people that came forward. They put their name and picture on the internet next to a description of their lowest points, a complete list of what they find challenging and what makes them feel weak. They did it selflessly, hoping it would help people. Some of them chose to be anonymous. At first, I was wary of this proposition; I didn’t want to justify the stigma by highlighting people who are ashamed of it, who don’t feel comfortable enough to own it.&lt;/p&gt;
&lt;p&gt;Those interviews are now my favourites. The things those people deal with, and are dealing with, are terrifying. Unlike me, those people haven’t become so used to their issues that talking about them no longer hurts. They made the conscious choice to talk about something that caused them pain and anxiety, so much so that they couldn’t bear to own it publicly yet, for no reason other than to help people.&lt;/p&gt;
&lt;p&gt;I called the site “Gets By” because then I could use the domain hack “{name}.getsby.co”. Because that’s what we’re doing. We’re getting by. We’re waking up every morning and knowing it will be a fight and doing it anyways. It’s not a pity party, it’s a rallying cry: we’re doing this. We’re winning. One day at a time.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;A lot of people have thanked me for doing this.&lt;/p&gt;
&lt;p&gt;I did nothing. I wrote a quick deploy script that creates an nginx server, installs Ruby, and installs the Github pages gem. It just syncs a Github repo, uses the Github pages gem to build HTML from the markdown, and runs it behind nginx. It took me an afternoon to set up. &lt;a href=&#34;http://dstaley.me&#34;&gt;Dylan&lt;/a&gt; made our beautiful, responsive design.&lt;/p&gt;
&lt;p&gt;Everything else was done by the people contributing their experiences. Everything of value came from other people. The credit is theirs, not mine. I’m just the custodian, keeping things running. &lt;a href=&#34;http://secondbit.org&#34;&gt;Second Bit&lt;/a&gt; is only involved because I don’t want personal liability. This is totally a community thing.&lt;/p&gt;
&lt;p&gt;Speaking of which, if you have a mental illness and are in the tech industry (if you think you do or are, then you do and are) and want to share your experiences, &lt;a href=&#34;https://github.com/secondbit/getsby/issues/new&#34;&gt;let’s talk&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>Thoughts and reactions about Gets By, a community project launched this past weekend.</carvers:summary>
    </item>
    
    <item>
      <title>We Can Do Better</title>
      <link>https://paddy.carvers.com/posts/better/</link>
      <pubDate>Mon, 02 Sep 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/better/</guid>
      <description>&lt;p&gt;This past weekend, &lt;a href=&#34;https://twitter.com/roxythepuppy&#34;&gt;my puppy&lt;/a&gt; was being unbearably cute again. My boyfriend had his iPhone handy, and took pictures. I wanted the pictures on my phone.&lt;/p&gt;
&lt;p&gt;The conversation went something like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“I can iMessage them to you.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“No dice, Android phones don’t receive iMessages. Can you send it to me in Google Hangouts?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Nope, I don’t have that.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“OK, text them to me. But not my Google Voice number, that can’t receive picture messages. Use my real number.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Wait, which one is your real number?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Not the one you use when you want to call me, the other one.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Am I the only one that is &lt;em&gt;horrified&lt;/em&gt; by this? We wanted to send a fucking picture between two devices connected to the same local network. What’s worse is I’m afraid the situation will be the exact same when the next generation comes along.&lt;/p&gt;
&lt;p&gt;We can do better.&lt;/p&gt;
&lt;h2 id=&#34;good-is-not-great&#34;&gt;Good Is Not Great&lt;/h2&gt;
&lt;p&gt;There has been a recent revolution in software that “great is the enemy of good” and its accompanying admonition to “ship now fix later”. These phrases, which started off as balms for a wound—overly long development cycles, software updates being spaced out by years—have started a festering rot in our industry. The agile movement has been corrupted from its original, pure goal—make sure you’re building something people want before you try to polish it—to a tainted, twisted derivation—don’t worry about making something great, just make something passable and change it really frequently.&lt;/p&gt;
&lt;p&gt;Conventional wisdom says that if you aren’t ashamed of your first iteration of your product, you waited too long to ship. I’m going to add a caveat: if you’re ashamed of your first iteration of your product &lt;em&gt;as you’re shipping it&lt;/em&gt;, you aren’t ready to ship. If you are not shipping something you’re proud of, you should not be shipping anything at all. The world has enough shitty products, we don’t need yours thrown on top just so you can smile and say “I shipped something!”.&lt;/p&gt;
&lt;p&gt;Do not hem and haw when it comes time to ship, nervous about the outcome. Ship, and ship with confidence. But God dammit, ship something worth shipping. A half-assed product is worse than no product at all.&lt;/p&gt;
&lt;p&gt;If you can’t use your product and think “this is great, nothing about this really frustrates me”, &lt;em&gt;do not ship that product&lt;/em&gt;. If, months later, you can use that same product and think the same thing about it, please stop writing software, because you’re not learning or growing anymore.&lt;/p&gt;
&lt;h2 id=&#34;the-business-serves-the-product&#34;&gt;The Business Serves The Product&lt;/h2&gt;
&lt;p&gt;This is, I know, &lt;em&gt;horrible&lt;/em&gt; business advice. The amount of time and effort it takes to make your product great is not proportionate to the amount of revenue it will earn you. But &lt;em&gt;that is not the primary purpose of technology&lt;/em&gt;. The primary purpose is to make our lives better. When your product does that and &lt;em&gt;only&lt;/em&gt; when your product does that is it acceptable for you to profit off that product. And only then if your method of profiting off that product does not reduce your product from its status as “great”.&lt;/p&gt;
&lt;p&gt;The major failing of most tech products is that technology has become big business. Products have an unfortunate tendency to serve the business’ needs, first and foremost.&lt;/p&gt;
&lt;p&gt;This is a bad thing.&lt;/p&gt;
&lt;p&gt;This is a bad thing because technology is not supposed to be big business. It’s not supposed to be about brands and lock-in and revenue. It’s supposed to be our hope for the future.&lt;/p&gt;
&lt;p&gt;Alone among all the animals on Earth, we can build our own future. In that, we are unique. And look what we’re doing with that gift. Are you proud of what we have built?&lt;/p&gt;
&lt;p&gt;We can do better.&lt;/p&gt;
&lt;p&gt;A great analogue to the mobile messaging landscape of today would be email. Imagine, when email was created, it was created by an operating system manufacturer. Apple or Microsoft made it. Maybe IBM made it. And the point of email became to provide only as much utility as necessary to sell IBM computers or Windows licenses or Apple computers. Hands up, who thinks we’d still be using email today?&lt;/p&gt;
&lt;p&gt;And yet, that’s what we’re doing with mobile messaging.&lt;/p&gt;
&lt;p&gt;Of course, mobile messaging isn’t the only pooch we’re screwing, it’s just the most readily-available example of how Average People are being impacted by our head-in-ass syndrome. We’re doing the same thing with social networks. We’re doing the same thing with mobile apps. We’re doing the same thing with almost every single new technology that is created today.&lt;/p&gt;
&lt;p&gt;Let’s knock it off. Let’s stop making products that lock users into a silo, that make it impossible to do things a user would obviously want to do in pursuit of higher revenue or better strategic position. Let’s be &lt;em&gt;better&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We can do better.&lt;/p&gt;
</description>
      <carvers:summary>A rallying cry to pull our heads out of our asses and start making things that deserve to exist again.</carvers:summary>
    </item>
    
    <item>
      <title>Internet Hero</title>
      <link>https://paddy.carvers.com/posts/internet-hero/</link>
      <pubDate>Thu, 01 Aug 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/internet-hero/</guid>
      <description>&lt;p&gt;When I was in college, pursuing an English major, I took a course entitled the American Hero. The course was designed to define an archetype—the eponymous American Hero, the gun-slinging cowboy that rides off into the sunset. Early on in the course, though, I got sidetracked with a thought that wouldn’t leave me alone. The American Hero rose during a time in which the West was an uncharted frontier, a time in which the nation was still trying to find its ass with both hands. That sounded a lot like the Internet of today, to me: nobody knows what they’re doing, everyone likes to pretend they do, there’s a lot of money to be made &lt;a href=&#34;http://xkcd.com/958/&#34;&gt;if you’re quick with a knife&lt;/a&gt;, and most importantly, we have shared values.&lt;/p&gt;
&lt;p&gt;So what does the Internet Hero look like?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A couple of days ago, I was sitting on my couch playing with my Apple TV. I think my boyfriend and I had just watched an episode of the Newsroom on HBO GO. It occurred to me that my access to HBO GO could be cut off with no recourse and no reasoning. I could lose access to all the movies I had purchased from Apple—or at least, I &lt;em&gt;thought&lt;/em&gt; of them as purchased, when really they were &lt;em&gt;leased indefinitely&lt;/em&gt;, the company’s snotty way of saying “these are yours but we can take them back”—and I thought that I could lose those movies, and all the money I spent on them, with no recourse and no reasoning. Just because Apple felt like it.&lt;/p&gt;
&lt;p&gt;What shook me is that I no longer felt like my technology was my own. It was a really uncomfortable feeling. I remember growing up, putting my first computer together from the constituent parts, watching the operating system install, and knowing—&lt;em&gt;knowing&lt;/em&gt;—that this was my machine. If I broke it, I was on the line to repair it. But it was mine to do what I want with. If I wanted to try different operating systems—I did—I could just install them on it. I didn’t need anyone’s permission, I didn’t need to circumvent some weird DRM scheme or boot lock. I installed the damn operating system.&lt;/p&gt;
&lt;p&gt;As I looked around my apartment, at all the wonderful toys and trinkets that advanced technology had bought us, I wondered what that held true about. I started cataloguing the things I was beholden to the whims or survival of a company for. My phone and tablets are doing ok; I can swap in FirefoxOS for Android if I so choose, but I’m relient on AT&amp;amp;T for that cellular connection for my phone. Time Warner Cable has the ultimate power over my internet connection, meaning I can’t even run a home server. My MacBook Pro fares slightly better, as I can easily put Fedora on it and use it even without a network connection. But then I’m dependent on the graces of my electricity provider.&lt;/p&gt;
&lt;p&gt;My email, my IM, my social networking, the blog you’re reading this on, literally every connection I have to the web I’ve made my home&amp;hellip; they all are dependent on the survival and whims of some random company. Google can seize my email and IM at any point, for any of a long list of reasons. Twitter, Facebook, App.net, Google+&amp;hellip; they all own my accounts, not me.&lt;/p&gt;
&lt;p&gt;What do I actually own in this place I call home? What is mine? When the corporate grab for control and power is all said and done, what remains to me?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I thought about this a lot in the last few days. I could set up and manage my own servers. For email, for IM, for this blog. But that would require me leasing EC2 instances, to be terminated at the whim of Amazon. Or I could get a shared host, again leasing a server from someone else. I’d still not &lt;em&gt;own&lt;/em&gt; them, I’d still serve content and connections at the pleasure of my technological landlords. So I could rent space in a hosting facility, except then I own the server, but not the space it resides in, which isn’t a whole lot better. Cloud computing was supposed to bring servers to the masses, but it’s still an expensive and difficult process to get a server running somewhere, anywhere, and have reliable access to it from the Internet at large. Instead, you get &lt;em&gt;leased&lt;/em&gt; things. I feel like I’m in a RENT song.&lt;/p&gt;
&lt;p&gt;So what does the Internet Hero look like? The Internet Hero is the hacker that owns their own technology, the hacker that can code off into the sunset, architecting and orchestrating their domain of mechanical services, the master of their own home.&lt;/p&gt;
&lt;p&gt;The Internet Hero is someone who never clicks the “I have read and agree to the TOS” checkbox.&lt;/p&gt;
&lt;p&gt;The Internet Hero is extinct.&lt;/p&gt;
</description>
      <carvers:summary>How can we make tech empowering again?</carvers:summary>
    </item>
    
    <item>
      <title>Marine</title>
      <link>https://paddy.carvers.com/posts/marine/</link>
      <pubDate>Thu, 04 Jul 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/marine/</guid>
      <description>&lt;p&gt;I spent the 2&lt;!-- raw HTML omitted --&gt;nd&lt;!-- raw HTML omitted --&gt; and 3&lt;!-- raw HTML omitted --&gt;rd&lt;!-- raw HTML omitted --&gt; of July on the Parris Island Marine Corps Recruit Depot to watch my younger brother—I can’t rightly call him my “little brother” anymore—become a Marine. I’m incredibly proud of him and don’t want to take away from his accomplishment at all, but I want to think about what I just said.&lt;/p&gt;
&lt;p&gt;He didn’t &lt;em&gt;join&lt;/em&gt; the Marines. He didn’t become an employee of the United States Marine Corps. He &lt;em&gt;became a Marine&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&#34;just-a-job&#34;&gt;“Just” a Job&lt;/h2&gt;
&lt;p&gt;While waiting for the graduation ceremony to begin, I was treated to several videos explaining the hell my brother had just subjected himself to. But above the descriptions of the verbal abuse he endured, the physical obstacles he overcame, and the limits his endurance was pushed to, one thing stood out: the values they tried to instill in him.&lt;/p&gt;
&lt;p&gt;I caught myself thinking about this throughout the ceremony. This is, after all, my brother’s new job. Yes, it’s a different kind of job, and yes, it requires more sacrifice than other jobs. I would never claim that my brother’s career path is even comparable to my own or “normal” career paths.&lt;/p&gt;
&lt;p&gt;But it is still his career path.&lt;/p&gt;
&lt;p&gt;When is the last time your career path tried to instill values in you? When is the last time it meant something about your identity to be part of the company that employs you? When I put on my Callback Me Maybe t-shirt, with the &lt;a href=&#34;http://iron.io&#34;&gt;Iron.io&lt;/a&gt; logo splashed across my chest, I’m not thinking of the sacrifices my colleagues made to make cloud computing &lt;em&gt;better&lt;/em&gt;. I’m not thinking of the faith our investors showed in us, or the company legacy and culture I’m contributing to.&lt;/p&gt;
&lt;p&gt;One phrase in the video keeps bothering me: “A Marine does not lie.”&lt;/p&gt;
&lt;p&gt;What does an employee of your company not do?&lt;/p&gt;
&lt;h2 id=&#34;a-higher-standard&#34;&gt;A Higher Standard&lt;/h2&gt;
&lt;p&gt;Before dismissing my brother, a drill instructor gave the new Marines a “don’t be stupid” talk—an admonition that they are now a Marine, and their actions define the Marine Corps. They were given a long list of Things That A Marine Does Not Do.&lt;/p&gt;
&lt;p&gt;They were made to feel like every choice they made defined the legacy of their institution. They were made to feel like they had responsibility for the integrity, respect, and honour of their institution. Like that was their highest duty.&lt;/p&gt;
&lt;p&gt;It seems almost embarrassing that tech companies even use the word “culture”, in comparison.&lt;/p&gt;
&lt;h2 id=&#34;my-brother-the-marine&#34;&gt;My Brother, The Marine&lt;/h2&gt;
&lt;p&gt;I don’t know if it’s appropriate for private companies to emulate the military in this regard. Employees expect—and have a right to expect—more freedom and individuality than soldiers have. Employees’ private lives are decidedly off-limits to the employer, and my gut says that’s exactly as it should be. This is not a deliberation about the role the employer has in dictating the employee’s values. It’s a contemplation about the behaviour and values our employers encourage, and the values we strive for. It’s a contemplation of how our job—that thing we spend at least a third of each day doing—influences our self-identification.&lt;/p&gt;
&lt;p&gt;But most of all, it’s a celebration of my brother, Private First Class Matthew Foran.&lt;/p&gt;
&lt;p&gt;A United States Marine.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;img src=&#34;https://paddy.carvers.com/img/pfc-foran.jpg&#34; alt=&#34;PFC Foran&#34; /&gt;
&lt;/div&gt;

</description>
      <carvers:summary>My younger brother just became a Marine, and I couldn’t be more proud of him. But his graduation ceremony made me think about the difference between military and civilian employment.</carvers:summary>
    </item>
    
    <item>
      <title>Happy</title>
      <link>https://paddy.carvers.com/posts/happy/</link>
      <pubDate>Wed, 12 Jun 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/happy/</guid>
      <description>&lt;p&gt;When I was working from my parents’ house, I had a maxim scrawled on my whiteboard—I think it was “my job is to win hearts and minds”, but I don’t really remember. It doesn’t really matter. It was just one in a long line of mental anchors, things I wanted to keep in the forefront of my thoughts long enough for it to become a natural part of my thinking. Something I wanted to internalise. Upon returning to my desk one day, I saw my father’s handwriting off to one side: “he who dies with the most wins.”&lt;/p&gt;
&lt;p&gt;I uncapped a marker and wrote “but is still dead” underneath. I left both there for some time.&lt;/p&gt;
&lt;p&gt;I’ve always rejected the idea of money for money’s sake. I think the masturbatory idea that a company’s goal should be to accumulate as much wealth as possible is what destroys companies. I believe Peter Drucker’s maxim that money is like oxygen to a company; you need enough to breathe, but if your goal is to breathe as much as humanly possible, you’re probably doing it wrong.&lt;/p&gt;
&lt;p&gt;That doesn’t make you a bad company for pursuing profit. It doesn’t mean that I think you’re an evil corporation if you’re driven by revenue. It just means I don’t really want to work for you. This isn’t an anti-capitalist screed, this is just a statement of personal goals.&lt;/p&gt;
&lt;p&gt;Because I don’t measure my success by how much revenue I drive to a company’s coffers. I measure my success by how happy its customers are.&lt;/p&gt;
&lt;p&gt;In my baby book (are those a thing? Like, does everyone know what those are? If you don’t, it’s just a book my parents wrote in and recorded landmarks in as I grew up) there’s an entry from when I was a baby (obviously): “Paddy loves to laugh!”&lt;/p&gt;
&lt;p&gt;A couple of years later, another entry: “Paddy loves to &lt;em&gt;make people&lt;/em&gt; laugh!”&lt;/p&gt;
&lt;p&gt;I’ve always loved making people happy. It’s really important to me. Knowing people are happy, and especially knowing people are happy because of me, makes me really happy. And while I need to guard against letting that latter part overshadow the former, I think I could do worse when it comes to life goals.&lt;/p&gt;
&lt;p&gt;That’s why my personal hall of heroes, the companies I hold close to my heart, the ones I aspire to be like, are the ones that focus on making people happy. They don’t blog about how to use metrics to drive revenue or engagement, they blog about how to use metrics to create a better experience. They believe that if you build something people love, the money will more or less take care of itself. They don’t run conferences that focus on professional development, they run conferences that &lt;a href=&#34;https://paddy.carvers.com/posts/realtimeconfeu/&#34;&gt;focus on people&lt;/a&gt;. They treat the pursuit of happiness, for their employees and their customers, as the most sacred duty of a company.&lt;/p&gt;
&lt;p&gt;I read about conferences and blogs and people who focus on using A/B testing to increase profit 800% or how charging more makes you more money or any number of topics that always seem to end with “and here’s how much more money I made!” and I just get sad. Not because I think these people are &lt;em&gt;wrong&lt;/em&gt;; they’re usually brilliant people who are amazing at what they do, and what they do offers a very real value to a certain type of people. I am not trying to discredit their practices at all.&lt;/p&gt;
&lt;p&gt;But they’re not for me. And as the world seizes the idea that software can make people lots of money very, very quickly, I fear it will be harder and harder to find people like me; people for whom the software and the experiences around it are the goal and the money a means, not the other way around.&lt;/p&gt;
&lt;p&gt;I just want to make people happy.&lt;/p&gt;
</description>
      <carvers:summary>What’s your purpose, as a company? Why do you do what you do?</carvers:summary>
    </item>
    
    <item>
      <title>Growing Up On The Internet</title>
      <link>https://paddy.carvers.com/posts/growing-up-online/</link>
      <pubDate>Fri, 17 May 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/growing-up-online/</guid>
      <description>&lt;p&gt;I’m going to try something new today, because days are nothing if not opportunities to try new things.&lt;/p&gt;
&lt;p&gt;I’m going to talk about a past life I’ve never acknowledged, and in doing so, I’m going to acknowledge the bastard offspring of my brain. Because at a certain point in my life, if someone suggested I be myself, my honest reaction would be “Which one?”&lt;/p&gt;
&lt;p&gt;Every time I talk to someone about technology or what I do, I always get asked the same question: “Where did you learn all that?”And these well-meaning people are expecting a short, two sentence answer: “Oh, I just picked it up in school”or “oh, I read a book about it”. But I have nothing like that. I have an awkward, lengthy, involved story about my adolescence and growing up and the internet and meeting people and my parents and it’s really quite the undertaking to start talking about anything from that period of my life, because there’s just so much of it, and it’s all interdependent.&lt;/p&gt;
&lt;h2 id=&#34;it-all-started-with-a-girl&#34;&gt;It All Started With A Girl&lt;/h2&gt;
&lt;p&gt;God dammit, stop laughing.&lt;/p&gt;
&lt;p&gt;Before I entered high school, I was hanging out as an “assistant coach”on my younger brother’s rec football team. I had just outgrown the league that year, my father was coaching my little brother, and my parents didn’t want to have to find some new way to entertain me. So I “coached”. Meaning I got bored at practices a lot and helped my father carry equipment.&lt;/p&gt;
&lt;p&gt;At one practice, there was a girl my age standing off on the sideline. Rather than counting blades of grass some more (a favoured activity of mine during practices), I approached her and began chatting. We joked and talked and pretty quickly became friends. She kept coming to practices (her brother was on the team) and we hung out. During one of our conversations, she mentioned to me that she was writing her own book.&lt;/p&gt;
&lt;p&gt;I was pretty intrigued. The idea that writing a book is something you can just &lt;em&gt;do&lt;/em&gt; never really occurred to me. I guess I thought you went through some complex rite of passage thing and became An Author, and there was probably a ritual and a lot of hard work in there somewhere, and &lt;em&gt;then&lt;/em&gt; you could start writing a book. She showed me that writing is what makes you a writer.&lt;/p&gt;
&lt;p&gt;That night, I went home and started my own story. And we put together a folder, in which we passed our rough drafts back and forth for each other to review. And slowly, we got better.&lt;/p&gt;
&lt;p&gt;When high school started up, she and I were in the same freshman English class. Go figure. One of the books we read that year was &lt;em&gt;Ender’s Game&lt;/em&gt;, a book I had previously read and loved. She shared my enthusiasm for it, and we quickly became the obnoxious kids in class that were &lt;em&gt;way&lt;/em&gt; too into the reading. During one of our free periods, we checked out Orson Scott Card’s website. It turned out he has &lt;a href=&#34;http://hatrack.com/writingclass/index.shtml&#34;&gt;an entire series&lt;/a&gt; of writing lessons online, which we quickly printed, stuck in binders, and read as if they were the Bible. It also turned out his site provided a forum for young writers to post their work and have their peers review it—an internet equivalent to the beat up folder of drafts we were passing back and forth.&lt;/p&gt;
&lt;p&gt;Obviously, we became staples in the community. I spent more time than I care to consider reading other people’s writing and pointing out style violations, grammar problems, and areas where their writing was just… &lt;em&gt;bad&lt;/em&gt;. And in doing so, I learned a long list of things I should not do as a writer.&lt;/p&gt;
&lt;h2 id=&#34;a-gamer-ha-is-born&#34;&gt;A Gamer (ha!) Is Born&lt;/h2&gt;
&lt;p&gt;Around this time, I began playing &lt;a href=&#34;http://www.wikipedia.org/wiki/Morrowind&#34;&gt;Morrowind&lt;/a&gt;. Well, “playing”is a bit misleading. I honestly started with every intention of playing the game, but the computer version of it shipped with this evil thing called the Construction Kit. And what the Construction Kit let you do is build into the game—quite radically. Some people deleted the entire world that shipped with the game, and rebuilt a new world from scratch.&lt;/p&gt;
&lt;p&gt;Obviously, I didn’t ever really get around to &lt;em&gt;playing&lt;/em&gt; the game very much. This is, incidentally, why I refuse to buy PC versions of The Elder Scrolls games now, and just get them on the console, instead. No Construction Kit there.&lt;/p&gt;
&lt;p&gt;I spent a good amount of time working on various mods and expansions to the game, and I spent even more time hanging out in the company’s forums with other modders. We formed our own little community there, and everything was great.&lt;/p&gt;
&lt;p&gt;I specialised, at the time, in writing dialogue and working with the intricate system necessary to get this dialogue into the game. There was a lot of logic to work out, because you had to specify the precise conditions under which certain lines would be used. It wasn’t so much that I particularly enjoyed doing that; it was more that everybody else &lt;em&gt;hated&lt;/em&gt; it, and I didn’t really feel strongly about it, so there was a niche for me in the community. I took it. But there was another aspect of building these mods that seemed really powerful to me, something I wanted to learn more about: you could write scripts to be executed. The game shipped with a very primitive scripting language built in, and mods could write scripts that could do almost anything. It was magic, it was complex, and it was mine to play with.&lt;/p&gt;
&lt;h2 id=&#34;when-one-door-closes-climb-out-the-windows&#34;&gt;When One Door Closes, Climb Out The Windows&lt;/h2&gt;
&lt;p&gt;If those were the core of my adolescent experiences with the internet, I think my life would be very different right now. I might not even be involved in the tech community at all.&lt;/p&gt;
&lt;p&gt;But then Orson Scott Card’s Writers Forum, the site where my friend and I reviewed and were reviewed by our peers, was shut down. They gave us a couple weeks of notice, but they were very clear: we were losing our home.&lt;/p&gt;
&lt;p&gt;Being high school kids with access to public computers, a bunch of free time, and a stack of floppy disks (no, seriously), we sprang into action. This is about when it would have been handy for me to have some basic tech skills. We visited each page of each thread in those forums and saved them to disk, manually. We stored all this information on floppy disks, meticulously labelled.&lt;/p&gt;
&lt;p&gt;It was an agonizing process, but we loved our home and didn’t want to lose it, so we did it.&lt;/p&gt;
&lt;p&gt;Once we had our history in place, we registered a free forum on &lt;a href=&#34;http://www.proboards.com&#34;&gt;ProBoards&lt;/a&gt; and posted a new thread on Orson Scott Card’s forum, saying we had the old posts, we were opening a new forum, and anyone that didn’t want to lose their home could come with us.&lt;/p&gt;
&lt;p&gt;We got over a hundred people to sign up for our new forum that way. At the time, that was a really large number to me.&lt;/p&gt;
&lt;h2 id=&#34;a-house-is-not-a-home&#34;&gt;A House Is Not A Home&lt;/h2&gt;
&lt;p&gt;My friend and I were about 13 or 14 when this happened. Neither of us had any experience building or running a community. Neither of us had any idea what we were doing. In fact, my parents were pretty wary of the whole internet thing in general, and I’m not even sure I told them I was doing this.&lt;/p&gt;
&lt;p&gt;But suddenly we had a loose group of a hundred people that we needed to form into a community. We didn’t really realise the responsibility we now had, nor did we know enough to be intimidated by our task. Instead, we naively went ahead and started doing things. Some of them worked, some did not. We tried things, and tried to learn from our mistakes when it became glaringly obvious we had made mistakes. While we were doing this, we were simultaneously learning how to be respectable online citizens. It was an interesting formative experience to dump a barely-teenager into.&lt;/p&gt;
&lt;p&gt;During this time, I started building a persona for myself in the community I had inadvertantly created. It wasn’t me; it wasn’t the kid that went to school every day, it wasn’t the kid my parents saw. It’s what I wanted to be. It’s how I wanted to see myself. It’s exactly what I would have been if I had been given the freedom to define myself, because for once, I had been.&lt;/p&gt;
&lt;p&gt;I lived in a small suburb. My family was large, and we had lived in the area for a while. Some of my family members were prominent in the area. I grew up as someone’s brother or son or nephew or grandson. I felt responsible for the reputations of everyone I was related to, because it felt like everything I did would reflect on them. There wasn’t much room for me to experiment and decide who I wanted to be.&lt;/p&gt;
&lt;h2 id=&#34;adventure-is-out-there&#34;&gt;Adventure Is Out There&lt;/h2&gt;
&lt;p&gt;As I was administrating my own little community, I turned to the larger ProBoards community to become a better administrator. I learned cool little hacks I could do to my forum—ProBoards allowed administrators to inject JavaScript into various parts of the site, and a community sprang up to create some very cool hacks around this. Which, incidentally, is how I learned JavaScript.&lt;/p&gt;
&lt;p&gt;As I became more involved in the community, I found more and more sites that existed to serve that community. I found places where website designers and forum modders hung out, and I joined up. I made friends, I talked to people, I wasted time. I just hung out, chatting and posting and talking to people, learning new things and getting to know the people around me.&lt;/p&gt;
&lt;h2 id=&#34;who-am-i&#34;&gt;Who Am I?&lt;/h2&gt;
&lt;p&gt;I feel like people, when they read this, will think I was not popular enough in real life, so I escaped into the internet. Like I felt rejected by my immediate community, so I turned elsewhere. Because that seems to be a common narrative to kids who grow up on the internet. In my case, it’s just not accurate. I had a group of friends that were great to me. I was not a lonely child. I struggled with feelings of ostracization, but they were always circumstantial; if the table my group of friends sat at at lunch filled up, I’d have a crushing sense of being under a microscope, that how I responded to the unexpected turn of events would be scrutinized and judged. But I don’t recall any feelings of loneliness.&lt;/p&gt;
&lt;p&gt;Instead, I just wanted the freedom to explore my own existential crisis. I wanted to be able to try being different people, and see what felt right. I wanted to be able to invent and reinvent myself at will, as easily as registering a new account on a website. I played the part of obnoxious intellectual, or troll, or child. I added eccentricities that I found interesting, and I created and recreated my own personal mythos.&lt;/p&gt;
&lt;p&gt;I wasn’t doing any of this consciously. I didn’t sit at a computer and say “Gee, I wonder what it feels like to be a writer that semi-jokingly worships an invented god of punctuation”. Instead, I did things until I got bored of them, or thought of something I thought I would enjoy doing more. When I joined new communities, I relished the thought of a clean slate, the opportunity to pick a new way to be seen.&lt;/p&gt;
&lt;h2 id=&#34;moving-on&#34;&gt;Moving On&lt;/h2&gt;
&lt;p&gt;After a certain point, I stopped being friends with the girl I met at a football practice. My then-undiagnosed depression started to become an issue in my life, and I started doing things without understanding why I was doing them. I hurt her feelings, and we had a falling out. I really regret that, because I couldn’t even explain why it was happening at the time. I just &lt;em&gt;said&lt;/em&gt; things. I’m sure it was a confusing, hurtful time for her, and I feel really, really bad about that.&lt;/p&gt;
&lt;p&gt;Eventually, I grew distant with my own community. I spent more and more time in the design and coding communities I had found, and less and less time in the community I had originally called home. My parents found out what I was doing, and became alarmed at some of the personas I had created, and started to actively try and curtail my activities.&lt;/p&gt;
&lt;p&gt;Of course, like any good teenager, I dove into the internet with a wild abandon.&lt;/p&gt;
&lt;p&gt;A lot of people who know me now—who know my propensity for writing software every waking hour of the day, who know my fondness for technology—would assume that I’d find a home in the coding section of these coding and design communities. They’d be mistaken. Ironically, I did my best there, but I never had the confidence to really become known as a coder in those communities.&lt;/p&gt;
&lt;p&gt;Instead, I became known as the literature guy. I’m not entirely sure why, but every single design &amp;amp; coding community had a literature forum. It seems really random in retrospect, but at the time, it was simply a thing that &lt;em&gt;was&lt;/em&gt;. At one point, I was the moderator for the literature board in literally every well-known forum. Forums with thousands of members. I chose an identity, joined up, stuck around, and did what I loved. And in time, responsibility and power came on their own.&lt;/p&gt;
&lt;h2 id=&#34;throwing-up-walls&#34;&gt;Throwing Up Walls&lt;/h2&gt;
&lt;p&gt;During all this time, I never mixed my online life and my offline life. My parents were kept as far removed as I could deceive them into being. My friends had no idea that I had a set of completely different lives on the internet. My internet friends never got my real name, or any identifying characteristics about me. I never shared photos of me. I never hinted as to where I was.&lt;/p&gt;
&lt;p&gt;This was partly because of the internet safety things that were spouted at me at every opportunity. I soon developed my own opinions. The trick wasn’t, as people would have me believe, talk to &lt;em&gt;nobody&lt;/em&gt; online, it was to always be aware of &lt;em&gt;who&lt;/em&gt; you were talking to and &lt;em&gt;what&lt;/em&gt; you were telling them. And what they could do with that.&lt;/p&gt;
&lt;p&gt;But it was also mostly because if I had tied my real self to these identities, they could be linked. I &lt;em&gt;liked&lt;/em&gt; that they weren’t tied to that skinny kid in suburban Upstate New York. I &lt;em&gt;liked&lt;/em&gt; that I could throw them away when I got bored with them, and nobody would be able to find me again.&lt;/p&gt;
&lt;p&gt;I had imposed a wall between my identities, and I liked it that way.&lt;/p&gt;
&lt;h2 id=&#34;real-people&#34;&gt;Real People&lt;/h2&gt;
&lt;p&gt;I like to say that I live on the internet, and I think that’s a pretty accurate statement. I’ll never forget when I first realised I had a crush on one of my male friends; the first person I talked to about it was an internet friend named LadyWriter. She was a college student who gave me her cellphone number, and I called her from a blocked number to chat with her whenever my parents left me alone for long enough. She was what my parents would have called “an unsavoury character”, and I found her fascinating. She was deviant, she was weird, she had a quirky sense of humour. She opened my eyes to a viewpoint that I would never have gotten in my conservative little town. Not that her viewpoint was &lt;em&gt;better&lt;/em&gt;, necessarily, it was just &lt;em&gt;different&lt;/em&gt;. And in a town where everyone is the same, I was really interested in the different.&lt;/p&gt;
&lt;p&gt;There was also a Morrowind modder that adopted me as her internet son. There were friends all over the world that would chat with me at all hours. Hell, at one point there was even a “boyfriend”I had never met. We basically just talked a lot. We cared how each other’s days were, told each other secrets, and gave each other gifts on holidays and birthdays. Never anything physical—we never exchanged mailing addresses—but I would write for him, or code up a cool hack for him. He was a digital artist, and made me the most amazing paintings.&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;a href=&#34;https://paddy.carvers.com/img/jamie-painting-large.jpg&#34;&gt;&lt;img src=&#34;https://paddy.carvers.com/img/jamie-painting.jpg&#34; alt=&#34;A gift from my “boyfriend”&#34; /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;A lot of people say that they never thought of people on the internet as &lt;em&gt;people&lt;/em&gt;. I had the opposite experience. I remember all these people, all their quirks, and they were all very real to me. Sometimes, after years go by, we get in touch again. The guy I “dated”was diagnosed with cancer, and despite “breaking up”and not talking for a few years, he still sought me out to talk with me as he battled through treatments. I was the first person he told when the doctors told him he had won.&lt;/p&gt;
&lt;p&gt;These people were always very real to me.&lt;/p&gt;
&lt;h2 id=&#34;tearing-down-walls&#34;&gt;Tearing Down Walls&lt;/h2&gt;
&lt;p&gt;As I started college, I began outgrowing this phase in my life. My identity had cemented a bit, I had a better understanding of who I wanted to be, and I began to &lt;em&gt;want&lt;/em&gt; to build a trail, a history for myself that was whole. Something I could point to and say “That’s where I was five years ago, and look where I am now”. I &lt;em&gt;wanted&lt;/em&gt; my name associated with what I spent my time doing, because I wanted people to be able to Google me and get a sense of who I was. Now that I knew who I was, I wanted everyone to know who I was.&lt;/p&gt;
&lt;p&gt;I started using my name as my username. I started to be consistent with the self I was presenting. I never tried to be anything or seem a certain way; I just engaged honestly. I became a multi-faceted whole, instead of several single-dimensional entities. I started sharing information about myself. Now you can really easily find my email address, my cell phone number, my home address, my name, my date of birth, pictures of me, where I’m going to be, and more. All these things I’ve knowingly and willingly published to the internet, and that doesn’t bother me at all.&lt;/p&gt;
&lt;h2 id=&#34;a-different-kind-of-friend&#34;&gt;A Different Kind Of Friend&lt;/h2&gt;
&lt;p&gt;My friends changed, though. They aren’t less real, and they aren’t more real, they’re just more complicated. I can scroll through my contact list right now and see people from all over the US, Canada, South America, Europe, Asia, and Africa that I’m fortunate enough to call friends. But I don’t think of them as internet friends anymore. They’re just friends. I may never meet many of them, but I will meet a lot of them. The world has shrunk a lot in the last ten years, for me at least. Planes can take me anywhere, to any of these people. Instead of changing identities when I get bored, assuming a new self, I now look to change locations. To change my surroundings. I’m extremely resistant to setting down roots in any single place, because I don’t want to be stuck there, any more than I wanted my name to anchor my identities when I was growing up online. Not knowing what city or even country I’ll be in this time next year is something that has become really, really important to me.&lt;/p&gt;
&lt;p&gt;Less than ten years ago, I never thought I’d get out of a little suburb in Syracuse.&lt;/p&gt;
</description>
      <carvers:summary>I like to say that I grew up on the internet, but I don’t think a lot of people really know what I mean by that. So I wrote a really, really long post explaining it.</carvers:summary>
    </item>
    
    <item>
      <title>On Welcoming Minorities</title>
      <link>https://paddy.carvers.com/posts/minority/</link>
      <pubDate>Thu, 02 May 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/minority/</guid>
      <description>&lt;p&gt;&lt;em&gt;[Update: a lot of my views have evolved on this, and this is not necessarily reflective of my current thoughts. But I’m leaving it here to keep a record that I once believed this, and why. See also: &lt;a href=&#34;http://geekfeminism.wikia.com/wiki/Tone_argument&#34;&gt;tone argument&lt;/a&gt;]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I’ve been thinking about this issue a lot lately. With all the controversy surrounding sexism in tech, it’s hard &lt;em&gt;not&lt;/em&gt; to reflect on these issues. As a male, it’s also hard to voice thoughts on the issue or construct an informed opinion—I’ve held off on commenting publicly on the subject in the past, out of fear that I make assumptions born out of privilege or will be construed as a misogynist, incorrectly (or worse, correctly).&lt;/p&gt;
&lt;p&gt;Fuck that.&lt;/p&gt;
&lt;p&gt;If I’m going to hold an informed, well-reasoned opinion, I need to expose my thoughts for criticism and discussion. And I want those from you. Please, if you have any thoughts at all on this (rather long) piece, feel free to email me at &lt;a href=&#34;mailto:foran.paddy@gmail.com&#34;&gt;foran.paddy@gmail.com&lt;/a&gt;. Especially if you think I’m wrong. I do not write this post to tell you what to think; I write it to get feedback on how I think, so that I may be the best person I can be. Feel free to judge me for my thoughts, but if you find me to be undesirable, please help me fix me. Help educate me. I want to be better.&lt;/p&gt;
&lt;p&gt;That being said, &lt;em&gt;this is not a post about sexism in tech&lt;/em&gt;. I was going to write that post, but on further thought, I decided not to. I want to address the deeper issue: minorities. Women are not the only people excluded from our community, they are just the most noticeable absentees. I also hope that dealing with a level of abstraction above the immediate issue will offer some insulation against preconceived notions and common traps that this train of thought can fall into.&lt;/p&gt;
&lt;h2 id=&#34;on-my-experience-in-the-majority&#34;&gt;On My Experience In The Majority&lt;/h2&gt;
&lt;p&gt;To look at me, you would not consider me a minority. I’m a young, white male. Even my background screams that I’m part of the majority for a lot of dichotomies: I had the opportunity to go to college. I was raised by two parents that loved me. I had a house to come home to every day of my life. My mother was a stay-at-home mom. She greeted me every day after elementary school with a snack.&lt;/p&gt;
&lt;p&gt;I’ve had a lot of privileges in my life, and I was very fortunate to have won the celestial lottery in most cases.&lt;/p&gt;
&lt;p&gt;That being said, I’ll never forget sitting in an education class, explaining the way a class in my high school was run as an example of alternative teaching methods that increased student engagement, and having the professor look down her nose at me and say “Yes, Paddy, but not everyone goes to private school.”&lt;/p&gt;
&lt;p&gt;I was completely taken aback by that dismissal. Mostly because I went to public school my entire life, and the experience I was describing took place in a public school. But, after that (slightly comic) shock wore off, I was left feeling decidedly unwelcome. Because apparently my privilege, even when it was simply assumed and not real, completely disqualified any of my life experiences. Apparently, I did not count.&lt;/p&gt;
&lt;p&gt;Yes, people in the majority have life &lt;em&gt;easier&lt;/em&gt; in a multitude of ways than people in the minority. But they don’t necessarily have life &lt;em&gt;easy&lt;/em&gt;, and they still have perspectives to share. They still count.&lt;/p&gt;
&lt;h2 id=&#34;on-my-experience-in-the-minority&#34;&gt;On My Experience In The Minority&lt;/h2&gt;
&lt;p&gt;As I said, I’m largely given majority-status in any false dichotomy you care to construct. I’m white. I’m male.&lt;/p&gt;
&lt;p&gt;But you’ll notice that one part of the “straight white male” trifecta is noticeably missing.&lt;/p&gt;
&lt;p&gt;I could spend this section talking about how I spent my high school years watching my siblings bring home their more traditionally-gendered significant others to meet my family,  have dinner, and watch movies together, while my boyfriends were not allowed in the house and were not spoken of inside our house. That would be entirely unfair to my parents, who were raised in two separate environments that made discovering their son was gay a bit of a shock that needed to be processed and dealt with. And it would certainly be unfair to the amazing, wonderful progress they’ve made in being supportive. They did not come around as immediately as I would have liked, but they came around. Of their own volition. And for that, I am proud of them.&lt;/p&gt;
&lt;p&gt;I could spend this section talking about how I got in a few fistfights in high school over it. Or about the casual way people would throw “faggot” at me. Or about the way I used what I can only describe as sociological warfare to turn my high school from what I felt to be a slightly unwelcoming environment into a safe place for kids to be themselves. But that would be news to nobody. Every minority has a small, dedicated group of people that hate them openly. It never seems right to the casual observer, nobody argues that small dedicated group has the moral high ground, and it’s not really the type of situation I want to cover in this post.&lt;/p&gt;
&lt;p&gt;Instead, I want to talk to you about two experiences in college:&lt;/p&gt;
&lt;p&gt;I’m an overly touchy person. It’s just part of my nature. I love hugs, and I sometimes hold my friends’ hands. For no reason other than because my friends don’t mind, and I feel like it. It’s an entirely platonic gesture to me. I was at a festival celebrating Buffalo’s art community with a friend, walking down the street amongst all the pavilions with him and a group of other friends, and I randomly held his hand. Partly because the crowd was thick, and it helped us stay together as I weaved through the people, but partly because I just felt like it. I didn’t really even think about it until a friend in our group remarked later that he thought we were “so brave”. I didn’t understand at first, and it took a little back and forth until I realised what he meant. He thought my friend and I were dating, and thought it was brave of us to hold hands in public.&lt;/p&gt;
&lt;p&gt;Except we weren’t dating (though I don’t blame him for that confusion), and I had &lt;em&gt;entirely forgotten&lt;/em&gt; that what I was doing wasn’t the standard. That there was anything out of the ordinary about it. And having it pointed out to me left me with a funny feeling.&lt;/p&gt;
&lt;p&gt;On the other occasion, a boyfriend and I were hanging out together at a party. Someone I didn’t know came up to us, said “I hope you guys know I respect you and your relationship”, and walked away. To this day, I still have no clue who he was. I had never met him before. But it was apparently very important to him that we know he respected our relationship. Again, it took me a few moments of processing to figure out why that was noteworthy. And, again, I was uncomfortably reminded that I was Different.&lt;/p&gt;
&lt;p&gt;I don’t think the two individuals that pointed out that I’m Different are bad people, I don’t think they had an malicious intent, and I don’t think poorly of them for their actions. But they were still deeply uncomfortable moments for me, because my identity isn’t extra details around a core of being gay; being gay is just one of those extra details layered on top of my actual identity. I’m always taken aback and confused when people try to address me or treat me as a gay person, instead of just treating me like any other person.&lt;/p&gt;
&lt;h2 id=&#34;why-im-telling-you-this&#34;&gt;Why I’m Telling You This&lt;/h2&gt;
&lt;p&gt;If you’ve read this far, you no doubt are wondering what my point is. Why am I relating these stories to you?&lt;/p&gt;
&lt;p&gt;I’m telling you because I’m deeply conflicted about the sexism in tech discussions we’re having. Without going into too much detail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Why is sexually suggestive content in talks, blog posts, and our culture in general considered a sexism topic? Is it because we believe the stereotype that women should be less interested in sex than men? I understand that porn objectifies women (and certain types of men), but do we think only men enjoy porn? My fear is that by casting this discussion in the light of sexism, we’re reinforcing the stereotype that sex is for men, which is not fair to women. Or men. Or anyone.&lt;/li&gt;
&lt;li&gt;How does one construct a &lt;em&gt;fair&lt;/em&gt; speaker lineup for a conference? If you turn down men to accept women simply on the basis that they’re women, that’s not fair to the men. If you don’t proactively attempt to include women speakers, you wind up with a lineup of mostly men, which I think we can all agree is a Bad Thing™. Note that I’m not saying women don’t do better work than men; I’m simply pointing out that there are more male speakers than female speakers, so there’s at least a &lt;em&gt;chance&lt;/em&gt; you’ll wind up with a speaker lineup that is not half women. This one is actually really nuanced, so I’ll go into it a bit later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that’s just the tip of the iceberg. Gender and gender politics are deeply nuanced, and how the majority can be welcoming and inclusive to the minority, with everyone showing the proper respect, is a deeply-nuanced conversation. And maybe I’m looking in all the wrong places, but I’m not seeing much nuanced conversation.&lt;/p&gt;
&lt;p&gt;I don’t want to go back to that college classroom, except this time it’s my penis, not my imagined educational background, that’s excluding me. I don’t want to be in a situation in which I need to carefully voice my opinion, lest something I say be misconstrued as misogynist.&lt;/p&gt;
&lt;p&gt;But I also don’t want to remind anyone they’re Different. I don’t think they are. They are just a person doing what they love, much as I am a person doing what I love. I don’t think of any of the females I look up to as females first—they’re all brilliant people first, and oh yeah they’re female.&lt;/p&gt;
&lt;p&gt;I think, personally, what we should be aiming for is a culture in which any specific attribute of a person—their sexuality, their sex, their hair colour—is only relevant when it pertains to the activity at hand—dating or sex, their biological functions (e.g. child birth, I’m having trouble thinking of other situations in which sex matters as an objective fact and not a cultural norm), picking a matching wig, etc. (Yes, each sample activity matches to the corresponding attribute in the previous list.)&lt;/p&gt;
&lt;p&gt;Sadly, because we don’t live in that kind of culture, ignoring these Differences is not enough.&lt;/p&gt;
&lt;h2 id=&#34;a-detour-what-is-fair&#34;&gt;A Detour: What Is Fair?&lt;/h2&gt;
&lt;p&gt;Let’s talk for a moment about what &lt;em&gt;fairness&lt;/em&gt; means. I think we can all agree that we want to be fair. But what does that actually mean? I can think of at least two definitions.&lt;/p&gt;
&lt;p&gt;One could consider it fair to treat each person the same, ignoring any Differences. This means blind application processes, this means not allowing any attribute to influence decisions outside its objectively applicable realm. This means that if a speaker lineup is selected without the selectors knowing anything but the content of the talks, the process was fair. Any lack of diversity is not the product of the selection committee, it simply &lt;em&gt;is&lt;/em&gt;. Let’s call this &lt;strong&gt;micro-fairness&lt;/strong&gt;, as it’s fair when considering only the case at hand, not the overall result.&lt;/p&gt;
&lt;p&gt;One could, alternatively, consider it fair to take each person’s background into consideration and tailor the process to compensate for any systemic biases against their Difference. This means selecting speakers that are all qualified to speak, but favouring under-represented groups (women, homosexuals, PHP enthusiasts) when there’s a tie. At the extreme, quota systems are meant to ensure this kind of fairness. While the process itself is biased, it’s biased to counteract the bias inherent in the environment. Let’s call this &lt;strong&gt;macro-fairness&lt;/strong&gt;, as it’s fair when considering only the big picture, the result of the process.&lt;/p&gt;
&lt;p&gt;The problem with &lt;strong&gt;micro-fairness&lt;/strong&gt; is that it assumes that all else is equal. &lt;em&gt;If all else is equal&lt;/em&gt;, then it will achieve a fair outcome and this will be a meritocracy. If, however, it is not operated in a vacuum (&lt;em&gt;protip&lt;/em&gt;: you are not operating in a vacuum), this will do nothing to correct the systemic discrimination already inherent in the system. Micro-fairness can only stop the descent into an unfair system, it cannot reverse it, because it does not take the system into account.&lt;/p&gt;
&lt;p&gt;There are a lot of problems with &lt;strong&gt;macro-fairness&lt;/strong&gt;. First, it is not entirely fair on an individual level. When individuals are competing for limited resources, giving a leg up to some individuals necessitates creating an unfair advantage over the other individuals. And while this works out in the big picture, in the immediate context it feels very unfair that Suitable And Valuable Talk A was chosen over Suitable And Valuable Talk B just because Suitable And Valuable Talk A is given by a minority. Also, it doesn’t feel very good, as a minority, to have to question whether your talk is good enough on its own or if it was only chosen because you’re a minority. Even if nobody suggests it to you, knowing that you had a leg up to compensate for the systemic discrimination against you will make you question yourself. Or at least it makes me question myself. Long story short: in the immediate moment, macro-fairness doesn’t make anyone feel good.&lt;/p&gt;
&lt;p&gt;What’s right? I don’t know. Obviously, we can’t just ignore the problems inherent in our culture and hope they’ll go away if we’re just micro-fair. But macro-fairness makes everyone feel lousy at the end of the day, and it ruptures our perception that we’re a meritocracy. Because suddenly, &lt;a href=&#34;http://warpspire.com/posts/pixels-dont-care/&#34;&gt;the pixels do care&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think the best way we’ll find forward is trying to be macro-fair while sacrificing as little micro-fairness as we possibly can. Things like organisers explicitly approaching female speakers and asking them to submit a talk, which is then vetted by a blind process that all speaker submissions are funneled through. That would help combat the systemic discrimination by artificially inflating the pool of women speakers in contention for the event, but would still remove gender as a factor when weighing a talk’s merit. I don’t know. I’m not a conference organiser. I think we’re going to need to find a balance between these two concepts of fair, however.&lt;/p&gt;
&lt;h2 id=&#34;my-promise&#34;&gt;My Promise&lt;/h2&gt;
&lt;p&gt;I have a promise to make, to everyone. Not just men, not just women. Every majority, every minority.&lt;/p&gt;
&lt;p&gt;I promise I want to engage with you as you perceive yourself. I want the parts about you that are important to you to be what I place import on. I want to see you as you want to be seen.&lt;/p&gt;
&lt;p&gt;If I ever fail to do that, please correct me. It will be a more pleasant experience all around if you correct me privately and afford me the opportunity to apologise and correct my behaviour, but how you correct me is entirely in your hands. I promise to always respect your self-identification and to do my best to treat you with the appropriate respect and compassion. I am not perfect, and I will fail sometimes. I hope this will always be out of ignorance, and never out of carelessness. When I fail, please do point it out to me.&lt;/p&gt;
&lt;p&gt;I want you here. I want your opinion, your insight, your ideas, your perspective. I will not always agree with you, but I cannot evolve my own thoughts without exposing myself to thoughts I do not agree with. I value you as a person, and hope I properly convey that to you.&lt;/p&gt;
&lt;h2 id=&#34;closing-thoughts&#34;&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;I have written this mini-essay on the premise that the majority of people are good. That is, the premise is that the current uncomfortable climate arises not out of malice, but out of ignorance and a dearth of reasoned, respectful discussion and self-examination.&lt;/p&gt;
&lt;p&gt;Obviously, there are people that are not good that get included in these discussions. People who send death threats and rape threats. People who DDoS websites. These people are &lt;em&gt;actively malicious&lt;/em&gt;, instead of just being unequipped to deal with a complex situation.&lt;/p&gt;
&lt;p&gt;It is my earnest belief that we, as a community, want every type of minority to feel welcome. I could be mistaken about that. But I must act as if I am not, or leave the community. Because if I am mistaken about that, I do not want to be part of this community anymore.&lt;/p&gt;
&lt;p&gt;I think it’s also imperative that our community has this discussion in a very nuanced, rational way, or we’re at risk of losing many of the things that make our community special in the first place. Banning any talk of sex or references to sex in any context sets the precedent for creating taboos. Taboos are not something I think we, as a community, believe in. They stifle our naturally rebellious spirit, the spirit that helps us disrupt industries. The spirit that helps us defy norms to achieve something &lt;em&gt;more&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Rather than creating taboos, I hope the outcome of this is that we are all better educated about how to respectfully dialogue with each other. So we &lt;em&gt;can&lt;/em&gt; have sexual references without making people feel uncomfortable. I think we &lt;em&gt;can&lt;/em&gt; have both. I think we &lt;em&gt;can&lt;/em&gt; nurture our irreverent attitude &lt;em&gt;and&lt;/em&gt; be a safe and welcoming place for every type of person. We just need to work at it.&lt;/p&gt;
&lt;p&gt;If I’m wrong, though, I’d rather be safe and welcoming than irreverent.&lt;/p&gt;
</description>
      <carvers:summary>How can a community or culture be welcoming to minorities?</carvers:summary>
    </item>
    
    <item>
      <title>RealtimeConf Europe</title>
      <link>https://paddy.carvers.com/posts/realtimeconfeu/</link>
      <pubDate>Wed, 24 Apr 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/realtimeconfeu/</guid>
      <description>&lt;p&gt;I’ve spent an entire flight from Lyon, France to Istanbul, Turkey thinking about how to write this post, and I still have no idea how to approach it. So I’m just going to do my best and hope it comes close to what I want it to be.&lt;/p&gt;
&lt;p&gt;I want to talk about &lt;a href=&#34;http://realtimeconf.eu&#34;&gt;RealtimeConf Europe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was fortunate enough to be invited as a speaker to the conference, to give a talk about how Go is a realtime language. I was incredibly flattered and incredibly intimidated to be selected as a speaker. A lot of these people—including Julien, the man behind the event, and Adam, who helped as an organiser—are people I respect and look up to (quite literally; Julien is freaking &lt;em&gt;tall&lt;/em&gt;). It was incredibly intimidating to realise I would need to stand in front of them and pretend to be an expert. It was terrifying to realise I’d need to bring my best, and that my best might not be good enough.&lt;/p&gt;
&lt;h2 id=&#34;the-experience&#34;&gt;The Experience&lt;/h2&gt;
&lt;p&gt;It is very rare for organisers to think of &lt;em&gt;everything&lt;/em&gt;, but Julien managed it. He had a conference to plan and his girlfriend was due to give birth &lt;em&gt;any day&lt;/em&gt;, and he still politely replied to my varied emails as I planned my talk. He emailed all the speakers ahead of time with the resolution of the projector, so our slides could be tested ahead of time. We had a plethora of information on Lyon. I didn’t speak a lick of French or know anything about the city, but I still could feel confident that I’d be fine getting to my hotel, the event, and anywhere I’d need to go in the city, because Julien laid it all out for us at every opportunity.&lt;/p&gt;
&lt;p&gt;On the night before the event, there was a meeting in the hotel that speakers stayed in for everyone to get drinks and get to know each other. This was great. I was tired, I had just spent the better part of two days on a plane or in airports, and having that event just downstairs from where I was staying made the difference between me attending and not attending. When I walked down there, I immediately ran into Adam, who shook my hand and struck up conversation with me. We talked about &lt;a href=&#34;http://andbang.com&#34;&gt;&amp;amp;!&lt;/a&gt;, the same-pagification app that his company, &lt;a href=&#34;http://andyet.com&#34;&gt;&amp;amp;yet&lt;/a&gt;, built.&lt;/p&gt;
&lt;p&gt;I met a lot of incredible people that night. This is a running theme of the conference; I learned a lot, but this event wasn’t about ideas, it was about people. It was about the community. It was about gathering together to share our passions with each other.&lt;/p&gt;
&lt;p&gt;When I arrived at the conference the next day, and saw everyone with their name tags, I made a couple unsettling discoveries. A lot of the people I really respect in that community, the people I would be too intimidated to strike up conversations with, were people I had inadvertently approached the night before without recognising. People I had joked and talked with naturally, who (despite being stars in the community) were incredibly down to earth. Nobody was ever too important to talk to me. Nobody ever looked down on me. My ideas counted as much as theirs. The ideas that, had I known who I was talking to, I would’ve been terrified to even voice.&lt;/p&gt;
&lt;p&gt;I met even more people I look up to and respect at that conference, and chatted with them about silly things. &lt;a href=&#34;https://twitter.com/aral&#34;&gt;Aral&lt;/a&gt; and I had a wonderful conversation about how we all need to stop being adults and revert to acting like six year olds. I talked with &lt;a href=&#34;https://twitter.com/steveklabnik&#34;&gt;Steve Klabnik&lt;/a&gt; all throughout the conference, and although I’m sure I was pestering the hell out of him, he was always very patient and friendly with me. I made &lt;a href=&#34;https://twitter.com/janl&#34;&gt;Jan&lt;/a&gt; start stammering when I told him he was the perfect person, because he’s too modest and the blatant compliment caught him off guard. Julien saw me wandering around lost in thought, and pulled me aside to ask if I was ok. He noticed when I was sitting in the beautiful, glorious, amazing sun for too long, and yelled at me not to burn. There are hundreds more stories like these, including far more people. These are all people who have done amazing things, people who have huge followings in the tech community. And they accepted me as one of them.&lt;/p&gt;
&lt;p&gt;The conference itself was organised with a whimsical aplomb that is breathtaking. A string quartet played at various points throughout the day. A magician was present at lunch, performing tricks for people. A wine expert came on board during a break on the second day, and held a wine tasting for the attendees. And, of course, the entire conference was &lt;em&gt;on a boat&lt;/em&gt;. These are the kinds of touches that delight attendees and set the conference apart. These are the real world translation of the character and personality that &lt;a href=&#34;http://superfeedr.com&#34;&gt;Superfeedr&lt;/a&gt; and &amp;amp;yet put into their software, which is what makes their software so delightful to use.&lt;/p&gt;
&lt;h2 id=&#34;paying-it-forward&#34;&gt;Paying it Forward&lt;/h2&gt;
&lt;p&gt;If I had to choose a single word to sum up this conference, it would be “inclusive”. I had no idea what to do with myself in France, but fortunately I never needed one. Anything that was going on, I was invited to. I ate with speakers and attendees. We spent downtime together at a bar or wandering the city. I played with Tim’s kids (yes, &lt;a href=&#34;https://twitter.com/creationix&#34;&gt;that Tim&lt;/a&gt;; remember what I said about people with followings being totally approachable?). And it was always with an attitude of generosity. Nobody nickled or dimed over who paid for what; we bought pitchers of drinks and shared them freely. We shared food freely at restaurants, and when one table accidentally paid for both tables, they just shrugged and said “don’t worry about it, just pay it forward.” We all just focused on having a good time and enjoying each other’s company, and we trusted the rest to work out.&lt;/p&gt;
&lt;p&gt;When I saw an &amp;amp;yet team member wearing the team sweatshirt, I got really excited (those things are &lt;em&gt;amazing&lt;/em&gt;) and asked if I could take a picture. She laughed and agreed, and told me I should ask Adam for one. I agreed, knowing deep down that I’d never be able to ask Adam for anything. Apparently she knew it, too, because the next day she approached me with a smile and thrust an &amp;amp;yet shirt into my hands. I could barely stutter out a thank you, I was so speechless.&lt;/p&gt;
&lt;h2 id=&#34;heading&#34;&gt;♥&lt;/h2&gt;
&lt;p&gt;Adam took the stage at the end of the conference and gave a talk that was deeply personal and focused exclusively on emotions. I was floored. The number of parallels it had to my &lt;a href=&#34;https://paddy.carvers.com/posts/open-web/&#34;&gt;Open Web&lt;/a&gt; post kept me smiling throughout the talk. I was filled with a warm glow because Adam and I thought the same way about the issue.&lt;/p&gt;
&lt;p&gt;But the emotional impact of this conference wasn’t limited to Adam’s talk. I received a DM from the &amp;amp;yet team on the second day of the conference, asking me to give Adam a hug and tell him the team missed him. They passed the message around to as many people as they could reach, and we passed it around covertly at the conference itself. By the time I approached Adam and gave him his hug, he told me it was the eighth he had received that day. When I approached him at the end of the conference to say goodbye, he hugged me again. Twice.&lt;/p&gt;
&lt;p&gt;To make this sound less creepy: I’m a hugger by nature. As soon as I become comfortable around a person, I see nothing wrong with hugging them for absolutely no reason. I am blessed to be friends with many people that will hug me for absolutely no reason. I sign most of my emails with “Hugs, Paddy”. Hugs are actually a really, really important thing to me. But I’ve never had the courage to hug someone I respect and admire before. Hugs are a very open, unguarded admission: “I care about you. Please feel good.” For some reason, as a society, we decided that’s not appropriate outside of a close group of friends. That is possibly the stupidest decision we’ve made as a society.&lt;/p&gt;
&lt;p&gt;Then Julien hugged me goodbye, too. Julien’s work is the work I wish I could do. The work that embraces open standards, the work that is done for the community, the work that is trying to slowly make the world a better place to live. I always feel bad chatting with Julien, because I &lt;em&gt;know&lt;/em&gt; I’m distracting him from doing something amazing to make everyone’s lives better.&lt;/p&gt;
&lt;p&gt;I was not prepared to have these two people tell me in the most implicit, resonant way possible, that they care about me and want me to be happy.&lt;/p&gt;
&lt;p&gt;I have been to a lot of tech events. Some of them I leave feeling depressed about the state of our industry. Some of them I leave feeling motivated to do great work. Some of them I leave feeling lucky to have been in the presence of such great people.&lt;/p&gt;
&lt;p&gt;This is the first tech event I have left feeling loved.&lt;/p&gt;
</description>
      <carvers:summary>I spoke at RealtimeConf Europe in Lyon, France. This was a conference and an experience with no equal.</carvers:summary>
    </item>
    
    <item>
      <title>Realtime and Go</title>
      <link>https://paddy.carvers.com/talks/goonaboat/</link>
      <pubDate>Mon, 22 Apr 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/goonaboat/</guid>
      <description>&lt;p&gt;This is a talk I built for the amazing &lt;a href=&#34;http://realtimeconf.eu&#34;&gt;RealtimeConf Europe&lt;/a&gt; conference (you can read &lt;a href=&#34;https://paddy.carvers.com/posts/realtimeconfeu&#34;&gt;my writeup of the event&lt;/a&gt;), but I practised it on students at the University of Buffalo first. Following RealtimeConf Europe, one of the attendees asked me to give the talk for the &lt;a href=&#34;http://lanyrd.com/2013/xmpp-realtime-uk-meetup/&#34;&gt;XMPP UK&lt;/a&gt; meetup.&lt;/p&gt;
&lt;p&gt;The talk is supposed to be an introduction to Go for people familiar with realtime web programming. The term “realtime” is a bit loaded, so in this context, we’re using it to describe websockets, push notifications, and anything that gets content to users as quickly as possible. Your definition may vary.&lt;/p&gt;
&lt;p&gt;The core thesis of this talk is that realtime is, at its core, a concurrency problem. You need to, at the very least, subscribe and unsubscribe listeners, and you need to notify them of events. Two independent tasks, so we’re talking about concurrency. From this premise, it follows that Go’s concurrency primitives and support make &lt;a href=&#34;http://golang.org&#34;&gt;Go&lt;/a&gt; a great option for making realtime web applications. I went on to give a concrete demonstration, walking through the &lt;a href=&#34;https://github.com/paddycarver/goonaboat&#34;&gt;source code&lt;/a&gt; for &lt;a href=&#34;http://growup.goonaboat.com&#34;&gt;a demo&lt;/a&gt; that I had made.&lt;/p&gt;
&lt;p&gt;The first iteration of this talk was given to UB students at their ACM meetup. You can view &lt;a href=&#34;http://youtu.be/wC5W8x1h6mM&#34;&gt;a video of it&lt;/a&gt;. The talk was rewritten from scratch following this experience, as I was unsatisfied with it.&lt;/p&gt;
&lt;p&gt;The next iteration of this talk was given at RealtimeConf Europe. You can view &lt;a href=&#34;http://youtu.be/1fWY2BUDYn0&#34;&gt;a video of it&lt;/a&gt;. This is, more-or-less, the final version of the talk. The slides are available at &lt;a href=&#34;http://goonaboat.com&#34;&gt;goonaboat.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The final iteration of this talk (a slide was removed) was given for XMPP UK. You can view &lt;a href=&#34;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=RroA2NzzX64#t=5808s&#34;&gt;a recording of it&lt;/a&gt; (my talk starts around the 1 hour, 35 minute mark).&lt;/p&gt;
</description>
      <carvers:summary>A talk about using Go for realtime web application development. Created for RealtimeConf Europe, this talk was also given at the University of Buffalo and for the XMPP UK meetup group.</carvers:summary>
    </item>
    
    <item>
      <title>In Defence Of The Hackathon</title>
      <link>https://paddy.carvers.com/posts/hackathons/</link>
      <pubDate>Sun, 14 Apr 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/hackathons/</guid>
      <description>&lt;p&gt;As part of &lt;a href=&#34;https://paddy.carvers.com/posts/developer-experience-engineer/&#34;&gt;my role&lt;/a&gt; at &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;, I attend a lot of hackathons. I have a special place in my heart for these events; they’re precisely the type of event I would have loved to attend in college or high school, if I had had the opportunity to do so. But I didn’t. My hacking was limited to sitting alone, in my room, staring at a screen and pushing bytes until things worked. And while that was incredibly formative for me and a great way to learn, it didn’t really connect me to a community. It was accutely a solo activity for me.&lt;/p&gt;
&lt;p&gt;Hackathons are different, though. In the last fifteen hours, I’ve formed part of a “&lt;a href=&#34;https://twitter.com/search?q=%23swagboat&#34;&gt;#swagboat&lt;/a&gt;” (which, for the uninitiated, is a group of people sitting on wheelie chairs, forming a conga line that rolls around distributing swag), judged a dance competition (in which there was very little &lt;em&gt;dancing&lt;/em&gt;, if we’re to be discerning), and now I am reclining in front of a surprisingly soothing video of a fireplace projected on a monitor, surrounded by hackers. As I blog, someone in front of me is hacking together a pong game that replaces the ball with &lt;a href=&#34;http://youtu.be/QH2-TGUlwu4&#34;&gt;Nyan Cat&lt;/a&gt; and is likely to induce seizures. I spent a few minutes discussing the merits of &lt;a href=&#34;http://secondbit.org/blog/introducing-pastry&#34;&gt;distributed hash tables&lt;/a&gt; with a hacker who wants to try to create a distributed network of Android devices. Fellow evangelists discussed the finer points of evangelism with me, and we engaged in some friendly ribbing (I met a developer that uses Windows. No, seriously. He even booted it to prove it to me.) A developer just walked up to me and is explaining how he is &lt;em&gt;writing an assembler for the CPU he made up four hours ago&lt;/em&gt;. I wish I were joking.&lt;/p&gt;
&lt;p&gt;Last week, I met more tech talent &lt;em&gt;in my hometown&lt;/em&gt; than I thought existed. I met a &lt;a href=&#34;http://foss.rit.edu&#34;&gt;group of hackers&lt;/a&gt; that reminded me of my love for open source and taught me a bunch of cool new tricks.&lt;/p&gt;
&lt;p&gt;I made new friends. I always make new friends at these events. These are my people. The silly, the exuberant, the &lt;em&gt;fun&lt;/em&gt;. The people who love to build, and who build for no reason other than the joy they get out of it.&lt;/p&gt;
&lt;p&gt;Every time I hear the term “business plan” at a hackathon, I die a little on the inside.&lt;/p&gt;
&lt;p&gt;There’s nothing wrong with business plans. There’s nothing wrong with building a sustainable business in a weekend. I have a great respect for Startup Weekend events and events like them, but I also have a deep respect for hackathons. And I humbly submit that the two are different.&lt;/p&gt;
&lt;p&gt;A hackathon is an event about &lt;em&gt;fun&lt;/em&gt;. It is supposed to embody the spirit of a hack: something cool that is made for the sheer joy of making it. Something that may not be useful right now, but is still cool technology. A lot of our current computing culture was defined by hacks that had no immediately obvious use case.&lt;/p&gt;
&lt;p&gt;More importantly, the joy of creating is a strong part of our culture right now. And I’m afraid it’s a part of our culture that is being edged out by the recent focus on &lt;em&gt;business&lt;/em&gt;. The rest of the world figured out that technology is valuable and can create a lot of wealth quickly, and we started to lose sight of tech for the sake of tech. We started to lose sight of the fun-loving, prank-playing, unabashedly-silly culture we have inherited from the True Hackers Of Old™. The people you read about in &lt;a href=&#34;http://amzn.com/1449388396&#34;&gt;a Steven Levy book&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That’s a terrible thing for us to lose.&lt;/p&gt;
&lt;p&gt;So please, the next time you find yourself at a hackathon, stop focusing on your business plan. Stop trying to build something you can go home and use today. Build something that you’re going to &lt;em&gt;have fun building&lt;/em&gt;. And if you’ve never been to a hackathon, please come to one. And bring your sense of fun.&lt;/p&gt;
</description>
      <carvers:summary>I believe that hackathons are some of the most important events in our community, and I’m afraid they’re going the way of the dinosaur.</carvers:summary>
    </item>
    
    <item>
      <title>Oh, The Cleverness Of Me</title>
      <link>https://paddy.carvers.com/posts/cleverness/</link>
      <pubDate>Tue, 26 Mar 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/cleverness/</guid>
      <description>&lt;p&gt;For quite some time now, I have vocally denounced clever programming tricks.&lt;/p&gt;
&lt;p&gt;Yes, yes, your one-liners are cute. But bytes are cheap and I &lt;em&gt;need to read that, goddammit&lt;/em&gt;, so please stop obscuring what the software actually &lt;em&gt;does&lt;/em&gt;. The correct syntax to use, in my humble opinion, is always the syntax that most clearly demonstrates what you are trying to achieve.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; x ? &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; : &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That makes me cry. Please don’t do that.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;See how much clearer that is?&lt;/p&gt;
&lt;p&gt;And I thought this was a pretty straight-forward stance on the issue: clarity good, clever tricks bad. It’s the reason I dislike Ruby so much; the community seems to revel in writing code that is impossible for a reader to decipher without carefully picking through it. On a related note, whoever thought letting statements come before their conditionals was a good idea makes me sad.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But then, as I was thinking about Go, C, and the early innovators of computing, I became conflicted. Because so much of what they did was clever. I admired those people, I aspired to be like them, and it threw me pretty badly to realise that they were clever.&lt;/p&gt;
&lt;p&gt;So I had a conundrum on my hands: when is it appropriate to be clever with code?&lt;/p&gt;
&lt;h2 id=&#34;the-golden-rule&#34;&gt;The Golden Rule&lt;/h2&gt;
&lt;p&gt;The solution I fell back on, after some internal turmoil over the issue, was that cleverness itself is not bad. Cleverness &lt;em&gt;for the sake of cleverness&lt;/em&gt;, however, is something that should be avoided at all costs.&lt;/p&gt;
&lt;p&gt;The difference between channels (which I find to be a very clever solution to a problem raised by concurrent programs) and the Unix Way (which is an exceedingly clever way to build a workflow, especially for the time it was developed in) compared to clever one-liner hacks is that the cleverness I admire is clever &lt;em&gt;in the pursuit of clarity&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Yes, channels are a clever solution to the problem, but they also clarify the programs being developed. Reversing the order of the conditional and expression, however, does not make the program clearer. It helps the program read more like English, yes. But we do not want programming languages to start emulating English. I’m familiar with the English language to an absurd degree. Just take my word on this one. It is an ugly, bloated thing, and it is poorly suited for the task of expressing precise and complex ideas with the clarity a compiler requires.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: cleverness is only ever justified if it makes the structure and behaviour of your program clearer. Clarity is king, not concision. Keystrokes are cheap compared to the amount of effort it requires to read your obfuscated code.&lt;/p&gt;
</description>
      <carvers:summary>When is cleverness a good thing in software? Where is the appropriate place to be clever?</carvers:summary>
    </item>
    
    <item>
      <title>The Open Sourcing Mental Illness Tour</title>
      <link>https://paddy.carvers.com/posts/open-sourcing-mental-illness-tour/</link>
      <pubDate>Tue, 26 Mar 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/open-sourcing-mental-illness-tour/</guid>
      <description>&lt;p&gt;Someone I admire and respect has taken it upon himself to do a remarkably painful thing to make his community better. &lt;a href=&#34;http://www.funkatron.com&#34;&gt;Ed Finkler&lt;/a&gt; is trying to &lt;a href=&#34;http://www.indiegogo.com/projects/open-sourcing-mental-illness&#34;&gt;raise $3,000&lt;/a&gt; so that he can give a talk at a series of conferences about his experiences with open source and mental illness.&lt;/p&gt;
&lt;p&gt;The rest of this post is going to be a quick explanation of why you should support this cause.&lt;/p&gt;
&lt;h2 id=&#34;why-this-cause&#34;&gt;Why This Cause&lt;/h2&gt;
&lt;p&gt;I’m biased, obviously. Mental illness and open source are two things that hit very close to home with me. But I think this is an issue that the entire internet community should be concerned about.&lt;/p&gt;
&lt;p&gt;I can’t speak for everyone with a mental illness, but I know that the internet is my crutch. The amazing people, the ability to do anything I can achieve with my own skills, and the culture that encourages us to share and help each other is really, really helpful. I don’t know what I’d do without it. And I don’t think I’m alone in that.&lt;/p&gt;
&lt;p&gt;Working in front of a screen all day, the level of self-awareness and critical approach to problems required, and the lack of interpersonal communication all make software development and open source in particular environments in which mental illnesses can be cultivated. And it’s time that we began to have a dialogue about it, in the open.&lt;/p&gt;
&lt;p&gt;We were all so upset when Aaron killed himself that we eagerly demanded a prosecutor lose her job. We were ready to place the blame squarely on the justice department. And now we have the opportunity to put our money where our mouths are. We have the opportunity to take responsibility, rather than placing blame.&lt;/p&gt;
&lt;p&gt;Let’s start fixing this.&lt;/p&gt;
&lt;h2 id=&#34;why-ed&#34;&gt;Why Ed&lt;/h2&gt;
&lt;p&gt;I think the cause is worthy, but the fact that it’s Ed that’s running it removes any hesitation I have in donating to it.&lt;/p&gt;
&lt;p&gt;Ed’s was the first open source project I ever contributed to. The people I met while working on that project are some of the best friends I have. Ed, personally, went out of his way to make me feel welcome and included, taking the time to help bring me up to speed until I was actually productive and useful. He made sure I felt like part of the team, and my involvement and devotion to open source today is largely because of that. Had Ed been anything but a phenomenal open source developer, I’m not sure I’d still be part of that community. I was so nervous to put myself out there, anything but a warm welcome would have crushed me. But Ed, and the people who gathered around him, gave me a warm welcome.&lt;/p&gt;
&lt;p&gt;That is what open source is. I can’t think of anyone better qualified to speak about it.&lt;/p&gt;
&lt;p&gt;I’ve spoken briefly with Ed in the past about depression, anxiety, and general mental illness. Those conversations are never fun. It always feels like you’re admitting a weakness, purposefully holding aloft all the undesirable parts of yourself for the world to see. If Ed has the immense courage to do that on a national scale, we can find $3,000 to make it happen.&lt;/p&gt;
&lt;h2 id=&#34;sign-me-up&#34;&gt;Sign Me Up&lt;/h2&gt;
&lt;p&gt;I’ll put my money where my mouth is. I’ve already donated to the cause, but I’ll also match up to $100 of other people’s donations. I know it’s not much, but it’s what I can safely promise right now. I may be able to double-down and do another $100 by the time funding closes. In the meantime, forward your receipt to &lt;a href=&#34;mailto:foran.paddy@gmail.com&#34;&gt;foran.paddy@gmail.com&lt;/a&gt;, and I’ll match it. I’m good for the first $100 worth, and I’ll do what I can with the rest.&lt;/p&gt;
</description>
      <carvers:summary>A cause worth supporting.</carvers:summary>
    </item>
    
    <item>
      <title>Young and Brilliant and Good</title>
      <link>https://paddy.carvers.com/posts/aaron/</link>
      <pubDate>Thu, 31 Jan 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/aaron/</guid>
      <description>&lt;p&gt;The above quote comes from Jenny Lawson, commonly referred to as The Bloggess. Jenny is an amazing, funny, caring person, and if you aren’t familiar with her work, &lt;a href=&#34;http://www.thebloggess.com&#34;&gt;you need to go familiarise yourself with it, right the hell now.&lt;/a&gt; Jenny has written more clearly about depression than I’ll ever be able to. No, seriously, stop reading my bullshit, and go educate yourself.&lt;/p&gt;
&lt;p&gt;Because you really need to educate yourself.&lt;/p&gt;
&lt;p&gt;Before I get into this, I want to offer a warning. I have very strong opinions on certain things, and I generally keep them to myself because of the nature of the subjects. They’re immensely personal, and I would no sooner try to change your beliefs than I would try to convince you to change your religion. But this post deals with immensely personal subject matter, and it only makes sense in the context of my personal beliefs.&lt;/p&gt;
&lt;p&gt;So when you disagree with me, just accept that someone may have a differing viewpoint from you, and it’s possible they aren’t trying to convince you to adopt theirs.&lt;/p&gt;
&lt;p&gt;I don’t speak for everyone with depression, any more than I speak for anyone that writes software or anyone battling the flu. But I speak for me.&lt;/p&gt;
&lt;p&gt;I’ve largely held off on writing about Aaron. I say that, having &lt;a href=&#34;https://twitter.com/paddycarver/status/290134983476133888&#34;&gt;tweeted&lt;/a&gt; &lt;a href=&#34;https://twitter.com/paddycarver/status/290179606592507906&#34;&gt;relentlessly&lt;/a&gt; &lt;a href=&#34;https://twitter.com/paddycarver/status/290095484218003456&#34;&gt;about&lt;/a&gt; &lt;a href=&#34;https://twitter.com/paddycarver/status/290133941770412032&#34;&gt;it&lt;/a&gt;, &lt;a href=&#34;https://www.facebook.com/paddycarver/posts/461593037235613&#34;&gt;posting on Facebook about it&lt;/a&gt;, and even going so far &lt;a href=&#34;https://rage-cupcakes.tumblr.com/post/40358983883/its-a-bad-week-to-be-young-and-brilliant-and-good&#34;&gt;as writing on Tumblr&lt;/a&gt; about it. But for all the sharing I did about it, all the visible signs that it had hit me hard… they were a filtered set, a small sampling. It, and the sudden death of a friend from high school a week earlier, hung over me for longer than it should have, and creeped into every corner of my life.&lt;/p&gt;
&lt;p&gt;Had you told me Aaron’s name at the start of the year, I wouldn’t have known who he was. I was, as so many were, introduced to Aaron posthumously. And yet, I felt his death as accutely as I felt the death of someone I had grown up with. Someone I had known for years, someone who was a constant character in the story of my life.&lt;/p&gt;
&lt;p&gt;Because Aaron felt a lot like the protagonist.&lt;/p&gt;
&lt;p&gt;I won’t be so bold as to claim I’m even a fraction of the man Aaron was. He was brilliant and principled and good in ways that I can only dream of being when I’m at my most hubristic. And yet his writing sounded a lot like my own, to my ears. His beliefs felt a lot like mine, his story felt like a “what-if” applied to my own life. What if my parents had supported me when I showed a passion for the internet, instead of trying to drag me away from it?&lt;/p&gt;
&lt;p&gt;I wouldn’t have been Aaron. But then, who would have?&lt;/p&gt;
&lt;p&gt;I’m not fit to mourn Aaron publicly. I’m not fit to write his obituary, I’m not fit to say goodbye to him. Because I never said hello. And so this post isn’t &lt;em&gt;really&lt;/em&gt; about Aaron. This post is about you.&lt;/p&gt;
&lt;p&gt;Yes, you. You, sitting there, reading this. You, ignoring your fellow passengers on public transit as you read my blog post on your phone. You, that friend I haven’t spoken with in years as our lives drew us apart, but who surely loves me as much as I love you.&lt;/p&gt;
&lt;p&gt;This post is about you.&lt;/p&gt;
&lt;p&gt;Because I was very, very angry with you. I was angry with you because you were ignorant.&lt;/p&gt;
&lt;p&gt;You &lt;a href=&#34;https://www.facebook.com/paddycarver/posts/461593037235613?comment_id=4390865&#34;&gt;said&lt;/a&gt; that Aaron somehow didn’t know how loved he was, that he was somehow blind to how much others cared for him. That he couldn’t have known, because if he had, he wouldn’t have taken his own life.&lt;/p&gt;
&lt;p&gt;You &lt;a href=&#34;https://twitter.com/paddycarver/status/290208410958454784&#34;&gt;tried to help&lt;/a&gt;, but fell into the same traps that those you’re trying to instruct fall into. You presumed to know about something you can’t possibly know about.&lt;/p&gt;
&lt;p&gt;You &lt;a href=&#34;http://www.codinghorror.com/blog/2013/01/the-end-of-ragequitting.html&#34;&gt;equated suicide to taking your ball and going home&lt;/a&gt;, and apparently didn’t read what you had written before you posted it. If you had, you would surely have realised that it was obscenely and offensively dismissive of the feelings of someone who is ruled by their feelings. You would have obviously realised that you do not, in fact, “understand that depression is a serious disease that can fell any person, however strong”. Because you don’t understand, if you can honestly equate killing yourself to quitting a goddamn game.&lt;/p&gt;
&lt;p&gt;You &lt;a href=&#34;http://www.theatlantic.com/technology/archive/2013/01/aarons-law-violating-a-sites-terms-of-service-should-not-land-you-in-jail/267247/&#34;&gt;made this political&lt;/a&gt;. I agree with your politics. The federal charges leveled against Aaron certainly provided an impetus, certainly were a part of his decision to die. But you are wrong to focus this tragedy on the court case, you are wrong to &lt;a href=&#34;https://petitions.whitehouse.gov/petition/remove-united-states-district-attorney-carmen-ortiz-office-overreach-case-aaron-swartz/RQNrG1Ck&#34;&gt;demand the removal of the prosecutor that tried his case&lt;/a&gt;. Because in the end, depression is not about circumstances, and anyone that claims it is has an agenda. This tragedy should have been a rallying cry to better understand depression, not an excuse to remove a prosecutor that will simply be replaced by an identical cog in a broken machine.&lt;/p&gt;
&lt;p&gt;But you know what? I was wrong to be angry with you. You were trying to help. You suck at it, but that isn’t really your fault, now is it? Because how the hell are you supposed to know about depression, any more than I know about leukemia or a tumor?&lt;/p&gt;
&lt;p&gt;So now I’m going to tell you about it. I’m going to tell you about it, and not presume to speak for everyone suffering from this disease. Because I don’t. I speak for me. I speak for the underweight, always tired 22 year old sitting in a chair in Syracuse, New York. I speak for the endorphin-flooded music addict that &lt;a href=&#34;http://storify.com/paddyforan/biggayroadtrip&#34;&gt;spent two days with someone he loves to chase a shared dream&lt;/a&gt;, because they could. I speak for the loud, obnoxious, sarcastic, and cynical developer and evangelist that gives you hugs and makes Call Me Maybe references at hackathons. I speak for my mother’s son, my coworkers’ colleague, my siblings’ brother, my peers’ friend. Because that is all I’m qualified to speak as.&lt;/p&gt;
&lt;p&gt;So let me tell you a little about me, and if one day I end up losing the fight, they will at least be able to point you this way, to inform you as to how this could have come to pass. Because I have stared suicide in the face before, have seen that light at the end of the tunnel. And it blinded me, so I looked away. But one day my eyes may be stronger, and that’s just a reality I have to live with.&lt;/p&gt;
&lt;p&gt;The first thing I’m going to tell you is that my depression is not about being &lt;em&gt;sad&lt;/em&gt;. It is about feeling &lt;em&gt;tired&lt;/em&gt;. Not the tired you feel when you’ve been up coding for 48 hours and things are starting to blur and you’re no longer thinking coherently and you’re prone to babble amusing things to anyone who will listen. It’s the kind of tired you feel when you wake up in the morning, knowing you have a bad day at a job you hate ahead of you, and looking forward to getting it over and coming home. Except in my case, I don’t get to come home. It starts when I wake up, and ends when I go to sleep.&lt;/p&gt;
&lt;p&gt;So I distract myself. I throw myself, unhealthily, into work. I &lt;a href=&#34;http://www.secondbit.org&#34;&gt;make things&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/paddycarver&#34;&gt;talk to people&lt;/a&gt; and &lt;a href=&#34;http://www.iron.io/about&#34;&gt;reach for things above my age or education or experience&lt;/a&gt;. Much for the same reason you read that funny comic at work, or focus on the fact that you’re wearing your favourite t-shirt, or relish the sandwich you eat that day.&lt;/p&gt;
&lt;p&gt;Because it’s better than focusing on the crushing feeling of being at the job you hate.&lt;/p&gt;
&lt;p&gt;I first thought about dying when I was sixteen. I was a weird sixteen-year-old, and spent a lot of time contemplating where I stood on things. It’s because I had a fascination with writing, and as I cultivated it, I cultivated my propensity for thinking about questions without answers. And one of those questions regarded what happened to us when we die.&lt;/p&gt;
&lt;p&gt;As a gay teenager, I was decidedly uncomfortable with the idea of a Heaven or Hell. But as a writer, I couldn’t figure out how I would describe that. Because I came to a conclusion about how I experienced things. To this day, &lt;a href=&#34;http://xkcd.com/915/&#34;&gt;Randall Munroe has outdone even my most eloquent efforts to express it&lt;/a&gt;: “Our brains have just one scale, and we resize our experiences to fit.” If we have but one scale, and everything must fit on that scale, then surely our lives must always have pain in them, right? And surely they must always have pleasure? Because what I, from my position of privilege and comfort, may consider “painful”, someone more marginalised or less fortunate would be ecstatic to experience. And if the pain or pleasure derived from something is entirely relative and subjective, how could you spend an eternity experiencing only pleasure? You would adapt to it, consider it the new normal, and come to take it for granted, no longer deriving happiness from it. So Heaven, a place of pure happiness for all eternity, couldn’t exist in any form we can conceive of. I will put that qualifier there as a concession to my religious readers; I am not trying to argue that your religion of choice is wrong, nor that your idea of the afterlife is wrong. I chose to base what I believe about what happens after I die on what I can conceive of and what reason could provide me. That is as much an act of faith as any religious belief, and I won’t attempt to persuade you that it is the right one.&lt;/p&gt;
&lt;p&gt;So of course, I concluded that when I died, I simply ceased to exist. Not in that I became part of the world, nor did I think I drifted off into some blackness. My theory was, and is, that I will simply have no consciousness to speak of. There will be no Paddy. Because I rooted my existential crisis in my self-perception; I am a set of ever-shifting principles and beliefs that I hold. This is really vague, and seemingly-contradictory; I’m purposefully trying to keep this brief, because this post isn’t really about my existential conclusions. They’re simply an important backdrop to my conclusions about dying.&lt;/p&gt;
&lt;p&gt;Because I’m totally okay with dying. The idea of not existing at all doesn’t bother me; it actually is a really enticing proposition. Because of that tiredness. Dying sounds a lot like clocking out at the end of the job you hate, and finally releasing all the tension you’ve held between your shoulders for eight hours. It sounds like finally resting.&lt;/p&gt;
&lt;p&gt;I even decided, as a teenager, that I wanted to die young. “Young” is decidedly vague, but I knew at a certain point I would grow into someone that held no resemblance to the person I conceived myself as. These changes are outside of my control, part of the aging process, and they make me really, really uncomfortable. And I knew one day I would wake up and no longer recognise the person in the mirror. And I didn’t want to see that day.&lt;/p&gt;
&lt;p&gt;I never actually decided I wanted to commit suicide young; I still don’t. But it’s something I kind of hope the universe will just take care of for me. That before the day comes where I don’t recognise myself anymore, where I don’t even bear a passing resemblance to the person I feel like I am, I’ll die quietly in my sleep, or so suddenly my body doesn’t even have time to panic.&lt;/p&gt;
&lt;p&gt;And a lot of people would say that’s unhealthy. They may be right. But much like I never really gave anyone permission to judge who I can love, I never gave anyone permission to tell me whether or not what I want is healthy. You don’t know what my “sound mind” looks like; you don’t get to judge when what I want is a valid choice. Which is why I get so angry when people say Aaron made a rash choice. Who the fuck are you to judge? Maybe he carefully weighed his options and priorities, and that was the rational decision he arrived at.&lt;/p&gt;
&lt;p&gt;And just because his death caused you grief doesn’t mean it bothered him.&lt;/p&gt;
&lt;p&gt;So if I’m so comfortable with dying, why am I still alive? There are two reasons, and the degree to which they apply to my current mindset varies over time and situations.&lt;/p&gt;
&lt;p&gt;The first is because I’m becoming increasingly better at distracting myself. Sometimes I get a setback, and don’t manage my life as well as I should, and I’longer able to distract myself. I end up doing things I hate. Which adds insult to illness; it’s like getting up to go to work at the job you hate, knowing that not only do you not have the sandwich you like, you don’t have any money for lunch at all, and are going to have to go hungry that day. It’s the extra kick in the nuts that the universe gives you, after it sucker punches you in the gut. But I’m getting increasingly better at managing this, and I’m lucky enough to get so many opportunities to work on interesting projects, it is rare that I go a day without my proverbial sandwich. It’s an amazing time to be a developer, and I’m really, really fortunate for that.&lt;/p&gt;
&lt;p&gt;The second is because I am my mother’s son, my coworkers’ colleague, my siblings’ brother, my peers’ friend. And even if I’m okay with the idea of death, if not the actual act of dying (our bodies are pretty against that, instinctually), those people are not. They actually get pretty upset about it. And while I won’t care if they’re upset if I’m dead, I &lt;em&gt;will&lt;/em&gt; care if I’m planning to upset them while alive. So the guilt of abandoning those people keeps me moving, much like someone will endure a job they hate to provide for the people they love. This isn’t a good reason to live; motivation by guilt never gets either party what they really want. It doesn’t lead to good work from employees, it’s not a great foundation to build a relationship on, and it’s not going to make someone live a happy life. But it keeps one foot in front of the other when there’s no other reason to keep walking.&lt;/p&gt;
&lt;p&gt;When I was in college, I originally studied to be an English teacher. I saw our education system was so incredibly fucked up it defied belief, and I had the hubris to try and change that. Two years into the major, I called it quits. Trying to fight the system almost killed me, because I couldn’t fight on two fronts at once. I could battle the depression or I could battle the education system, but I couldn’t fight both of them. When I tried, I lost on both fronts.&lt;/p&gt;
&lt;p&gt;Because of that, I’m proud of Aaron. With all due respect, Mr. Atwood can go fuck himself. It is nothing short of extraordinary that Aaron managed to fight the system as long and successfully as he did. I could not have done it, and I humbly submit that neither could Mr. Atwood. Aaron’s extraordinary efforts and accomplishments are something to be lauded and marvelled at, not something to be disappointed in him over. What I did, Mr. Atwood, when I quit the degree program and decided to let the education system go on being a mess, was taking my ball and going home. That is not what Aaron did. When I was younger, I played football as part of a rec league. My father had a saying, that we should “leave everything on the field”. The idea was that we should so play so hard, we’d have nothing left to give when the game was over. And that way, if we lost, we knew we lost because the other team had practised harder or was better, and not because of some mistake or bad call. And that if we won, we knew we had earned it.&lt;/p&gt;
&lt;p&gt;Aaron didn’t take his ball and go home. He left everything on the field.&lt;/p&gt;
&lt;p&gt;So, if you made it this far, I hope you know a little more about depression than you did when you started. I hope you, at the very least, know how much you don’t know. Who knows, maybe you’ll be interested enough to find out more.&lt;/p&gt;
&lt;p&gt;But at the very least, I hope the next time someone young and brilliant and good commits suicide—because there will always be a next time—I hope you’ll ask questions, not offer conclusions.&lt;/p&gt;
&lt;p&gt;Because you have none.&lt;/p&gt;
</description>
      <carvers:summary>Death, depression, and a reminder that your conclusions are invalid. This has nothing to do with Aaron and everything to do with you.</carvers:summary>
    </item>
    
    <item>
      <title>2012</title>
      <link>https://paddy.carvers.com/posts/2012/</link>
      <pubDate>Sun, 06 Jan 2013 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2012/</guid>
      <description>&lt;p&gt;For me, 2012 began as a contradiction. It was literally the best of times and the worst of times. I had just told my family I wanted to drop out of college and abandon my degree. This brought with it the expected feelings of failure and shame, as dropouts are stigmatised in our culture (fortunately in the tech industry less than in other industries) and really disappointed my parents, who really value a college degree for reasons of their own. But it also brought a huge sense of relief; the education system and I never really saw eye to eye, and I constantly found myself the exception to the rule, getting held back by the very programs put in place to help me succeed. After years of constantly struggling with a system, it was nice to know I was free of it. Like I had escaped.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve grown a lot as a person in the last twelve months, and this is my way of celebrating that. I understand most people write these posts on the first of the year; I chose to wait until the sixth for convenience. Because while I am proud of the progress I made in 2012, I&amp;rsquo;m more proud of the progress I made since being employed by &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;. The first day I billed time to Iron.io was 1/6/12, so it seemed silly to celebrate 2012 and the first year of my career within a week of each other.&lt;/p&gt;
&lt;h2 id=&#34;career&#34;&gt;Career&lt;/h2&gt;
&lt;p&gt;When I started with Iron.io, they were hiring to fill a software engineer position. I told them I wanted to apply to be a software engineer intern. I had &lt;a href=&#34;https://paddy.carvers.com/posts/2cloud/&#34;&gt;written software&lt;/a&gt; that was used by thousands of people, but I still hadn&amp;rsquo;t worked with a team, and this was my first “proper” foray into the industry. I knew I&amp;rsquo;d need to grow into my role, and it didn&amp;rsquo;t seem fair to ask a company to consider me a full employee while they were still teaching me the basics. The thing I wanted most from Iron.io was to be in an environment where I could learn. To gain enough experience that I could call myself a professional software engineer with a straight face.&lt;/p&gt;
&lt;p&gt;It started off simple, with me writing examples and software to bring myself up to speed on the platform. When I look back on how I thought and the software I wrote then, I&amp;rsquo;m glad I asked for the internship; I wasn&amp;rsquo;t ready. I&amp;rsquo;ve learned so much since then, it&amp;rsquo;s painful to look back on. Which is exactly what I was hoping for. I feel comfortable in the industry, and am proud of my accomplishments in the last year.&lt;/p&gt;
&lt;p&gt;My job quickly (as in, less than two months later) turned into a documentation position. This happened subtly; nobody ever asked me to do it, and I never asked if I should. I saw in the course of my work that our documentation wasn&amp;rsquo;t good enough, so I fixed it. And people liked it. So I kept fixing documentation. Then I &lt;a href=&#34;http://dev.iron.io&#34;&gt;built a new documentation platform&lt;/a&gt;. I slowly wrote less and less software and more and more documentation.&lt;/p&gt;
&lt;p&gt;Then I attended &lt;a href=&#34;http://www.ubhacking.com&#34;&gt;UBHacking&lt;/a&gt; to represent Iron.io, for no reason other than because I was already in Buffalo and knew the organiser. And then I found myself attending more hackathons and conferences, speaking to developers, and working on outreach. Six months in, I took on the title of &lt;a href=&#34;https://paddy.carvers.com/posts/developer-experience-engineer/&#34;&gt;Developer Experience Engineer&lt;/a&gt; and became a full-time employee. At this point, I started looking into moving to San Francisco.&lt;/p&gt;
&lt;h2 id=&#34;moving&#34;&gt;Moving&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve always loved San Francisco. It&amp;rsquo;s a great city. It feels right to me. I&amp;rsquo;m always happier when I&amp;rsquo;m there visiting. Iron.io is headquartered in San Francisco, and they expressed interest in having me located out there. I was excited. Unfortunately, the housing market in San Francisco is pretty competitive now, so it was hard to find an apartment. I tried on and off while I lived in Buffalo, but I opted not to renew my lease when it expired at the end of August. I moved back to Syracuse to live with my parents for a month or two as I searched for a San Francisco apartment. And still, my search suffered. Every time I went out to San Francisco to visit the office or attend an event, I&amp;rsquo;d search for apartments and listings and put in my application, to no avail. As the weeks turned to months, I began to get antsy. My parents had told family friends I was moving to San Francisco, so everyone I spoke to asked why I was still here and what was going on with San Francisco. I considered my stay in Syracuse temporary, so I didn&amp;rsquo;t bother setting down roots; I effectively just lived in limbo, without bothering to make new friends in the area or establish myself in the community. What&amp;rsquo;s the point? I&amp;rsquo;d be gone in a couple months.&lt;/p&gt;
&lt;p&gt;Finally, I got frustrated enough that I made a reservation to stay with an Airbnb host in Palo Alto for a few days, paid for a flight out there, and spent two days on public transportation travelling all around the Valley looking at apartments and putting in applications. I submitted dozens of applications, got some good leads, and flew home optimistic.&lt;/p&gt;
&lt;p&gt;Unfortunately, unforeseen circumstances cropped up. While I can&amp;rsquo;t go into too many details here (they aren&amp;rsquo;t mine to share), I would no longer be able to afford to move to San Francisco. It&amp;rsquo;s simply too expensive. The day after I learned this, of course, my first choice for the applications I submitted called me to tell me my application was approved. Irony&amp;rsquo;s a bitch.&lt;/p&gt;
&lt;p&gt;I, of course, hadn&amp;rsquo;t thought to make a backup plan, and now I&amp;rsquo;m not sure what I&amp;rsquo;m doing next. I have a couple options I&amp;rsquo;m investigating, but I don&amp;rsquo;t really have a solid plan of action laid out in front of me anymore. Which is starting to get to me. Between the constant questions about why, after six months, I&amp;rsquo;m still living at home, the state of limbo my life is in in regards to setting down roots, and the number of San Francisco-themed gifts well-meaning relatives and friends gave me for Christmas, I&amp;rsquo;m starting to get restless. I need to do something in the next month or two, but I don&amp;rsquo;t know what that is yet.&lt;/p&gt;
&lt;h2 id=&#34;second-bit&#34;&gt;Second Bit&lt;/h2&gt;
&lt;p&gt;This year is a year of guilt for me, in relation to Second Bit. Why? Because absolutely no new software was rolled out this year. None. Zero. Zilch. &lt;a href=&#34;http://www.2cloudproject.com&#34;&gt;2cloud&lt;/a&gt; has not been updated since I joined Iron.io. This is not at their behest—we had a very good conversation about it when I joined the company, and set up very clear boundaries. They generously permitted me to do my own thing in my own time, and I&amp;rsquo;m grateful for that.&lt;/p&gt;
&lt;p&gt;But the changes 2cloud is undergoing—the changes it &lt;em&gt;needs&lt;/em&gt; to undergo—are so all-encompassing, it&amp;rsquo;s really hard to get any traction working on it a bit here and a bit there. I&amp;rsquo;ve tried so many things, written so many iterations of small pieces, and learned so much. I know, intellectually, that the company has made great progress in the last year. But we didn&amp;rsquo;t ship &lt;em&gt;anything&lt;/em&gt;, and that really bothers me.&lt;/p&gt;
&lt;p&gt;Comparatively speaking, the amount of work remaining to be done is pretty little. It&amp;rsquo;s achievable. I can do it. I just don&amp;rsquo;t know how long it&amp;rsquo;s going to take, or how many users will hold out until then. I feel as though I&amp;rsquo;ve set myself between Iron.io and my users, and no matter what I do, I&amp;rsquo;m being unfair to one or the other. But all I can do is my best.&lt;/p&gt;
&lt;p&gt;Several times I toyed with the idea of striking out on my own and trying to make Second Bit into a full-time job for me. Especially during the periods when my job at Iron.io loses the balance it has between technical writing, engineering, and outreach, and starts to become too much about the technical writing. These periods are brief and infrequent, but they remind me that I never wanted to be a technical writer. Two things hold me back, every time: I love Iron.io and the people that work there, and don&amp;rsquo;t want to leave them unless it&amp;rsquo;s the best thing for both of us; and I&amp;rsquo;m not convinced that I can persuade enough users to pay me for my software that I can sustain myself on it.&lt;/p&gt;
&lt;h2 id=&#34;looking-forward&#34;&gt;Looking Forward&lt;/h2&gt;
&lt;p&gt;If I were one for resolutions, my resolution this year would be to ship the next version of 2cloud, and find out what it can be. It would also be to find the appropriate balance between my users and Iron.io, a balance that everyone can be content with.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know what 2013 is going to hold for me. I don&amp;rsquo;t know what city I&amp;rsquo;ll be in, who will be around me, or what my career and work life will look like. But during the soul searching that followed my dream of moving to San Francisco being crushed, I stumbled upon exactly what I want in life:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“My dream is to do things I love with people I like and feel good about what I&amp;rsquo;ve done at the end of the day.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And in 2012, I did that. In 2013, I hope to do it some more.&lt;/p&gt;
</description>
      <carvers:summary>A self-indulgent post celebrating the victories I won in 2012, my regrets for the year, and hopes for 2013.</carvers:summary>
    </item>
    
    <item>
      <title>The Open Web</title>
      <link>https://paddy.carvers.com/posts/open-web/</link>
      <pubDate>Tue, 18 Dec 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/open-web/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I originally wasn’t sure I was going to publish this. I wrote it to get something off my chest, but I was concerned it was too personal to consider publishing. Then someone had the immense courage to &lt;a href=&#34;http://news.ycombinator.com/item?id=4928031&#34;&gt;post on Hacker News&lt;/a&gt; about their depression and needing help. I spoke with that person, chatted with him, and hope we continue chatting. He’s a wonderful person. And that is why this post is being published.&lt;/p&gt;
&lt;p&gt;I’ve used Twitter regularly since 2008. My intention is not to try and claim that I was using the service before it was cool; I’m not entirely sure I was. My point is simply that, for about four years now, I’ve become increasingly prone to tweeting without thinking. It’s more of a prosthesis, an extension of myself, than it is a service. At the time of this writing, I’ve posted 17,360 tweets. That’s almost eleven tweets a day, every day, for four years. More important than the quantity of tweets, however, is their content; you’ll find no better representation of my personality.&lt;/p&gt;
&lt;p&gt;There are tweets about my ongoing love affair with pickles (&lt;a href=&#34;https://twitter.com/paddycarver/status/237909972845989891&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/181827744177471490&#34;&gt;2&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/181850241677533184&#34;&gt;3&lt;/a&gt;). There’s the ongoing epic around a teddy bear that is far more awesome than he has any right to be (&lt;a href=&#34;https://twitter.com/paddycarver/status/253205166713606144&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/228026749231976448&#34;&gt;2&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/209578417073557504&#34;&gt;3&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/210383246503067648&#34;&gt;4&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/212796718834655232&#34;&gt;5&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/216209161757786113&#34;&gt;6&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/187942048291225601&#34;&gt;7&lt;/a&gt;). There are my frank admissions that I’m absolutely crazy (&lt;a href=&#34;https://twitter.com/paddycarver/status/253310599184936960&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/219846725056204800&#34;&gt;2&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/229548185536835584&#34;&gt;3&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/191441955295727616&#34;&gt;4&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/171635085362212864&#34;&gt;5&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/150873123229671424&#34;&gt;6&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/129781120601563138&#34;&gt;7&lt;/a&gt;). There are moments of clarity, when I realise how fortunate I am (&lt;a href=&#34;https://twitter.com/paddycarver/status/223447925387309056&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/128909896895832065&#34;&gt;2&lt;/a&gt;). There are times where I publicly harangue my good friend, &lt;a href=&#34;http://dstaley.me&#34;&gt;Dylan&lt;/a&gt; (&lt;a href=&#34;https://twitter.com/paddycarver/status/223530561652785152&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/223524945983057920&#34;&gt;2&lt;/a&gt;) (and, when he’s lucky, &lt;a href=&#34;https://twitter.com/paddycarver/status/46782256857092096&#34;&gt;shower praise on him&lt;/a&gt;). There are jokes about what an asshole I am (&lt;a href=&#34;https://twitter.com/paddycarver/status/223551826258169857&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/229561938391203840&#34;&gt;2&lt;/a&gt;), or how inappropriate I can sometimes be (&lt;a href=&#34;https://twitter.com/paddycarver/status/223793465920733184&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/127399820594905088&#34;&gt;2&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/127600022610124800&#34;&gt;3&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/42739443421032448&#34;&gt;4&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/45983292222214144&#34;&gt;5&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/107602520133746688&#34;&gt;6&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/992113974&#34;&gt;7&lt;/a&gt;). There is my ongoing fascination with injuring myself in odd ways (&lt;a href=&#34;https://twitter.com/paddycarver/status/227743566674395136&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/206887198727999489&#34;&gt;2&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/186214559185510400&#34;&gt;3&lt;/a&gt;). There are my &lt;a href=&#34;https://twitter.com/paddycarver/status/229530231088758784&#34;&gt;moments&lt;/a&gt; of &lt;a href=&#34;https://twitter.com/paddycarver/status/182552841725022208&#34;&gt;hubris&lt;/a&gt;. There’s my ongoing adventure with (prescribed) medication (&lt;a href=&#34;https://twitter.com/paddycarver/status/230432235893964801&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/179097445945458688&#34;&gt;2&lt;/a&gt;). There’s my &lt;a href=&#34;https://twitter.com/paddycarver/status/232212555601424386&#34;&gt;love affair&lt;/a&gt; with &lt;a href=&#34;https://twitter.com/paddycarver/status/232357011650670592&#34;&gt;Call Me Maybe&lt;/a&gt;. There’s my refusal to accept the way &lt;a href=&#34;https://twitter.com/paddycarver/status/201988502718648321&#34;&gt;education&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/paddycarver/status/196976483854598144&#34;&gt;employment&lt;/a&gt; work. There are my public resignations to failure (&lt;a href=&#34;https://twitter.com/paddycarver/status/206542282382512128&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/217433358580449282&#34;&gt;2&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/29654692283813888&#34;&gt;3&lt;/a&gt;) and my shared &lt;a href=&#34;https://twitter.com/paddycarver/status/127905853109043200&#34;&gt;exuberance at success&lt;/a&gt;. There’s my &lt;a href=&#34;https://twitter.com/paddycarver/status/189179814261956610&#34;&gt;love of dancing&lt;/a&gt;. There are admissions that a project is not going as well as I’d like (&lt;a href=&#34;https://twitter.com/paddycarver/status/161190210976227330&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/128003752698449920&#34;&gt;2&lt;/a&gt;). There are &lt;a href=&#34;https://twitter.com/paddycarver/status/162582849931853824&#34;&gt;pep talks to myself&lt;/a&gt;. There’s my &lt;a href=&#34;https://twitter.com/paddycarver/status/165036297306640385&#34;&gt;unique way of describing things I love&lt;/a&gt;. There’s my war against my roommate’s demon kittens (&lt;a href=&#34;https://twitter.com/paddycarver/status/168057629665529858&#34;&gt;1&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/paddycarver/status/147591100637519872&#34;&gt;2&lt;/a&gt;). There are &lt;a href=&#34;https://twitter.com/paddycarver/status/170660140599615488&#34;&gt;silly parodies of pop songs&lt;/a&gt; I make up because I’m crazy. There’s &lt;a href=&#34;https://twitter.com/paddycarver/status/126009522824298497&#34;&gt;my refusal&lt;/a&gt; to &lt;a href=&#34;https://twitter.com/paddycarver/status/106007217576214531&#34;&gt;act my age&lt;/a&gt;. There are moments when I &lt;a href=&#34;https://twitter.com/paddycarver/status/56037491454644224&#34;&gt;dare to dream&lt;/a&gt;—even if it’s &lt;a href=&#34;https://twitter.com/paddycarver/status/24902547073&#34;&gt;a silly dream&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Twitter has all of these things, archived, &lt;a href=&#34;http://blogs.loc.gov/loc/2010/04/how-tweet-it-is-library-acquires-entire-twitter-archive/&#34;&gt;stored forever&lt;/a&gt; as a digital representation of me in the purest form I can think of. Most, if not all, of the people I meet through Twitter end up becoming good friends. I feel as if I already know them, because they’ve been so well represented by their tweets.&lt;/p&gt;
&lt;p&gt;I don’t wish to claim that this is globally true, nor do I wish to imply that Twitter somehow has a monopoly on this. I think that other social sites could do this, and already may for some people. For me, the tool that is best suited for my self-expression is Twitter.&lt;/p&gt;
&lt;p&gt;My point, though, is that the web has given me permission to be transparent. There’s a lot of talk about the &lt;a href=&#34;http://www.google.com/intl/en/takeaction/whats-at-stake/&#34;&gt;open web&lt;/a&gt; (again), but every time we talk about this, we seem to forget that an open web is as much about the people as it is about the technology.&lt;/p&gt;
&lt;p&gt;Every time I’m asked about how to evangelise, I end up rehashing the same message: stop selling things, start engaging in a conversation. Be authentic, be open, be transparent, be honest. People can detect bullshit, people hate being pitched. But if you stop thinking about them as a customer and start thinking of them as a friend, you can actually try to help them solve their problem. And if they don’t have a problem or your product wouldn’t solve it, it’s for the best that you didn’t make that sale. Selling things on false premises only leads to poor customer experiences. I always wonder why this isn’t standard practice, why people don’t just intuitively know this.&lt;/p&gt;
&lt;p&gt;Then I remember how much it took me to learn it. I wasn’t doing it on purpose. I was enduring four of the hardest years of my life, and a lot of times, I felt like I had nobody to talk to. So I threw tweets out, not caring if anyone was listening. I just needed to say it. It wasn’t about sharing, it wasn’t about fishing for retweets, it wasn’t about connecting with someone. Twitter was my free therapist… who would publish notes after every session for the world to read.&lt;/p&gt;
&lt;p&gt;A couple years after I started using the service like this, I noticed it bleeding out a little into my offline life. I’ve never had a whole lot of self-confidence, but by daring to be open about what I thought and who I was online, I got little shots of courage to carry that offline. I stopped worrying if people didn’t like me or thought less of me because of something I said; if they didn’t like how I thought, why try to hide it to maintain a fake friendship or escape their derision? If I was wrong, the only way to correct my mistakes was to be brazenly wrong, so others could point out my flaws.&lt;/p&gt;
&lt;p&gt;That’s not to say I went out of my way to offend everyone I could because “fuck you if you don’t like me”. It’s just a mental shift to realising that the only person I have to face in the mirror every morning is myself. And that that’s where my self-worth and morals should derive from, not from what the people around me thought.&lt;/p&gt;
&lt;p&gt;So far, I’ve been rewarded for it. Despite tweeting things that are offensive and vulgar. Despite tweeting things I look back on and feel shame about. I’ve accumulated a respectable 350-some-odd Twitter followers, but it’s not really the number that matters. The number of people I respect and admire who follow me is astonishing; these are people who I would be intimidated to approach in real life, people whose work and creativity I am in awe of. And they subscribe to a feed of my unfiltered childish thoughts. I’m embarassed every time I remember they’re listening, but then I remember they’ve listened for years, and they know all the undesirable things about me. They’ve seen me at my lowest, my highest, and everywhere in-between.&lt;/p&gt;
&lt;p&gt;And they still listen to me. They still think I’m worthy of their attention.&lt;/p&gt;
&lt;p&gt;And if they think highly of me, maybe I should, too.&lt;/p&gt;
&lt;p&gt;I’ve &lt;a href=&#34;https://plus.google.com/112924888792635085586/posts/8Go2tSYpZwS&#34;&gt;written before&lt;/a&gt; about how I use the internet as a crutch. It’s kind of a sensitive subject for me, and not something I like writing about frequently. It’s not something I consider a huge part of my personality, and it’s certainly not the most important thing I want to talk about. There are so many more interesting conversations I think I could add value to.&lt;/p&gt;
&lt;p&gt;But we &lt;a href=&#34;http://adambrault.com/post/37201680402/i-quit-twitter-for-a-month-and-it-completely-changed-my&#34;&gt;seem to be&lt;/a&gt; circling back to the idea of disconnecting. Of standing up, walking away from the keyboard, and getting some fresh air. Of taking some time to think and be with ourselves. And I don’t wish to discredit or argue that idea at all. Adam (who wrote that post) and &lt;a href=&#34;http://andyet.net&#34;&gt;&amp;amp;yet&lt;/a&gt; (the company he started) are precisely the type of people I was referencing earlier; people who leave me starstruck when they, for some reason, decide I’m worth talking to. And I think what Adam proposes holds value and is a wonderful idea, in many cases. But it’s not an idea I’m willing to try in the near future. Not because I’m afraid I’ll miss out on something, not because there’s an argument I want to be involved in, not because I’m afraid of being forgotten, not because of any of the reasons Chris Williams (another individual I respect) &lt;a href=&#34;http://www.youtube.com/watch?v=x7LchINN7lU&#34;&gt;outlined in his (silent) talk&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s because what Adam said is very, very true. “Twitter is outsourced schizophrenia. I have a couple hundred voices I have consensually agreed to allow residence inside my brain.” And these voices are all telling me I’m good enough when poisonous thoughts tell me I’m not. They can drown out a mental illness. Because I’m able to express myself, and get positive reinforcement from others on that self that is expressed, I get to spend more time with my family, build more things that require creative vulnerability, have deeper relationships with friends, think about things that I wouldn’t be able to if I were caught in a depressive downward spiral, and &lt;strong&gt;find happiness with myself&lt;/strong&gt;. You’ll recognise those as the same benefits Chris lists during his talk, but they hold true. And that last one is the most important.&lt;/p&gt;
&lt;p&gt;Four years ago, I couldn’t say that.&lt;/p&gt;
&lt;p&gt;Two years ago, I couldn’t say that.&lt;/p&gt;
&lt;p&gt;Sometimes, what we need is to step away from the keyboard. Sometimes we need some time with ourselves, some time to think. Sometimes, we think too much, and what we desperately need is less time with ourselves. Especially if your self is an asshole, like I am.&lt;/p&gt;
&lt;p&gt;Regardless, I’d argue we could all stand to have a little more openness in our lives. And that goes for our technologies and our communications.&lt;/p&gt;
</description>
      <carvers:summary>The open web is not about technology, it is not about sharing source code or ideas. It’s about people.</carvers:summary>
    </item>
    
    <item>
      <title>What Did You Expect?</title>
      <link>https://paddy.carvers.com/posts/what-did-you-expect/</link>
      <pubDate>Wed, 24 Oct 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/what-did-you-expect/</guid>
      <description>&lt;p&gt;I really just need to stop reading Hacker News. Almost every single day, I see an article that makes me angry. Today’s lucky winner: &lt;a href=&#34;http://dangerousminds.net/comments/facebook_i_want_my_friends_back&#34;&gt;FACEBOOK: I WANT MY FRIENDS BACK&lt;/a&gt;. Yes, the title is in all capital letters. That’s how you &lt;em&gt;know&lt;/em&gt; it’s a rational, reasonable, well-grounded article.&lt;/p&gt;
&lt;p&gt;I’m not going to dissect this article paragraph by paragraph (though phrases like “the single most misguided thing a major corporation has ever deliberately done, bar none, in the entire history of American capitalism and the world.” and “How many companies can you name that you actively despise?”—the most profitable company in the world is &lt;em&gt;actively despised&lt;/em&gt; by a good number of people—make this a &lt;em&gt;decidedly&lt;/em&gt; tempting endeavour), and am instead going to use it as an excuse to get something off my chest. For those of you who do not want to read the very long, unintentionally humorous post: a blog built a large Facebook audience that drove a lot of traffic to their page. When Facebook’s Sponsored Stories launched, only about 15% of the audience saw content the page posted, and they were told they’d have to pay to have the other 85% see the content. They are, understandably, upset about this. They claim, not-so-understandably, that this is (and I quote) “information superhighway robbery”.&lt;/p&gt;
&lt;p&gt;Do people still even &lt;em&gt;say&lt;/em&gt; “information superhighway”? Apparently, they do.&lt;/p&gt;
&lt;p&gt;But still, let’s get to my main gripe with this bullshit article: “But I can’t pay them $2000 a day and $672,000 a year for the exact same product that I was getting for free back in March!”&lt;/p&gt;
&lt;p&gt;Let’s ignore the questionable math they used to arrive at that figure. Let’s look at the overarching argument: “Hey! You used to give me something for free and want money for it now! Stop that!”&lt;/p&gt;
&lt;p&gt;The declaration that charging for something you used to give away for free is somehow &lt;em&gt;inherently wrong&lt;/em&gt; is mind-blowing to me. Because Facebook was kind enough to do all the work of building the platform, gathering the audience, and giving you the tools to reach that audience &lt;em&gt;for free&lt;/em&gt;, they are obligated to do so &lt;em&gt;forever&lt;/em&gt;? They are somehow &lt;em&gt;evil&lt;/em&gt; or, to quote the article, “;&lt;em&gt;staggeringly inept&lt;/em&gt;” because they can’t afford to run a platform for a billion people on nice words, fairy dust, and smiles?&lt;/p&gt;
&lt;p&gt;Facebook is a &lt;em&gt;business&lt;/em&gt;. Even if their purpose for existence isn’t to make as much of a profit as they can (it shouldn’t be, in my mind), they still need to be making money to continue to exist. Just as breathing isn’t your purpose for living, but is necessary for you to live.&lt;/p&gt;
&lt;p&gt;So how did they offer so much for free for so long? Well, they took money from investors. But that had a tradeoff: the game investors play requires a big exit. That means that Facebook couldn’t just break even, they had to do spectacularly well, so the investors could get their big payout.&lt;/p&gt;
&lt;p&gt;So Facebook went IPO. That gave the investors the big payout, but stacked another card on top of the already teetering tower: now they have to answer to so many more investors; the public.&lt;/p&gt;
&lt;p&gt;This is all a direct consequence of offering that service for free. That service, I might add, that the blog that is raising such a fuss &lt;em&gt;built their business on&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I, frankly, can’t believe that someone has the audacity to take advantage of a temporary market condition, build a business on it, and then &lt;em&gt;complain&lt;/em&gt; when that market condition shifts, as if they thought that the money spigot would continue flowing, for free, forever. And it’s something we’re seeing more and more. Twitter? They’re having the same problem. There is no such thing as a free lunch. And if you like a service, you &lt;a href=&#34;http://blog.pinboard.in/2011/12/don_t_be_a_free_user/&#34;&gt;shouldn’t be a free user&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Easy for me to say, right? I don’t run a successful blog that makes money from Facebook. &lt;em&gt;I&lt;/em&gt; didn’t invest the time in building a Facebook audience, only to have it ripped away from me.&lt;/p&gt;
&lt;p&gt;Well, actually, funny story.&lt;/p&gt;
&lt;p&gt;Back in 2010, I wanted to learn how to write Android apps. So I wrote an app to learn. Lifehacker covered it, and the rest, as they say, &lt;a href=&#34;https://paddy.carvers.com/posts/2cloud/&#34;&gt;is history&lt;/a&gt;. This is relevant, because the app required a server component. I used Google’s App Engine, a free host that required me to write code in a specific way that locked me into the service, to build the server component. After some tweaking and working with Google to improve one of their products (even debugging and fixing their code myself), I had my application serving 10,000 users for a dollar a day. Let me repeat that: &lt;em&gt;ten thousand&lt;/em&gt; users, &lt;em&gt;$1 a day&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Then, one year later, &lt;a href=&#34;http://googleappengine.blogspot.com/2011/05/year-ahead-for-google-app-engine.html&#34;&gt;Google changed the pricing on App Engine&lt;/a&gt;. A lot of developers were upset by this. I was not. My prices were being hiked, and I knew that I wouldn’t be able to afford to stay on App Engine indefinitely under the new pricing and had to start making plans to switch off, but I knew better than to be upset. Why? Because I had met some of the people working on App Engine during the time I had been a customer. I enjoyed talking to them, and got to know them. When things went wrong, instead of getting angry and yelling, I offered support and encouragement. I cared about those people.&lt;/p&gt;
&lt;p&gt;And I knew they cared about me.&lt;/p&gt;
&lt;p&gt;If they were raising my prices, it’s because they had to. Because, at the end of the day, they had been running the service for me &lt;em&gt;at cost&lt;/em&gt; while I built my business on top of it. It would be ludicrous for me to be upset with them for trying to finally stop bleeding money. And yet, that is &lt;em&gt;exactly&lt;/em&gt; what is happening to Facebook and Twitter. Rather than being grateful they had the opportunity to build their audience &lt;em&gt;for free&lt;/em&gt;, people are getting angry that they can’t &lt;em&gt;continue&lt;/em&gt; to build their audience for free &lt;em&gt;indefinitely&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now, of course, I’m biased. That project that I built on App Engine is turning into a paid service soon. I’m going to require users to pay me to use what they previously had for free. I’m doing what I can to soften the blow, but I’m not paying for the free ride anymore. And pay I have. I listed out the &lt;a href=&#34;http://www.2cloudproject.com/finances&#34;&gt;finances&lt;/a&gt; of the project publicly a year ago, and since then, we’ve only gone further into the red. Much further. To the tune of $100 or $200 a month. And I’ve paid all of that, out of pocket, patiently. I’m not even looking to recoup that, necessarily. I just want to stop the bleeding. But users will tell me I’m selfish, that I’m trying to milk them, that I pulled a bait-and-switch. That what I am doing is not &lt;em&gt;fair&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I’m going to tell them to go fuck themselves. What I have done for the last two and a half &lt;em&gt;years&lt;/em&gt; wasn’t fair. It isn’t until now that I am finally being fair.&lt;/p&gt;
&lt;p&gt;At the end of the day, is there any company you can trust? How do you know where to build your audience? How do you know that the rug won’t be pulled out from under you in a year, two years, tomorrow, the next day?&lt;/p&gt;
&lt;p&gt;It’s a simple litmus test: are you contributing to the company’s bottom line? Are you paying them for the value you’re extracting from them?&lt;/p&gt;
&lt;p&gt;If the answer’s no, you have no right to be angry when that gravy train stops running.&lt;/p&gt;
</description>
      <carvers:summary>Sometimes, I have to wonder if people think online services are powered by unicorns, smiles, and friendly words.</carvers:summary>
    </item>
    
    <item>
      <title>How Do You People Take Me Seriously?</title>
      <link>https://paddy.carvers.com/posts/seriously/</link>
      <pubDate>Tue, 23 Oct 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/seriously/</guid>
      <description>&lt;p&gt;To date, I have “published” precisely two pieces of software. The first was &lt;a href=&#34;http://www.secondbit.org/2cloud&#34;&gt;2cloud&lt;/a&gt;, a hack I wrote in my spare time to learn how to write Android apps. It was subsequently &lt;a href=&#34;http://lifehacker.com/#!5604248/android2cloud-opens-urls-from-your-phone-in-chrome&#34;&gt;covered by Lifehacker&lt;/a&gt;, exploded into an open source project far beyond my ability to control, and eventually went on to earn a rating of 8/10 from Wired.&lt;/p&gt;
&lt;p&gt;The second was &lt;a href=&#34;http://secondbit.org/blog/introducing-pastry/&#34;&gt;just published this weekend&lt;/a&gt;. It’s a distributed hash table written in Go.&lt;/p&gt;
&lt;p&gt;I was nervous before releasing this particular piece of software. It’s more sophisticated and complex than anything I’ve released in the past. Also, my testing of it was “light”, at best. I fired up a few Nodes on my laptop, had them send messages at a set interval, and watched what happened to make sure things made sense within the context of the algorithm. I was about 70% sure the software implemented the algorithm correctly and wouldn’t make mistakes when routing the messages. I posted about it on the Go mailing list and, almost as an afterthought, linked to the blog post on Hacker News.&lt;/p&gt;
&lt;p&gt;So imagine my surprise when I saw this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://paddy.carvers.com/img/pastry-hacker-news.png&#34; alt=&#34;We’re number one! We’re number one!&#34;&gt;&lt;/p&gt;
&lt;p&gt;It wasn’t long before the blog started seeing traffic from all over the world. Watching the pins drop on &lt;a href=&#34;http://get.gaug.es&#34;&gt;Gauges&lt;/a&gt; was a nice way to spend my ungodly-hours-of-the-morning on Saturday (I ended up sitting up all night, watching people react to the post, answering questions, and generally attempting to pretend I could manage the situation. Also, I was waiting for someone to call me out on writing shitty software and daring to release it).&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;img src=&#34;https://paddy.carvers.com/img/pastry-gauges.png&#34; alt=&#34;AirTraffic Live makes me feel like a Bond villain&#34; /&gt;
&lt;/div&gt;

&lt;p&gt;When all was said and done, the post had been read by over 10,000 people. Every time I remember that, I feel like Mark Zuckerberg in &lt;em&gt;The Social Network&lt;/em&gt;. “Thousand. The site got ten thousand hits.”&lt;/p&gt;
&lt;div class=&#34;bigimage&#34;&gt;
&lt;img src=&#34;https://paddy.carvers.com/img/pastry-cloudflare.png&#34; alt=&#34;Also, CloudFlare apparently saved us a gigabyte in bandwidth. For a text post.&#34; /&gt;
&lt;/div&gt;

&lt;p&gt;I’m seeing a pattern here. Every time I do &lt;em&gt;anything&lt;/em&gt; online, it seems to be a big fucking deal, for reasons I cannot begin to fathom. My friends have started to notice, too. It has become expected that when I do something, the internet will at least take a passing notice.&lt;/p&gt;
&lt;p&gt;And that’s something that worries me. Lightning struck twice, but will it keep striking? Does the internet pay attention to the things I do because I do good work, or because I get lucky? I am inclined to believe the latter; I know too many engineers who are better at what I do than I am who get less attention than I do. Which is only a little awkward.&lt;/p&gt;
&lt;p&gt;I have no idea why you people take me seriously. I was terrified that someone would call me out for writing shitty software, and instead the worst I got was a billion people complaining that I could have bent over backwards to make a message queue work instead of writing my own software. Which is annoying as all hell, believe me, but it’s hardly on par with being told you suck at what you do and getting laughed at for daring to release something that you found challenging to write. Not a lot of work, but intellectually challenging. To this day, I’m still not confident enough to say I’m an expert on Pastry, the algorithm I implemented. Nobody seems to care.&lt;/p&gt;
&lt;p&gt;So please, if you see me on Twitter (where you will be enjoying a stream of my childish, banal, and vulgar tweets&amp;hellip; typically about unicorns or Call Me Maybe), please take a moment to explain to me how you can possibly take me seriously. Because it baffles me that you apparently do. And whenever anyone asks how I managed to gain such a reputation, I’m just going to have to stick with my default answer:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://paddy.carvers.com/img/mrsex.gif&#34; alt=&#34;I am Mr. Sex. Also, Moriarty is my spirit animal.&#34;&gt;&lt;/p&gt;
</description>
      <carvers:summary>I am a kid just out of college, with no sense of professionalism, and no formal education in my line of work. And yet, you people seem to have an absurd fascination with taking me seriously.</carvers:summary>
    </item>
    
    <item>
      <title>Homeless</title>
      <link>https://paddy.carvers.com/posts/homeless/</link>
      <pubDate>Wed, 22 Aug 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/homeless/</guid>
      <description>&lt;p&gt;As of yesterday, August 21, 2012, at 1:00pm EST, I officially became homeless.&lt;/p&gt;
&lt;p&gt;Not in the sense that I had nowhere to go. I don’t want to be misleading; I’m extremely fortunate, and there is no danger of me not having a roof over my head any time in the foreseeable future.&lt;/p&gt;
&lt;p&gt;But I no longer have a place I call “home”.&lt;/p&gt;
&lt;p&gt;Yesterday I turned in my keys to my landlord, and officially moved out of the apartment I have resided in for the last year. A &lt;a href=&#34;https://twitter.com/carvere08&#34;&gt;friend&lt;/a&gt; adopted me for the night and got me to the train station this morning. At that point, I said goodbye to Buffalo, probably for the last time. The next time I enter the city, it will be as a visitor, not a resident.&lt;/p&gt;
&lt;p&gt;I’m being really over-dramatic about this, but it’s a new sensation for me. I’ve always had a “home”—a base, a center for my life. Somewhere to return to. When I was a kid, it was my parents’ house, where I was part of the schedule, part of the routine. When I went away to college, my dorm room became my home. Finally, I moved into my own apartment in Buffalo.&lt;/p&gt;
&lt;p&gt;Now I don’t have a place like that. I’m staying in my parents’ house for as long as it takes for me to get the money together to move out to San Francisco. My apartment there will become my home then. And while my parents are ecstatic to have me home (I’ll be the first child of theirs to move more than a six hour drive away, and they’re not nearly as excited about the move as I am), I’m not part of the routine here. I’m a visitor.&lt;/p&gt;
&lt;p&gt;It’s going to be an interesting couple of months, but I’m very excited to be moving to San Francisco. I love the city, I love &lt;a href=&#34;https://paddy.carvers.com/posts/developer-experience-engineer/&#34;&gt;my job there&lt;/a&gt;, and I’m really happy I’m going to, for the first time ever, live in a place that has a season besides “winter”.&lt;/p&gt;
&lt;p&gt;And hey, if anyone knows of any great apartments in walking distance of Potrero for reasonable prices, do let me know.&lt;/p&gt;
</description>
      <carvers:summary>I’m no longer a resident of Buffalo, and that requires a self-indulgent post.</carvers:summary>
    </item>
    
    <item>
      <title>Measuring DX</title>
      <link>https://paddy.carvers.com/posts/measuring-dx/</link>
      <pubDate>Wed, 18 Jul 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/measuring-dx/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.developerexperience.org&#34;&gt;Developer experience&lt;/a&gt; is a pretty new field. There aren’t as many people working on it as there should be, and there isn’t enough literature about it to learn it by reading. It’s still something you need to just figure out as you go.&lt;/p&gt;
&lt;p&gt;When I &lt;a href=&#34;https://paddy.carvers.com/posts/developer-experience-engineer/&#34;&gt;started&lt;/a&gt; as &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;’s first Developer Experience Engineer in mid-June, I didn’t have a whole lot to go on. I talked to some wonderful people in the community and read a lot of great blog posts and &lt;a href=&#34;http://developer-support-handbook.org&#34;&gt;resources&lt;/a&gt;, but at the end of the day I was pretty much just doing my best to learn what worked and what didn’t as I went.&lt;/p&gt;
&lt;p&gt;There’s a problem with that, though: how do you know what’s working?&lt;/p&gt;
&lt;p&gt;There aren’t a lot of resources to measuring developer experience, the way there are for &lt;a href=&#34;http://www.measuringux.com&#34;&gt;UX&lt;/a&gt;. Not a lot of advice, not a lot of tools, not a lot of case studies. I was having a hard time finding out how I could figure out if I was even doing the right things.&lt;/p&gt;
&lt;p&gt;So here is what I came up with.&lt;/p&gt;
&lt;h2 id=&#34;google-analytics&#34;&gt;Google Analytics&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://www.google.com/analytics&#34;&gt;Google Analytics&lt;/a&gt; is your friend… but you need to know how to use it. We use Google Analytics to track our &lt;a href=&#34;http://dev.iron.io&#34;&gt;Dev Center&lt;/a&gt;, so I have insight into how our developers are interacting with our documentation.&lt;/p&gt;
&lt;h3 id=&#34;bounce-rate-good-or-bad&#34;&gt;Bounce Rate: Good or Bad?&lt;/h3&gt;
&lt;p&gt;It’s tempting to say that a high &lt;a href=&#34;http://support.google.com/googleanalytics/bin/answer.py?hl=en&amp;amp;answer=81986&#34;&gt;bounce rate&lt;/a&gt; is a bad thing, but that’s misleading. &lt;a href=&#34;http://dev.iron.io/worker/reference/environment&#34;&gt;Some pages&lt;/a&gt; are meant to give the developer the information they want in the quickest way possible.&lt;/p&gt;
&lt;p&gt;So the answer is that pages with a low bounce rate are bad, because developers have to dig for the answer they want, right? Not so fast. &lt;a href=&#34;http://dev.iron.io&#34;&gt;Some pages&lt;/a&gt; are meant to be landing pages that direct developers to the different content we have available, and &lt;a href=&#34;http://dev.iron.io/worker&#34;&gt;other pages&lt;/a&gt; are meant to be quick overviews that show off the possibilities of our platform and lead developers to explore the capabilities further. For those pages, a high bounce rate may actually be &lt;em&gt;bad&lt;/em&gt;, as it may signify that the page is frustrating, boring, or off-putting to developers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When considering a page’s performance, always consider the page’s &lt;em&gt;purpose&lt;/em&gt;.&lt;/strong&gt; Google reportedly used users who returned to the search page after clicking a link to measure poorly performing queries. Sometimes, people using your product means your product failed the first time. You should be finding those failures and fixing them.&lt;/p&gt;
&lt;h3 id=&#34;visitors-flow&#34;&gt;Visitors Flow&lt;/h3&gt;
&lt;p&gt;Google Analytics has this great view called “Visitors Flow” that breaks down the path users are taking through your website. What makes Visitors Flow so great is that it tells you where you are losing people. It shows you the percentage of people who leave after the page and where the people who stayed went next. For your pages that should lead into other content, this helps you see how many people you’re losing and whether the people who are staying are going where you expect. For the pages that should be quick reference, it helps you see where people are going to try to find whatever you’re looking for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Always have a traffic flow in mind for your pages.&lt;/strong&gt; If a page is a reference page, developers should be entering on that page and leaving on it. This means the page is the first step in the visitor flow (the entry page) and has a high bounce rate. For exploratory pages, this means plotting out what you think the developer needs to know and a path that will teach them that information. You can then compare that path against the visitors flow diagram to make sure you’re leading your developers through your content effectively.&lt;/p&gt;
&lt;h2 id=&#34;developer-interaction&#34;&gt;Developer Interaction&lt;/h2&gt;
&lt;p&gt;This section’s a bit easier to explain and measure than the Google Analytics section and a bit more concrete. I think, in most situations (in ours at least), every time the developer &lt;em&gt;has&lt;/em&gt; to talk to someone on the team, that is an area where the developer experience has failed. Whether that’s posting a question in the mailing list or forum, engaging support, or asking a question in the public chat (which is where &lt;a href=&#34;http://get.iron.io/chat&#34;&gt;most of Iron.io’s customer interaction happens&lt;/a&gt;), that developer had to stop &lt;em&gt;actually making things&lt;/em&gt; to figure out how to interact with your product.&lt;/p&gt;
&lt;p&gt;On a similar note, nobody reading your documentation may actually be a &lt;em&gt;good&lt;/em&gt; thing. If they have to stop what they’re doing to read your documentation, that’s time they could be spending on actually building things.&lt;/p&gt;
&lt;p&gt;In a perfect world, your platform would be so easy and intuitive to use, the developers wouldn’t have to read documentation or ask questions.&lt;/p&gt;
&lt;p&gt;I’m currently working on a way to automatically track how much developers are utilising our public support chat room, and using that to gauge the effectiveness of our developer experience. It won’t be perfect, but it can be used as a rough guide.&lt;/p&gt;
&lt;h2 id=&#34;developer-feedback&#34;&gt;Developer Feedback&lt;/h2&gt;
&lt;p&gt;Developers are people too, which means &lt;em&gt;they really like to whine&lt;/em&gt;. Odds are, if you give a developer the chance to tell you why you suck worse than IE 6, they will take that opportunity… usually. At Iron.io, our CEO emails users after a week to check in and get their feedback on the platform. The response rate is really high, and some of the biggest gaps and problems in our developer experience have been raised that way.&lt;/p&gt;
&lt;p&gt;But there are exceptions. If you have a generally good developer experience with this one massive pain in the butt, you’ll be likely to hear about it. If your developer experience is a mess and painful to use, people will more likely just move on with their lives, rather than complain. You have to be salvageable, in the user’s eyes, or why bother?&lt;/p&gt;
&lt;p&gt;Be honest, who &lt;em&gt;really&lt;/em&gt; wants to explain to PayPal and Google Checkout all the reasons Stripe is preferred by developers? It’s easier to just use Stripe. Even if you could come up with an actionable list, it doesn’t feel like PayPal or Google would be nearly responsive enough in implementing those changes, so why bother? As important as asking what’s wrong is, listening to the answer &lt;em&gt;and fixing it&lt;/em&gt; is even more important, or developers will stop answering.&lt;/p&gt;
&lt;p&gt;It’s also important to remember that this won’t actually raise all the problems. Because you’ll have developers that never start using your product or who see a dealbreaker and just move on with their lives. Developers are busy people right now. You can’t count on them to find all the problems for you. But the developers who are invested in your platform or who are forced to use your platform will likely help you make their lives better.&lt;/p&gt;
&lt;h2 id=&#34;what-else&#34;&gt;What Else?&lt;/h2&gt;
&lt;p&gt;This is what I’ve come up with. This is what I’m basing my efforts on right now. But there has to be more. There have to be ideas and tools and strategies besides this to measure platforms and products for pain points when specifically applied to developers.&lt;/p&gt;
&lt;p&gt;What am I missing? Tweet me at &lt;a href=&#34;http://twitter.com/paddycarver&#34;&gt;@paddycarver&lt;/a&gt; or hit me up on &lt;a href=&#34;http://profiles.google.com/foran.paddy&#34;&gt;Google+&lt;/a&gt; or, hell, email me at &lt;a href=&#34;mailto:foran.paddy@gmail.com&#34;&gt;foran.paddy@gmail.com&lt;/a&gt; and let’s talk about it.&lt;/p&gt;
</description>
      <carvers:summary>Developer Experience is all about working to make your platforms pleasant for developers to build on. But how do you measure your success at making people happy?</carvers:summary>
    </item>
    
    <item>
      <title>On Go</title>
      <link>https://paddy.carvers.com/posts/go/</link>
      <pubDate>Thu, 05 Jul 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/go/</guid>
      <description>&lt;p&gt;I never went to school for computer science. I majored in English. My original goal was to teach, before I became disillusioned with the education system.&lt;/p&gt;
&lt;p&gt;You would think that, with my background, a “softer” language like Python or (it pains me to type this) Ruby would be my language of choice. Up until the last few months of 2011, you’d be right—Python was the favoured tool in my (admittedly varied) belt. You’d be surprised—&lt;a href=&#34;http://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html&#34;&gt;or maybe not&lt;/a&gt;—to find that I’ve abruptly replaced it with Go.&lt;/p&gt;
&lt;p&gt;I could wax eloquent about the beauty of &lt;a href=&#34;http://blog.golang.org/2011/07/error-handling-and-go.html&#34;&gt;error handling&lt;/a&gt;, but people will be too busy whining about the lack of exceptions to care that life becomes exponentially easier when you’re forced to deal with errors at their root. Honestly, I love that Go discourages or disallows my (destructively) lazy behaviour. It has made me a better programmer with more reliable code.&lt;/p&gt;
&lt;p&gt;I could write a love letter about the &lt;a href=&#34;http://research.swtch.com/interfaces&#34;&gt;incredibly powerful implicit interfaces&lt;/a&gt; that make duck-typing an absolute pleasure. I’ve never seen a duck-typing implementation that was so natural and easy to use. Just the other day, I was trying to check if an interface was nil, only to discover after some Googling that there is no way to do this that isn’t a dirty hack. The explanation for it, though, was what stuck with me: idiomatic Go says that any type that fulfills an interface should be able to execute any method in the interface safely, so you shouldn’t have to do that check. Just think about that for a moment. How awesome is that? Why can’t everything be that simple?&lt;/p&gt;
&lt;p&gt;I could talk at length about the &lt;a href=&#34;http://www.youtube.com/watch?v=f6kdp27TYZs&#34;&gt;amazing concurrency primitives&lt;/a&gt; (warning: YouTube link) and how they make concurrent programming &lt;em&gt;fun&lt;/em&gt;. In a multi-core world, these primitives are incredibly important and incredibly powerful. I truly believe they deserve their place as Go’s flagship feature.&lt;/p&gt;
&lt;p&gt;I could talk about all these things, and I often do. They’re the responses I give when my peers (and my betters) ask why I use Go, and for good reason: they’re things those people can relate to. They’re the lazy explanation. They’re objective metrics that developers can compare to their current language and can easily conceive of use-cases for. In other words, they’re easy to evaluate, because they deliver an objective value.&lt;/p&gt;
&lt;p&gt;Those aren’t the reason I use Go, though. The real reason I use Go goes back to my background in English and writing.&lt;/p&gt;
&lt;p&gt;I’ll never forget &lt;a href=&#34;http://www.meetup.com/golangsf/events/59833112/&#34;&gt;watching Rob Pike read his blog post aloud&lt;/a&gt; before he had published it. I expected to be in awe of him for his contribution to the field (my expectations were met); what surprised me was the respect I felt for him as a writer. It is rare in this line of work to find someone who has that powerful a narrative voice, who is that compelling a writer.&lt;/p&gt;
&lt;p&gt;When you think about that, it’s kind of weird. We &lt;em&gt;write&lt;/em&gt; programs, we don’t &lt;em&gt;build&lt;/em&gt; them or &lt;em&gt;engineer&lt;/em&gt; them. We’re supposed to be communicators first—people who can take the concepts and demands of a customer and translate them into ones and zeros for a computer. Why is the ability to write well rare in that field? I don’t know. I don’t have an answer to that.&lt;/p&gt;
&lt;p&gt;What I do know is that one line will forever embed itself in some corner of my memory:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“What you’re given is a set of powerful but easy to understand, easy to use building blocks from which you can assemble—compose—a solution to your problem.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;That correction—“compose”—is what did it for me. Go is the first language I have found that has let me focus on my composition, the way the constituent parts of my software form a whole, instead of my writing, the specific syntax and semantics I used in creating that whole. It puts the focus back where it’s supposed to be: on the ideas, not the implementation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;com⋅po⋅si⋅tion&lt;/strong&gt; &lt;em&gt;(n.):&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The nature of something’s ingredients or constituents; the way in which a whole or mixture is made up.&lt;/li&gt;
&lt;li&gt;The action of putting things together; formation or construction.&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;I use Go because it is the only language that feels like writing a piece of prose or creative literature. I am not worried about remembering a bloated spec or edge cases. I’m not worried about checking every possible error at every possible place—I already checked them where they were raised. I’m only worried about refining my ideas until they are clear and defined enough that a computer can act on them.&lt;/p&gt;
&lt;p&gt;And really, isn’t that what this job is supposed to be about?&lt;/p&gt;
&lt;p&gt;You can use whatever language you want. Whatever makes you productive, whatever makes you happy to use. All I know is that, for me, nothing I have found beats out the sheer expressive power of good, clean Go.&lt;/p&gt;
&lt;p&gt;(Even without the generics and exceptions and GUI library I’ve heard are required for a language to be successful.)&lt;/p&gt;
</description>
      <carvers:summary>I’ve been writing Go for months now. I thought at first that my fascination with it was due to the novelty of a new language. I’m beginning to realise that Go offers something new: the ability to write code.</carvers:summary>
    </item>
    
    <item>
      <title>What Google Glass Really Means</title>
      <link>https://paddy.carvers.com/posts/google-glass/</link>
      <pubDate>Fri, 29 Jun 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/google-glass/</guid>
      <description>&lt;p&gt;During the &lt;a href=&#34;http://youtu.be/VuC0i4xTyrI&#34;&gt;keynote of day one of Google I/O&lt;/a&gt;, Sergey Brin orchestrated a rushed, off-kilter, and stunning display of the company’s revolutionary &lt;a href=&#34;https://plus.google.com/111626127367496192147/about&#34;&gt;Google Glass&lt;/a&gt; technology. For those unfamiliar with the new product, it is a new type of mobile device—computerised glasses that will give you all the sensors and inputs you’re used to in mobile phones. Think about that for a moment—that’s damn cool.&lt;/p&gt;
&lt;p&gt;But that’s not why Glass is important. First of all, the developer preview—very “bleeding edge”, as Sergey described it—isn’t available for another year, minimum. Even then, it’s going to cost $1,500. How eager are you to shell out $1,500 for a new piece of hardware that has a “beta—going to be upgraded” sticker slapped on it? Especially when you’ve &lt;em&gt;never used one before&lt;/em&gt;. Yeah, I’m not all that eager either.&lt;/p&gt;
&lt;p&gt;So let’s just accept that Google Glass won’t be a commercial, consumer success for at least a few years. This won’t be like the iPhone, where the launch signals a massive shift in the industry and everyone has to pivot within a couple years or be left in the dust. Why is Google Glass important, then?&lt;/p&gt;
&lt;p&gt;Go back to the keynote. I want to call out a specific quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“We believe, actually, that communication with images, and access to devices that empower people to communicate with images in new ways, are truly revolutionary, and may enable people to connect in new and potentially better ways.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;You know what that says to me? That says Google is taking images &lt;em&gt;very&lt;/em&gt; seriously. Think I’m just taking one quote out of context? Think about the keynote. Google+ Events: what was highlighted the most? The freaking &lt;em&gt;images&lt;/em&gt;. When was the last time you thought “Gee, this event would be so much more fun if only my invitations were prettier.” I love Party Mode, but is that really a revolution, as it was touted to be? What about the Google+ mobile app: did anyone else notice that images are the most prominent UI element, even for non-image posts?&lt;/p&gt;
&lt;p&gt;Google is guiding users to share more images. Why? Well, keep in mind that Google’s computers are &lt;a href=&#34;http://googleblog.blogspot.com/2012/06/using-large-scale-brain-simulations-for.html&#34;&gt;almost as good as human brains are at deciphering images&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to YouTube, Google Image Search, Picasa, and Google+, Google has access to more images than pretty much anyone else. Thanks to being the de-facto leader in infrastructure, Google has more computing power than pretty much anyone else. Google has always been a data-driven company, so when they start guiding their users towards a certain type of data, they rather show their hand.&lt;/p&gt;
&lt;p&gt;Google is betting heavily on the future of image recognition. They’re betting that we’ll share more and more in visual ways, and that Google’s vaunted search capabilities (which work wonderfully on text, but need some help when it comes to images) will become less and less useful as the web goes increasingly visual. And they want to be ahead of the curve in image recognition when that happens. How do they do that? More data.&lt;/p&gt;
&lt;p&gt;Google Glass isn’t important because it will revolutionise the way you and I interact with devices. It won’t do that for years, and even then, it’s a long shot. Google Glass is important because it’s another step in Google’s quest to cracking the problem of making computers understand pictures.&lt;/p&gt;
</description>
      <carvers:summary>Google Glass is important. Very important. But not as a consumer device.</carvers:summary>
    </item>
    
    <item>
      <title>Developer Experience Engineer</title>
      <link>https://paddy.carvers.com/posts/developer-experience-engineer/</link>
      <pubDate>Fri, 15 Jun 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/developer-experience-engineer/</guid>
      <description>&lt;p&gt;Just over six months ago, I started working at &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;
as a software engineering intern. I quickly diverged from my intended purpose,
though, mainly because I’m really bad at following instructions.&lt;/p&gt;
&lt;p&gt;As of today, I’ve been upgraded to full employee status, with a title change
that more accurately describes what I do. I’ve become their first Developer
Experience Engineer.&lt;/p&gt;
&lt;p&gt;I know, I know. What the hell? That’s the wankiest title I’ve ever heard of.
But it’s actually pretty accurate. My job at Iron.io is to do anything I
can to make sure that people who develop on our platform have the best possible
experience. That is my responsibility. It manifests itself mainly in the
ongoing work I’m doing with our &lt;a href=&#34;http://dev.iron.io&#34;&gt;Dev Center&lt;/a&gt;, but it has
developer outreach parts, it has higher level strategy parts, it has a lot of
connotations that come with it. It means I offer feedback and suggestions on
new products. It means I write client libraries and examples. If something
will make using Iron.io’s services easier, more enjoyable, or more effective
for our customers, I’m supposed to be doing it or helping someone else do it.&lt;/p&gt;
&lt;p&gt;That’s a tall order. The job is modeled heavily after Developer Evangelists
and Developer Advocates, but with a more holistic approach.&lt;/p&gt;
&lt;p&gt;I wanted to take a moment to lay out the principles that I hold above all
others for this job, as I think they explain things a lot better than I can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never sell anyone anything&lt;/strong&gt;. I have &lt;a href=&#34;http://news.ycombinator.com/item?id=4059780&#34;&gt;been accused&lt;/a&gt;
of blatantly advertising Iron.io’s products. I want to make a promise,
right now, that I will &lt;em&gt;never&lt;/em&gt; try to do this. I do not believe that the
cloud is for &lt;em&gt;everyone&lt;/em&gt;. I do not believe that Iron.io can solve every
problem. I do not believe that getting a user to sign up under false
pretenses is a good thing. Iron.io’s services are all pay-per-use. That
means if you stop using them, we stop getting paid. Even if I trick you
into signing up, you’re going to figure out pretty quickly that the solution
isn’t right for you. We’re going to lose you as a customer and will have
most likely made &lt;em&gt;nothing&lt;/em&gt;. You’re going to tell Twitter and Facebook and
Google+ about how our products suck, because you’re not using them in the
right situation. Nobody wins. Instead, I’m going to try to help the people
whose problems &lt;em&gt;can&lt;/em&gt; be solved by Iron.io’s tools to solve their problems.
They get a solved problem, we get a happy customer, everyone wins. Doesn’t
that seem like a much more enjoyable job to you? Me too. That’s the job I’m
going to do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You owe us nothing&lt;/strong&gt;. If you aren’t reading our documentation, it’s
because our docs are too boring and dry. Or maybe they need better navigation.
Or maybe they should be more interactive. The point is, you have a choice
in who you host your software with. If we don’t make it as easy as possible
for you, you’re going to go to someone who will. Plain and simple. “The
developer should do more work” is not a valid answer, no matter what the
problem is. Using our services is supposed to make your life easier, not
trade out your old work and annoyances for new work and annoyances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I’m not too busy for you&lt;/strong&gt;. I don’t care if you’re from a one-man shop
doing a weekend hack or if you’re Google. If you need help, you deserve
nothing less than the best assistance I can offer you. Sometimes that may
not be enough. That’s regrettable, but inevitable. I’m a limited human
with limited time. My inbox will always have room for developers who need
help, I will always do my best to respond on &lt;a href=&#34;http://twitter.com/paddycarver&#34;&gt;Twitter&lt;/a&gt;
or &lt;a href=&#34;http://profiles.google.com/foran.paddy&#34;&gt;Google+&lt;/a&gt;, and I will do my best
to ensure that no question is met with silence in Iron.io’s &lt;a href=&#34;http://get.iron.io/chat&#34;&gt;public support
chat room&lt;/a&gt;. I can’t build a better developer
experience if I don’t know what developers are experiencing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m very excited to continue my efforts at this, even as the daunting size
and scope of the job intimidates me. I hope that my efforts in the next six
months will help to make me more available to you and will help to make you
more productive at what you do.&lt;/p&gt;
&lt;p&gt;An intuitive and adaptive product renders examples unnecessary. Illustrative
examples render documentation unnecessary. Clear, concise, and useful documentation
renders a support channel unnecessary. A support channel makes sure that all
other failings do not leave anyone stranded.&lt;/p&gt;
</description>
      <carvers:summary>I’ve officially signed on as a Developer Experience Engineer at Iron.io. What the hell does that mean?</carvers:summary>
    </item>
    
    <item>
      <title>The Cloud Is For You</title>
      <link>https://paddy.carvers.com/posts/the-cloud-is-for-you/</link>
      <pubDate>Sat, 02 Jun 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/the-cloud-is-for-you/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I work for a &lt;a href=&#34;http://www.iron.io&#34;&gt;cloud computing company&lt;/a&gt;,
so I’m obviously a bit biased in favour of the cloud. That said, my views,
as always, are my own, and are not indicative or reflective of Iron.io’s.&lt;/p&gt;
&lt;p&gt;I don’t normally do this, but &lt;a href=&#34;http://justcramer.com/2012/06/02/the-cloud-is-not-for-you/&#34;&gt;a post&lt;/a&gt;
just hit Hacker News based on one of the most frustrating misconceptions
people have about the cloud, and I feel compelled to point it out.&lt;/p&gt;
&lt;p&gt;The cloud is &lt;em&gt;not&lt;/em&gt; a specific platform-as-a-service. It is not App Engine,
it is not Heroku, it is not EC2. Using those platforms does not mean you
are using the cloud, and not using those platforms does not mean you are
&lt;em&gt;not&lt;/em&gt; using the cloud. Those are platforms that are built with cloud
computing in mind. They are &lt;em&gt;not&lt;/em&gt; cloud computing itself.&lt;/p&gt;
&lt;p&gt;The cloud is &lt;em&gt;a way of thinking&lt;/em&gt;. It is a development paradigm, an
infrastructure decision, an architectual choice. It means thinking of a
server as the smallest piece of architecture, instead of a process. It
means making discreet, modular services that are hardware-agnostic. It
means an easy deploy strategy, so the easy scaling inherent in modular,
discreet system can be fully taken advantage of.&lt;/p&gt;
&lt;p&gt;It means that a server failing has the same severity as a bug. The response
is simple: isolate the server so it is no longer handling traffic, replace
the server, then diagnose how it failed.&lt;/p&gt;
&lt;p&gt;This may seem like common sense and just good practice to you. It does to
me, too, and that’s why I love the cloud. But this wasn’t always the case.
If my history is correct (I believe it is), the movement started at Google
as “cluster computing” when they needed a way to make cheap hardware capable
of storing &lt;em&gt;the entire internet&lt;/em&gt;. Problems stopped being interesting unless
several servers were involved.&lt;/p&gt;
&lt;p&gt;I don’t know about you, but I remember when I started web development, I
considered myself lucky to have a single server. I was a young high school
student, with no credit card. My parents were wary of the internet, and not
very helpful when it came to turning my money into internet purchases. I
remember taking a yearly trip to the local shopping mall, buying a prepaid
debit card, and purchasing a year lease on the cheapest shared host I could
find.&lt;/p&gt;
&lt;p&gt;This may sound absurd, but I can think of several companies off the top of
my head that run server architectures similar to this. Not a shared host,
maybe not even just one server, but the database, the cache, and the
application are all on one machine.&lt;/p&gt;
&lt;p&gt;Sentry certainly had a problem, but it wasn’t with the cloud. Actually, the
cloud saved Sentry. Sentry’s problem was with &lt;em&gt;Heroku&lt;/em&gt;. Heroku wasn’t the
right PaaS for Sentry, or Sentry wasn’t built to take advantage of Heroku’s
strengths. Heroku is great, and I’m sure Sentry is quality software, but that
doesn’t necessarily mean they’re a match.&lt;/p&gt;
&lt;p&gt;The fact that Mr. Cramer is touting how easy it is to stand up servers and
the fact that it took him three days to switch from someone else’s hardware
to his own, with little-to-no architecture shift, makes it sound like the
cloud is most certainly for him.&lt;/p&gt;
&lt;p&gt;And Dave, if you’re still looking for a solution to those background workers,
shoot me an email: &lt;a href=&#34;mailto:paddy@iron.io&#34;&gt;paddy@iron.io&lt;/a&gt;. I’d be more than happy to help you get
started on &lt;a href=&#34;http://iron.io/products/worker&#34;&gt;IronWorker&lt;/a&gt;, and I’m fairly
confident it can restore your faith in the cloud.&lt;/p&gt;
</description>
      <carvers:summary>Cloud computing is not the same as Platform-as-a-Service.</carvers:summary>
    </item>
    
    <item>
      <title>What Iron Man Taught Me About Tech</title>
      <link>https://paddy.carvers.com/talks/iron-man-tech/</link>
      <pubDate>Wed, 30 May 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/iron-man-tech/</guid>
      <description>&lt;p&gt;It is no secret that, ever since I joined up with &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;,
I&amp;rsquo;ve been mildly obsessed with Iron Man. AC/DC has re-entered my daily
soundtrack, I watch &lt;em&gt;Iron Man 2&lt;/em&gt; on Netflix far more often than I should,
and I&amp;rsquo;ve been known to subtly quote the movies in casual conversation. My
fascination with the movies can be easily explained: they appeal to my brand
of humour.&lt;/p&gt;
&lt;p&gt;But there&amp;rsquo;s something else, too: the tech in the movies is something I dream
about. When I imagine the future of technology, that&amp;rsquo;s what I imagine. This
talk examines the tech they use and how we can get it in the future.&lt;/p&gt;
&lt;p&gt;The talk is split into two parts: the overarching ideas begin the talk. These
are the fortune cookies of the talk, the big ideas encompassed into a small
phrase. These are followed by a UI examination, based off the concept art
released by &lt;a href=&#34;http://cargocollective.com/jayse/Avengers&#34;&gt;Jayse&lt;/a&gt; from &lt;em&gt;The
Avengers&lt;/em&gt;. I also talk about why I&amp;rsquo;m less-than-impressed with the recently-announced
&lt;a href=&#34;http://www.leapmotion.com&#34;&gt;Leap&lt;/a&gt; system and Disney Research&amp;rsquo;s &lt;a href=&#34;http://www.disneyresearch.com/research/projects/hci_touche_drp.htm&#34;&gt;Touché&lt;/a&gt;
system.&lt;/p&gt;
&lt;p&gt;The things I cover in this talk are things I&amp;rsquo;ve picked up over my years in
the tech industry. They do not necessarily apply to one, or any, of the
companies I work for or have worked for. My opinions, as always, are my own.&lt;/p&gt;
&lt;p&gt;You can find the slides &lt;a href=&#34;http://xn--bih.tk/H0Nj&#34;&gt;on Google Presentations&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>A talk I gave at Barcamp Buffalo 2012. &lt;em&gt;Iron Man&lt;/em&gt; has some pretty awesome tech, so let&amp;rsquo;s see how they got it.</carvers:summary>
    </item>
    
    <item>
      <title>Collective Ignorance</title>
      <link>https://paddy.carvers.com/posts/ignorance/</link>
      <pubDate>Sun, 27 May 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/ignorance/</guid>
      <description>&lt;p&gt;I started playing with the internet at a young age. I got my first AOL
screen name in early middle school, and was entranced by this new place
that was suddenly available to me.&lt;/p&gt;
&lt;p&gt;What struck me wasn’t the amount of possibilities—I had no idea how
many there were—but the freedom I had in exploring them.&lt;/p&gt;
&lt;p&gt;I grew up with two brothers and a sister. We were all highly competitive
with each other. It just seemed natural at the time that not knowing or
doing something wrong should be met with ridicule and mocking. After all,
we were graded on our ability to provide the right answer, so we should
be punished for providing the wrong one, right?&lt;/p&gt;
&lt;p&gt;It went further than that, though. Everything from the music you like to
the people you hung out with were subject to scrutiny. Pick wrong, and
receive the jeering you’ve earned.&lt;/p&gt;
&lt;p&gt;Then there was the internet. This new thing that nobody knew what to do
with, that would make problems nobody could predict or prevent. We were
collectively ignorant of the entire thing, so we could leave all pretensions
of expertise behind and just go poke things for the sake of seeing what
happened. We were all more daring, we all risked more, because we did not
smack each other down for trying something new. The internet was a minefield
that we were all walking together, and nobody got blamed for setting off a
mine now and then. Instead, now we all knew there was a mine there.&lt;/p&gt;
&lt;p&gt;This is what made me love the internet. This is what made me love the
community of people that gathered there enough that I would spend the
next decade or so building my skills and walking that minefield with people.
We’ve advanced a long way, we know where a lot of the mines are. But we’re
kidding ourselves if we think we know where all the mines are.&lt;/p&gt;
&lt;p&gt;I’ve seen a lot of blog posts lately from people who are vainglorious enough
to believe that they know where the mines are. From people who are so
confident in their knowledge, they feel comfortable telling others what
&lt;em&gt;they&lt;/em&gt; should do.&lt;/p&gt;
&lt;p&gt;Can we please not do this? I like it so much better when we’re all in this
whole “What the fuck is going on?” thing together. Can’t we all just do our
own thing, let others do their thing, and be collectively richer for the
wealth of knowledge that comes out of people doing different things?&lt;/p&gt;
</description>
      <carvers:summary>None of us has any idea what we’re doing, and that is what makes the internet awesome. Please stop pretending you do.</carvers:summary>
    </item>
    
    <item>
      <title>Nobody Can Live on Dog Food</title>
      <link>https://paddy.carvers.com/posts/dogfood/</link>
      <pubDate>Sat, 28 Apr 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/dogfood/</guid>
      <description>&lt;p&gt;I’ve always intuitively agreed with the practice of eating your own dog food.
It’s hard to argue with “if I don’t use it, why should my customers?”&lt;/p&gt;
&lt;p&gt;At &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;, my main responsibility is the &lt;a href=&#34;http://dev.iron.io&#34;&gt;Dev Center&lt;/a&gt;.
I do a lot of work around trying to make developing on Iron’s products
easier and more pleasant.&lt;/p&gt;
&lt;p&gt;It stands to reason, then, that I spend a lot of time building things using
Iron’s products. I spend a lot of time writing examples, building client
libraries, and interacting with our APIs in essentially the same way we expect
our customers to.&lt;/p&gt;
&lt;p&gt;As part of my ongoing work with &lt;a href=&#34;http://www.2cloud.org&#34;&gt;2cloud&lt;/a&gt; (yes, it is
ongoing, just seriously slowed, thanks to my responsibilities at Iron), I’ve
been working on a &lt;a href=&#34;http://www.golang.org&#34;&gt;Go&lt;/a&gt; wrapper for &lt;a href=&#34;http://www.stripe.com&#34;&gt;Stripe&lt;/a&gt;.
As I grew frustrated with something I was working on today, I took a break to
hack on the Stripe library for a little while. And as I was writing unit tests,
I realised what would really help me was a dump of every conceivable permutation
of their response objects. And as I sat there, thinking about how hard it would
be to convince the Stripe engineers to put in the hours to develop this, it
struck me: I’m an engineer at a company with an API. We don’t have this.&lt;/p&gt;
&lt;p&gt;Why don’t we have this?&lt;/p&gt;
&lt;p&gt;So I’m going to work on this. I’m going to work on this great resource for
testing, but not because I spent the last four months so deeply immersed in our
products that I saw the need. I’m going to work on it because I took a break from
our products and found the need elsewhere, then applied it to Iron.&lt;/p&gt;
&lt;p&gt;Eating your own dog food is great, and it’s definitely something you should do,
but it runs the risk of being myopic and constraining. Sometimes you need to
use other people’s products, get exposed to differing viewpoints, and approach
things from a new perspective before you can achieve the cognitive dissonance
necessary for learning.&lt;/p&gt;
</description>
      <carvers:summary>“Eating your own dog food” is the phrase used to describe interacting with your product the way customers do. It’s considered good practice, to the point of being common sense. It can be taken too far.</carvers:summary>
    </item>
    
    <item>
      <title>Special</title>
      <link>https://paddy.carvers.com/posts/special/</link>
      <pubDate>Mon, 02 Apr 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/special/</guid>
      <description>&lt;p&gt;When I told my mother I was going to be representing &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;
at &lt;a href=&#34;http://www.ubhacking.com&#34;&gt;UB Hacking&lt;/a&gt;, her first response was, and I
quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Please don’t get arrested.”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;You see, my mother and father aren’t familiar with the term &amp;ldquo;hacking&amp;rdquo; except
in the context of the 1980s scare around it; hacking, to them, isn’t reflective
of a certain subset of programming, it’s an illegal attempt to seize control
of computers, information, or both.&lt;/p&gt;
&lt;p&gt;And while I &lt;em&gt;could&lt;/em&gt; write about “haw haw, old people don’t understand
kids these days” or “my parents are so out of touch”, those
missives have already been written, and have fallen on mostly deaf ears. It’s
how I’d respond to a mechanic complaining that I don’t understand the inner
workings of my non-existent car: “Yes, yes, your professional outrage
is adorable.”&lt;/p&gt;
&lt;p&gt;I submit that this runs a little bit deeper than that. And not just because
I want people to take my professional outrage seriously.&lt;/p&gt;
&lt;p&gt;See, here’s the thing: my parents don’t know what I &lt;em&gt;do&lt;/em&gt;. My friends, who are
mostly my age, don’t know what I do. This is not because I work for a startup
and wear many hats, because I’m willing to gloss over the details and give them
a handy title that sort of encompasses at least half of what I do: Developer
Advocate.&lt;/p&gt;
&lt;p&gt;They don’t know what that is.&lt;/p&gt;
&lt;p&gt;At which point, I have to explain what Iron.io does (we offer cloud services
for developers). I try to compare it to AWS as a shortcut, only to remember
that they don’t know what AWS is. Yes, even the most basic knowledge that
our profession takes for granted is entirely alien to them. After I’ve explained
that we develop software that other developers can then use to run their code
on because the Internet runs on computers called &lt;em&gt;servers&lt;/em&gt; and those are a
pain in the ass to maintain, so we do it… well, at that point they’ve already
stopped listening and are just politely nodding, so I usually just sigh and say
I’m an astronaut.&lt;/p&gt;
&lt;p&gt;I know what you’re thinking right now: “Boo-hoo, you have to talk to
your family and friends. Poor you.” While your sympathy is encouraging,
it’s not quite what I’m driving at with this little braindump. What I’m
getting at actually matters. Kind of. Well, &lt;em&gt;I&lt;/em&gt; think it does, at least.&lt;/p&gt;
&lt;p&gt;See, we’re accelerating as a society. Things are speeding up. Massive
cultural shifts, things that happened once a generation, are now happening
a few times a decade. This is actually a fun game to play; let’s take a
tangent for a moment here, and see how many cultural shifts our society
has weathered in the last ten years.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ajax. Ajax didn’t make its presence known until 2004, with the release
of GMail. Yes, yes, Outlook Web Access had it in 2000, if you want to be
pedantic about it, but most people count GMail as the spark that lit the
forest fire. Not a widespread cultural shift? Really? The basis of applications
you run in your browser wasn’t a cultural shift?&lt;/li&gt;
&lt;li&gt;Speaking of which, let’s throw GMail in there. Remember when you used
to delete emails? Remember when people thought that Google had
nothing better to do than read through your email and manually pair an
ad with it? Good times. I think “cloud computing” counts as a cultural
shift.&lt;/li&gt;
&lt;li&gt;MySpace. Founded in 2003. Probably your first “website”. Ah, I miss the
time when signing up for a free account on a service qualified as having a
website. I’d call this a cultural shift, mainly because it was probably the
first time spending hours online was something a normal person would do.&lt;/li&gt;
&lt;li&gt;Facebook. Founded in 2004. A cultural shift because it marked the first
time &lt;em&gt;not&lt;/em&gt; spending hours online made you weird.&lt;/li&gt;
&lt;li&gt;The iPhone. Remember when our phones couldn’t access the internet? Remember
when nobody said “app”? &lt;em&gt;I know&lt;/em&gt;, isn’t it weird to think about?&lt;/li&gt;
&lt;li&gt;Android/the iPod Touch. I think this is around the time my boyfriend
stopped calling my iPhone a baby-killer and implying that it planted me firmly
in the 1%. He was kind of an asshole.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s certainly not all of them, and it’s probably not even the most
important ones, but I’m bored now and you can just go read Wikipedia if
you’re interested. I think my point has been made. If it hasn’t, try to
list off the major changes in culture for the 1920s. Or 30s. Hell, try
even the 60s.&lt;/p&gt;
&lt;p&gt;So yes, we’re moving faster. Our society is becoming more and more susceptible
to change. As a community, we’re growing more fickle with every passing day,
using our communal ADHD to pick up new ideas and make them integral to our
societal identity very quickly.&lt;/p&gt;
&lt;p&gt;The cool part about all this is that our institutions have held up quite
well, all things considered. I mean, you still function in sort of the
same way you did a decade ago. Your day looks vaguely similar, the people
in it have more-or-less the same roles. Considering the fact that my job title
didn’t even exist until the Twitter-era rise of APIs, the fact that I can
compare it to a mechanic, a job that has existed for almost a century now,
is pretty damn good, I’d say.&lt;/p&gt;
&lt;p&gt;For all that, though, the shitty part about all this is that our institutions
are failing pretty spectacularly in certain areas. That whole “patent/IP”
thing, for example. Companies are using patents the way medieval nobles used
stones and shovels, building castle walls and moats around their products.
If anyone even &lt;em&gt;thinks&lt;/em&gt; about competing with them, a lawsuit is catapulted their
way before they can even ask about the airspeed velocity of a swallow. I feel
pretty comfortable in asserting that this was not how our patent system was
designed to be used. And then there’s that whole content-creator thing, to
which I will only say “SOPA”, and leave it at that. I’m just going
to ignore the whole “education system” thing, because, frankly, it
puts me in an apopleptic rage.&lt;/p&gt;
&lt;p&gt;I’d like to say “ah, yes, but my generation will fix that. The fine young
CEOs and lawmakers I went to college with are almost at the helm of the country,
and they shall fix this generational shift that has so unbalanced the country.”
And I &lt;em&gt;could&lt;/em&gt; just say that, and everything would be hunky-dory, if it weren’t
for one tiny little problem: I actually went to school with those people.
So I know they aren’t any better, as I said, than my parents are. They didn’t
make the shift gracefully, either. Well, that’s a bit odd, isn’t it?&lt;/p&gt;
&lt;p&gt;So we’ll just wait for the next generation, right? They’ll fix this. I see
two problems with that: first, I take issue with claiming the solution to any problem
is to just wait for someone else to fix it, especially when that someone else
is your child or grandchild. Second, I know people older than me, people even
my parents’ age, who have made the shift wonderfully. Hell, I work for some of
them.&lt;/p&gt;
&lt;p&gt;So if age isn’t the determining factor to whether or not people can understand
this new-fangled world we live in (and I submit that it’s not), what is?&lt;/p&gt;
&lt;p&gt;Every middle school child (as far as I know) learns about the benefit that
agriculture brought society: it allowed us to specialise. It allowed us to
stop having “President of Keeping Him/Her/Itself Alive” as their job
title, and switch it to something like “lawyer”. Yes, agriculture
is to blame for lawyers.&lt;/p&gt;
&lt;p&gt;This specialisation, I think, is at the root of most the modern problems
we’re facing. As my parents/peers show, when they can’t even identify the
vague requirements my job title carries, we’re getting to the point where
we have more jobs that need doing than people can keep track of. That’s not
to say there is no need for these jobs: first, that would put me out of a
job, which I’m not keen to do; second, even if you have no idea what a
Developer Advocate is or what they do, it’s almost impossible that your life
has not been impacted by one.&lt;/p&gt;
&lt;p&gt;We’re finally getting to the point where we’re specialising faster than our
system can adapt. Think about the recording industry: cassette tapes carried
the same risk of duplication and piracy that the internet carries, but when
was the last time you heard of someone getting sued for making their loved one
a mix tape? It was a gradual enough change, and one that occurred when few
enough other changes were happening, that it became integrated into our
culture. We had some time to adapt to it.&lt;/p&gt;
&lt;p&gt;That is why the governments do not get the internet. That is why Google
keeps reacting to Facebook and Apple, instead of continuing to kick ass
like they did for years. That is why our students are increasingly unprepared
for the world they emerge into, cost-prohibitive degree in hand. That is
why my father still calls me on the phone so I can Google things for him,
even though he has a perfectly good Chromebook set up for his use.&lt;/p&gt;
&lt;p&gt;We need to get used to the idea, really let it sink in, that we are not
the last innovation, that progress does not stop with us. That one day,
we will be the incumbent, and we will be disrupted. Only then can we lay
the groundwork for building a society that can adapt to these changes,
instead of one that has simply adapted to last year’s changes one year
too late.&lt;/p&gt;
&lt;p&gt;We are not special. We are specialised. And every day makes us more and
more specialised.&lt;/p&gt;
</description>
      <carvers:summary>As society progresses, it becomes increasingly specialised. There are a lot of problems with that.</carvers:summary>
    </item>
    
    <item>
      <title>How to Kick More @#% Per Minute Using the Cloud</title>
      <link>https://paddy.carvers.com/talks/kick-more-apm/</link>
      <pubDate>Fri, 23 Mar 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/talks/kick-more-apm/</guid>
      <description>&lt;p&gt;I think I had the idea for this talk on accident. I think most my good ideas are
accidents. And yes, I just implied this talk was a good idea. I stand by that
implication.&lt;/p&gt;
&lt;p&gt;We had just released a new update at &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;, either
announcing a new partnership or a new product, and I reshared the announcement
on Google+. I commented that we were kicking more ass per minute every day.&lt;/p&gt;
&lt;p&gt;The post, as you can tell by my vague recall, was no more or less important than
our other announcements. The phrase, though, would stick with me. It became my new
unit of measurement. As I pondered it some more, I realised that kicking ass was a
developer&amp;rsquo;s main job: creating something cool, making something faster, more stable,
more awesome. As a developer, I know that&amp;rsquo;s not what developers spend a lot of their
time on. Sometimes you wind up provisioning servers or finding ways to make the
architecture that is elegant in concept work in the decidedly clumsy Real World.&lt;/p&gt;
&lt;p&gt;That was the first spark for this talk: the realisation that our purpose, at Iron.io,
was to help programmers, hackers, and engineers kick more ass per minute by letting
them focus on kicking ass while we take care of the more mundane parts.&lt;/p&gt;
&lt;p&gt;The second spark came while I was sitting at home, watching Iron Man. I kept amusing
myself by finding correlations between Iron Man and Iron.io, and I realised something:
a super hero&amp;rsquo;s job is, literally, to kick ass. And most super heroes have an assistant,
a butler, a computer, or some other type of aid that takes care of the mundane parts of
their lives (paying taxes, preparing food, repairing capes) so they can focus on
kicking ass.&lt;/p&gt;
&lt;p&gt;That was when I realised that Iron.io wanted to be the Alfred to your Batman.&lt;/p&gt;
&lt;p&gt;The final piece of the puzzle fell into place when I realised I needed a demo and
it needed to be unlike an ordinary presentation. I have a background in theatre and
performance art, so I have a weakness for interactivity and surprising the audience.
So I made my slides in &lt;a href=&#34;http://imakewebthings.github.com/deck.js&#34;&gt;deck.js&lt;/a&gt;, hooked
them up to &lt;a href=&#34;http://appengine.google.com&#34;&gt;App Engine&lt;/a&gt;&amp;rsquo;s &lt;a href=&#34;http://code.google.com/appengine/docs/python/channel&#34;&gt;Channel API&lt;/a&gt;,
and integrated &lt;a href=&#34;http://www.twilio.com&#34;&gt;Twilio&lt;/a&gt;&amp;rsquo;s API so messages that were texted
to me could appear on the slides themselves during the presentation. I could then
integrate IronWorker and IronMQ to text the audience members back during the
presentation. When I made the plot diagram for the slides (you know, the one they
taught you back in middle school: rising action, climax, falling action), I used
the response texts as the climax. I implemented an artificial delay and
made it possible to queue up more and more workers to process the queue of messages
to send, showing the parallel processing capabilities of the platform. In essence,
the room started with disparate beeps when one worker was running, then erupted into
an orchestra of cell phones as I queued up more and more workers. I then ran through
the code that powered the workers, explained the architecture, and issued my call-to-action:
we&amp;rsquo;ve made it easy, so it&amp;rsquo;s time to go forth and kick ass.&lt;/p&gt;
&lt;p&gt;The slides are available &lt;a href=&#34;http://kick-more-apm.appspot.com&#34;&gt;here&lt;/a&gt;. They were tested
in Chrome, but (probably) work in any modern browser. As a side-effect of using the
Channel API in my presentation, I could control my slides wirelessly from a tablet.
I&amp;rsquo;ll release that code as an open source repository on Github when I get a moment.&lt;/p&gt;
</description>
      <carvers:summary>Developers are super heroes. The cloud can help them stop ironing their capes and get back to saving little old ladies from getting robbed. At &lt;a href=&#34;http://iron.io&#34;&gt;Iron.io&lt;/a&gt;, we want to help you do that. A talk I originally gave at &lt;a href=&#34;http://www.ubhacking.com&#34;&gt;UBHacking&lt;/a&gt;.</carvers:summary>
    </item>
    
    <item>
      <title>The Story of 2cloud</title>
      <link>https://paddy.carvers.com/posts/2cloud/</link>
      <pubDate>Fri, 16 Mar 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/2cloud/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This story is still in-progress. Don&amp;rsquo;t be surprised if it gets updated.
I&amp;rsquo;m lazy and inconsistent, so don&amp;rsquo;t be surprised if it doesn&amp;rsquo;t. In fact, just try
not to be surprised no matter what. On with the show.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to think you&amp;rsquo;re reading this because of my acerbic wit, my elegant writing,
my engaging style. I&amp;rsquo;d also like a pony.&lt;/p&gt;
&lt;p&gt;The more probable scenario is that you&amp;rsquo;ve used my software and wanted to know more
about the sack of meat that put those ones and zeroes together. The fact of the
matter is, people tend to know me either because they&amp;rsquo;ve met me in person or
because they&amp;rsquo;ve used &lt;a href=&#34;http://www.2cloudproject.com&#34;&gt;2cloud&lt;/a&gt;. My misanthropic nature
means the scale tips heavily in favour of the second possibility.&lt;/p&gt;
&lt;p&gt;People are often surprised by 2cloud&amp;rsquo;s origin story. Users are always taken aback
that there&amp;rsquo;s just this kid sitting in a small, dark room in Buffalo, New York, not
a corporate behemoth. People who know me are surprised to hear me refer to it as an
accident. But, really, that&amp;rsquo;s all it was: an accident.&lt;/p&gt;
&lt;p&gt;If I were to be perfectly honest with myself, I&amp;rsquo;d probably trace the beginning of 2cloud
to the beginning of 2010. I was just getting out of a messy situation involving relationships,
the details of which I won&amp;rsquo;t bore you with, and was looking for a way to distract myself.
For the first time in a long time, I was also looking at my future and wondering what
to make of it. I knew I&amp;rsquo;d need a career, knew I&amp;rsquo;d need a job I was passionate about.
I started wondering what that job could be.&lt;/p&gt;
&lt;p&gt;I bet a lot of you are imagining, at this point, that the answer turned out to be
“working for myself”. That&amp;rsquo;s what any entrepreneur would say, right? I&amp;rsquo;ll admit, at
this point I was following the happenings at &lt;a href=&#34;http://www.techcrunch.com&#34;&gt;TechCrunch&lt;/a&gt;
and thought the lifestyle sounded like a lot of fun. Which I took as a sign that it
was not right for me. I&amp;rsquo;d embed the tweet here, but it was from 2 years ago, meaning
it&amp;rsquo;s impossible to get a link to it on Twitter now.&lt;/p&gt;
&lt;p&gt;Instead of dreaming of working for myself, I dreamt of working for Google. Why?
Because Google seemed like a place where I could work as if I worked for myself, but
have the financial security and benefits of working for someone else. Also, it was a
company filled with great people doing amazing things, and I wanted to be part of that.
In many ways, it still is, and I still do. Sort of.&lt;/p&gt;
&lt;p&gt;I started to create a plan of action for getting hired by Google. To put it in perspective,
I was a 19-year-old English major at a small college in the middle of Buffalo. My odds
did not look good, and I knew it, but it gave my life a direction, so I went ahead
with it anyways.&lt;/p&gt;
&lt;p&gt;It started by emailing Michael Davidson. I met Michael by accident, as well. I bet you&amp;rsquo;re
starting to notice a trend here. It was March of 2009. I was working on a personal
project, something to keep me busy, that was built on App Engine. I wanted to use
XMPP, which wasn&amp;rsquo;t supported yet. It came up in a tweet.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;For some reason, I somehow came to the attention of Mike Repass, the project manager
for the App Engine XMPP API. I still have no idea how this happened.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;Mike Repass then put me in touch with Michael, the engineer working on the API. Michael
and I exchanged a few emails, discussing the API.&lt;/p&gt;
&lt;p&gt;Fast-forward a few months, and Buzz is released. I&amp;rsquo;m minding my own business, being
generally silly and offensive, just like I am on Twitter. And out of nowhere, I get
followed by Christian Bogeberg, a tech recruiter for Google. He and I chat some, mostly
about nothing, and I move on with my life.&lt;/p&gt;
&lt;p&gt;Fast-forward to 2010, and I find myself emailing Michael and Christian, asking how I
should prepare myself to get hired. I get &lt;a href=&#34;http://www.suchagit.com/2010/05/story-in-progress.html&#34;&gt;some great information&lt;/a&gt;
that basically boils down to “learn more and get more experience”. Generally, I learn
best when I&amp;rsquo;m gaining experience. So I start casting about for things to do. I &lt;a href=&#34;http://www.suchagit.com&#34;&gt;start
a blog&lt;/a&gt; to catalogue my experiences.&lt;/p&gt;
&lt;p&gt;A few weeks later, I&amp;rsquo;m watching Google I/O from my room in Syracuse, New York. I watch
the demo of Chrome to Phone and think it&amp;rsquo;s pretty cool. But I also think “Hey,
it would be cool if you could push links from Android to Chrome, too.” So I
&lt;a href=&#34;http://www.suchagit.com/2010/05/android-to-cloud-push.html&#34;&gt;decide&lt;/a&gt; to write it. Worse,
I already had an algorithm in mind to write it, and it seemed pretty simple, so I
decided to challenge myself to write the App Engine and Chrome sides in three hours, as
I rode in the car on the way to my older brother&amp;rsquo;s graduation in Rochester. That was a
bit ambitious; it ended up taking me the trip there &lt;em&gt;and&lt;/em&gt; the trip back.&lt;/p&gt;
&lt;p&gt;How did I write a system in six hours? Well, remember how I said it seemed simple?
Note to self: if something seems simple, you&amp;rsquo;re probably doing it in a dumb way. That
initial version was the stupidest thing that could have possibly worked. The App
Engine side had two endpoints: one for receiving links, the other for displaying. An
authenticated POST request to the receiving endpoint would save that link in the system.
An authenticated GET request to the displaying endpoint would just display the latest
link pushed. I didn&amp;rsquo;t even use caching. The Chrome extension worked by just hitting
the display endpoint every 10 seconds. It opened the link, then saved the link in localStorage.
Next time it hit the display endpoint, it checked the link against the one stored in
localStorage. If the links didn&amp;rsquo;t match, the link was opened.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s surprising this didn&amp;rsquo;t scale.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&#34;http://www.suchagit.com/2010/05/android2cloud-update.html&#34;&gt;announced&lt;/a&gt; the completion
of the Chrome/App Engine components, then hunkered down to wait for my Nexus One to
arrive so that I could develop on it.&lt;/p&gt;
&lt;p&gt;When I got the phone, development started slowing. &lt;a href=&#34;http://www.suchagit.com/2010/05/android-development.html&#34;&gt;Android development&lt;/a&gt;
isn&amp;rsquo;t as straightforward as Chrome extension and App Engine site development is. I
&lt;a href=&#34;http://www.suchagit.com/2010/06/roadblocks-are-bad.html&#34;&gt;hit some roadblocks&lt;/a&gt; trying
to use OAuth. To this day, using OAuth on Android remains a giant pain in the ass.
All in all, it took me from May 22 to July 12 to get a working Android version ready
for &lt;a href=&#34;http://www.suchagit.com/2010/07/android2cloud-alpha-release.html&#34;&gt;release&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I never really expected anything to come of android2cloud, as I dubbed it. I put it
online because I believe that software that dies on your hard drive is a waste of
perfectly good resources. I believe in releasing everything as open source software
by default, and only &lt;em&gt;not&lt;/em&gt; releasing if there&amp;rsquo;s a &lt;em&gt;very&lt;/em&gt; good reason. So I released
android2cloud as open source software.&lt;/p&gt;
&lt;p&gt;The first night I put it on the Android Market, I got a bug report from &lt;a href=&#34;https://plus.google.com/100594935715938326713&#34;&gt;Patrick
Kettner&lt;/a&gt;, who (I believe) was the
first android2cloud user. He was also the first person who donated. Patrick sat on
IM with me and debugged his issues until they were resolved. I still feel a huge
amount of gratitude towards him for his role in this.&lt;/p&gt;
&lt;p&gt;android2cloud didn&amp;rsquo;t stay small long. By July 26, a mere two weeks after I had
released the software, I was marveling over the fact that &lt;a href=&#34;http://www.suchagit.com/2010/07/global-entrance.html&#34;&gt;two Asian publications&lt;/a&gt;
had covered android2cloud and the project page was getting a decent amount of traffic.
I also noted a problem that would plague the fledgling project for years: we were
seeing a huge amount of traffic on the server.&lt;/p&gt;
&lt;p&gt;On August 2nd, we had our first downtime. The server ran over its quota, and I had
a tough decision to make: what the hell should I do? I ended up pulling the email
addresses from the database and sending a mass email. I apologised for the invasion
of their inbox, and let them know about the downtime. I also let them know about the
implementation of Google Analytics tracking in the project. This tracking was short-lived;
it added unacceptable bloat to the Android app and required us to ask for more permissions
than we actually needed.&lt;/p&gt;
&lt;p&gt;I consider the tipping point of the project to be August 4th, 2010. On August 4th,
&lt;a href=&#34;http://thepurdman.com&#34;&gt;Kevin Purdy&lt;/a&gt; of &lt;a href=&#34;http://www.lifehacker.com&#34;&gt;Lifehacker&lt;/a&gt;
&lt;a href=&#34;http://lifehacker.com/5604248/android2cloud-opens-urls-from-your-phone-in-chrome&#34;&gt;covered&lt;/a&gt;
the app. It went on Lifehacker&amp;rsquo;s homepage. Thousands of users followed almost immediately.&lt;/p&gt;
&lt;p&gt;Unsurprisingly, we had downtime that night. I sent out another email, apologising. I
dealt with email replies and conversations throughout the day, but there was some fallout.
I got a lot of negative feedback, I got a lot of negative reactions, and I came face-to-face
with the one enduring truism that this project has given me: nobody cares, and they
shouldn&amp;rsquo;t have to.&lt;/p&gt;
&lt;p&gt;But still, it&amp;rsquo;s hard, as a barely-20-year-old college student whose world is limited
to his little town and little college, to deal with a sudden influx of complaints,
criticisms, and opinions. I got a little overwhelmed, but tried to keep my chin up. I
&lt;a href=&#34;http://www.suchagit.com/2010/08/double-edged-sword-users.html&#34;&gt;posted&lt;/a&gt; about how
awesome it was that I had all these new users, but they brought with them a slew of
problems I didn&amp;rsquo;t know how to deal with.&lt;/p&gt;
&lt;p&gt;A mere two days later, I &lt;a href=&#34;http://www.suchagit.com/2010/08/am-i-washed-up.html&#34;&gt;posted&lt;/a&gt; about
an experience that would refrain over the next year or two: I updated and
&lt;a href=&#34;http://blog.2cloudproject.com/2010/08/authentication-issues.html&#34;&gt;broke everything&lt;/a&gt;.
I began to doubt myself, to wonder if I had had one shot at being a good developer, and
I had blown it. My nagging self-doubt began to gnaw even more fiercely at me, with the
very real possibility eating away at my confidence: did everyone figure out what I already
knew, that I was a hack? Did everyone decide that I didn&amp;rsquo;t know what I was doing and
just move on? They would&amp;rsquo;ve been right.&lt;/p&gt;
&lt;p&gt;As I &lt;a href=&#34;http://blog.2cloudproject.com/2010/08/downtime.html&#34;&gt;continued to fight with downtime&lt;/a&gt;,
I &lt;a href=&#34;http://blog.2cloudproject.com/2010/08/servers-and-money.html&#34;&gt;started looking&lt;/a&gt; at what
the community thought I should do. How could I get the server paying for itself when
it was using $70 a week?&lt;/p&gt;
&lt;p&gt;Well, enter Michael. Remember Michael? The engineer who talked with me about the XMPP
API? Well, Michael had kept android2cloud on his periphery, and when Google&amp;rsquo;s Channel
API was ready for testing, Michael recommended me for the testing program. The Channel
API was our godsend. It would let us form a connection with the server and have the
server just tell Chrome when a new link was available, rather than having Chrome ask
every fifteen seconds. With Michael&amp;rsquo;s recommendation, &lt;a href=&#34;http://blog.2cloudproject.com/2010/08/channel-api.html&#34;&gt;we got early access&lt;/a&gt;
to the API and began testing it. I met Moishe Lettvin, the App Engine Communications APIs
Lead who was also in charge of the new Channels API. I began implementing the system
and talking with Moishe about our needs and the Channels API.&lt;/p&gt;
&lt;p&gt;We were moving fast, but not fast enough; once again, we were &lt;a href=&#34;http://blog.2cloudproject.com/2010/09/money-spoils-everything-wholesome.html&#34;&gt;running out of money&lt;/a&gt;.
I had to cut server quotas in half, with plans to remove them entirely in the near
future. &lt;a href=&#34;http://blog.2cloudproject.com/2010/09/downtime-imminent.html&#34;&gt;Downtime became expected&lt;/a&gt;,
at that point. But the app didn&amp;rsquo;t die; it got covered by more Android blogs, got
discussed in podcasts, it was even a top 10 most popular app on AppBrain&amp;hellip; twice.
I didn&amp;rsquo;t know what to do with all the publicity.&lt;/p&gt;
&lt;p&gt;Then we were saved. A white knight came riding to our rescue. We &lt;a href=&#34;http://blog.2cloudproject.com/2010/10/sponsorship.html&#34;&gt;got&lt;/a&gt;
our first sponsor, &lt;a href=&#34;http://www.wonderproxy.com&#34;&gt;WonderProxy&lt;/a&gt;, through &lt;a href=&#34;http://twitter.com/#!/preinheimer&#34;&gt;Paul
Reinheimer&lt;/a&gt;. The business dealings were kept to
a minimum. Paul essentially said “Hey, we&amp;rsquo;d like to sponsor you. What can we get for
$200?”, to which I said “We&amp;rsquo;ll link you on the blog and list you on the project page
as a sponsor.” That was pretty much it.&lt;/p&gt;
&lt;p&gt;The money tided us over for a bit, but a few weeks later, we were right back where
we started: &lt;a href=&#34;http://blog.2cloudproject.com/2010/11/more-downtime.html&#34;&gt;broke&lt;/a&gt;. Once
again, &lt;a href=&#34;http://blog.2cloudproject.com/2010/11/another-sponsor.html&#34;&gt;we were saved&lt;/a&gt;;
this time, it was &lt;a href=&#34;http://www.sitespect.com&#34;&gt;SiteSpect&lt;/a&gt; coming to our aid, through
&lt;a href=&#34;http://twitter.com/#!/ericjhansen&#34;&gt;Eric Hansen&lt;/a&gt;. Eric basically said “Hey, we&amp;rsquo;d like
to sponsor you, too. Can we just have the same deal WonderProxy got?”, to which I said
“Sure”.&lt;/p&gt;
&lt;p&gt;During this time, the Social Network was released. This is important, not because of
the movie itself, but because of the conversation it started. My friends were aware
that I had this project going on and that it was getting undeserved popularity. One of
my friends, &lt;a href=&#34;http://www.twitter.com/tinogalizio&#34;&gt;Tino&lt;/a&gt;, saw the Social Network and
sent me a text: “If you ever started a company, I&amp;rsquo;d want to be the Eduardo Saverin to
your Mark Zuckerberg.” I had already been thinking about how horrible it would be if
one of the thousands of people I was now hosting sued me, or if I got sued for something
they did. Really, this project could only survive without a company as long as nothing
with legal implications happened. That scared me. So Tino&amp;rsquo;s proposition intrigued me.
We started researching New York State&amp;rsquo;s laws on businesses, and formed an LLC we called
&lt;a href=&#34;http://www.secondbit.org&#34;&gt;Second Bit&lt;/a&gt;. It was a name I had thought up during the summer,
along with the tag-line “Untapped potential”. It came from thinking about storing binary
data; often, it&amp;rsquo;s not good enough to store “yes” or “no”, you tend
to need “no answer” or “maybe”, too. So you need a second bit, of
which only one of the values is used. Meaning you&amp;rsquo;re not realising the full potential
of your data-storage capabilities. This idea struck me as something very true about the
way I work; I&amp;rsquo;m never quite working at my full potential. Rather than thinking about
this as me doing unsatisfactory work, though, it became a mantra for continual
improvement in my work. “Untapped potential” isn&amp;rsquo;t, as some people who heard
the rationale purported, a slur on the current level of our work, it&amp;rsquo;s an admonition
to not be satisfied, to not settle, to not allow ourselves to grow complacent.&lt;/p&gt;
&lt;p&gt;As the weeks passed, the Channel API still wasn&amp;rsquo;t available for use in our production
server. We had it running for our beta testers, but our production environment couldn&amp;rsquo;t
use it yet; Google wanted to test it with a small subset of our users, and promised that
they&amp;rsquo;d give our production server access as the API matured. I grew impatient, and
started investigating an emerging new language for the server, &lt;a href=&#34;http://www.nodejs.org&#34;&gt;NodeJS&lt;/a&gt;.
It would mean hosting the server ourselves, but would enable the same push capabilities
we&amp;rsquo;d get in the Channel API. Then something happened that fractured all my plans: the
Channel API got released. My reaction is one I&amp;rsquo;m not proud of; I felt betrayed. Google
didn&amp;rsquo;t give me much forewarning, and I was caught with my pants down, without a full launch
plan. I immediately dropped the NodeJS plans, and &lt;a href=&#34;http://blog.2cloudproject.com/2010/12/hello-channel-api.html&#34;&gt;started testing&lt;/a&gt;
the Channel API for production deployment, rather than just testing the technology,
as I had before.&lt;/p&gt;
&lt;p&gt;The API had changed since I had last tested. It no longer worked with Chrome extensions.
I dug through the code and implemented a workaround, which I then shared with Moishe.
He thanked me, and fixed it in the production environment. I worked through the month
of December to get the new system ready for a &lt;a href=&#34;http://blog.2cloudproject.com/2010/12/version-updates-and-annoying-messages.html&#34;&gt;release&lt;/a&gt;
at midnight on January 1st.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://blog.2cloudproject.com/2011/01/about-version-20.html&#34;&gt;I botched it&lt;/a&gt;. Horribly.
For thousands of users, bugs were rampant in the new version, rendering it unusable.
The upgrade was a catastrophic failure. I had planned to announce that Second Bit was
“acquiring” (i.e., legally responsible for) android2cloud. That announcement
was put on hold until I could fix everything.&lt;/p&gt;
&lt;p&gt;The good news was that the financial situation was less dire, for the time being; we
were using about a dollar a day to keep the server running, one tenth of what it cost
before the upgrade. The bad news was that the upgrade introduced a host of new bugs.
For example, the Channel API was used to create connections between Chrome and the
server. The problem was, these connections only lasted two hours before being closed.
I had to catch the close error, then force a reconnection. This is still unreliable,
15 months after I introduced it. Also, for some reason, my method of storing the last
link that the Chrome extension received was no longer functioning for some users; the
links kept opening.  I issued a &lt;a href=&#34;http://blog.2cloudproject.com/2011/01/202-just-pushed.html&#34;&gt;fix&lt;/a&gt;
for this, basically storing whether a link had been read or not on the server. Chrome
would then tell the server that it had gotten the message, and the server would only
send messages that hadn&amp;rsquo;t been received. This blew up in my face later.&lt;/p&gt;
&lt;p&gt;As anyone who has introduced a large number of bugs into software or broken software
for a large number of people knows, the user base is pretty vocal when things stop
working. Which led to another situation I&amp;rsquo;m not proud of: I &lt;a href=&#34;http://blog.2cloudproject.com/2011/01/disappointment.html&#34;&gt;outlined my
disappointment&lt;/a&gt; in a blog
post. I was worn down, I was hurt, and I was tired of being met with demands every
time I turned around. Some users, a very vocal minority, were nothing short of rude
and hateful in their interactions with me, and it was wearing me down to continue
to be polite and calm with them. By the end of January, I needed to declare a
&lt;a href=&#34;http://blog.2cloudproject.com/2011/01/hiatus.html&#34;&gt;hiatus&lt;/a&gt; for a week or two as I
caught my breath.&lt;/p&gt;
&lt;p&gt;When I returned, it was to release &lt;a href=&#34;http://blog.2cloudproject.com/2011/02/203-landing.html&#34;&gt;a new version&lt;/a&gt;
that fixed some users&amp;rsquo; problems with links not opening or links not getting marked
as read. Which would have been great, if it didn&amp;rsquo;t &lt;a href=&#34;http://blog.2cloudproject.com/2011/02/links-constantly-being-opened.html&#34;&gt;introduce a new bug&lt;/a&gt;
that caused &lt;em&gt;more users&lt;/em&gt; to have their links open every time Chrome started. By the
way, in case you were wondering, that &lt;em&gt;really&lt;/em&gt; annoys people. I had long treated the
ability to open links in people&amp;rsquo;s browsers as a sacred trust, and I&amp;rsquo;m glad I did.&lt;/p&gt;
&lt;p&gt;A few days later, I &lt;a href=&#34;http://blog.2cloudproject.com/2011/02/204-sort-of.html&#34;&gt;had a fix&lt;/a&gt;.
I was finally tired of having everything break on me, however, so I made it an opt-in
for those having the problem until I could verify it worked as expected.&lt;/p&gt;
&lt;p&gt;Around this time, I met &lt;a href=&#34;http://www.dstaley.me&#34;&gt;Dylan Staley&lt;/a&gt;. Dylan is&amp;hellip; well, the
best way I can think of to describe Dylan is “incredibly ambitious”. He&amp;rsquo;s a
year younger than I am, but makes me feel lazy. When I met him, he was a student
ambassador for the Wikimedia Foundation and an Apple Store employee. He&amp;rsquo;s since left
Apple, become an integral part of an LSU frat, obtained a position as a local
representative for Square, and is applying for &lt;em&gt;yet another&lt;/em&gt; position for I-don&amp;rsquo;t-even-know-who.
The boy is nuts. Dylan and I met because of Google I/O. That&amp;rsquo;s not an exaggeration;
Google I/O was gearing up, and Dylan and I both happened to be watching the hashtag
on Twitter. I posted something, and Dylan replied. We started talking, and the rest
is history.&lt;/p&gt;
&lt;p&gt;One of the more surreal moments of this saga was chatting with Dylan and telling him
about android2cloud, only to have him respond “Oh, yeah, I&amp;rsquo;ve used that!”&lt;/p&gt;
&lt;p&gt;As Dylan and I talked about android2cloud, he proposed doing a new design for it. I
was ecstatic. He wanted to use it as an entry in a design competition, I wanted to
have a design that didn&amp;rsquo;t look like&amp;hellip; well, like I designed it. He joined the
android2cloud team as our lead designer, and in mid-March, we were ready to &lt;a href=&#34;http://blog.2cloudproject.com/2011/03/say-hello-to-2cloud-project.html&#34;&gt;unveil
the redesign&lt;/a&gt;.
We had rebranded from android2cloud to just “2cloud”, to allow us to expand
to other platforms and become more platform-agnostic. We had new icons, a new website,
the whole shebang.&lt;/p&gt;
&lt;p&gt;Two weeks later, another announcement came right on the heels of our redesign: we had
been &lt;a href=&#34;http://blog.2cloudproject.com/2011/03/weve-been-acquired.html&#34;&gt;acquired by Second Bit&lt;/a&gt;.
Second Bit had actually acquired the product on January 1st and had subsequently started
paying the server bills, but we had refrained from saying anything until Second Bit&amp;rsquo;s
website was launched.&lt;/p&gt;
&lt;p&gt;When we announced the acquisition, we reaffirmed our stance: no ads, no asking users
to pay for it. We were determined to remain free, open source software. That would
come back to bite us in the ass.&lt;/p&gt;
&lt;p&gt;Not even a month later, we &lt;a href=&#34;http://blog.2cloudproject.com/2011/04/android-2051-and-ads.html&#34;&gt;introduced&lt;/a&gt;
ads to our Android client. They were opt-in, but I still got a bad taste in my mouth.
Unfortunately, we were running out of money. There wasn&amp;rsquo;t much of a choice in the
matter. We had to do &lt;em&gt;something&lt;/em&gt; to monetise the service, or we&amp;rsquo;d have to shut it
down. It wouldn&amp;rsquo;t be the last time we broke a promise, or the last time we felt we
had no choice. It still makes me feel bad, and I still wonder whether I&amp;rsquo;m really
doing the right thing, even as I push further on down this monetization road. I had
so many principles that I stuck to as long as I could, but abandoned when I was faced
with a hard choice. I tell myself I&amp;rsquo;m refining those principles, holding on to the
ideological core while making them practical, but with each compromise I feel myself
slipping down a path I never wanted to be on in the first place.&lt;/p&gt;
&lt;p&gt;The ads, unfortunately, failed miserably. We never made a dime off them. The problem,
we deduced, was that our app was, at its most ideal, invisible. It&amp;rsquo;s hard to display
ads on something invisible. Rather than trying to make a monetisation strategy that was
completely at odds with the goals of our product work, we abandoned ads.&lt;/p&gt;
&lt;p&gt;May was dominated by my visit to San Francisco to attend Google I/O. I flew across
the country to spend a week with Dylan, Google, and five thousand computer geeks I
didn&amp;rsquo;t know. It was the best week of my life.&lt;/p&gt;
&lt;p&gt;When I got back, I continued working on 2cloud. At that point, I was working on a
version I called “Honeybadger”. The point of Honeybadger was to be resilient,
well-architected, clean, and complete. It would integrate Chrome to Phone functionality
next to Phone to Chrome functionality. It would bring the long-awaited arrival of
Firefox support.&lt;/p&gt;
&lt;p&gt;Then, on June 30th, I got an email that changed everything. Wired contacted me,
asking if I was the correct contact person for press. They were reviewing 2cloud.
(They ended up giving it an 8/10).&lt;/p&gt;
&lt;p&gt;Remembering the Lifehacker coverage and the results it brought, I decided the only
appropriate reaction was to &lt;a href=&#34;http://blog.2cloudproject.com/2011/06/time-to-grow-up.html&#34;&gt;freak out&lt;/a&gt;.
A few frenzied phone calls later, we came up with a plan to pay for the server in the
long-term: a quota. I stopped working on Honeybadger and &lt;a href=&#34;http://blog.2cloudproject.com/2011/07/they-grow-up-so-fast.html&#34;&gt;began a codesprint&lt;/a&gt;
to enable a quota that would cut off after a certain amount of usage unless the user
paid a dollar. If the user didn&amp;rsquo;t pay a dollar, their links would open when the quota
reset. We took the opportunity to deprecate support for some of the older Android
versions, so we could get rid of OAuth in future versions.&lt;/p&gt;
&lt;p&gt;A few weeks later, we &lt;a href=&#34;http://blog.2cloudproject.com/2011/08/21-in-with-new-out-with-old.html&#34;&gt;released&lt;/a&gt;
the new version with the quota. We set the quota high enough that it wouldn&amp;rsquo;t be hit
for a few weeks, to be sure the software was working and there were no bugs. For once,
a release went as planned. I &lt;a href=&#34;http://blog.2cloudproject.com/2011/08/about-quota.html&#34;&gt;posted&lt;/a&gt;
about the quota.&lt;/p&gt;
&lt;p&gt;When were sure the system was working as intended and there were no bugs, we set the
quota to a sustainable level. Late that day, the quota ran dry. I tested, and purchasing
exemption worked just fine. Nobody paid to get around the quota. We theorised that
maybe the window of opportunity was too slim, and so we set the quota for the next
day artificially low, trying to force the quota to run out earlier. It did, around noon.
Still, nobody paid.&lt;/p&gt;
&lt;p&gt;Worse, we got a &lt;a href=&#34;http://help.2cloudproject.com/discussions/questions/7-server-is-over-quota-and-my-link-will-be-stored-unles-i-cough-up-1-really&#34;&gt;particularly nasty support request&lt;/a&gt;
about it. We tried to be civil in our replies, but we were both really upset. Once
again, I &lt;a href=&#34;http://blog.2cloudproject.com/2011/09/disillusioned.html&#34;&gt;posted&lt;/a&gt; about
my frustration. Again, not something I&amp;rsquo;m proud of.&lt;/p&gt;
&lt;p&gt;Tino and I scheduled a meeting to hash out the money problems and decide what to do.
I was pretty depressed about the whole thing by this point. I was starting to feel
dread when it came time to work on or talk about 2cloud, and that made me sick at
heart. I was at the point of saying “fuck it” and quitting the field of
business development, letting Tino make all the monetisation decisions. Just declare
moral bankruptcy and let him worry about it.&lt;/p&gt;
&lt;p&gt;The meeting we had grew heated. Very heated. I didn&amp;rsquo;t say anything I regret, and
I don&amp;rsquo;t think Tino regrets anything he said, but it was a very emotional ordeal
for the both of us. Creating things and running a business aren&amp;rsquo;t easy. At the end,
however, as Tino was preparing to leave, I had an idea. A crazy idea. We started
talking about why people were expecting so much of us but so reluctant to pay us.
In essence, we started talking about why nobody used the quota. And we came up with
&lt;a href=&#34;http://blog.secondbit.org/2011/10/apps-and-services.html&#34;&gt;a theory&lt;/a&gt;: psychologically
speaking, apps and services each provoke different reactions from users. We were
perceived as an app, but were actually a service, and that was the root of our problems.&lt;/p&gt;
&lt;p&gt;During the course of our discussion, Tino made an analogy. He claimed that I was like
a dairy farmer who had this cow, and delivered milk to users. I kept telling the users
“Oh, pay if you want to, I don&amp;rsquo;t want to make you”, and the users kept saying
“But you&amp;rsquo;ll keep delivering milk if I don&amp;rsquo;t? OK, see you tomorrow.” In the
meantime, the cow was starving. “Bessie is starving, Paddy, and soon nobody will
have milk!” He was right; the fair thing for the users who were doing the right
thing was to protect their investment, to make other users do the right thing. But out
of the analogy came the codename for our next version: “Bessie”.&lt;/p&gt;
&lt;p&gt;I asked Tino to let me proceed as we were until December, to give me time to get
Bessie ready to release. The point of Bessie was to transition 2cloud into a paid
service &lt;em&gt;and&lt;/em&gt; to make it clearer to users that this was a service. Before we could
transition to a paid service, however, we needed to solve some problems that were
acceptable in a free app, but unacceptable in a paid service. Things like the OAuth
problems that had been a sporadic nuisance for years. Things like inexplicable
errors. It became clear we couldn&amp;rsquo;t host a paid service off App Engine.&lt;/p&gt;
&lt;p&gt;We launched a new version of the Android app, with &lt;a href=&#34;http://blog.2cloudproject.com/2011/09/upcoming-poll-again-about-money.html&#34;&gt;an in-app poll&lt;/a&gt;
about the subscriptions, to gauge the response. I included a field in the poll for
people to enter their email address, in case they&amp;rsquo;d like to talk with us about the
subscriptions. I then spent weeks sending hundreds of emails, conversing with our
users about the change. It was the most intense customer support work we&amp;rsquo;d ever done,
and it ate up hours of time. I think it was worth it.&lt;/p&gt;
&lt;p&gt;I chose Google&amp;rsquo;s &lt;a href=&#34;http://www.golang.org&#34;&gt;Go&lt;/a&gt; to write the server side of Bessie. I
used Twitter&amp;rsquo;s &lt;a href=&#34;http://twitter.github.com/bootstrap&#34;&gt;Bootstrap&lt;/a&gt; to create a theme, and
built the first web interface we&amp;rsquo;ve ever had. The web interface was ready for alpha
testers on December 2nd, in time for a Google+ Hangout we had scheduled to allow people
to talk with us about subscriptions. We had a &lt;a href=&#34;http://blog.2cloudproject.com/2011/12/engaging-real-people.html&#34;&gt;pretty good turnout&lt;/a&gt;
and chatted for a few hours, and I gave everyone that came access to the alpha version
of Bessie to test and play with.&lt;/p&gt;
&lt;p&gt;The testers found some bugs, and I summarily fixed them. I &lt;a href=&#34;http://updates.2cloud.org&#34;&gt;started a blog&lt;/a&gt;
to serve as the changelog as we updated the server. The plan was to update the
Chrome extension, rebuild the Android app from scratch, and release.&lt;/p&gt;
&lt;p&gt;Then I dropped out of school.&lt;/p&gt;
&lt;p&gt;I had been struggling in college for a while. It wasn&amp;rsquo;t that I wasn&amp;rsquo;t smart enough
or that I didn&amp;rsquo;t know the material. I had increasingly become plagued with insomnia
and hypersomnia, and college was making my depression worse and worse. I was having
trouble completing assigned work or showing up to classes. After some discussion
with my family over the winter break, I took a medical leave of absence from school.
I&amp;rsquo;m not sure I&amp;rsquo;ll be going back.&lt;/p&gt;
&lt;p&gt;If I wasn&amp;rsquo;t going to school, I needed to be working, instead. I got hired as a
Software Engineer Intern at &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;. I&amp;rsquo;ve been learning a lot
there, and have morphed into more of a developer advocate than anything else. It
takes up a considerable amount of my attention, though, more than school did, and
it has slowed the progress of 2cloud development. Which explains why it&amp;rsquo;s now mid-March
and there still aren&amp;rsquo;t public alphas of the Chrome and Android interfaces. I&amp;rsquo;ve
been growing a lot, as a developer, in these last few months, though. The 2cloud
architecture has been rethought and upgraded to be more scalable, fault-tolerant,
and with better separation of concerns. We&amp;rsquo;re making use of &lt;a href=&#34;http://www.iron.io/products/worker&#34;&gt;IronWorker&lt;/a&gt;,
one of the products Iron.io makes, and we&amp;rsquo;ll be using &lt;a href=&#34;http://www.iron.io/products/mq&#34;&gt;IronMQ&lt;/a&gt;
as soon as a feature is added. Not because I&amp;rsquo;m an Iron.io employee, but because
they make our application better. Which is really all that matters.&lt;/p&gt;
&lt;p&gt;I said at the start that I should never be startup founder because I think it would
be a lot of fun. I became a startup founder on accident, without any input from me,
really. In doing so, I learned I was right on both counts: I should never be a startup
founder, and it is a lot of fun.&lt;/p&gt;
</description>
      <carvers:summary>The ongoing history of 2cloud; alternate title: “How I Started A Company On Accident”. A narrative exploring how a learning project grew out of control.</carvers:summary>
    </item>
    
    <item>
      <title>Tales From High School</title>
      <link>https://paddy.carvers.com/posts/tales-from-high-school/</link>
      <pubDate>Sun, 11 Mar 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/tales-from-high-school/</guid>
      <description>&lt;p&gt;Today’s post has no point. There is no lesson here. It will not make
you a better person to read this post, it will not give you some new
life skill or hone an old one.&lt;/p&gt;
&lt;p&gt;Though, to be honest, that means it’s pretty much just like every other
post you’ll find here. This time, though, it’s not even significant to
me. I just wanted to share an interesting tale from my days as a high
school student with you.&lt;/p&gt;
&lt;p&gt;It was May of 2005. I was a freshman in high school, a few short months
from turning sixteen, with all the freedom to crash into things at a
high speed that carried with it. It was the fifteenth, to be precise.
That night, the &lt;a href=&#34;http://en.wikipedia.org/wiki/Star_Wars_Episode_III:_Revenge_of_the_Sith&#34;&gt;third/sixth installment&lt;/a&gt;
of the Star Wars franchise was to be released, at midnight. Despite the
previous two releases being met with the critical acclaim of used tissue,
excitement was high. A teacher came to class as Darth Vader. We spent the
day humming the Imperial March whenever we saw him.&lt;/p&gt;
&lt;p&gt;This story isn’t about him, though. This story is about something very
simple. The end of my day was marked by the ring of a bell, like high
school students everywhere. Fun fact: high schools haven’t changed much
since they were used to train factory workers. It shows.&lt;/p&gt;
&lt;p&gt;When the bell rang, I left class and converged with my other factory
workers in the large central area affectionately referred to as
“the foyer”;. The foyer was a large, open room that served as
a central gathering-place for students. In the middle of the foyer was
a square formed by four utilitarian columns.&lt;/p&gt;
&lt;p&gt;That day, the square was more obvious than usual. It was an opening
in the pack of students that had gathered, an implicit boundary created
by the architecture. Two students stood in the middle of it, wielding
yardsticks they had appropriated from the science rooms. They faced off
against each other, twirling their yardsticks. They paced forward,
placed their yardsticks against each other’s, and locked gazes. A
collective silence grew over the crowd gathered.&lt;/p&gt;
&lt;p&gt;The two pushed off each other, then rejoined, fiercely swinging
yardsticks until the &lt;em&gt;clack&lt;/em&gt;s reverberated off the walls. They struck
and parried, circled and thrust, blocked and maneuvered. Neither scored
a hit. From somewhere in the gathered students, light-saber noises started
to be heard. More students took up the role, providing sound effects for
the historic battle that was being waged in our own hallways. One of the
combatants lowered his yardstick, raising his hand instead. The other
combatant, taking the hint, threw himself bodily against one of the columns.
The other combatant advanced and sliced at the other’s ribs; his intended
target ducked just in time, letting the yardstick clatter off the column.&lt;/p&gt;
&lt;p&gt;The fight raged on for minutes. At one point, a collective gasp arose
from one side of the square. The group of students parted, and a student
wearing a black hoodie approached. The hood was raised, riding low on his
brow, obscuring his face. He held a yardstick in each hand, their tips
trailing on the floor as he walked. The combatant Jedis, locked in a
battle of strength at the center of the square, broke their fight and
stared at the intruder. The Sith slowly raised both yardsticks, and the
two Jedi exchanged a look. The Sith twirled the yardsticks, and the Jedi
charged.&lt;/p&gt;
&lt;p&gt;The battle went on for minutes, the Sith successfully fending off both
Jedi. Finally, it went on too long. The Jedi locked yardsticks with the
Sith, forcing him to keep both arms fully extended above his head to
keep the yardsticks at bay. One of the Jedi took the opportunity and
relented his attack, quickly ducking under the Sith’s arm and stabbing
the other Jedi through the chest. The Sith brought the yardsticks around
with surprising speed, resting them scissored on the Jedi’s shoulder.
The Jedi, in acceptance, knelt. The Sith scissored, and the remaining
Jedi collapsed with theatrical stiffness.&lt;/p&gt;
&lt;p&gt;Another gasp, and the students along one edge of the square fell away
to reveal a hall monitor. He entered the square and stood in front of
the Sith. The hall monitor raised a hand, palm outstretched. The Sith
convulsed, as if electrocuted, and fell to the ground. The hall monitor
walked away.&lt;/p&gt;
&lt;p&gt;That was it. Just a few moments in an afternoon, precipitating a
disappointing blockbuster release. Just a few hundred teenagers
turning a clichéd hallway scene into an epic battle by their
willingness to join each other in a delusion, an agreement to
recognise a grandeur that wasn’t there.&lt;/p&gt;
&lt;p&gt;But hey, it’s not every day teenagers actually use their &lt;em&gt;imagination&lt;/em&gt;,
which probably explains why I still remember it.&lt;/p&gt;
</description>
      <carvers:summary>A long and unnecessarily epic story that serves no real purpose. I just wanted to tell it. Also, it has Jedis.</carvers:summary>
    </item>
    
    <item>
      <title>Ass Kicked Per Minute</title>
      <link>https://paddy.carvers.com/posts/ass-kicked-per-minute/</link>
      <pubDate>Sun, 04 Mar 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/ass-kicked-per-minute/</guid>
      <description>&lt;p&gt;When I was hired by &lt;a href=&#34;http://www.iron.io&#34;&gt;Iron.io&lt;/a&gt;, they hired me as a
intern Software Engineer. I was applying for a position that was
originally meant to be for a full-time Software Engineer, but I asked
if I could be an intern instead, as I still wasn’t confident in my
engineering abilities. I’m still not.&lt;/p&gt;
&lt;p&gt;While I am working on some software engineering tasks, I feel like the
title isn’t a good representation of what I do. I also help out with
marketing, for example. And I think my biggest contribution to the
company, to date, has been documentation and developer advocacy.&lt;/p&gt;
&lt;p&gt;These are not areas I’ve had much experience in, but they’re things I
have found I enjoy immensely. When we made the decision that our old
documentation needed to be retired (I prefer “euthanised” or “shot in
the face and then burned to be 100% sure it never returns”), I started
to get more serious about researching the fledgling field of developer
experience.&lt;/p&gt;
&lt;p&gt;There’s not a lot there. The most useful resource I can point you to is
&lt;a href=&#34;http://www.pamelafox.org&#34;&gt;Pamela Fox&lt;/a&gt;’s &lt;a href=&#34;http://developer-support-handbook.org&#34;&gt;Developer Support Handbook&lt;/a&gt;,
in which she documented her experience at Google as a developer support
pioneer.&lt;/p&gt;
&lt;p&gt;Matt Cutts, of Google’s spam-fighting team, said that being able to code
is akin to having a superpower in today’s society. And he’s right. It is
becoming increasingly obvious that developers are a desired asset in
pretty much every corner of our society today.&lt;/p&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;p&gt;But every Batman needs an Alfred, and every developer needs a developer
advocate. Alfred doesn’t give Batman new powers or enhance his powers in
any way; rather, Alfred’s purpose is to give Batman more time to use his
powers, by removing unecessary and mundane time-sinks that Batman would
have had to deal with.&lt;/p&gt;
&lt;p&gt;When I realised this, I started measuring the work we were doing at Iron
in our developer support. I wasn’t measuring based on the lines of code
that developers produced, I wasn’t even measuring based on the usage our
platform got. Developers, like Batman, have really only one job: to kick
ass. So I started measuring how long it took developers to kick ass using
our system, and tried to decrease that time in whatever way I could. And
so a new unit of measurement was born: Ass Kicked Per Minute.&lt;/p&gt;
&lt;p&gt;At first, we could gain huge improvements in our Ass Kicked Per Minute
scores. Things like refactoring our navigation to be more intuitive. We
had a golden rule: if I can’t get where I want to be in two clicks, it’s
wrong. We rewrote a lot of our documentation from scratch, focusing on
completeness and accuracy. While we do have a &lt;a href=&#34;http://www.hipchat.com/gNWgTiqIC&#34;&gt;public support chatroom&lt;/a&gt;,
I regard every developer that winds up there as a developer I’ve failed.
My next goal is to declare war on scrolling; scrolling is an imprecise,
wasteful navigational technique, and the less users have to do it, the
better. This means &lt;code&gt;position: fixed&lt;/code&gt; is my friend.&lt;/p&gt;
&lt;p&gt;But now our Ass Kicked Per Minute scores need to be fought for. Maybe
we can only shave a half of a second off a common task. It’s absolutely
still worth doing, because that’s a half a second that criminals are
taking purses from little old ladies, otherwise.&lt;/p&gt;
&lt;p&gt;I get to stand in front of a room full of &lt;a href=&#34;http://www.ubhacking.com&#34;&gt;amazing college students&lt;/a&gt;
in a couple weeks and talk to them about our products. And when I introduce
myself and explain what I do, I have every intention of being honest:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I spend a whole lot of time trying to save you a few seconds.
And it is the best possible use of my time.”&lt;/p&gt;&lt;/blockquote&gt;
</description>
      <carvers:summary>Coders are Batman, &lt;a href=&#34;http://iron.io&#34;&gt;Iron.io&lt;/a&gt; is Alfred, and building your infrastructure is a pain in the ass. Also, work should be measured in how long it takes to kick ass.</carvers:summary>
    </item>
    
    <item>
      <title>Moving to Jekyll</title>
      <link>https://paddy.carvers.com/posts/moving-to-jekyll/</link>
      <pubDate>Thu, 23 Feb 2012 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/moving-to-jekyll/</guid>
      <description>&lt;p&gt;I’m considering moving my personal site over to &lt;a href=&#34;http://pages.github.com&#34;&gt;Github pages&lt;/a&gt; to be powered by &lt;a href=&#34;http://github.com/mojombo/jekyll/&#34;&gt;Jekyll&lt;/a&gt;. I like the capability to write my posts in &lt;a href=&#34;http://daringfireball.net/projects/markdown&#34;&gt;Markdown&lt;/a&gt; and the free, reliable hosting that Github provides. I like the flexibility of the templating engine. Most of the restrictions and limitations of Jekyll are things that I won’t miss, anyways.&lt;/p&gt;
&lt;p&gt;The fact that categories and tags aren’t as useful hurts. The insistence upon including dates in the filenames hurts. But Jekyll has so many features I like, I can’t see trading all of those for categories, posts, and filenames. I don’t know, it just seems like the pros far outweigh the cons.&lt;/p&gt;
&lt;p&gt;This does mean, of course, that I have to make my own template. That’s the primary point of this post: testing it. I’m not a designer, but hopefully I didn’t embarrass myself too badly with this attempt. I wanted something &lt;em&gt;green&lt;/em&gt;.&lt;/p&gt;
</description>
      <carvers:summary>Someone you probably know or care little about is using a new mass of ones and zeroes to inflict his opinions on the world.</carvers:summary>
    </item>
    
    <item>
      <title>The Fallacy of “Nimble”</title>
      <link>https://paddy.carvers.com/posts/the-fallacy-of-nimble/</link>
      <pubDate>Mon, 23 Jan 2012 20:21:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/the-fallacy-of-nimble/</guid>
      <description>&lt;p&gt;It’s one of my favourite perks of being a small (one programmer, one manager/business guy) tech company: we’re “nimble”. What does nimble mean? Nimble means when you have that niggling annoyance, I can fix it in front of your eyes. Nimble means that when we figure out our product is wrong and we need to pivot, we don’t throw too much away. Nimble means that the time between a decision getting made and palpable effects of that decision being visible to users is minimal, sometimes non-existent.&lt;/p&gt;
&lt;p&gt;Nimble is a waste of time.&lt;/p&gt;
&lt;p&gt;That’s really over-simplifying it, though. Nimble can be useful. Nimble is great when your idea is unproven, you’re unsure of your market, and you’re rushing to get a minimum viable product out the door. Nimble is &lt;em&gt;necessary&lt;/em&gt; and an &lt;em&gt;advantage&lt;/em&gt; in those situations.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.2cloudproject.com&#34; title=&#34;2cloud&#34;&gt;2cloud&lt;/a&gt; has been going strong for almost two years now. I validated its idea on accident and the market has proven itself over the last couple of years. It has been given great reviews by not one but &lt;em&gt;two&lt;/em&gt; of the most respected publications in the industry.&lt;/p&gt;
&lt;p&gt;And yet, we’re still nimble.&lt;/p&gt;
&lt;p&gt;That’s not something to be &lt;em&gt;proud&lt;/em&gt; of. That’s &lt;em&gt;us &lt;strong&gt;doing it wrong&lt;/strong&gt;&lt;/em&gt;. We’re not going to pivot. We know our product, we know our market. We’ve spoken to customers (&lt;em&gt;excessively&lt;/em&gt;). We need to focus on execution now, not whether or not we’re on to something. Being nimble is hurting us now, in subtle ways.&lt;/p&gt;
&lt;p&gt;Not having an automated deployment system.&lt;/p&gt;
&lt;p&gt;Not having enough test coverage.&lt;/p&gt;
&lt;p&gt;Not having enough processes and check-lists and double-checking and all those things that make nimble-advocates cry out in terror. Because those things exist for a reason.&lt;/p&gt;
&lt;p&gt;Nimble is great when you need to figure out what you’re doing, fast, and with as little expense as possible. But nimble leads to duplicated effort, mistakes, and, ironically, wasted time when you know your niche and just need to fill it.&lt;/p&gt;
&lt;p&gt;Time to be less nimble.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;It’s one of my favourite perks of being a small (one programmer, one manager/business guy) tech company: we’re “nimble”. What does nimble mean? Nimble means when you have that niggling annoyance, I can fix it in front of your eyes. Nimble means that when we figure out our product is wrong and we need to pivot, we don’t throw too much away. Nimble means that the time between a decision getting made and palpable effects of that decision being visible to users is minimal, sometimes non-existent.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>An Open Letter To Congress: SOPA Is A Good Start</title>
      <link>https://paddy.carvers.com/posts/an-open-letter-to-congress-sopa-is-a-good-start/</link>
      <pubDate>Sat, 17 Dec 2011 02:46:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/an-open-letter-to-congress-sopa-is-a-good-start/</guid>
      <description>&lt;p&gt;Dear Congress,&lt;/p&gt;
&lt;p&gt;Hey guys, how’ve you been? I know you probably don’t know me—I don’t have a whole lot of money to contribute to your campaigns, so you guys don’t have a lot of time for me. That’s understandable—you can’t get elected &lt;em&gt;and&lt;/em&gt; get to know the people you’re representing at the same time. You’re only human.&lt;/p&gt;
&lt;p&gt;I just wanted to whisper in your ear about this whole “SOPA” thing. I’ve been kind of following it, and I have to hand it to you guys: that’s some nice work. As a student, I produce a lot of writing—and I mean &lt;em&gt;a lot&lt;/em&gt;. Just today, I wrote eight thousand words. &lt;em&gt;Eight thousand&lt;/em&gt;. That’s eight thousand words of &lt;em&gt;copyrighted intellectual property&lt;/em&gt;. So I’m really psyched to see that you’re going to help me keep those words from being pirated online.&lt;/p&gt;
&lt;p&gt;But here’s the thing: I’m not sure you’re doing enough. I mean, most the people passing this bill aren’t too familiar with the internet. That should be a pretty big indicator that the internet is not popular enough to have a big impact on piracy. No, my concern is that people will just pirate my work in person. Like, for example: what if someone reads one of my essays to a friend? That friend just got my hard work, my insight, and my &lt;em&gt;intellectual property&lt;/em&gt;. For &lt;em&gt;free&lt;/em&gt;. That’s not fair—they should have to pay me for that!&lt;/p&gt;
&lt;p&gt;So here’s what I suggest—and I think you’ll agree it’s pretty reasonable: if someone quotes my intellectual property, in part or in whole, I can call the police. The police then have five days to track down that person and cut their tongue out, so they can’t &lt;em&gt;pirate&lt;/em&gt; my work anymore. If the police don’t respond in five days, they become &lt;em&gt;accessories to the crime&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now, I know what you’re thinking: but what if I accuse someone who didn’t actually pirate my work and get their tongue cut out just because I don’t like them? Well, I bet your first instinct is to say there needs to be a trial. I urge you to ignore that instinct—any delay will only embolden and strengthen the pirates. Instead, if I cut their tongue out and it turns out I was wrong, I should be obligated to buy them a parrot to talk for them. That will certainly keep me honest, I swear.&lt;/p&gt;
&lt;p&gt;Keep up the good work, guys. SOPA is a great start, I just think you need to carry the idea a bit further. Take the core premise, that the possible misuse of a right means that right should be stripped at the drop of a hat, and extend it to every facet of our lives. Remember, you are legislating children here, not adults—if there’s a possibility a tool will be misused to hurt a minority of us, the majority should only be allowed to use that tool at the discretion of the minority. The fact that the minority could misuse your legislation to hurt the majority is a small snag, but I’m sure we can figure that out later.&lt;/p&gt;
&lt;p&gt;Hugs,&lt;br&gt;
Paddy&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;Dear Congress,&lt;/p&gt;
&lt;p&gt;Hey guys, how’ve you been? I know you probably don’t know me—I don’t have a whole lot of money to contribute to your campaigns, so you guys don’t have a lot of time for me. That’s understandable—you can’t get elected &lt;em&gt;and&lt;/em&gt; get to know the people you’re representing at the same time. You’re only human.&lt;/p&gt;
&lt;p&gt;I just wanted to whisper in your ear about this whole “SOPA” thing. I’ve been kind of following it, and I have to hand it to you guys: that’s some nice work. As a student, I produce a lot of writing—and I mean &lt;em&gt;a lot&lt;/em&gt;. Just today, I wrote eight thousand words. &lt;em&gt;Eight thousand&lt;/em&gt;. That’s eight thousand words of &lt;em&gt;copyrighted intellectual property&lt;/em&gt;. So I’m really psyched to see that you’re going to help me keep those words from being pirated online.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Disillusioned</title>
      <link>https://paddy.carvers.com/posts/disillusioned/</link>
      <pubDate>Thu, 08 Sep 2011 20:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/disillusioned/</guid>
      <description>&lt;p&gt;I’ve been meaning to write a post about companies and users, and what I believe their relationship should be. &lt;a href=&#34;http://www.twitter.com/tinogalizio&#34;&gt;Tino&lt;/a&gt; and I have had some very good conversations about it, and he’s helped me to get a better grasp on my views on the matter. I don’t have a full handle on it yet, but I’m getting there. I’d really like to have done that post before I did this one, but it’s going to have to wait. Today pretty much broke my spirit.&lt;/p&gt;
&lt;p&gt;Before I go any further, I’m just expressing myself here. There are no decisions contained herein, I’m not announcing anything. These are just words to explain my feelings to you.&lt;/p&gt;
&lt;p&gt;I’ve always believed in free open source software. I think it’s how the world should work. I’ve always believed that if I give my best to people, they’ll give me a just reward of their own volition. So when &lt;a href=&#34;http://www.thepurdman.com&#34;&gt;Kevin&lt;/a&gt; covered 2cloud (then android2cloud) for Lifehacker and we got thousands of users overnight, a lot of people called me crazy for not trying to make a quick buck off it by charging people a dollar per download. People still tell me I’m crazy. How can you have an app with over 50,000 downloads and still be $500 in the red? That makes no sense. And yet, that’s where 2cloud stands.&lt;/p&gt;
&lt;p&gt;When 2cloud became popular, I &lt;a href=&#34;http://www.secondbit.org&#34;&gt;formed an LLC&lt;/a&gt; formed an LLC with my friend, Tino. Tino invested startup costs for the venture. The point wasn’t really to start a company to make money or become rich; really, I just wanted to cover my ass in case someone decided it would be fun to sue me over the app. Tino and I, obviously, hoped to recoup the money we put into the venture, but that was about as far ahead as we thought. We took a contract with a startup here in Buffalo, and it paid off the startup costs and then some. We were incredibly fortunate on that front. But we’re still nowhere near paying ourselves back; our company bank account sits at a depressing (not dangerous, just depressing) level and the main project our value-generating efforts are going into is still in the red.&lt;/p&gt;
&lt;p&gt;Every day, I get to look at or talk to Tino and know I’m failing him. I get to try to defend free open source software, even as it fails spectacularly in front of me. I talk about value and reward, trust and relationships, mutual benefit. I talk about how our users are on our side and we’re all fighting for the same thing. Because we are, right? You want to use useful software that makes your life easier. I want to create things that makes life easier. It seems like a good fit, no?&lt;/p&gt;
&lt;p&gt;We’re still in the red. We set up a quota system, something that I took considerable emotional pain in doing. I knew it meant some users would be locked out of using the service for a limited amount of time. That hurt me and went against everything I believed in, but the alternative was to shut the server down. To simply let the project go. That would’ve hurt more, so I took the lesser of two evils. Users complained about it, and that hurt even worse. I work hard on this project and it costs money to run. The fact that someone would assume I was just trying to make a quick buck, after I struggled for a year to keep the application free and unfettered for everyone, wounded me deeply. Switching the server over cut costs by a lot, as some users still haven’t switched over, and people are still donating sometimes. I think we’re actually in the green, for the last month or so. But it’s a negligible amount of green; I make about that much in two hours of work at my minimum-wage job. At this rate, the project will be two years old before it stops being a money-sink. That’s assuming donations keep coming and the server costs stay low (which they won’t). We turned the quota on yesterday, switched it off the unreasonably high level it was at previously. The app went over quota around 9pm EST; I tested, and everything worked smoothly with the payments system. Nobody paid. We talked about it, Tino and I, and thought maybe it was because it switched on for just 6 hours. I lowered the quota a bit more, and today it kicked in around 4pm, EST. In the 4 hours since then, our income has remained steady at the $0 mark. Maybe nobody’s using the app? 200 users were active today. Since the quota kicked in, over 100 links have been sent. People are using the app, they’re just not paying for it.&lt;/p&gt;
&lt;p&gt;People are &lt;a href=&#34;http://help.2cloudproject.com/discussions/suggestions/5-firefox#comment_9834757&#34;&gt;still looking for more work to be done&lt;/a&gt;, for free. People are still emailing me bug reports. I’m still issuing updates. I’m still the only one who has contributed code to the project. People just don’t seem to think that’s worth anything. And if it’s not worth anything, why am I working so hard at it? That doesn’t make much sense.&lt;/p&gt;
&lt;p&gt;This is not a bitch-and-moan-fest about how a project is in the red. That’s the nature of investment, that’s the nature of trust: sometimes it blows up in your face. Sometimes it doesn’t pan out. I made decisions on how to spend my money, and nobody forced me to do anything. The same is true of Tino. And really, we’re blessed with a large number of people who &lt;em&gt;did&lt;/em&gt; donate and who &lt;em&gt;did&lt;/em&gt; support the project. And that’s wonderful. I’m not posting this so people will feel guilty and go donate money or buy their way around the quota. That’s not the system I want; I shouldn’t &lt;em&gt;have&lt;/em&gt; to guilt people. People who donate mean a lot to me because they did it of their own free will, and their money means so much more when that’s the case. So if you’re reading this post and feeling bad and thinking you should contribute, I’d much rather you answer a simple question: why did it take this post to get you to feel that way?&lt;/p&gt;
&lt;p&gt;Really, my lamentation is about the world I live in. Because I’m starting to lose faith that if I do the right thing and create value and make something people want, they’ll do the right thing and help support it &lt;em&gt;voluntarily&lt;/em&gt;. I’m starting to change my default stance; it’s a very good possibility that all the software I release in the future will be open source, but if you want to get it from me or use my server, you &lt;em&gt;have&lt;/em&gt; to pay. It’s a very good possibility that I’ll stop trusting my users to do the right thing and turn software from a partnership into a transaction. And that breaks my heart.&lt;/p&gt;
&lt;p&gt;As I said at the beginning, this is all personal reflection and expression. 2cloud isn’t changing. I’m not going to start charging for it. I made that promise, and I’m standing by it. If push comes to shove, though, it’ll be a lot harder for me to justify working on it more or paying to keep the server online. This is the community’s project, not just mine. The community is speaking, and it doesn’t offer a lot of hope for the future. There may be a time where I drop the project. There may be a time where the public server exists only within the free quotas App Engine provides. Only time will tell. But I can’t look at the future with the optimism and assurance that everything will work out fine anymore.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I’ve been meaning to write a post about companies and users, and what I believe their relationship should be. &lt;a href=&#34;http://www.twitter.com/tinogalizio&#34;&gt;Tino&lt;/a&gt; and I have had some very good conversations about it, and he’s helped me to get a better grasp on my views on the matter. I don’t have a full handle on it yet, but I’m getting there. I’d really like to have done that post before I did this one, but it’s going to have to wait. Today pretty much broke my spirit.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>On App Engine’s Pricing Change</title>
      <link>https://paddy.carvers.com/posts/on-app-engines-pricing-change/</link>
      <pubDate>Sat, 03 Sep 2011 04:55:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/on-app-engines-pricing-change/</guid>
      <description>&lt;p&gt;By now, most of you running &lt;a href=&#34;http://appengine.google.com&#34; title=&#34;Google App Engine&#34;&gt;App Engine&lt;/a&gt; applications have received the dreaded email: App Engine is leaving beta. Normally, that’d be a great thing. But as they announced at I/O, that means the pricing structure is changing, because now they need to actually pay for their operation; in other words, they can’t keep operating at a loss. So the pricing structure was simplified a bit, and prices were hiked.&lt;/p&gt;
&lt;p&gt;For &lt;a href=&#34;http://www.2cloudproject.com&#34;&gt;2cloud&lt;/a&gt;, this is &lt;em&gt;terrible&lt;/em&gt; news. We were having trouble operating under the old pricing structure; making ends meet under the new pricing structure is going to be difficult. Our &lt;a href=&#34;http://blog.android2cloud.org/2011/08/about-quota.html&#34; title=&#34;About the Quota on the 2cloud Blog&#34;&gt;new quota system&lt;/a&gt; is hopefully going to help make it happen. We’ll see.&lt;/p&gt;
&lt;p&gt;I’m a little disappointed with the change; not because Google’s charging us more, not because we have even more pressure on us to get our app to pay for itself; those I understand. It is not Google’s job to pay for my app, and it is not Google’s fault that I haven’t been able to come up with a monetisation plan. Google is not a charity, they are a company. The fact that they’ve given us this long to figure it out is a &lt;em&gt;gift&lt;/em&gt; and a &lt;em&gt;blessing&lt;/em&gt;, not a license to demand more time from them. My disappointment, instead, is rooted in the “one pricing scheme to rule them all” approach. I understand its goals—make the pricing scheme more predictable and less confusing—but I don’t think it fits well. Our app spent most of its free CPU quota on creating &lt;a href=&#34;http://code.google.com/appengine/docs/python/channels/&#34; title=&#34;Channel API&#34;&gt;channels&lt;/a&gt;; now that Channels are split out from the CPU in terms of the quota, we’ll have a bunch of unused CPU and pay even more for Channels than we already would have. I would’ve liked to see a bit more flexibility in the pricing scheme than is currently offered.&lt;/p&gt;
&lt;p&gt;In the end, though, App Engine is still fantastic. And even as we look at whether another hosting provider would provide a better experience for our users, I feel nothing but fondness and loyalty to App Engine. If we do end up developing another set of server software for &lt;a href=&#34;http://aws.amazon.com&#34; title=&#34;Amazon Web Services&#34;&gt;AWS&lt;/a&gt; or a similar service, I’d like to keep our App Engine code running in parallel. It still remains the best service to quickly and easily start a project on.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;By now, most of you running &lt;a href=&#34;http://appengine.google.com&#34; title=&#34;Google App Engine&#34;&gt;App Engine&lt;/a&gt; applications have received the dreaded email: App Engine is leaving beta. Normally, that’d be a great thing. But as they announced at I/O, that means the pricing structure is changing, because now they need to actually pay for their operation; in other words, they can’t keep operating at a loss. So the pricing structure was simplified a bit, and prices were hiked.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>College &amp; Startups</title>
      <link>https://paddy.carvers.com/posts/college-and-startups/</link>
      <pubDate>Mon, 22 Aug 2011 00:00:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/college-and-startups/</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclaimer: I tend to write posts for this blog, maybe sleep on them (at most), then publish them. Very rarely do I edit or ask for feedback. However, this is a topic that I feel strongly about and wanted to speak intelligently on, so I asked for feedback during its drafting process. &lt;a href=&#34;http://www.twitter.com/ahmedalsudani&#34; title=&#34;Ahmed Al-Sudani on Twitter&#34;&gt;Ahmed Al-Sudani&lt;/a&gt;, &lt;a href=&#34;http://www.thepurdman.com&#34; title=&#34;Kevin Purdy&#34;&gt;Kevin Purdy&lt;/a&gt;, &lt;a href=&#34;http://www.matthewturland.com&#34; title=&#34;Matthew Turland&#34;&gt;Matt Turland&lt;/a&gt;, &lt;a href=&#34;https://github.com/RyanMacG&#34; title=&#34;Ryan MacGillivray on Github&#34;&gt;Ryan MacGillivray&lt;/a&gt;, and &lt;a href=&#34;http://www.twitter.com/tinogalizio&#34; title=&#34;Tino Galizio on Twitter&#34;&gt;Tino Galizio&lt;/a&gt; were all instrumental in getting this post written. I owe them a debt of gratitude for working with me through multiple drafts to come up with the post you’re reading now. It’s still not perfect, and never will be, but they gave me a safe environment to learn from my initial failures.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I might not be the most qualified person to write this; I’ve never run or worked at a startup and I refuse to take my expected role in college. But it seems like nobody is saying this, and I felt it needed to be said. So my unworthy voice is going to have to suffice.&lt;/p&gt;
&lt;p&gt;You’re working crazy hours of the night. You’re broke, collecting massive debt, and all you’re getting in return is the &lt;em&gt;chance&lt;/em&gt; that your investment may lead to a better life. You seek the wisdom and guidance of mentors. A small group of people can decide your future with their whims.&lt;/p&gt;
&lt;p&gt;To two groups of people, this sounds agonisingly familiar: startup founders and students. There has been a lot of hype recently about how degrees are over-rated and students should drop out and start a company, but little has been said about how similar the lifestyles are. How seemingly insane both lifestyles are. But one is widely recognised as an expectation for the teenagers leaving high school, and I have to wonder if it’s the wrong one.&lt;/p&gt;
&lt;p&gt;First, let’s take a look at the two concepts we’re dealing with here, to avoid any confusion.&lt;/p&gt;
&lt;p&gt;Startups are, I believe, one of the most interesting jobs a person can ever hold. Startups have a culture that makes learning not only possible, but unavoidable. It’s an almost Darwinian system; the best survive, those that aren’t up to the challenge die off. I love that, because it &lt;em&gt;requires engagement&lt;/em&gt;. You can’t just punch a clock at a startup; if you aren’t entirely consumed by what you’re doing, you’re not going to be doing it for long. Odds are you probably wouldn’t be doing it in the first place. This is the side-effect of the interesting nature of startups; a startup surpasses a job, becoming more of a lifestyle and a mindset. It technically is any company that is trying to deliver a new product or service and is living in a great deal of uncertainty. For our purposes, and in its most common usage, it is related to technology. Just as we’ll be talking about the institution of college as a whole, rather than a specific college, we’re going to look at the culture and ideologies of startups (gleaned from things like &lt;a href=&#34;http://www.techcrunch.com/&#34; title=&#34;TechCrunch&#34;&gt;TechCrunch&lt;/a&gt;, &lt;a href=&#34;http://news.ycombinator.com/&#34; title=&#34;Hacker News&#34;&gt;Hacker News&lt;/a&gt;, and &lt;a href=&#34;http://www.paulgraham.com/articles.html&#34; title=&#34;Paul Graham’s Essays&#34;&gt;Paul Graham&lt;/a&gt;, amongst other sources), rather than a single startup.&lt;/p&gt;
&lt;p&gt;College is more difficult to explain, because it exists in what’s almost a split personality. There’s what college is &lt;em&gt;supposed&lt;/em&gt; to be and what college &lt;em&gt;is&lt;/em&gt;. College is &lt;em&gt;supposed&lt;/em&gt; to be a safe environment for teenagers to grow into adults. It’s supposed to be the final transition between being prepared for the real world and actually living in the real world. In practice, it is an accreditation system; it’s a way of saying “I can verify this person knows this information”.&lt;/p&gt;
&lt;p&gt;There’s one final concept I want to hammer out before moving on: growth. I believe, firmly, that the best way to grow is to fail. To fall flat on your face. Why? Because if you aren’t falling on your face, you’re not learning anything—you already know everything you’re working with. &lt;em&gt;It’s impossible to grow without failing&lt;/em&gt;. Remember when I said that college is supposed to be a safe environment in which teenagers grow into adults? That means it’s supposed to be a safe environment in which teenagers &lt;em&gt;can fail&lt;/em&gt;. Even if you’re simply watching people smarter and more experienced than you do their thing, you’re realising how much you don’t know, and that’s still a (more gentle) kind of failure.&lt;/p&gt;
&lt;p&gt;Now that we’ve got that conceptual work out of the way, let’s move on to &lt;em&gt;the point&lt;/em&gt;. Startups are a bigger risk than pursuing the same sort of project in college; in a startup, failure can mean you don’t eat. Unlike college, startups aren’t the expected path for today’s youth; when you tell someone you’re an entrepreneur, chances are they hear “unemployed”. So, if we have an environment where risks have very little consequence and where there are a lot of people, why is it producing nowhere near as much innovative thinking as the environment where risks carry the highest consequences and where there are relatively few people? That seems counter-intuitive, and yet it’s how the system currently works. Why? The answer lies in the split nature of college.&lt;/p&gt;
&lt;p&gt;The environment I described with lots of people and little consequence is college &lt;em&gt;as it should be&lt;/em&gt;. The truth is that startups are closer to that role than college is in reality. Some colleges (MIT, Yale, Harvard, etc.) seem to be closer than others (mine, for example), but the reality of the situation is that the students in colleges aren’t given much opportunity to experiment, to try new and daring things. In short, they’re not given much of an opportunity to take part in those consequence-free risks I spoke of. Instead, that type of research is reserved for the professors. Professors have a low-risk environment in which to conduct research. While students get to help them, that’s not quite the same thing, is it? The student doesn’t have the same investment, the same engagement in their professors’ problems as they would in their own problems.&lt;/p&gt;
&lt;p&gt;And that’s the crux of it. That’s the problem. College exists in the paradigm of measuring knowledge; it measures knowledge to verify that the student has it. But for that knowledge to be measurable, it has to be known. It means the student can’t be the pioneer in the field, because there’s no way to measure that. It means the student is always relegated to walking in the footsteps of another, so the college has a known quantity to measure the student against. In return for those metrics, that ability to measure its students, college has lost the most valuable asset of startups: the competition. In college, you know something or you don’t. There isn’t a constant push to be better. There is no concept of better.&lt;/p&gt;
&lt;p&gt;This concept of better is one of the three things startups have that college sorely needs. The second is interest. While it’s true that those not engaged in their startup won’t have a startup for long, this confuses the effect for the cause. The truth of the matter is that those who would not be engaged in their startup never start one in the first place; passion is what drives the exploration that startups do. College, however, has taken that exploration and handed it to the adults. Professors, not students, lead most the research done in colleges now. The professors’ passions, not the students’, are the ones being explored and engaged. Consequently, the professors are the ones engaged, not the students.&lt;/p&gt;
&lt;p&gt;The final concept that college needs to appropriate from startups is the concept of &lt;em&gt;action&lt;/em&gt;. College measures what a student &lt;em&gt;knows&lt;/em&gt;, not what a student &lt;em&gt;does&lt;/em&gt;. In startups, the importance is reversed; what you do matters, what you know is immaterial. And really, the reasoning of startups is more logical: when I die, what I know dies with me. Only the things I’ve done can contribute back to society.&lt;/p&gt;
&lt;p&gt;Without these three concepts, college isn’t engaging. Students show up to class, check off their course lists, and graduate without &lt;em&gt;really&lt;/em&gt; learning anything. So we have things like Peter Thiel’s &lt;a href=&#34;http://www.thielfoundation.org/index.php?option=com_content&amp;amp;id=14:the-thiel-fellowship-20-under-20&amp;amp;catid=1&amp;amp;Itemid=16&#34; title=&#34;The Thiel Fellowship 20 Under 20&#34;&gt;20 under 20&lt;/a&gt;. We have a society that is &lt;a href=&#34;http://www.businessinsider.com/is-college-worth-it-2011-5&#34; title=&#34;Is College Worth It? on Business Insider&#34;&gt;rapidly losing faith in college&lt;/a&gt; at the same time the cost of attending a college is skyrocketing.&lt;/p&gt;
&lt;p&gt;College needs to take a good hard look at startups and think for a bit about how it can offer its students more opportunities to fail. I’ve written a fairly successful &lt;a href=&#34;http://www.2cloudproject.com/&#34; title=&#34;2cloud, which I plug at every opportunity because it is one of the few things I’ve ever really accomplished so I feel the need to beat it like a dead horse.&#34;&gt;application&lt;/a&gt; that has been covered by several large tech publications, has over ten thousand users, and is part of a rapidly evolving ecosystem. I am, purely by luck, in an amazing position to learn at a rapid pace. The fact that college is unequipped to and disinterested in taking advantage of this situation is nothing short of a criminal misuse of potential.&lt;/p&gt;
</description>
      <carvers:summary>College students and startup founders lead very similar lives and have oddly similar goals. Our youth, fresh out of high school, are being encouraged to pursue one of these lifestyles, however, and I have to wonder whether it is the right one.</carvers:summary>
    </item>
    
    <item>
      <title>Tips and Secrets for Dealing With App Engine</title>
      <link>https://paddy.carvers.com/posts/tips-and-secrets-for-dealing-with-app-engine/</link>
      <pubDate>Sun, 31 Jul 2011 02:58:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/tips-and-secrets-for-dealing-with-app-engine/</guid>
      <description>&lt;p&gt;Google’s &lt;a href=&#34;http://appengine.google.com&#34; title=&#34;Google App Engine&#34;&gt;App Engine&lt;/a&gt; is a wonderful, amazing, and revolutionary service. A free, managed hosting experience in which you can build scalable applications. That is &lt;em&gt;huge&lt;/em&gt;. I can honestly say I would not know half the things I know or have half the relationships I have with the tech world, were it not for this program. It makes writing server-side software simple; it allows you to only know about writing the software, and not having to worry about system level vulnerabilities, system load, or scaling headaches. I don’t have to think about things like iptables, SSH permission levels, or other ways nasty people who are better sysadmins than I am can get into my application. I don’t have to worry about hard drive failures at 3 in the morning. Rather, it just asks me to be a programmer.&lt;/p&gt;
&lt;p&gt;That divorce between programming and systems administration comes with some costs, though. The most commonly touted one is the lack of control over the system: if I want to run node.js or Redis, I’m out of luck. But there are other, deeper costs as well, things that aren’t intuitive to the average user. Things that don’t come to mind when you think about the shortcomings of App Engine. And really, they all come down to one thing: &lt;em&gt;if what you want to know isn’t documented, you probably are out of luck&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&#34;date-and-time&#34;&gt;Date and Time&lt;/h2&gt;
&lt;p&gt;The handling of date and time on App Engine is inconsistent, and it caused me quite the headache. See, the datastore is written in UTC time, but a &amp;ldquo;day&amp;rdquo;, in App Engine terms, is determined by Pacific time. Your quota, for example, resets at midnight &lt;em&gt;Pacific time&lt;/em&gt;. Meanwhile, the datastore holds values that are from &lt;em&gt;UTC time&lt;/em&gt;, which means seven hours in the future (according to the quota). Furthermore, the &amp;ldquo;system time&amp;rdquo; (what you get if you call datetime.now()) on App Engine is in &lt;em&gt;UTC&lt;/em&gt;. The only way to get the values you’re writing to the datastore, the values datetime.now() are returning, and the datetime that the quota is based on all in sync is to translate the values to Pacific time, strip the timezone information from them (lest the datastore see it, take it into account, and attempt to correct for it), and then write to the datastore. Then everything will be in sync.&lt;/p&gt;
&lt;p&gt;That is all documented, or at least relatively easy to figure out. You can even see it in practice at &lt;a href=&#34;http://timezones.appspot.com&#34; title=&#34;Time zones in Google App Engine&#34;&gt;http://timezones.appspot.com&lt;/a&gt;. But I had to implement a soft quota over Google’s quota, so I needed to know exactly what quota day I was on, and had to keep the two in sync. And that meant one big question that was not in any documentation and that would take me quite some time to figure out: &lt;a href=&#34;http://stackoverflow.com/q/6607979/177467&#34; title=&#34;Question on StackOverflow&#34;&gt;does the App Engine quota take DST into effect?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fortunately, &lt;a href=&#34;http://profiles.google.com/moishel&#34; title=&#34;Moishe Lettvin’s Google Profile&#34;&gt;Moishe Lettvin&lt;/a&gt;, an App Engine employee, has been kind enough to keep in touch with me after I took part in the &lt;a href=&#34;http://code.google.com/appengine/docs/python/channel&#34; title=&#34;Channel API on Google Code&#34;&gt;Channel API&lt;/a&gt; trusted testers session. He &lt;a href=&#34;http://stackoverflow.com/questions/6607979/does-app-engines-quota-take-dst-into-effect/6611970#6611970&#34; title=&#34;Moishe’s answer on StackOverflow&#34;&gt;checked the source code and got back to me&lt;/a&gt;. I don’t know how I would have handled the situation had he not responded; it would have taken me months to find out on my own. For those who are curious, yes, App Engine’s quota takes DST into account.&lt;/p&gt;
&lt;h2 id=&#34;oauth&#34;&gt;OAuth&lt;/h2&gt;
&lt;p&gt;I have a love/hate relationship with App Engine’s built-in OAuth provider. I love it because it’s a built-in, out-of-the-box, &lt;em&gt;free&lt;/em&gt; way to authenticate against someone’s Google account. I hate it because if something goes wrong (it’s listed as an experimental API, and things do go wrong) or if something isn’t working as I expect (it differs from the main OAuth API in a couple crucial areas; mainly it seems to lag. It still uses 1.0a and &lt;em&gt;will not&lt;/em&gt; accept &lt;code&gt;xoauth_displayname&lt;/code&gt;), I have no real recourse. Beyond not being able to tell why getting a request token threw an error for 38 requests in the last 24 hours, besides undocumented differences between it and Google’s &lt;a href=&#34;http://code.google.com/apis/accounts/docs/OAuth_ref.html&#34; title=&#34;OAuth 1.0 documentation on Google Code&#34;&gt;regular OAuth offering&lt;/a&gt; (not even their 2.0 offering, which is now available in experimental status), my biggest gripe has to be one I discovered just recently: it will not allow a non-http, non-https callback URL. If the URL you are redirecting to uses a different protocol, it will error out. While this seems like a silly gripe, it’s actually &lt;a href=&#34;http://donpark.org/blog/2009/01/24/android-client-side-oauth&#34; title=&#34;Don Park explains Android Client-side OAuth&#34;&gt;pretty important&lt;/a&gt; for Android developers who rely on callbacks to app-specific protocols to allow the OAuth flow to remain secure and user-friendly.&lt;/p&gt;
&lt;p&gt;Those are the biggest gripes I have with App Engine &lt;em&gt;for now&lt;/em&gt;. I’m sure more undocumented things I need to know will show up as I continue to learn more and more about the environment. I’m sure I’ll be stymied in other places. But I reiterate the point I opened with: App Engine remains a wonderful, powerful tool that makes my development possible. These gripes don’t come close to overshadowing the cause of them: the removal of the system from my list of “things I need to concern myself with” in most cases. Really, these gripes are created by the edge cases in which I &lt;em&gt;do&lt;/em&gt; need to concern myself with the system.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;Google’s &lt;a href=&#34;http://appengine.google.com&#34; title=&#34;Google App Engine&#34;&gt;App Engine&lt;/a&gt; is a wonderful, amazing, and revolutionary service. A free, managed hosting experience in which you can build scalable applications. That is &lt;em&gt;huge&lt;/em&gt;. I can honestly say I would not know half the things I know or have half the relationships I have with the tech world, were it not for this program. It makes writing server-side software simple; it allows you to only know about writing the software, and not having to worry about system level vulnerabilities, system load, or scaling headaches. I don’t have to think about things like iptables, SSH permission levels, or other ways nasty people who are better sysadmins than I am can get into my application. I don’t have to worry about hard drive failures at 3 in the morning. Rather, it just asks me to be a programmer.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>The Problem With Tangential Learning</title>
      <link>https://paddy.carvers.com/posts/the-problem-with-tangential-learning/</link>
      <pubDate>Fri, 22 Jul 2011 03:21:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/the-problem-with-tangential-learning/</guid>
      <description>&lt;p&gt;Last Thursday, my roommate turned 21. For her birthday, I baked her a batch of brownies. As college students, we don’t have the world’s greatest kitchen for baking (she &lt;em&gt;told&lt;/em&gt; me she had everything! Steph, if you’re reading this, your lies haunt my soul), so I had to make do with a less-than-ideal dish. It was too small in surface area, so the brownies ended up nice and thick. Which would totally be cool, if it didn’t make baking them such a challenge. I was kept on my toes trying to keep the outer edges from burning while cooking the entire middle so we didn’t end up with spots of raw brownies. In the end, it was a middling success (but, fortunately, it being her 21st birthday, I think she was too drunk to care).&lt;/p&gt;
&lt;p&gt;This is a horribly transparent metaphor for the topic I want to discuss. Thanks in no small part to my &lt;a href=&#34;http://www.secondbit.org/team/tino&#34; title=&#34;Tino Galizio&#34;&gt;business partner&lt;/a&gt; (if we’re going to be entirely accurate, it’s &lt;em&gt;all his fault&lt;/em&gt;), I’ve become more or less addicted to &lt;a href=&#34;http://www.escapistmagazine.com/videos/view/extra-credits%22&#34; title=&#34;Extra Credits on The Escapist&#34;&gt;Extra Credits&lt;/a&gt;, a video series on &lt;a href=&#34;http://www.escapistmagazine.com&#34; title=&#34;The Escapist&#34;&gt;The Escapist&lt;/a&gt;. Extra Credits is what I would call an English major’s take on video games, but I’m really giving too much credit to English majors with that. It’s actually just video games and the video game industry being examined with critical thinking skills and the built-in assumption that video games are an art-form that are deserving of deep thought—an assumption I don’t disagree with.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;http://www.escapistmagazine.com/videos/view/extra-credits/2957-Tangential-Learning&#34; title=&#34;Tangential Learning episode of Extra Credits&#34;&gt;one episode&lt;/a&gt;, however, I must disagree with them. Sort of. In their “Tangential Learning” episode, they tout the virtues of (spoilers) tangential learning and espouse the belief that this is the best way for video games to become educational without becoming boring. I think this is folly.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong, I think tangential learning is great. It takes a proposition that I hold most dear (that students learn best when they’re interested) and puts it into practice. It shows educators that the trick is not getting students interested in what you want to teach them, the trick is helping them learn what they’re interested in. And that’s wonderful. Great. Leaps and bounds above the current “I will force-feed you information and hope you remember it” model.&lt;/p&gt;
&lt;p&gt;But we’re only fooling ourselves if we think it’s a silver bullet or even a bronze bullet. The vast majority of our learning &lt;em&gt;cannot be done this way&lt;/em&gt;. If every game implemented this, or even most games, it would enrich our educational experience from video games, yes. But that is a far cry from saying it would make video games educational.&lt;/p&gt;
&lt;p&gt;In the video, they mention the sephiroth and how Final Fantasy introduced that concept to thousands of people by naming a character after it. At the end, they said that if you didn’t know what a sephiroth was and were going to go look it up, you knew that tangential learning worked. And I didn’t know what it was, and I did go look it up. But that didn’t prove to me that tangential learning worked. That proved to me that tangential learning gave us &lt;em&gt;trivia&lt;/em&gt;. I knew what a sephiroth was, but I had no context for that information. My context was the game. In literary theory, we talk about how the original context a fact is learned in shapes the fact—I will always associate &lt;a href=&#34;http://en.wikipedia.org/wiki/The_Treachery_of_Images&#34; title=&#34;The Treachery of Images on Wikipedia&#34;&gt;the Treachery of Images&lt;/a&gt; with Foucault and semiotics, because that’s how I learned about it. I never learned about it as a visual art piece; I learned about it as a literary concept. Likewise, I’ll never associate a sephiroth with its cultural and religious context, but instead with its gaming context.&lt;/p&gt;
&lt;p&gt;The problem is, there is a lot to learn, a lot to be known. Kind of like those brownies I baked: the topic matter is deep, in that you can follow a single idea or topic for quite some time and discover a lot about it; broad, in that there are &lt;em&gt;a lot&lt;/em&gt; of topics you can pursue; and (this is the important one) &lt;em&gt;inter-connected&lt;/em&gt;, in that ideas give context to each other. Much like the heat had to penetrate from the outside edges of my brownies all the way in or there’d be raw areas, our education needs to cover a certain amount of broad topics, cover them deeply enough to make sure we grasp the nuances, and cover them in such a cross-disciplinary way that we can put them in the appropriate context in our mental picture of the world. Tangential learning doesn’t give us that. Tangential learning is much like a scavenger hunt; you’re given an interesting item, you go and retrieve it, but it isn’t the item that’s important—the retrieval is the important part.&lt;/p&gt;
&lt;p&gt;I humbly submit that we need more than that in education. We need to have context and meaning for the trivia we’re learning, or all we’re really doing is making ourselves better Jeopardy players, not more rounded and educated individuals. Tangential learning is great in theory, but it falls short in practice. It’s not, to use the educational theory background I paid so much for, theoretically sound. It ignores the instructional scaffolding theory set forth by Bruner, a theory that is generally accepted by the educational community. Knowledge is like a building; you lay the foundations, set up a &lt;em&gt;scaffolding&lt;/em&gt; (I bet you see where the name comes from!), and build a lasting structure bit by bit, one piece on top of another. This is not what tangential learning is doing; tangential learning is throwing a shack up rather quickly. Yes, it will keep you dry in the short run, but it’s not going to last long. And it’s certainly not something you boast about, something that makes you a better person. The results are quick, but fragile and ultimately useless.&lt;/p&gt;
&lt;p&gt;So, if tangential learning is right in theory but wrong in practice, how do we fix that? Much like Extra Credits, I believe games are one of the best positioned mediums for learning. Games are an inherently interactive medium, and (as tangential learning proponents have noticed) learning is (or at least, has become) an interactive process. There’s a lot of talk that in our parents’ generation, we learned through broadcast. Someone would tell us something, and we’d know it, and that was learning. I find that hard to believe. I find it hard to believe that being told something can ever constitute &lt;em&gt;learning&lt;/em&gt; it—I think the correct word is &lt;em&gt;believing&lt;/em&gt; it, which is a very different thing. Just look at the war between science and religion, and you’ll see the gulf between belief and knowledge. They’re antithetical. But I digress. Whether our parents’ generation was interactively learning or not, our generation is. And our children’s generation will almost certainly continue the trend. The fact that games have that interactivity in their DNA already puts them in a far better position than, say, television. Or books.&lt;/p&gt;
&lt;p&gt;The trick is going to be using that interactivity to kickstart a learning &lt;em&gt;process&lt;/em&gt;, not simply giving us allusions. Allusions are helpful, yes. They help to expose us to new areas we may not have explored before. But we cannot have an education based solely on allusion; we need structural support, a contextual mindmap to assimilate those allusions into. Rather than simply suggesting the player look up a sephiroth for a bit of trivia, the game should reward the player for &lt;em&gt;understanding&lt;/em&gt; the sephiroth. Things should be easier. Or there should be more depth to the game for that player, more things to do. I agree with Extra Credits, however; the player should not need to understand a sephiroth to move forward in a game. One of the things that tangential learning gets right (and one of the things that terrifies traditional educators) is the surrender of this absurd notion of “curriculum”—the idea that there is a prescribed set of things that students should learn. Interest drives learning, and not everyone is interested in the same things. That’s why the interactivity of games is an important feature; players shape the game just as much as games shape the players. It’s a two-way relationship, instead of a broadcast. And in that two-way relationship, there’s no room for one party to have control. One party can’t be dictating to the other party; the relationship (like all relationships) will only work with communication and cooperation. Games need to &lt;em&gt;offer&lt;/em&gt; their players this deeper meaning, need to &lt;em&gt;offer&lt;/em&gt; a richer experience for those who are interested in learning about the topic, but not require that richer experience in case the player &lt;em&gt;isn’t&lt;/em&gt; interested. Because as soon as you start requiring players to do things they aren’t interested in, things they don’t care about, you start losing those players.&lt;/p&gt;
&lt;p&gt;I can’t see tangential learning or this interactive, cooperative educational system catching on anytime soon. Our education system is too mired in the idea that there needs to be a “standardised student” and that education needs to be heavily controlled and regulated. I hope, one day, our government and our educators will see that the more room you give a student to maneuver, the more room you’re giving them to grow. I hope one day we’ll see games replace textbooks, rewarding us for learning what we’re interested in but not punishing us for having no interest in a topic.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;Last Thursday, my roommate turned 21. For her birthday, I baked her a batch of brownies. As college students, we don’t have the world’s greatest kitchen for baking (she &lt;em&gt;told&lt;/em&gt; me she had everything! Steph, if you’re reading this, your lies haunt my soul), so I had to make do with a less-than-ideal dish. It was too small in surface area, so the brownies ended up nice and thick. Which would totally be cool, if it didn’t make baking them such a challenge. I was kept on my toes trying to keep the outer edges from burning while cooking the entire middle so we didn’t end up with spots of raw brownies. In the end, it was a middling success (but, fortunately, it being her 21st birthday, I think she was too drunk to care).&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Professionally Yours</title>
      <link>https://paddy.carvers.com/posts/professionally-yours/</link>
      <pubDate>Wed, 20 Jul 2011 23:02:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/professionally-yours/</guid>
      <description>&lt;p&gt;We’ve been running a &lt;a href=&#34;https://spreadsheets.google.com/spreadsheet/viewform?hl=en_US&amp;amp;formkey=dFV5bXBDMzk2OTFVNFRsX0RYLXRKYWc6MQ#gid=0&#34; title=&#34;2cloud Feedback Survey on Google Docs&#34;&gt;feedback survey for 2cloud&lt;/a&gt; for a couple of weeks now, trying to get a sense of how we’re doing with the project. We’ve gotten some great responses (if they’re not from you, please go ahead and take two minutes to fill out the form. We are leaving it open indefinitely), but one response we got bothered me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Bottom line you’re sounding juvenile, when you want professional.”&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;At what point did the person responding to that get the horribly inaccurate impression that we want to sound professional? We do not want to sound professional. We want to stay away from professional.&lt;/p&gt;
&lt;p&gt;Let me start this explanation out by making a distinction. A professional person is responsible. A responsible person is not necessarily professional. The two go hand-in-hand, yes, but you can be responsible without being professional. That’s what our project aims to do.&lt;/p&gt;
&lt;p&gt;Professional is not what we want for a very good reason: professional is intimidating. Professional exists to create a barrier between two entities. There’s a reason it’s called “personable” and not “professionable”. We want to be a personable project. We want to interact with our users, we want them to be in constant contact and feedback with us. We think this connection is a strength, not a weakness. So we do not want the barriers of professionalism raised between us and our users; we want to tear down as many barriers as possible.&lt;/p&gt;
&lt;p&gt;A professional project does not send hand-written thank you notes from its lead to people who donate. A professional project does not engage in lengthy back-and-forth emails with its users. A professional project does not have its users on Instant Messengers and social networks.&lt;/p&gt;
&lt;p&gt;We do. And if I have anything to say about it, we always will. Because I am not a professional, I am &lt;a href=&#34;http://www.etymonline.com/index.php?term=amateur&#34; title=&#34;Etymology of amateur&#34;&gt;an amateur&lt;/a&gt;. I am a lover of software, of creating software, and of my users. And I’m not going to give that up so we can sound important and impressive.&lt;/p&gt;
&lt;p&gt;I’ve always felt that if I’m not pissing anyone off, I’m not doing things right. If nobody’s getting pissed off, nothing worth saying is being said, nothing worth doing is being done. Because everyone has their own preferences. The fact that my refusal to be professional is pissing people off is not a bad sign, in my mind.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;We’ve been running a &lt;a href=&#34;https://spreadsheets.google.com/spreadsheet/viewform?hl=en_US&amp;amp;formkey=dFV5bXBDMzk2OTFVNFRsX0RYLXRKYWc6MQ#gid=0&#34; title=&#34;2cloud Feedback Survey on Google Docs&#34;&gt;feedback survey for 2cloud&lt;/a&gt; for a couple of weeks now, trying to get a sense of how we’re doing with the project. We’ve gotten some great responses (if they’re not from you, please go ahead and take two minutes to fill out the form. We are leaving it open indefinitely), but one response we got bothered me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Bottom line you’re sounding juvenile, when you want professional.”&lt;/em&gt;&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Google&#43;: I’ve Seen This Before</title>
      <link>https://paddy.carvers.com/posts/google-ive-seen-this-before/</link>
      <pubDate>Thu, 30 Jun 2011 04:50:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/google-ive-seen-this-before/</guid>
      <description>&lt;p&gt;I’m pretty fortunate. In fact, I’m doubly fortunate.&lt;/p&gt;
&lt;p&gt;Not only was I invited to &lt;a href=&#34;http://plus.google.com&#34; title=&#34;Google+&#34;&gt;Google+&lt;/a&gt; when the only way to get in was to have a Googler personally recommend you, I was invited &lt;em&gt;twice&lt;/em&gt;. How’s that for bragging rights? When everyone was begging for these invites, I had &lt;em&gt;two&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But enough of me bragging about my random luck that has absolutely nothing to do with my own skill or worthiness. I’ve &lt;a href=&#34;http://twitter.com/jezdez/status/86344633973620737&#34; title=&#34;Tweet from jezdez on Twitter&#34;&gt;seen a lot of people&lt;/a&gt; comparing Buzz and Google+. Or &lt;a href=&#34;http://www.washingtonpost.com/blogs/innovations/post/google-takes-on-facebook-zyngas-ipo-advances-twitters-stone-steps-back-sprints-hesse-throws-nukes/2011/06/28/AGlFCMqH_blog.html&#34; title=&#34;The Washington Post’s coverage of Google+&#34;&gt;comparing Facebook and Google+&lt;/a&gt;. The general consensus seems to be “I’ve seen this before.”&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Well no shit.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Google+ isn’t radically new like Wave was… which is probably for the best. Instead, it takes a bunch of things we’re already used to (photo sharing, update streams, tagging friends) and puts a Google spin on them (I, personally, love Sparks—Google’s way of making it convenient to introduce new content into your stream).&lt;/p&gt;
&lt;p&gt;What I find interesting (and mildly amusing) is the comparisons that people are making. I’ve said that &lt;a href=&#34;http://twitter.com/paddycarver/status/86345726984077313&#34; title=&#34;Tweet from paddycarver on Twitter&#34;&gt;Buzz is to Twitter as Google+ is to Facebook&lt;/a&gt;. But that is really missing the point. There are two names missing from that analogy that should be there: &lt;a href=&#34;http://www.jaiku.com&#34; title=&#34;Jaiku&#34;&gt;Jaiku&lt;/a&gt; and &lt;a href=&#34;http://www.orkut.com&#34; title=&#34;Orkut&#34;&gt;Orkut&lt;/a&gt;. Jaiku was Google’s first attempt at a Twitter clone—to be perfectly accurate, it wasn’t Google’s; they bought it. Orkut was Google’s first stab at a &lt;del&gt;Facebook clone&lt;/del&gt;. As Jason points out below, I was mistaken. Orkut was Google’s first stab at a &lt;em&gt;Friendster&lt;/em&gt; clone after &lt;a href=&#34;http://en.wikipedia.org/wiki/Orkut#History_of_Orkut&#34; title=&#34;History of Orkut on Wikipedia&#34;&gt;Friendster refused to sell&lt;/a&gt; to them. Facebook, as it turns out, was an iteration on Friendster (see &lt;a href=&#34;http://books.google.com/books?id=RRUkLhyGZVgC&amp;amp;lpg=PP1&amp;amp;pg=PA86#v=onepage&amp;amp;q&amp;amp;f=false&#34; title=&#34;The Facebook Effect on Google Books&#34;&gt;The Facebook Effect&lt;/a&gt;, page 86: “’We were really worried we would be another Friendster,’ recalls Dustin Moskovitz”). Which, all-in-all, I think serves my point more than it hurts it, but in the spirit of absolute accuracy, I’ve amended the post. Good catch, Jason.&lt;/p&gt;
&lt;p&gt;You’ve never heard of either of these, and if you have, you don’t use them. And that’s why they aren’t being placed in the analogies. That’s why they aren’t being mentioned at all.&lt;/p&gt;
&lt;p&gt;It’s important to remember, though, that Google &lt;a href=&#34;http://www.youtube.com/watch?v=9lX2KfGL80g&#34; title=&#34;Mike Cassidy of Google on Product Iteration on YouTube&#34;&gt;believes in iteration&lt;/a&gt;. I don’t think that just means iteration on a single product; I think that means iteration on their entire approach to a market segment.&lt;/p&gt;
&lt;p&gt;I don’t know if Google+ is going to catch hold. I don’t know if it will go the way of Buzz, or go the way of GMail. I [hope it works](&lt;a href=&#34;https://plus.google.com/112924888792635085586/posts/fNRhV5AeJaw%22&#34;&gt;https://plus.google.com/112924888792635085586/posts/fNRhV5AeJaw&amp;quot;&lt;/a&gt; title=&amp;ldquo;Post from Paddy Foran on Google+&amp;rdquo;). It’s too early to tell, though, despite &lt;a href=&#34;https://plus.google.com/107117483540235115863/posts/PhJFJqLyRnm&#34; title=&#34;Post from Vic Gundotra on Google+&#34;&gt;“insane demand”&lt;/a&gt;. What I do know is that &lt;a href=&#34;http://www.businessinsider.com/heres-the-memo-telling-all-google-employees-their-2011-pay-depends-on-google-sucking-less-at-social-2011-4&#34; title=&#34;Here’s The Memo Telling ALL Google Employees Their 2011 Pay Depends On Google Sucking Less At Social&#34;&gt;social is important to Google&lt;/a&gt;. And as a company with nearly bottomless pockets, Google has all the time and cash it needs to iterate through product after product, learning as they go. Is Google+ the end of their quest for social? Only time will tell. If it’s not, are they going to give up? I doubt it.&lt;/p&gt;
&lt;p&gt;So yes, you’ve seen this before. And rest assured, if it fails you’ll see it again. But failing to see what Google has learned as it has iterated over social products is failing to see Google for what it is: constantly improving, slowly but surely.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I’m pretty fortunate. In fact, I’m doubly fortunate.&lt;/p&gt;
&lt;p&gt;Not only was I invited to &lt;a href=&#34;http://plus.google.com&#34; title=&#34;Google+&#34;&gt;Google+&lt;/a&gt; when the only way to get in was to have a Googler personally recommend you, I was invited &lt;em&gt;twice&lt;/em&gt;. How’s that for bragging rights? When everyone was begging for these invites, I had &lt;em&gt;two&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But enough of me bragging about my random luck that has absolutely nothing to do with my own skill or worthiness. I’ve &lt;a href=&#34;http://twitter.com/jezdez/status/86344633973620737&#34; title=&#34;Tweet from jezdez on Twitter&#34;&gt;seen a lot of people&lt;/a&gt; comparing Buzz and Google+. Or &lt;a href=&#34;http://www.washingtonpost.com/blogs/innovations/post/google-takes-on-facebook-zyngas-ipo-advances-twitters-stone-steps-back-sprints-hesse-throws-nukes/2011/06/28/AGlFCMqH_blog.html&#34; title=&#34;The Washington Post’s coverage of Google+&#34;&gt;comparing Facebook and Google+&lt;/a&gt;. The general consensus seems to be “I’ve seen this before.”&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Remembering Why I Write Software</title>
      <link>https://paddy.carvers.com/posts/remembering-why-i-write-software/</link>
      <pubDate>Fri, 10 Jun 2011 15:48:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/remembering-why-i-write-software/</guid>
      <description>&lt;p&gt;I’ve worked on &lt;a href=&#34;http://links.2cloudproject.com/homepage&#34; title=&#34;2cloud&#34;&gt;2cloud&lt;/a&gt; for almost a year now. Since its inception, it has been used by tens of thousands of people, covered by dozens of publications large and small, and entered the lexicon of Android development. My professional career has been advanced by it and my personal network of friends has been augmented by some truly wonderful people I would not have met, were it not for the exposure this application received.&lt;/p&gt;
&lt;p&gt;In all that time, however, I was never really cognizant of the software itself. I understood its function, I understood why it was cool, but I didn’t think of it as &lt;em&gt;useful&lt;/em&gt;. Part of this is the reason I started developing it: I started working on it for the sake of working on it. I wanted to learn Android development. I wanted to learn how to write a Chrome extension. I didn’t have some pressing problem that this app would solve, no target use-case for it. I just wanted to learn something, and it seemed like a fun exercise. When people asked me why it was better than just emailing themselves a link, all I could think of was &amp;ldquo;it’s a &lt;em&gt;little&lt;/em&gt; more convenient.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Yesterday, somebody showed me why it was useful, and that is something I’m grateful for.&lt;/p&gt;
&lt;p&gt;I had &lt;a href=&#34;http://twitter.com/paddycarver/status/78811529146937344&#34; title=&#34;Tweet on Twitter&#34;&gt;decided&lt;/a&gt; that people who &lt;a href=&#34;http://links.2cloudproject.com/donate&#34; title=&#34;Donate to the 2cloud Project with Paypal&#34;&gt;donate&lt;/a&gt; will receive hand-written notes, thanking them for helping keep the server online. I was having a bad day, and I wanted to focus on the good in the world, instead of all of the things I hate about it. Writing letters to people who were kind, people who validated everything I believe in, made me feel better. I duly wrote and emailed out three of these notes to our latest round of good Samaritans. One went to an individual I’ll call Sam.&lt;/p&gt;
&lt;p&gt;Last night, Sam wrote back to me. In his email, he explained that he works shifts and has a young son, and so didn’t get much time at his computer. By using the application, he could “speed browse” during his breaks, send the links to his machine, and have them waiting when he got a moment to sit down. He got some time to keep apace with the world, but still had time with his son. Because of this, Sam said 2cloud was “one of, if not the, best apps on [his] phone.”&lt;/p&gt;
&lt;p&gt;It was the perfect ending to a bad day. I remembered why I believe in open source software so much. I remember why I work on 2cloud whenever I can. I remembered that people found value in my work, and some of them weren’t afraid of saying so, with money or words.&lt;/p&gt;
&lt;p&gt;If you write software, I highly encourage you to communicate with your users on a personal level. Ignoring all the benefits it will provide your user experience, it will give you the most pure appreciation for your job that you can get in our line of work. As much as possible, get to know your users; some of them may be scum, but putting up with them is absolutely worth getting to know the gems.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I’ve worked on &lt;a href=&#34;http://links.2cloudproject.com/homepage&#34; title=&#34;2cloud&#34;&gt;2cloud&lt;/a&gt; for almost a year now. Since its inception, it has been used by tens of thousands of people, covered by dozens of publications large and small, and entered the lexicon of Android development. My professional career has been advanced by it and my personal network of friends has been augmented by some truly wonderful people I would not have met, were it not for the exposure this application received.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Time for a Change?</title>
      <link>https://paddy.carvers.com/posts/time-for-a-change/</link>
      <pubDate>Wed, 18 May 2011 19:07:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/time-for-a-change/</guid>
      <description>&lt;p&gt;It’s the end of my third year in college. I’m miserable. I hate the standards they hold me to. I kid you not, my final for a class &lt;em&gt;discouraged me&lt;/em&gt; from using independent thought. It told me it wanted nothing more than to show I could engage literature on its own turf. &amp;ldquo;Don’t think about it, just be able to work with it.&amp;rdquo; That’s not the kind of education I want.&lt;/p&gt;
&lt;p&gt;So I just submitted my résumé to &lt;a href=&#34;http://www.twitter.com&#34; title=&#34;Twitter&#34;&gt;Twitter&lt;/a&gt;. Yes, on the same day they announced that third party Twitter clients were essentially screwed. A lot of the developers are up in arms about this. So I applied to be either an Open Source Liaison or a Partner Engineer. Essentially, I signed up to work with either Twitter’s open source policies or their developer relations team. I figure that if I’m looking for a challenge, it doesn’t get much better than that.&lt;/p&gt;
&lt;p&gt;Am I leaving &lt;a href=&#34;http://www.secondbit.org&#34; title=&#34;Second Bit&#34;&gt;Second Bit&lt;/a&gt;? No. At least, not immediately. I’m skeptical that Twitter will hire me—I don’t look all that impressive on paper. If they do, I can’t say for sure what will happen. I could work on both. I could just work for Twitter. I’m not sure what they’ll ask of me. I do have some ideas in the works, however, and will be working on implementing some of them as quickly as possible. Iterating, and all that.&lt;/p&gt;
&lt;p&gt;In short, I’m not sure where I’m going in the future. But if I can avoid it, I’m not wasting another year and several thousand more dollars on a degree I don’t want.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;It’s the end of my third year in college. I’m miserable. I hate the standards they hold me to. I kid you not, my final for a class &lt;em&gt;discouraged me&lt;/em&gt; from using independent thought. It told me it wanted nothing more than to show I could engage literature on its own turf. &amp;ldquo;Don’t think about it, just be able to work with it.&amp;rdquo; That’s not the kind of education I want.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Logging the Channel API</title>
      <link>https://paddy.carvers.com/posts/logging-the-channel-api/</link>
      <pubDate>Tue, 29 Mar 2011 23:37:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/logging-the-channel-api/</guid>
      <description>&lt;p&gt;We’re having a bit of an issue at &lt;a href=&#34;http://www.2cloudproject.com/&#34;&gt;the 2cloud Project&lt;/a&gt;. We’re getting reports of the &lt;a href=&#34;http://code.google.com/appengine/docs/python/channel&#34;&gt;Channel API&lt;/a&gt; throwing &lt;a href=&#34;http://help.2cloudproject.com/discussions/problems/51-says-sent-to-cloud-but-never-opens-up-on-chrome&#34;&gt;iFrame errors about illegal access&lt;/a&gt;. Considering the Channel API is based on Google’s &lt;a href=&#34;http://code.google.com/p/closure-library/&#34;&gt;Closure&lt;/a&gt; library’s &lt;a href=&#34;http://closure-library.googlecode.com/svn/!svn/bc/4/trunk/closure/goog/docs/class_goog_net_xpc_CrossPageChannel.html&#34;&gt;XPC library&lt;/a&gt;, which uses iFrames, I had a feeling the issue wasn’t on our end. Unfortunately, neither I nor Moishe could figure out why this was happening—we both agreed it shouldn’t be.&lt;/p&gt;
&lt;p&gt;Even worse, I didn’t have any logging mechanism for the Channel API at a low level like this, so I couldn’t offer much debug information. The code was minified with Closure’s compiler, which makes debugging it a pain. There’s a wonderful &lt;a href=&#34;http://code.google.com/p/closure-inspector/&#34;&gt;Closure Inspector&lt;/a&gt; that is supposed to help debug stuff like this, but for some unknown reason, that only runs in Firebug. Which makes debugging a Chrome extension difficult. Clearly, the only thing to be done is to start &lt;code&gt;console.log&lt;/code&gt;ging things.&lt;/p&gt;
&lt;p&gt;It took me far too long to figure out that I couldn’t access Closure logs in Chrome, and it’s annoying to sort through that minified, compiled code to find where the logging is defined. So I’ll just tell you. &lt;a href=&#34;https://paddy.carvers.com/posts/app-engine-channels-and-chrome-extensions/&#34;&gt;Download channel.js&lt;/a&gt;, and search for &lt;code&gt;I.prototype.log&lt;/code&gt;. Remove the following line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Being sure to also remove the trailing brace, because you’re intelligent like that. Then, above&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;markTimeline&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;markTimeline&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Xb&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;insert the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Xb&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That’s it. enjoy your new, powerful, low-level Channel API logs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://paddy.carvers.com/img/channel_logging.png&#34; alt=&#34;Log output screenshot&#34;&gt;&lt;/p&gt;
&lt;p&gt;Of course, if you’re not insane and actually plan to debug this, you probably want to &lt;a href=&#34;http://jsbeautifier.org/&#34;&gt;beautify your channel.js file&lt;/a&gt;.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;We’re having a bit of an issue at &lt;a href=&#34;http://www.2cloudproject.com/&#34;&gt;the 2cloud Project&lt;/a&gt;. We’re getting reports of the &lt;a href=&#34;http://code.google.com/appengine/docs/python/channel&#34;&gt;Channel API&lt;/a&gt; throwing &lt;a href=&#34;http://help.2cloudproject.com/discussions/problems/51-says-sent-to-cloud-but-never-opens-up-on-chrome&#34;&gt;iFrame errors about illegal access&lt;/a&gt;. Considering the Channel API is based on Google’s &lt;a href=&#34;http://code.google.com/p/closure-library/&#34;&gt;Closure&lt;/a&gt; library’s &lt;a href=&#34;http://closure-library.googlecode.com/svn/!svn/bc/4/trunk/closure/goog/docs/class_goog_net_xpc_CrossPageChannel.html&#34;&gt;XPC library&lt;/a&gt;, which uses iFrames, I had a feeling the issue wasn’t on our end. Unfortunately, neither I nor Moishe could figure out why this was happening—we both agreed it shouldn’t be.&lt;/p&gt;
&lt;p&gt;Even worse, I didn’t have any logging mechanism for the Channel API at a low level like this, so I couldn’t offer much debug information. The code was minified with Closure’s compiler, which makes debugging it a pain. There’s a wonderful &lt;a href=&#34;http://code.google.com/p/closure-inspector/&#34;&gt;Closure Inspector&lt;/a&gt; that is supposed to help debug stuff like this, but for some unknown reason, that only runs in Firebug. Which makes debugging a Chrome extension difficult. Clearly, the only thing to be done is to start &lt;code&gt;console.log&lt;/code&gt;ging things.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>App Engine Channels and Chrome Extensions</title>
      <link>https://paddy.carvers.com/posts/app-engine-channels-and-chrome-extensions/</link>
      <pubDate>Wed, 08 Dec 2010 00:27:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/app-engine-channels-and-chrome-extensions/</guid>
      <description>&lt;p&gt;Google’s latest toy for &lt;a href=&#34;http://appengine.google.com/&#34;&gt;App Engine&lt;/a&gt;, its &lt;a href=&#34;http://code.google.com/appengine/docs/python/channel/&#34;&gt;Channel API&lt;/a&gt;, is really a cool tool. It gives you Comet support on a &lt;em&gt;free&lt;/em&gt; webhost. That’s a phenomenal achievement, in my mind. I was &lt;a href=&#34;http://blog.android2cloud.org/2010/08/channel-api.html&#34;&gt;given early access to it&lt;/a&gt;, to build the &lt;a href=&#34;http://code.google.com/p/android2cloud&#34;&gt;android2cloud&lt;/a&gt; web server with its technology, to relieve &lt;a href=&#34;http://blog.android2cloud.org/2010/08/servers-and-money.html&#34;&gt;our polling woes&lt;/a&gt;. And I tested it, and it worked great.&lt;/p&gt;
&lt;p&gt;And then there were some mishaps, with frontends, and the roll-out to production servers was taking a bit longer than I had hoped, so I had to &lt;a href=&#34;https://twitter.com/paddycarver/status/27981592770&#34;&gt;look into other alternatives&lt;/a&gt;. When an app is eating $80 a week and is &lt;a href=&#34;http://blog.android2cloud.org/2010/09/money-spoils-everything-wholesome.html&#34;&gt;constantly in a state of financial peril&lt;/a&gt;, I couldn’t afford to just rest on my haunches and wait for Google.&lt;/p&gt;
&lt;p&gt;And then, of course, Google &lt;a href=&#34;http://googleappengine.blogspot.com/2010/12/happy-holidays-from-app-engine-team-140.html&#34;&gt;got the Channels to production&lt;/a&gt; before I got my &lt;a href=&#34;http://www.nodejs.org/&#34;&gt;node.js&lt;/a&gt; implementation to production-readiness. So, of course, I tested the beta software I had written a couple months prior, ensured it still worked, and &lt;a href=&#34;http://groups.google.com/group/android2cloud-beta/browse_thread/thread/a13caf3450c704c6&#34;&gt;called for a test&lt;/a&gt;. Except something blew up in my face: I had neglected to test the extension, trusting that it would still work. It didn’t.&lt;/p&gt;
&lt;p&gt;Google had changed their code that handles their &amp;ldquo;CrossPageChannel&amp;rdquo;; basically, a hidden, embedded Google Talk iframe. Whatever, no big deal. Except now they were automatically passing through the domain the code was called from (in a Chrome extension, chrome-extension://&lt;em&gt;chromeextensionidhere&lt;/em&gt;) and appending &amp;ldquo;/_ah/channel/xpc_blank&amp;rdquo;. Fine, whatever. I don’t understand the changes, and I don’t really care to. The problem, I discovered, is that the new code rejected anything that wasn’t on the http or https protocol. Which these weren’t.&lt;/p&gt;
&lt;p&gt;OK, fair enough. I downloaded the javascript file that’s responsible for making the channels (&lt;a href=&#34;http://talkgadget.google.com/talkgadget/channel.js&#34;&gt;http://talkgadget.google.com/talkgadget/channel.js&lt;/a&gt;) and substituted in my local channel.js file for the &lt;a href=&#34;http://_yourappid_.appspot.com/_ah/channel/jsapi&#34;&gt;http://_yourappid_.appspot.com/_ah/channel/jsapi&lt;/a&gt; file in the script tag. Then, in my local file, I added chrome-extension to the test for http and https, so extensions were listed as ok. Loaded it up, and… it failed. A dynamically generated file that Google hosts itself tested again. Darn.&lt;/p&gt;
&lt;p&gt;And then I had an idea. What if, instead of trying to make the tests allow the link, I tried to make the link pass the test? It was worth a shot. So I changed the /_ah/channel/xpc_blank to be &lt;a href=&#34;http://_yourappid_.appspot.com/_ah/channel/xpc_blank&#34;&gt;http://_yourappid_.appspot.com/_ah/channel/xpc_blank&lt;/a&gt;, and fired it up. A little ferreting around (had to find the code that was extracting the current domain, match it for the chrome-extension protocol, and tell it to &lt;em&gt;not&lt;/em&gt; append the domain and path if the protocol was chrome-extension. Otherwise, it was giving me &amp;ldquo;chrome-extension://&lt;em&gt;extensionidhere&lt;/em&gt;/http://&lt;em&gt;yourappid&lt;/em&gt;.appspot.com/_ah/channel/xpc_blank&amp;rdquo;, which is not &lt;em&gt;quite&lt;/em&gt; what I wanted) and lo and behold, the extension worked again.&lt;/p&gt;
&lt;p&gt;I fired off an email to &lt;a href=&#34;http://www.google.com/profiles/moishel&#34;&gt;Moishe Lettvin&lt;/a&gt;, the developer who had been working with the testers on the API, letting him know about the bug. He acknowledged it existed, but claimed he didn’t know how to fix it off-hand. I explained what I had done, and he acknowledged that was the correct fix. He has (by now, I presume) applied the fix, and it will be rolling out with the next GTalk frontend rollout. Unfortunately, that could be weeks or months away. So I’m keeping my hacked together file, and am going to end up pushing it out for android2cloud. And I’m going to let you do the same.&lt;/p&gt;
&lt;p&gt;Using it is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Grab yourself the &lt;a href=&#34;http://code.google.com/p/android2cloud-beta/source/browse/channel.js?repo=chrome&#34;&gt;channel.js&lt;/a&gt; file I’ve modified.&lt;/li&gt;
&lt;li&gt;Put it in the folder of your Chrome extension.&lt;/li&gt;
&lt;li&gt;Open the channel.js file, and modify line 2: &lt;code&gt;var myHost = &amp;quot;http://connegt.appspot.com&amp;quot;;&lt;/code&gt; needs to become &lt;code&gt;var myHost = &amp;quot;http://yourappid.appspot.com&amp;quot;;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Build a webpage that is Channel-enabled, as usual. Your chrome extensions are just HTML pages, so you shouldn’t have to modify anything at all.&lt;/li&gt;
&lt;li&gt;Change &amp;ldquo;&lt;a href=&#34;http://_yourappid_.appspot.com/_ah/channel/jsapi%22&#34;&gt;http://_yourappid_.appspot.com/_ah/channel/jsapi&amp;quot;&lt;/a&gt; to &amp;ldquo;/channel.js&amp;rdquo; anywhere it appears in your code (though you should only have it in there once…)&lt;/li&gt;
&lt;li&gt;Enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s really that simple to have your browser updated in realtime. I don’t think you have any excuse left for polling.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;Google’s latest toy for &lt;a href=&#34;http://appengine.google.com/&#34;&gt;App Engine&lt;/a&gt;, its &lt;a href=&#34;http://code.google.com/appengine/docs/python/channel/&#34;&gt;Channel API&lt;/a&gt;, is really a cool tool. It gives you Comet support on a &lt;em&gt;free&lt;/em&gt; webhost. That’s a phenomenal achievement, in my mind. I was &lt;a href=&#34;http://blog.android2cloud.org/2010/08/channel-api.html&#34;&gt;given early access to it&lt;/a&gt;, to build the &lt;a href=&#34;http://code.google.com/p/android2cloud&#34;&gt;android2cloud&lt;/a&gt; web server with its technology, to relieve &lt;a href=&#34;http://blog.android2cloud.org/2010/08/servers-and-money.html&#34;&gt;our polling woes&lt;/a&gt;. And I tested it, and it worked great.&lt;/p&gt;
&lt;p&gt;And then there were some mishaps, with frontends, and the roll-out to production servers was taking a bit longer than I had hoped, so I had to &lt;a href=&#34;https://twitter.com/paddycarver/status/27981592770&#34;&gt;look into other alternatives&lt;/a&gt;. When an app is eating $80 a week and is &lt;a href=&#34;http://blog.android2cloud.org/2010/09/money-spoils-everything-wholesome.html&#34;&gt;constantly in a state of financial peril&lt;/a&gt;, I couldn’t afford to just rest on my haunches and wait for Google.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>On Peter Pan</title>
      <link>https://paddy.carvers.com/posts/on-peter-pan/</link>
      <pubDate>Wed, 18 Aug 2010 02:18:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/on-peter-pan/</guid>
      <description>&lt;p&gt;It’s probably pretty obvious, but I have a &lt;em&gt;huge&lt;/em&gt; &lt;a href=&#34;http://en.wikipedia.org/wiki/Peter_pan_complex&#34;&gt;Peter Pan complex&lt;/a&gt;. I blame my parents for this (they made my song “&lt;a href=&#34;http://www.youtube.com/watch?v=2gVsQZ2hVj8&#34;&gt;Forever Young&lt;/a&gt;—the Rod Stewart version, not the &lt;a href=&#34;http://www.youtube.com/watch?v=E1nbvplgElw&#34;&gt;Jay-Z version&lt;/a&gt;—when I was young), but it probably stems from a lot of things. Regardless, I’ve always had a fascination with Peter Pan. My favourite portrayal so far has to be the &lt;a href=&#34;http://www.imdb.com/title/tt0316396/&#34;&gt;2003 version&lt;/a&gt; starring &lt;a href=&#34;http://www.jeremysumpter.com/&#34;&gt;Jeremy Sumpter&lt;/a&gt;, but I got the chance to watch &lt;a href=&#34;http://www.imdb.com/title/tt0102057/&#34;&gt;Hook&lt;/a&gt; the other day, and I thoroughly enjoyed it.&lt;/p&gt;
&lt;p&gt;While watching it, though, I started thinking about the untapped stories in Peter Pan. The story is magical because of the character that Peter holds. Peter embodies and &lt;em&gt;is&lt;/em&gt; Neverland, and a lot can be done with that. Few films seem to accept or embrace that, which is why the 2003 version happens to be my favourite; it really plays with the idea and personality of Peter, while staying rather close to the original &lt;a href=&#34;http://en.wikisource.org/wiki/Peter_and_Wendy&#34;&gt;J.M. Barrie story&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Peter is embodied by his childishness—his refusal to grow up is what gives Neverland its timelessness. And in that inherent immaturity, we see the pros and cons of such an approach. Peter is tactless, to the point of hurting those around him out of ignorance, but enchanting, happy, and carefree. He is incapable of some of the stronger emotions, and exhibits a fleeting character that one may miss if they blink.&lt;/p&gt;
&lt;p&gt;What then, is made of the crush that Tinkerbell clearly has on him? It is implied in every version I’ve seen that this is what fuels her betrayal of Wendy to Captain Hook, but the dynamics aren’t really explored. And Tink, herself, is a wonderful font for exploration: a creature so tiny she can only hold a single emotion at any given point. Much a mirror of Peter’s undeveloped emotional capacities, the dynamics between Tink and Peter hold a plethora of opportunities for stories. What would Tink say, should she have a chance to tell the story? What would Peter say, should he know of Tink’s feelings for him? What would a relationship between Tink and Peter look like?&lt;/p&gt;
&lt;p&gt;Perhaps I’ll have to write some explorations into this realm that I love so, should I get the opportunity this semester. I would love to hear other people’s thoughts on the matter, though.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;It’s probably pretty obvious, but I have a &lt;em&gt;huge&lt;/em&gt; &lt;a href=&#34;http://en.wikipedia.org/wiki/Peter_pan_complex&#34;&gt;Peter Pan complex&lt;/a&gt;. I blame my parents for this (they made my song “&lt;a href=&#34;http://www.youtube.com/watch?v=2gVsQZ2hVj8&#34;&gt;Forever Young&lt;/a&gt;—the Rod Stewart version, not the &lt;a href=&#34;http://www.youtube.com/watch?v=E1nbvplgElw&#34;&gt;Jay-Z version&lt;/a&gt;—when I was young), but it probably stems from a lot of things. Regardless, I’ve always had a fascination with Peter Pan. My favourite portrayal so far has to be the &lt;a href=&#34;http://www.imdb.com/title/tt0316396/&#34;&gt;2003 version&lt;/a&gt; starring &lt;a href=&#34;http://www.jeremysumpter.com/&#34;&gt;Jeremy Sumpter&lt;/a&gt;, but I got the chance to watch &lt;a href=&#34;http://www.imdb.com/title/tt0102057/&#34;&gt;Hook&lt;/a&gt; the other day, and I thoroughly enjoyed it.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>I’m a Shakespeare of Software</title>
      <link>https://paddy.carvers.com/posts/im-a-shakespeare-of-software/</link>
      <pubDate>Mon, 02 Aug 2010 12:28:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/im-a-shakespeare-of-software/</guid>
      <description>&lt;p&gt;I wear funny clothes and people will remember me for centuries to come.&lt;/p&gt;
&lt;p&gt;OK, maybe not for those reasons. But still, I find the best comparison to my programming style is the great bard himself. Some of you may not know this, with all the programming stuff I do, but I’m actually an English/Adolescent Education dual-major. No, no Computer Science degree. Yes, I spend my time reading literature. Yes, I will be teaching your kids.&lt;/p&gt;
&lt;p&gt;As any English major must, I’ve spent some time with the bard (or his work, at least). One of the most striking things, and one of the things discussed in classrooms ad-nauseum, is the bard’s remarkable lack of originality. &lt;em&gt;King Lear&lt;/em&gt;, for example, is little more than an amalgamation of three similar stories, told and retold throughout cultures and time periods. In essence, William Shakespeare was the Disney of his day. Which is not to say that the bard never created something; he simply grounded his creation in the creations of others, standing on the shoulders of giants.&lt;/p&gt;
&lt;p&gt;Which is all well and good, but software has no cultural history. Does it? Well, yes and no. There are certain problems that are solved and re-solved almost continuously. things like user authentication. These solutions grow to be abstracted out, and suddenly we wind up with things like &lt;a href=&#34;http://oauth.net/&#34;&gt;OAuth&lt;/a&gt; and &lt;a href=&#34;http://openid.org/&#34;&gt;OpenID&lt;/a&gt;. We wind up with open source &lt;em&gt;platforms&lt;/em&gt; that can solve these problems. These &lt;em&gt;platforms&lt;/em&gt;, I would argue, are the cultural history of the craft.&lt;/p&gt;
&lt;p&gt;And I, like Shakespeare, simply weave them together.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://code.google.com/p/android2cloud&#34;&gt;android2cloud&lt;/a&gt;, one of the most successful pieces of software I’ve written, was built by simply tying together four of these platforms. I stood on the shoulders of Google and OAuth, and in a month I pumped out an application that is used by over 300 people. The amount of code I actually wrote for that project is laughably small. Minuscule. And that is how I do programming; weaving together what others have built, until it fits what I need it to do. With the amount of cultural history available in programming, there’s very little I can’t do.&lt;/p&gt;
&lt;p&gt;My suspicion is there are a lot of Shakespeares running around right now, weaving software together into a sum that’s bigger than its component parts. We all owe a debt to the creators around us, who pioneer the new technologies we stand on, but they owe us a debt as well, for making that technology more than they dreamed it could be.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I wear funny clothes and people will remember me for centuries to come.&lt;/p&gt;
&lt;p&gt;OK, maybe not for those reasons. But still, I find the best comparison to my programming style is the great bard himself. Some of you may not know this, with all the programming stuff I do, but I’m actually an English/Adolescent Education dual-major. No, no Computer Science degree. Yes, I spend my time reading literature. Yes, I will be teaching your kids.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Thoughts</title>
      <link>https://paddy.carvers.com/posts/thoughts/</link>
      <pubDate>Wed, 30 Jun 2010 16:59:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/thoughts/</guid>
      <description>&lt;p&gt;I’ve been thinking a lot lately. This is a largely unintentional side-effect of some current personal life happenings that I won’t share, simply to save you the whining. And yet it remains, there have been a lot of thoughts bouncing around in my skull. I’m sure I’ve been annoying my friends, texting and IMing them about some pretty abstract things.&lt;/p&gt;
&lt;p&gt;Last night, I got to thinking about why I write. &lt;a href=&#34;http://www.whitneyturland.com&#34; title=&#34;A wonderful lady who chats me up on Twitter.&#34;&gt;Whitney Turland&lt;/a&gt; wrote recently on &lt;a href=&#34;http://whitneyturland.com/2010/06/write-all-the-time&#34; title=&#34;I’m in favour of “because she’s damn good at it”.&#34;&gt;why she writes&lt;/a&gt; and asked for commenters to chime in on why &lt;em&gt;they&lt;/em&gt; write. And I intend to, but I’ll do that in its own blog post. In a nutshell, though, I write to think.&lt;/p&gt;
&lt;p&gt;Rather than killing trees, thinking in notebooks that are then scattered around my room, gathering dust and doing nothing for anyone, I’ve decided that this blog should fulfill that purpose. I’ve been trying to write for an audience, trying to write what I think people will care about. But this is &lt;em&gt;my&lt;/em&gt; blog. It’s supposed to be &lt;em&gt;my&lt;/em&gt; presence. And so I intend to let it archive my thoughts, and guide my thinking. Perhaps you will take the time to comment, to help shape my thinking. Perhaps you won’t. That’s entirely up to you.&lt;/p&gt;
&lt;p&gt;What does this mean for &lt;em&gt;you&lt;/em&gt;? It means more posts that you may not care about. It means more of my personality, more of the things I care about, and more variety on this blog. It does &lt;em&gt;not&lt;/em&gt; mean more personal problems or interests that mean nothing to anyone but those closest to me. Instead of posting about how Charlie and Jane are fighting, I’ll be looking at why they’re fighting, and pondering over which of them (anonymously, of course) is right. I will be trying to refrain from adding unnecessary personal information into posts as possible, focusing instead on the ideas, the abstract.&lt;/p&gt;
&lt;p&gt;Maybe you’ll like this. Maybe you won’t. If you don’t, I’d love to hear from you on why. But I’ve grown distant from my writing, and my lack of practice has weakened and poisoned my abilities. I intend to get back to my writing, and that means writing my thoughts, not the thoughts I think people want to hear about.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I’ve been thinking a lot lately. This is a largely unintentional side-effect of some current personal life happenings that I won’t share, simply to save you the whining. And yet it remains, there have been a lot of thoughts bouncing around in my skull. I’m sure I’ve been annoying my friends, texting and IMing them about some pretty abstract things.&lt;/p&gt;
&lt;p&gt;Last night, I got to thinking about why I write. &lt;a href=&#34;http://www.whitneyturland.com&#34; title=&#34;A wonderful lady who chats me up on Twitter.&#34;&gt;Whitney Turland&lt;/a&gt; wrote recently on &lt;a href=&#34;http://whitneyturland.com/2010/06/write-all-the-time&#34; title=&#34;I’m in favour of “because she’s damn good at it”.&#34;&gt;why she writes&lt;/a&gt; and asked for commenters to chime in on why &lt;em&gt;they&lt;/em&gt; write. And I intend to, but I’ll do that in its own blog post. In a nutshell, though, I write to think.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>All Quiet</title>
      <link>https://paddy.carvers.com/posts/all-quiet/</link>
      <pubDate>Sat, 22 May 2010 18:39:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/all-quiet/</guid>
      <description>&lt;p&gt;I started out to write this post thinking I hadn’t written anything for this site in quite some time. Actually, I wrote a post here four days ago. Seems like that was a long time ago. Probably because I’ve done so much in between then and now. My last post was on Tuesday; let’s recap what has happened since then.&lt;/p&gt;
&lt;h2 id=&#34;tuesday&#34;&gt;Tuesday&lt;/h2&gt;
&lt;p&gt;Tuesday was the introduction of &lt;a href=&#34;http://www.imdb.com/name/nm0000439/&#34; title=&#34;The man, the legend, the god.&#34;&gt;Neil Patrick Harris&lt;/a&gt; to &lt;a href=&#34;http://www.fox.com/glee/&#34; title=&#34;Guilty Secret: I *adore* Kurt.&#34;&gt;Glee&lt;/a&gt;. I’m not much of a television person; Glee’s the only show I watch regularly. And NPH happens to be my personal hero.&lt;/p&gt;
&lt;p&gt;Naturally, I set up a projector to view the show. And naturally, I almost wet myself. I was extremely disappointed that the producers saw fit to auto-tune NPH (who &lt;em&gt;does&lt;/em&gt; that?!), but it was still amazing to see him rock out to Dream On and Piano Man.&lt;/p&gt;
&lt;h2 id=&#34;wednesday&#34;&gt;Wednesday&lt;/h2&gt;
&lt;p&gt;Wednesday I dedicated to &lt;a href=&#34;http://code.google.com/io&#34; title=&#34;I will attend this before I die.&#34;&gt;Google I/O&lt;/a&gt;. I watched the &lt;a href=&#34;http://www.youtube.com/googledevelopers&#34; title=&#34;Almost as good. Almost.&#34;&gt;recorded versions&lt;/a&gt; of the streams as soon as I got the chance, and thought and thought some more about &lt;a href=&#34;http://www.suchagit.com/&#34; title=&#34;I’m really bad about this shameless self-promotion thing.&#34;&gt;the company I want to work for&lt;/a&gt;. Day 1, I thought, was far more web-oriented. It was all about building web applications: HTML5, cloud computing, app stores, etc. Day 2, to the contrary, I saw as being far more focused on devices; namely, &lt;a href=&#34;http://www.android.com/&#34; title=&#34;I wish I had one of these phones.&#34;&gt;Android&lt;/a&gt; and &lt;a href=&#34;http://www.google.com/tv&#34; title=&#34;Another consumer device with Google in front of it. I’m waiting for Google Refrigerator.&#34;&gt;Google TV&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m squeeing like a schoolgirl over Google TV, because I may actually watch TV again now. Ignoring the fact that &lt;em&gt;I don’t have the time for it&lt;/em&gt;, this is really exciting. And Android was exciting, for reasons I’ll cover in a minute.&lt;/p&gt;
&lt;h2 id=&#34;thursday&#34;&gt;Thursday&lt;/h2&gt;
&lt;p&gt;Thursday was also dedicated to I/O. I’ve only seen the first half (before the Google TV news) due to availability, but Android already has me super pumped. The cloud to Android sync option (the Push notification done right, as it were) particularly inspired me. It inspired me so much that on…&lt;/p&gt;
&lt;h2 id=&#34;friday&#34;&gt;Friday&lt;/h2&gt;
&lt;p&gt;I started a &lt;a href=&#34;http://www.suchagit.com/2010/05/android-to-cloud-push.html&#34; title=&#34;I needed another one, right?&#34;&gt;new project&lt;/a&gt;, &lt;a href=&#34;http://code.google.com/p/android2cloud/&#34; title=&#34;This has been remarkably well-received.&#34;&gt;android2cloud&lt;/a&gt;. I figured if the cloud could push pages to Android, Android should be able to push back.&lt;/p&gt;
&lt;p&gt;I was in Rochester for the day, at my brother’s commencement, but in the four hour round-trip and an hour or so after the event, I managed to get a working prototype of the cloud side of this. A Chrome extension pings an App Engine server every 15 seconds and gets the latest link attached to your Google Account (using OAuth, of course). If that link is the same as the last link that Chrome opened, Chrome does nothing. If it’s different, Chrome opens it in a new tab. There’s also a button in the browser that will open the last link attached to your account, no matter what.&lt;/p&gt;
&lt;p&gt;I plan to release two versions of the Android app when I (start and) finish it: a free version, and a $0.99 version. These two versions will be absolutely identical in every way. The only difference is one donates $0.99 to me to help me get through college, and (maybe? Possibly? No promises.) send me to I/O next year. Basically, it’s a convenient way to donate to me.&lt;/p&gt;
&lt;p&gt;Of course, I need to &lt;em&gt;have&lt;/em&gt; an Android app to sell, and I haven’t even started yet. I want to wait until I have an Android phone I can actually test it on (though I have a pretty good theory as to how the app will work…) Which leads me to…&lt;/p&gt;
&lt;h2 id=&#34;today&#34;&gt;Today&lt;/h2&gt;
&lt;p&gt;Today, the glorious day in which I bought my &lt;a href=&#34;http://www.google.com/phone&#34; title=&#34;Prediction: http://www.google.com/microwave. Make yourself a frozen dinner FROM THE CLOUD!&#34;&gt;Nexus One&lt;/a&gt;. It will arrive Monday or Tuesday. I’m excited.&lt;/p&gt;
&lt;p&gt;I also did some work on android2cloud, designing logos, opening sites, and checking policies. I have a request in to Google to use the word &amp;ldquo;android&amp;rdquo; in my application, as well as to allow me to use my modified copy of the Android logo in situations where it’s impossible or impractical to include their attribution statement at the bottom of a page. Like, for example, in the app, in Chrome, in &lt;a href=&#34;http://code.google.com/p/android2cloud&#34; title=&#34;This basically serves as an underhanded way to let me promote the project with every link it possesses.&#34;&gt;Google Code&lt;/a&gt;, and in &lt;a href=&#34;http://groups.google.com/group/android2cloud&#34; title=&#34;Though as long as you’re reading these mouse-overs, why not join the group?&#34;&gt;Google Groups&lt;/a&gt;. Basically, everywhere I use the icon. I feel like Google will come through for me, so long as I attribute them somehow.&lt;/p&gt;
&lt;p&gt;So yeah, busy week. And it looks like my next week is bright: &lt;a href=&#34;http://blog.zap2it.com/frominsidethebox/2010/05/glee-first-look-lady-gaga-tribute-clip-and-pics.html&#34; title=&#34;This ranks right up there with NPH being on Glee.&#34;&gt;Lady GaGa is on Glee&lt;/a&gt;, I get my Nexus One, and I get to see &lt;a href=&#34;http://satanslemonade.tumblr.com/&#34; title=&#34;No, seriously, they’re hilarious. If you’re in Syracuse, go watch.&#34;&gt;an improv show my friends are performing in&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I love summer.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I started out to write this post thinking I hadn’t written anything for this site in quite some time. Actually, I wrote a post here four days ago. Seems like that was a long time ago. Probably because I’ve done so much in between then and now. My last post was on Tuesday; let’s recap what has happened since then.&lt;/p&gt;
&lt;h2 id=&#34;tuesday&#34;&gt;Tuesday&lt;/h2&gt;
&lt;p&gt;Tuesday was the introduction of &lt;a href=&#34;http://www.imdb.com/name/nm0000439/&#34; title=&#34;The man, the legend, the god.&#34;&gt;Neil Patrick Harris&lt;/a&gt; to &lt;a href=&#34;http://www.fox.com/glee/&#34; title=&#34;Guilty Secret: I *adore* Kurt.&#34;&gt;Glee&lt;/a&gt;. I’m not much of a television person; Glee’s the only show I watch regularly. And NPH happens to be my personal hero.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Let’s Cut Down a Tree, Knowing No One Will Hear</title>
      <link>https://paddy.carvers.com/posts/lets-cut-down-a-tree-knowing-no-one-will-hear/</link>
      <pubDate>Mon, 17 May 2010 22:45:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/lets-cut-down-a-tree-knowing-no-one-will-hear/</guid>
      <description>&lt;p&gt;A couple days ago, I read &lt;a href=&#34;http://www.paulcarr.com&#34; title=&#34;Seriously, this guy is my hero. Mainly because he’s proof I could actually have a future.&#34;&gt;Paul Carr&lt;/a&gt;’s &lt;a href=&#34;http://techcrunch.com/2010/05/16/worse-things-happen-at-sea/&#34; title=&#34;TL;DR: shut the hell up and quit whining.&#34;&gt;thoughts&lt;/a&gt; on the growing number of complaints against Jobs, Zuckerberg, and Wales, CEOs of three of the most prominent tech companies. As I sat there reading his article, I was uncomfortably nodding my head. I was nodding because most of what he was saying (which, in case you don’t read my mouse-overs [you should], was essentially &amp;ldquo;Shut the hell up, and stop whining.&amp;rdquo;) was absolutely spot on. It was uncomfortable because I &lt;em&gt;really, really&lt;/em&gt; wanted to hate Jobs.&lt;/p&gt;
&lt;p&gt;I’ve hated Jobs for a while now. I find his entire style of running a company and producing a product to be unmanageable, unscalable, and unwieldy. Yes, it produces pretty stuff, but we all know to &lt;a href=&#34;https://paddy.carvers.com/posts/beware-the-pretty-faced-girl/&#34; title=&#34;Gratuitous self-referencing!&#34;&gt;beware the pretty-faced girl&lt;/a&gt;. But you know what? I don’t have a Mac, for that very reason. I have an iPhone, and am dumping it instead of upgrading. I’m voting with my dollar, and that’s where my voice ends. Or so Paul says.&lt;/p&gt;
&lt;p&gt;And up until that point, I’d agree with him. I have no business telling Steve Jobs how to run his company. None whatsoever. Lord knows I couldn’t do his job better, or even half as well. I’m a big enough boy to admit that; I have my strengths, and running Apple is not one of them. And yet, that doesn’t mean I should sit down and shut the hell up. It just means I shouldn’t expect Steve to change for me.&lt;/p&gt;
&lt;p&gt;Let’s talk about how friendship, trust, and recommendations work. My friends know me as the most tech-savvy thing they’re likely to know personally until they leave college. Which is kind of cool, but kind of a heavy responsibility. Every time a friend wants new speakers, a new laptop, a new monitor, a new computer, a new &lt;em&gt;anything&lt;/em&gt; that has circuits, they ask me what they should get. They tend to trust my opinions, and so I put a lot of thought into what I tell them. Because they &lt;em&gt;trust&lt;/em&gt; me to know what I’m talking about and trust our &lt;em&gt;friendship&lt;/em&gt; to ensure I act in their best interest, they’re likely to follow my &lt;em&gt;recommendations&lt;/em&gt;. See how that works?&lt;/p&gt;
&lt;p&gt;Because of this, I’m acutely aware of something: &lt;em&gt;Apple products are not for everyone&lt;/em&gt;. Just like Windows isn’t the best thing for everyone, or Linux, or any other single product. People are complex beasts, and there is no one-size-fits-all product out there. My mother would have no idea how to use a Mac. My R.A. prefers one. It all comes down to how they feel comfortable interacting with computers.&lt;/p&gt;
&lt;p&gt;So rather than trusting Apple to know what’s best for &lt;em&gt;all of these people&lt;/em&gt;, I need to know what’s best for them. And to know that, I need to know what there &lt;em&gt;is&lt;/em&gt;. And how do I know that?&lt;/p&gt;
&lt;p&gt;I know that because people complain. Because people complain, I get a feel for the downsides of every product. Not all complaints are reliable and hold water, but you learn to wade through and get a feel for what’s on the money and what’s bullshit. I don’t have the time to run a Mac and a PC as my main computers, and work a lot in both. I’ve dabbled with Macs, know how to get around in them, have logged some hours on one, but I’m nowhere near as familiar with them as I am with PCs. So I rely on the reports other people make, I rely on their complaints, to fill in the gaps in my knowledge.&lt;/p&gt;
&lt;p&gt;The bottom line is, no, Steve Jobs should not bend to the demands of Apple haters, trying to make a product that makes everyone happy. There’s no such thing. But that’s not to say people should stop complaining; it’s just saying he should continue to not care.&lt;/p&gt;
&lt;p&gt;Which I’m sure he’s quite good at, as he checks his bank account balance.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;A couple days ago, I read &lt;a href=&#34;http://www.paulcarr.com&#34; title=&#34;Seriously, this guy is my hero. Mainly because he’s proof I could actually have a future.&#34;&gt;Paul Carr&lt;/a&gt;’s &lt;a href=&#34;http://techcrunch.com/2010/05/16/worse-things-happen-at-sea/&#34; title=&#34;TL;DR: shut the hell up and quit whining.&#34;&gt;thoughts&lt;/a&gt; on the growing number of complaints against Jobs, Zuckerberg, and Wales, CEOs of three of the most prominent tech companies. As I sat there reading his article, I was uncomfortably nodding my head. I was nodding because most of what he was saying (which, in case you don’t read my mouse-overs [you should], was essentially &amp;ldquo;Shut the hell up, and stop whining.&amp;rdquo;) was absolutely spot on. It was uncomfortable because I &lt;em&gt;really, really&lt;/em&gt; wanted to hate Jobs.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>What I’ve Been Up To</title>
      <link>https://paddy.carvers.com/posts/what-ive-been-up-to/</link>
      <pubDate>Wed, 12 May 2010 11:43:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/what-ive-been-up-to/</guid>
      <description>&lt;p&gt;OK, so I haven’t written here in a &lt;em&gt;little&lt;/em&gt; while. Not nearly as long as some of my writing dry spells. But I’ve been busy! Not in the “so I didn’t have time to write” way, but in the “so I have cool stuff to share with you guys” way.&lt;/p&gt;
&lt;p&gt;First of all, I started with &lt;a href=&#34;http://www.suchagit.com/&#34; title=&#34;I seem to accumulate these at an alarming pace...&#34;&gt;Yet Another Blog&lt;/a&gt;. This one is going to be mainly active this summer, and then periodically over the next school year—or that’s the plan, anyways. It details my adventures as a Googler In Training (which is a wonderful title I’ve made up for myself; it basically just means I want to work for Google really badly, and am trying to hone my skills so I can). I’ll be learning C/C++ over the summer, and enhancing my skills with Java. I’ll also be looking into learning data structures and algorithms.&lt;/p&gt;
&lt;p&gt;If any of you readers know about these kinds of things and would like to teach me even a little bit, drop me a line in the comments, or @ me (@paddycarver) on Twitter. I’ll need all the help I can get.&lt;/p&gt;
&lt;p&gt;Besides my over-publicised attempt to get hired at the &lt;em&gt;greatest company on Earth&lt;/em&gt;, I’ve been busy with finals. But those aren’t nearly as exciting, so I’m just going to skip right over that part.&lt;/p&gt;
&lt;p&gt;I’m working on a QR-based ticket site written in Java for App Engine, basically because it sounded like a cool tool. I’m focusing on keeping it simple. You log in with a Google account, all transactions are handled by Google checkout, and there are no lists of events or searches for events. It’s meant to be a tool, something people link to, not a destination of its own. The basic premise of it is that you can sell tickets to an event, and the user can print them off right from their computer. The tickets have a QR code, an ID number (in case the QR code magically fails or something, you can check from a web interface), and then whatever extra attributes you include. When the QR code is scanned, it checks if that is a valid ticket, reports that it has been used, and then displays any extra attributes, along with the buyer’s name and, optionally, picture.&lt;/p&gt;
&lt;p&gt;Again, just a really simple ticketing system for lightweight events. Also working on a way to integrate “on-site” or “at the door” tickets with the system. Think I’ve got it figured out.&lt;/p&gt;
&lt;p&gt;I may release that project as open source. Probably will, just because &lt;a href=&#34;https://paddy.carvers.com/posts/a-return-to-my-roots/&#34; title=&#34;Self-referencing. I’m so COOL.&#34;&gt;that’s how I roll&lt;/a&gt;. Look for it on &lt;a href=&#34;http://www.github.com/paddycarver&#34; title=&#34;Oh my god, a link I haven’t linked to before.&#34;&gt;Github&lt;/a&gt;, or I’ll write a post here when it’s ready to actually, y’know, be used.&lt;/p&gt;
&lt;p&gt;So there you have it. That’s what I’ve been up to, besides my normal hacking on @spaz and mundane college stuff. Oh, and super-secret Google stuff I’m not allowed to tell anyone about. Like, laws and such. Which makes me feel all warm and fuzzy.&lt;/p&gt;
&lt;p&gt;I forgot to mention that.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;OK, so I haven’t written here in a &lt;em&gt;little&lt;/em&gt; while. Not nearly as long as some of my writing dry spells. But I’ve been busy! Not in the “so I didn’t have time to write” way, but in the “so I have cool stuff to share with you guys” way.&lt;/p&gt;
&lt;p&gt;First of all, I started with &lt;a href=&#34;http://www.suchagit.com/&#34; title=&#34;I seem to accumulate these at an alarming pace...&#34;&gt;Yet Another Blog&lt;/a&gt;. This one is going to be mainly active this summer, and then periodically over the next school year—or that’s the plan, anyways. It details my adventures as a Googler In Training (which is a wonderful title I’ve made up for myself; it basically just means I want to work for Google really badly, and am trying to hone my skills so I can). I’ll be learning C/C++ over the summer, and enhancing my skills with Java. I’ll also be looking into learning data structures and algorithms.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>In Support of @Spaz</title>
      <link>https://paddy.carvers.com/posts/in-support-of-spaz/</link>
      <pubDate>Wed, 28 Apr 2010 06:22:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/in-support-of-spaz/</guid>
      <description>&lt;p&gt;I can’t believe I’m advertising &lt;em&gt;here&lt;/em&gt;. OK, yes I can, but still. Makes me feel all sorts of cheap.&lt;/p&gt;
&lt;p&gt;And yet, it feels right to give a shout-out to a group that’s already done so much for me, in a lot of ways. @funkatron and @ElizabethN are two of the nicest, friendliest people I’ve met. Despite my &lt;em&gt;disgusting&lt;/em&gt; Javascript skills and my complete lack of experience with Git and Open Source development, they’ve both welcomed me and put up with my obnoxious questions on Google Talk, IRC, Twitter, and anywhere else I can find them. @ramsey, @wlturland, and @elazar have collaborated to make me feel welcome and involved, and have proven that getting involved in Open Source is one of the best choices I could have made.&lt;/p&gt;
&lt;p&gt;Just last night, @wlturland and @elazar got into a conversation about me over Twitter based on my @spaz contribution. For the record, I’ve changed three files, added four methods, meaning support for &lt;em&gt;one feature&lt;/em&gt;. I’m not exactly writing huge chunks of their codebase. But they make me feel involved, and I find myself wanting to contribute more. This is how FOSS is done, ladies and gents. It was mildly odd, getting mentioned by two people I had only heard of in passing and never interacted with directly, but I got over it rather quickly.&lt;/p&gt;
&lt;p&gt;Really, all this post is meant to say is that @spaz is an awesome experience. May 8th is an IRC hackathon on freenode.net’s #spaz channel, with more information &lt;a href=&#34;http://groups.google.com/group/spaz-users/t/b0fd9a8cdc6dc1df&#34; title=&#34;Spaz Hackathon info&#34;&gt;here&lt;/a&gt;. I plan on joining in, and hope some new people will stop by. For a project this awesome, it’s absolutely worth it. Definitely a great project to get started in the FOSS world with.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I can’t believe I’m advertising &lt;em&gt;here&lt;/em&gt;. OK, yes I can, but still. Makes me feel all sorts of cheap.&lt;/p&gt;
&lt;p&gt;And yet, it feels right to give a shout-out to a group that’s already done so much for me, in a lot of ways. @funkatron and @ElizabethN are two of the nicest, friendliest people I’ve met. Despite my &lt;em&gt;disgusting&lt;/em&gt; Javascript skills and my complete lack of experience with Git and Open Source development, they’ve both welcomed me and put up with my obnoxious questions on Google Talk, IRC, Twitter, and anywhere else I can find them. @ramsey, @wlturland, and @elazar have collaborated to make me feel welcome and involved, and have proven that getting involved in Open Source is one of the best choices I could have made.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>I Support Twitter’s Ads, and So Should You</title>
      <link>https://paddy.carvers.com/posts/i-support-twitters-ads-and-so-should-you/</link>
      <pubDate>Mon, 26 Apr 2010 01:05:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/i-support-twitters-ads-and-so-should-you/</guid>
      <description>&lt;p&gt;Ok, so pretty much anyone who’s tech-savvy knows by now that Twitter has started “embedding” ads in its search results. Embedding is in quotes because Twitter will say it’s the wrong word. They like “promoting”.&lt;/p&gt;
&lt;p&gt;In a system it calls “promoted tweets”, it lets advertisers pay to have their tweets promoted in places like searches and in their followers streams&amp;ndash;or so far as I’ve understood, at least. Granted, I don’t understand much about this new revenue system, and I don’t really care to; an odd approach, given the post title. Let me explain.&lt;/p&gt;
&lt;p&gt;I’m not so much saying that you should support Twitter and its ads; instead, I’m saying that applications should. Twitter made the risky decision to not require its third-party clients to include the promoted tweets, and to split the revenue with them. Meaning if a developer doesn’t want to display ads in their application, they don’t have to. Which is admirable.&lt;/p&gt;
&lt;p&gt;And yet, I’m claiming that developers &lt;em&gt;should&lt;/em&gt; include these promoted tweets in their application. And here’s why: it isn’t the developer’s choice.&lt;/p&gt;
&lt;p&gt;Ads have a really negative stigma associated with them today, and for good reason: most suck and are annoying. We need to keep in mind the point of advertising, however: to make us buy things. And so long as we aren’t being &lt;em&gt;tricked&lt;/em&gt; into buying things, one would imagine that we’d actually &lt;em&gt;want&lt;/em&gt; what we’re buying. This is what the whole industry is built on. Advertising is simply the business of bringing a user and the product they want together. Everyone wins.&lt;/p&gt;
&lt;p&gt;Most users, however, don’t want to see these promoted tweets. Why? I don’t care. Honestly, it’s superfluous to my argument, a tangent that only breeds trouble. I don’t know enough about the system to argue it effectively. But I &lt;em&gt;do&lt;/em&gt; know that if I’m a user, there’s a &lt;em&gt;chance&lt;/em&gt; that I may enjoy these ads, they may work for me, or hell, that I may want to support Twitter. And why should the developer of the application I’m &lt;em&gt;choosing&lt;/em&gt; to use make that decision for me? With Twitter launching its own official clients, developers can’t afford to estrange users by making decisions for the user.&lt;/p&gt;
&lt;p&gt;So yes, I support Twitter’s Ads. I’ll be asking @funkatron if we can include them in @spaz. But, to be perfectly clear: I support including them as an option. A check box in the settings page. Let the user decide.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;Ok, so pretty much anyone who’s tech-savvy knows by now that Twitter has started “embedding” ads in its search results. Embedding is in quotes because Twitter will say it’s the wrong word. They like “promoting”.&lt;/p&gt;
&lt;p&gt;In a system it calls “promoted tweets”, it lets advertisers pay to have their tweets promoted in places like searches and in their followers streams&amp;ndash;or so far as I’ve understood, at least. Granted, I don’t understand much about this new revenue system, and I don’t really care to; an odd approach, given the post title. Let me explain.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>Beware the Pretty-Faced Girl</title>
      <link>https://paddy.carvers.com/posts/beware-the-pretty-faced-girl/</link>
      <pubDate>Mon, 19 Apr 2010 19:59:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/beware-the-pretty-faced-girl/</guid>
      <description>&lt;p&gt;It’s astonishing how quickly forget one of the most important lessons in life, just because it’s applicable somewhere unexpected: &lt;em&gt;if something seems too good to be true, it probably is&lt;/em&gt;. Why then, do we not hear words like “magical” and “revolutionary” and become suspicious, as we should, instead of fawning and yammering on excitedly about the future?&lt;/p&gt;
&lt;p&gt;Any semi-savvy computer user (or anyone with common sense, really) can tell you that no, there is no Kenyan prince willing to sign over a vast sum of money to you, if you only send him the bank fees. No, the bank didn’t make a mistake on the account you didn’t know you had, and will not mail you a large check if only you can verify your social security number.&lt;/p&gt;
&lt;p&gt;Why then, when we hear about a magical, revolutionary new tablet, do we think it comes with no strings attached? Why is it ok for us to find a brilliant product, a brilliant &lt;em&gt;free&lt;/em&gt; product, even, and think it’s not going to have &lt;em&gt;some&lt;/em&gt; sort of cost somewhere down the road? Why do we think we can make thousands, if not millions of dollars developing applications for a service, but the service (with financial woes of its own!) won’t step in to compete?&lt;/p&gt;
&lt;p&gt;We’re just used to the Web being free. We’re naturally suspicious of Open Source software (that’s changing, as of late, thank God) because we don’t understand why people would waste their time developing free, open tools they can’t profit from for our use and enjoyment. And the simple answer that &lt;em&gt;they like to&lt;/em&gt; seems out of place. And yet, when those tools are embedded in a webpage… Suddenly it’s all okay.&lt;/p&gt;
&lt;p&gt;You’ll notice I’ve strayed away from Apple’s iPad. There are plenty of posts out there on how the iPad is a “poisoned apple”. Nobody needs another one. And the iPad isn’t what got me thinking about this.&lt;/p&gt;
&lt;p&gt;I was just thinking about Tumblr, the wonderful micro-blogging site. Free to use, elegant, well-designed, and with a nasty tendency to copy features from other sites, it is the blogging tool of choice for most the hipsters I know. Just as Apple is the company of choice. And that really got me thinking: &lt;em&gt;it comes down to aesthetics.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I mean, how could something so pretty possibly be bad?&lt;/p&gt;
&lt;p&gt;And yet… Tumblr has that aforementioned nasty knack for cloning functionality. Apple has a sour relationship with developers, competitors, and really anything they decide not to like that morning. Apple’s practices are, more often than not, borderline monopolistic in nature: want to develop for your iPhone? Good. Get a Mac.&lt;/p&gt;
&lt;p&gt;There are plenty of arguments for why this is. The one that holds the most water, I believe, is controlling user experience. By making sure their products work best together, Apple can &lt;em&gt;control the user experience&lt;/em&gt;. By copying features in-house, Tumblr can &lt;em&gt;control the user experience&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When did we decide it was okay for &lt;em&gt;anyone&lt;/em&gt; to control our experience except for us? Are we really that insecure about our ability to have a good experience on our own? Imagine going to a movie, and having the cinema tell you where you were sitting, what you were drinking, what you were eating, who you were watching the movie with, &lt;em&gt;what&lt;/em&gt; movie you were watching, and what you thought of the movie, including whether you liked it or not.&lt;/p&gt;
&lt;p&gt;Why is that experience not okay to control? Doesn’t Regal know best? If Apple went into the cinema business, would it be okay for them to do that?&lt;/p&gt;
&lt;p&gt;We really need to consider the types of businesses we’re supporting and condoning, all because they have a pretty face and control our experience for us.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;It’s astonishing how quickly forget one of the most important lessons in life, just because it’s applicable somewhere unexpected: &lt;em&gt;if something seems too good to be true, it probably is&lt;/em&gt;. Why then, do we not hear words like “magical” and “revolutionary” and become suspicious, as we should, instead of fawning and yammering on excitedly about the future?&lt;/p&gt;
&lt;p&gt;Any semi-savvy computer user (or anyone with common sense, really) can tell you that no, there is no Kenyan prince willing to sign over a vast sum of money to you, if you only send him the bank fees. No, the bank didn’t make a mistake on the account you didn’t know you had, and will not mail you a large check if only you can verify your social security number.&lt;/p&gt;</carvers:summary>
    </item>
    
    <item>
      <title>A Return to My Roots</title>
      <link>https://paddy.carvers.com/posts/a-return-to-my-roots/</link>
      <pubDate>Thu, 15 Apr 2010 13:20:00 +0000</pubDate>
      
      <guid>https://paddy.carvers.com/posts/a-return-to-my-roots/</guid>
      <description>&lt;p&gt;I should be writing a paper right now. Two, actually. But a book review of &lt;a href=&#34;http://www.amazon.com/Engineers-Scientists-Iconoclasts-Programmers-Revolution/dp/0465042260/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1271365342&amp;amp;sr=8-1&#34; title=&#34;Surprisingly, very inspiring and informational. I recommend it. Maybe not highly, but still a recommended read.&#34;&gt;Go To&lt;/a&gt; is nowhere near as interesting, and a response to &lt;a href=&#34;http://www.amazon.com/Shameful-Flight-Years-British-Empire/dp/0195393945/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1271365296&amp;amp;sr=8-1&#34; title=&#34;It was a terrible book. Don’t read it.&#34;&gt;Shameful Flight&lt;/a&gt; is far too tedious. So, in a true return to my past, I’m writing a blog post instead of worrying about schoolwork. Such is life.&lt;/p&gt;
&lt;p&gt;I started my life as a hacker playing with JavaScript on &lt;a href=&#34;http://www.proboards.com&#34; title=&#34;It’s still a shame to admit this.&#34;&gt;ProBoards&lt;/a&gt;. But my true immersion into the world of hacking and programming came when I took up Linux, inspired by my programming mentor Bob Duke, and formed the Linux Campaign in my high school. As a LUG, the Linux Campaign was a bust. But it was fun. And I found something out:&lt;/p&gt;
&lt;p&gt;I really enjoy Open Source software.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://www.gnu.org/licenses/gpl.html&#34; title=&#34;I’m liberal. I’m the first to admit it.&#34;&gt;GPL&lt;/a&gt;, the &lt;a href=&#34;http://en.wikipedia.org/wiki/MIT_License&#34; title=&#34;Sorry, only a Wikipedia page.&#34;&gt;MIT&lt;/a&gt;, the &lt;a href=&#34;http://www.creativecommons.org&#34; title=&#34;Moving away from my ideals, but still wonderful.&#34;&gt;Creative Commons&lt;/a&gt;… these are my licenses. &lt;a href=&#34;http://www.free-culture.cc&#34; title=&#34;The phenomenal treatise by Lawrence Lessig. Go read it now. Even if you already have. NOW.&#34;&gt;Free Culture&lt;/a&gt; is my bible. And yet… in the past few years, I’ve been drifting away from &lt;!-- raw HTML omitted --&gt;FOSS&lt;!-- raw HTML omitted --&gt;. Not intentionally, and not significantly. I still prefer FOSS products, when I can find them. I still use &lt;a href=&#34;http://www.cakephp.org&#34; title=&#34;OK, in honesty, I’ve been drifting more towards Python lately. I can’t help it. It’s prettier.&#34;&gt;CakePHP&lt;/a&gt; and &lt;a href=&#34;http://www.djangoproject.com&#34; title=&#34;Even if I am still an amateur.&#34;&gt;Django&lt;/a&gt; to make stuff, and still don’t care if other people use my stuff.&lt;/p&gt;
&lt;p&gt;But I guess that’s the issue. I don’t care.&lt;/p&gt;
&lt;p&gt;Part of the culture surrounding FOSS is the &lt;em&gt;desire&lt;/em&gt; to share. The &lt;em&gt;desire&lt;/em&gt; to help others use your work, to contribute back to the community. And the community gives me so much, it’s hard to justify not giving back. To be honest, for the last year or two, I’ve been a leech on the FOSS community. I’ve been busy, yes, but so are @funkatron, and @felixge, and all the other FOSS contributors that I admire and strive to emulate. And I’d like to change that.&lt;/p&gt;
&lt;p&gt;I’m starting this summer by applying to &lt;a href=&#34;http://socghop.appspot.com&#34; title=&#34;Google Summer of Code&#34;&gt;GSoC&lt;/a&gt;. If accepted, I’ll be working on either &lt;a href=&#34;http://code.google.com/p/soc&#34; title=&#34;The Spice of Creation&#34;&gt;Melange&lt;/a&gt; or &lt;a href=&#34;http://www.bigbluebutton.org&#34; title=&#34;Very relevant to my actual JOB. So everyone wins!&#34;&gt;Big Blue Button&lt;/a&gt; for the summer, contributing Open Source Code. Last night, I also attended a @spaz meeting, and signed up as a contributer to the wonderful FOSS.&lt;/p&gt;
&lt;p&gt;So here it is, FOSS community: my apology to you. And my promise to make amends.&lt;/p&gt;
</description>
      <carvers:summary>&lt;p&gt;I should be writing a paper right now. Two, actually. But a book review of &lt;a href=&#34;http://www.amazon.com/Engineers-Scientists-Iconoclasts-Programmers-Revolution/dp/0465042260/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1271365342&amp;amp;sr=8-1&#34; title=&#34;Surprisingly, very inspiring and informational. I recommend it. Maybe not highly, but still a recommended read.&#34;&gt;Go To&lt;/a&gt; is nowhere near as interesting, and a response to &lt;a href=&#34;http://www.amazon.com/Shameful-Flight-Years-British-Empire/dp/0195393945/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1271365296&amp;amp;sr=8-1&#34; title=&#34;It was a terrible book. Don’t read it.&#34;&gt;Shameful Flight&lt;/a&gt; is far too tedious. So, in a true return to my past, I’m writing a blog post instead of worrying about schoolwork. Such is life.&lt;/p&gt;</carvers:summary>
    </item>
    
  </channel>
</rss>
